diff mbox

[05/13] 9p: introduce ftruncate file op

Message ID 146702049783.5764.10514201575160012308.stgit@bahia.lan
State New
Headers show

Commit Message

Greg Kurz June 27, 2016, 9:41 a.m. UTC
This patch adds a ftruncate operation to the fsdev API. It is then used if
we have an open fd, so that ftruncate() in the guest is functional even
if the file was unlinked or its file permissions would cause truncate() to
fail.

Signed-off-by: Greg Kurz <groug@kaod.org>
---
 fsdev/file-op-9p.h  |    1 +
 hw/9pfs/9p-handle.c |   15 +++++++++++++++
 hw/9pfs/9p-local.c  |   15 +++++++++++++++
 hw/9pfs/9p-proxy.c  |   14 ++++++++++++++
 hw/9pfs/9p-synth.c  |    8 ++++++++
 hw/9pfs/9p.c        |   17 +++++++++++++++--
 hw/9pfs/cofs.c      |   18 ++++++++++++++++++
 hw/9pfs/coth.h      |    1 +
 8 files changed, 87 insertions(+), 2 deletions(-)
diff mbox

Patch

diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 55614949740d..930bcc623f8b 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -140,6 +140,7 @@  struct FileOperations
     int (*renameat)(FsContext *ctx, V9fsPath *olddir, const char *old_name,
                     V9fsPath *newdir, const char *new_name);
     int (*unlinkat)(FsContext *ctx, V9fsPath *dir, const char *name, int flags);
+    int (*ftruncate)(FsContext *, int, V9fsFidOpenState *, off_t);
     void *opaque;
 };
 
diff --git a/hw/9pfs/9p-handle.c b/hw/9pfs/9p-handle.c
index 2e741535df24..e48e48a7145d 100644
--- a/hw/9pfs/9p-handle.c
+++ b/hw/9pfs/9p-handle.c
@@ -349,6 +349,20 @@  static int handle_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
     return ret;
 }
 
+static int handle_ftruncate(FsContext *ctx, int fid_type, V9fsFidOpenState *fs,
+                            off_t size)
+{
+    int fd;
+
+    if (fid_type == P9_FID_DIR) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    fd = v9fs_get_fd_fid(fid_type, fs);
+    return ftruncate(fd, size);
+}
+
 static int handle_rename(FsContext *ctx, const char *oldpath,
                          const char *newpath)
 {
@@ -696,4 +710,5 @@  FileOperations handle_ops = {
     .name_to_path = handle_name_to_path,
     .renameat     = handle_renameat,
     .unlinkat     = handle_unlinkat,
+    .ftruncate    = handle_ftruncate,
 };
diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
index 6804c6558b8e..b4c31c49da69 100644
--- a/hw/9pfs/9p-local.c
+++ b/hw/9pfs/9p-local.c
@@ -874,6 +874,20 @@  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;
+
+    if (fid_type == P9_FID_DIR) {
+        errno = EINVAL;
+        return -1;
+    }
+
+    fd = v9fs_get_fd_fid(fid_type, fs);
+    return ftruncate(fd, size);
+}
+
 static int local_rename(FsContext *ctx, const char *oldpath,
                         const char *newpath)
 {
@@ -1275,4 +1289,5 @@  FileOperations local_ops = {
     .name_to_path = local_name_to_path,
     .renameat  = local_renameat,
     .unlinkat = local_unlinkat,
+    .ftruncate = local_ftruncate,
 };
diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c
index d78ff7b1bd8d..9abcc201bd67 100644
--- a/hw/9pfs/9p-proxy.c
+++ b/hw/9pfs/9p-proxy.c
@@ -864,6 +864,19 @@  static int proxy_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
     return 0;
 }
 
+static int proxy_ftruncate(FsContext *ctx, int fid_type, V9fsFidOpenState *fs,
+                           off_t size)
+{
+    int fd;
+
+    if (fid_type == P9_FID_DIR) {
+        return -EINVAL;
+    }
+
+    fd = v9fs_get_fd_fid(fid_type, fs);
+    return ftruncate(fd, size);
+}
+
 static int proxy_rename(FsContext *ctx, const char *oldpath,
                         const char *newpath)
 {
@@ -1207,4 +1220,5 @@  FileOperations proxy_ops = {
     .name_to_path = proxy_name_to_path,
     .renameat     = proxy_renameat,
     .unlinkat     = proxy_unlinkat,
+    .ftruncate    = proxy_ftruncate,
 };
diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c
index 4b6d4e6a3f1c..70c71ce305c9 100644
--- a/hw/9pfs/9p-synth.c
+++ b/hw/9pfs/9p-synth.c
@@ -344,6 +344,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;
@@ -566,4 +573,5 @@  FileOperations synth_ops = {
     .name_to_path = synth_name_to_path,
     .renameat     = synth_renameat,
     .unlinkat     = synth_unlinkat,
+    .ftruncate    = synth_ftruncate,
 };
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 3301cef0980d..3aa4c8e22ed9 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -1181,6 +1181,19 @@  out_nofid:
     pdu_complete(pdu, retval);
 }
 
+static int v9fs_do_truncate(V9fsPDU *pdu, V9fsFidState *fidp, off_t size)
+{
+    int err;
+
+    if (fid_has_file(fidp)) {
+        err = v9fs_co_ftruncate(pdu, fidp, size);
+    } else {
+        err = v9fs_co_truncate(pdu, &fidp->path, size);
+    }
+
+    return err;
+}
+
 /* Attribute flags */
 #define P9_ATTR_MODE       (1 << 0)
 #define P9_ATTR_UID        (1 << 1)
@@ -1266,7 +1279,7 @@  static void v9fs_setattr(void *opaque)
         }
     }
     if (v9iattr.valid & (P9_ATTR_SIZE)) {
-        err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
+        err = v9fs_do_truncate(pdu, fidp, v9iattr.size);
         if (err < 0) {
             goto out;
         }
@@ -2754,7 +2767,7 @@  static void v9fs_wstat(void *opaque)
         }
     }
     if (v9stat.length != -1) {
-        err = v9fs_co_truncate(pdu, &fidp->path, v9stat.length);
+        err = v9fs_do_truncate(pdu, fidp, v9stat.length);
         if (err < 0) {
             goto out;
         }
diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c
index 70f584fcbd21..969c24730cb0 100644
--- a/hw/9pfs/cofs.c
+++ b/hw/9pfs/cofs.c
@@ -177,6 +177,24 @@  int v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size)
     return err;
 }
 
+int 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 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 5b02a63ad9fd..4f493ad29ec4 100644
--- a/hw/9pfs/coth.h
+++ b/hw/9pfs/coth.h
@@ -94,5 +94,6 @@  extern int v9fs_co_name_to_path(V9fsPDU *, V9fsPath *,
                                 const char *, V9fsPath *);
 extern int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t,
                           V9fsStatDotl *v9stat);
+extern int v9fs_co_ftruncate(V9fsPDU *, V9fsFidState *, off_t);
 
 #endif