From: Miklos Szeredi Date: Wed, 10 Nov 2010 10:41:21 +0000 (+0100) Subject: add write_buf method to high level API X-Git-Tag: fuse_2_9_0~85 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=df31f2b11efd0d024f12c7035ab0d3646ad9c7c6;p=qemu-gpiodev%2Flibfuse.git add write_buf method to high level API Add new write_buf() method to the highlevel API. Similarly to the lowlevel write_buf() method, this allows implementing zero copy writes. --- diff --git a/ChangeLog b/ChangeLog index 52a000a..9057c9a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2010-11-10 Miklos Szeredi + + * 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 * Fix check for read-only fs in mtab update diff --git a/include/fuse.h b/include/fuse.h index 51ccb89..c2708cf 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -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, diff --git a/lib/fuse.c b/lib/fuse.c index 3793233..9e5c49b 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -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, diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript index da1cd90..7c754e9 100644 --- a/lib/fuse_versionscript +++ b/lib/fuse_versionscript @@ -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; diff --git a/lib/modules/iconv.c b/lib/modules/iconv.c index a03a587..fa777a7 100644 --- a/lib/modules/iconv.c +++ b/lib/modules/iconv.c @@ -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, diff --git a/lib/modules/subdir.c b/lib/modules/subdir.c index b989b53..788765c 100644 --- a/lib/modules/subdir.c +++ b/lib/modules/subdir.c @@ -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,