aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Kurz <groug@kaod.org>2025-03-12 16:29:29 +0100
committerChristian Schoenebeck <qemu_oss@crudebyte.com>2025-05-05 11:28:29 +0200
commit0c798dd52355f3489b29bba0dfd7df0e24cfa1dd (patch)
treed563a14ff4c72b91fa2e0ab4865827c8453a4598
parentf2bb367d2b265c6c0ead1e0d4a8f7c43310b3107 (diff)
downloadqemu-0c798dd52355f3489b29bba0dfd7df0e24cfa1dd.zip
qemu-0c798dd52355f3489b29bba0dfd7df0e24cfa1dd.tar.gz
qemu-0c798dd52355f3489b29bba0dfd7df0e24cfa1dd.tar.bz2
9pfs: Introduce ftruncate file op
Add an ftruncate operation to the fs driver and use if when a fid has a valid file descriptor. This is required to support more cases where the client wants to do an action on an unlinked file which it still has an open file decriptor for. Only 9P2000.L was considered. Signed-off-by: Greg Kurz <groug@kaod.org> Reviewed-by: Christian Schoenebeck <qemu_oss@crudebyte.com> Message-Id: <20250312152933.383967-4-groug@kaod.org> Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com>
-rw-r--r--fsdev/file-op-9p.h2
-rw-r--r--hw/9pfs/9p-local.c9
-rw-r--r--hw/9pfs/9p-synth.c8
-rw-r--r--hw/9pfs/9p.c6
-rw-r--r--hw/9pfs/cofs.c18
-rw-r--r--hw/9pfs/coth.h2
6 files changed, 44 insertions, 1 deletions
diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index b815cea4..26ba143 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -152,6 +152,8 @@ struct FileOperations {
int (*fstat)(FsContext *, int, V9fsFidOpenState *, struct stat *);
int (*rename)(FsContext *, const char *, const char *);
int (*truncate)(FsContext *, V9fsPath *, off_t);
+ int (*ftruncate)(FsContext *ctx, int fid_type, V9fsFidOpenState *fs,
+ off_t size);
int (*fsync)(FsContext *, int, V9fsFidOpenState *, int);
int (*statfs)(FsContext *s, V9fsPath *path, struct statfs *stbuf);
ssize_t (*lgetxattr)(FsContext *, V9fsPath *,
diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
index b161322..0b33da8 100644
--- a/hw/9pfs/9p-local.c
+++ b/hw/9pfs/9p-local.c
@@ -1042,6 +1042,14 @@ static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
return ret;
}
+static int local_ftruncate(FsContext *ctx, int fid_type, V9fsFidOpenState *fs,
+ off_t size)
+{
+ int fd = local_fid_fd(fid_type, fs);
+
+ return ftruncate(fd, size);
+}
+
static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
{
char *dirpath = g_path_get_dirname(fs_path->data);
@@ -1617,4 +1625,5 @@ FileOperations local_ops = {
.renameat = local_renameat,
.unlinkat = local_unlinkat,
.has_valid_file_handle = local_has_valid_file_handle,
+ .ftruncate = local_ftruncate,
};
diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c
index be0492b..3d28afc 100644
--- a/hw/9pfs/9p-synth.c
+++ b/hw/9pfs/9p-synth.c
@@ -356,6 +356,13 @@ static int synth_truncate(FsContext *ctx, V9fsPath *path, off_t offset)
return -1;
}
+static int synth_ftruncate(FsContext *ctx, int fid_type, V9fsFidOpenState *fs,
+ off_t size)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
static int synth_chmod(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
{
errno = EPERM;
@@ -656,4 +663,5 @@ FileOperations synth_ops = {
.renameat = synth_renameat,
.unlinkat = synth_unlinkat,
.has_valid_file_handle = synth_has_valid_file_handle,
+ .ftruncate = synth_ftruncate,
};
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 4586822..c96f2d2 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -1752,7 +1752,11 @@ static void coroutine_fn v9fs_setattr(void *opaque)
}
}
if (v9iattr.valid & (P9_ATTR_SIZE)) {
- err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
+ if (fid_has_valid_file_handle(pdu->s, fidp)) {
+ err = v9fs_co_ftruncate(pdu, fidp, v9iattr.size);
+ } else {
+ err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
+ }
if (err < 0) {
goto out;
}
diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
index 67e3ae5..893466f 100644
--- a/hw/9pfs/cofs.c
+++ b/hw/9pfs/cofs.c
@@ -184,6 +184,24 @@ int coroutine_fn v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size)
return err;
}
+int coroutine_fn v9fs_co_ftruncate(V9fsPDU *pdu, V9fsFidState *fidp, off_t size)
+{
+ int err;
+ V9fsState *s = pdu->s;
+
+ if (v9fs_request_cancelled(pdu)) {
+ return -EINTR;
+ }
+ v9fs_co_run_in_worker(
+ {
+ err = s->ops->ftruncate(&s->ctx, fidp->fid_type, &fidp->fs, size);
+ if (err < 0) {
+ err = -errno;
+ }
+ });
+ return err;
+}
+
int coroutine_fn v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp,
V9fsString *name, uid_t uid, gid_t gid,
dev_t dev, mode_t mode, struct stat *stbuf)
diff --git a/hw/9pfs/coth.h b/hw/9pfs/coth.h
index 2c54249..62e922d 100644
--- a/hw/9pfs/coth.h
+++ b/hw/9pfs/coth.h
@@ -73,6 +73,8 @@ int coroutine_fn v9fs_co_chmod(V9fsPDU *, V9fsPath *, mode_t);
int coroutine_fn v9fs_co_utimensat(V9fsPDU *, V9fsPath *, struct timespec [2]);
int coroutine_fn v9fs_co_chown(V9fsPDU *, V9fsPath *, uid_t, gid_t);
int coroutine_fn v9fs_co_truncate(V9fsPDU *, V9fsPath *, off_t);
+int coroutine_fn v9fs_co_ftruncate(V9fsPDU *pdu, V9fsFidState *fidp,
+ off_t size);
int coroutine_fn v9fs_co_llistxattr(V9fsPDU *, V9fsPath *, void *, size_t);
int coroutine_fn v9fs_co_lgetxattr(V9fsPDU *, V9fsPath *,
V9fsString *, void *, size_t);