add write_buf method to high level API
authorMiklos Szeredi <miklos@szeredi.hu>
Wed, 10 Nov 2010 10:41:21 +0000 (11:41 +0100)
committerMiklos Szeredi <mszeredi@suse.cz>
Wed, 10 Nov 2010 10:41:21 +0000 (11:41 +0100)
Add new write_buf() method to the highlevel API.  Similarly to the
lowlevel write_buf() method, this allows implementing zero copy
writes.

ChangeLog
include/fuse.h
lib/fuse.c
lib/fuse_versionscript
lib/modules/iconv.c
lib/modules/subdir.c

index 52a000a9ffe3b7ae3b84499a3a2829415cdd26d5..9057c9ae8ab01f670086878424e533014b09832c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2010-11-10  Miklos Szeredi <miklos@szeredi.hu>
+
+       * Add new write_buf() method to the highlevel API.  Similarly to
+       the lowlevel write_buf() method, this allows implementing zero
+       copy writes.
+
 2010-11-08  Miklos Szeredi <miklos@szeredi.hu>
 
        * Fix check for read-only fs in mtab update
index 51ccb89b4347dbbf11229a6bf6a6ebc19fc1f7e5..c2708cfb9fb55dba20840398190acac8fb2c8557 100644 (file)
@@ -513,6 +513,17 @@ struct fuse_operations {
         */
        int (*poll) (const char *, struct fuse_file_info *,
                     struct fuse_pollhandle *ph, unsigned *reventsp);
+
+       /** Write contents of buffer to an open file
+        *
+        * Similar to the write() method, but data is supplied in a
+        * generic buffer.  Use fuse_buf_copy() to transfer data to
+        * the destination.
+        *
+        * Introduced in version 2.9
+        */
+       int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off,
+                         struct fuse_file_info *);
 };
 
 /** Extra context that may be needed by some filesystems
@@ -726,6 +737,9 @@ int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
                 off_t off, struct fuse_file_info *fi);
 int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf,
                  size_t size, off_t off, struct fuse_file_info *fi);
+int fuse_fs_write_buf(struct fuse_fs *fs, const char *path,
+                     struct fuse_bufvec *buf, off_t off,
+                     struct fuse_file_info *fi);
 int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
                  struct fuse_file_info *fi);
 int fuse_fs_flush(struct fuse_fs *fs, const char *path,
index 37932332ab2b3546f50ad6f8849a6f7b02952614..9e5c49b3243a75dbc78d0529a1e79cd09e26a1e3 100644 (file)
@@ -1273,23 +1273,55 @@ int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
        }
 }
 
-int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf,
-                 size_t size, off_t off, struct fuse_file_info *fi)
+int fuse_fs_write_buf(struct fuse_fs *fs, const char *path,
+                     struct fuse_bufvec *buf, off_t off,
+                     struct fuse_file_info *fi)
 {
        fuse_get_context()->private_data = fs->user_data;
-       if (fs->op.write) {
+       if (fs->op.write_buf || fs->op.write) {
                int res;
+               size_t size = fuse_buf_size(buf);
 
+               assert(buf->idx = 0 && buf->off == 0);
                if (fs->debug)
                        fprintf(stderr,
-                               "write%s[%llu] %lu bytes to %llu flags: 0x%x\n",
+                               "write%s[%llu] %zu bytes to %llu flags: 0x%x\n",
                                fi->writepage ? "page" : "",
                                (unsigned long long) fi->fh,
-                               (unsigned long) size, (unsigned long long) off,
+                               size,
+                               (unsigned long long) off,
                                fi->flags);
 
-               res = fs->op.write(path, buf, size, off, fi);
+               if (fs->op.write_buf) {
+                       res = fs->op.write_buf(path, buf, off, fi);
+               } else {
+                       void *mem = NULL;
+                       struct fuse_buf *flatbuf;
+                       struct fuse_bufvec tmp = FUSE_BUFVEC_INIT(size);
+
+                       if (buf->count == 1 &&
+                           !(buf->buf[0].flags & FUSE_BUF_IS_FD)) {
+                               flatbuf = &buf->buf[0];
+                       } else {
+                               mem = malloc(size);
+                               if (mem == NULL)
+                                       goto out;
+
+                               tmp.buf[0].mem = mem;
+                               res = fuse_buf_copy(&tmp, buf, 0);
+                               if (res <= 0)
+                                       goto out_free;
 
+                               tmp.buf[0].size = res;
+                               flatbuf = &tmp.buf[0];
+                       }
+
+                       res = fs->op.write(path, flatbuf->mem, flatbuf->size,
+                                          off, fi);
+out_free:
+                       free(mem);
+               }
+out:
                if (fs->debug && res >= 0)
                        fprintf(stderr, "   write%s[%llu] %u bytes to %llu\n",
                                fi->writepage ? "page" : "",
@@ -1304,6 +1336,16 @@ int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf,
        }
 }
 
+int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *mem,
+                 size_t size, off_t off, struct fuse_file_info *fi)
+{
+       struct fuse_bufvec bufv = FUSE_BUFVEC_INIT(size);
+
+       bufv.buf[0].mem = (void *) mem;
+
+       return fuse_fs_write_buf(fs, path, &bufv, off, fi);
+}
+
 int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
                  struct fuse_file_info *fi)
 {
@@ -1946,6 +1988,8 @@ static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
 void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn)
 {
        fuse_get_context()->private_data = fs->user_data;
+       if (!fs->op.write_buf)
+               conn->want &= ~FUSE_CAP_SPLICE_READ;
        if (fs->op.init)
                fs->user_data = fs->op.init(conn);
 }
@@ -2588,8 +2632,9 @@ static void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size,
        free(buf);
 }
 
-static void fuse_lib_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
-                          size_t size, off_t off, struct fuse_file_info *fi)
+static void fuse_lib_write_buf(fuse_req_t req, fuse_ino_t ino,
+                              struct fuse_bufvec *buf, off_t off,
+                              struct fuse_file_info *fi)
 {
        struct fuse *f = req_fuse_prepare(req);
        char *path;
@@ -2600,7 +2645,7 @@ static void fuse_lib_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
                struct fuse_intr_data d;
 
                fuse_prepare_interrupt(f, req, &d);
-               res = fuse_fs_write(f->fs, path, buf, size, off, fi);
+               res = fuse_fs_write_buf(f->fs, path, buf, off, fi);
                fuse_finish_interrupt(f, req, &d);
                free_path(f, ino, path);
        }
@@ -3391,7 +3436,7 @@ static struct fuse_lowlevel_ops fuse_path_ops = {
        .create = fuse_lib_create,
        .open = fuse_lib_open,
        .read = fuse_lib_read,
-       .write = fuse_lib_write,
+       .write_buf = fuse_lib_write_buf,
        .flush = fuse_lib_flush,
        .release = fuse_lib_release,
        .fsync = fuse_lib_fsync,
index da1cd90893f833dd8a7589d865ef1073485d2035..7c754e97ca4e004aac0f778084654bd41a252682 100644 (file)
@@ -184,6 +184,7 @@ FUSE_2.9 {
        global:
                fuse_buf_copy;
                fuse_buf_size;
+               fuse_fs_write_buf;
                fuse_lowlevel_notify_retrieve;
                fuse_lowlevel_notify_store;
                fuse_reply_data;
index a03a587e3be903189615fc53797218bb838d9e75..fa777a7cc9e170d8e3df0c24a660062f315fbd4f 100644 (file)
@@ -410,14 +410,14 @@ static int iconv_read(const char *path, char *buf, size_t size, off_t offset,
        return err;
 }
 
-static int iconv_write(const char *path, const char *buf, size_t size,
-                      off_t offset, struct fuse_file_info *fi)
+static int iconv_write_buf(const char *path, struct fuse_bufvec *buf,
+                          off_t offset, struct fuse_file_info *fi)
 {
        struct iconv *ic = iconv_get();
        char *newpath;
        int err = iconv_convpath(ic, path, &newpath, 0);
        if (!err) {
-               err = fuse_fs_write(ic->next, newpath, buf, size, offset, fi);
+               err = fuse_fs_write_buf(ic->next, newpath, buf, offset, fi);
                free(newpath);
        }
        return err;
@@ -605,7 +605,7 @@ static struct fuse_operations iconv_oper = {
        .create         = iconv_create,
        .open           = iconv_open_file,
        .read           = iconv_read,
-       .write          = iconv_write,
+       .write_buf      = iconv_write_buf,
        .statfs         = iconv_statfs,
        .flush          = iconv_flush,
        .release        = iconv_release,
index b989b5331ecb07eaf85fd00f7445f77e5c04578e..788765c602551a880feab133b61d5fad581b6086 100644 (file)
@@ -397,14 +397,14 @@ static int subdir_read(const char *path, char *buf, size_t size, off_t offset,
        return err;
 }
 
-static int subdir_write(const char *path, const char *buf, size_t size,
+static int subdir_write_buf(const char *path, struct fuse_bufvec *buf,
                        off_t offset, struct fuse_file_info *fi)
 {
        struct subdir *d = subdir_get();
        char *newpath;
        int err = subdir_addpath(d, path, &newpath);
        if (!err) {
-               err = fuse_fs_write(d->next, newpath, buf, size, offset, fi);
+               err = fuse_fs_write_buf(d->next, newpath, buf, offset, fi);
                free(newpath);
        }
        return err;
@@ -588,7 +588,7 @@ static struct fuse_operations subdir_oper = {
        .create         = subdir_create,
        .open           = subdir_open,
        .read           = subdir_read,
-       .write          = subdir_write,
+       .write_buf      = subdir_write_buf,
        .statfs         = subdir_statfs,
        .flush          = subdir_flush,
        .release        = subdir_release,