aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2010-11-10 11:41:21 +0100
committerMiklos Szeredi <mszeredi@suse.cz>2010-11-10 11:41:21 +0100
commit63322038855660cc106c8f87a2ae42bcac37a4af (patch)
tree36445b71a1cc00b5f30e3f1da4b08d7fea644caa /lib
parentdf31f2b11efd0d024f12c7035ab0d3646ad9c7c6 (diff)
downloadlibfuse-63322038855660cc106c8f87a2ae42bcac37a4af.tar.gz
add read_buf method to high level API
Add a new read_buf() method to the highlevel API. This allows returning a generic buffer from the read method, which in turn allows zero copy reads.
Diffstat (limited to 'lib')
-rw-r--r--lib/fuse.c96
-rw-r--r--lib/fuse_versionscript1
-rw-r--r--lib/modules/iconv.c8
-rw-r--r--lib/modules/subdir.c8
4 files changed, 82 insertions, 31 deletions
diff --git a/lib/fuse.c b/lib/fuse.c
index 9e5c49b..4d24aea 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -1244,35 +1244,90 @@ int fuse_fs_open(struct fuse_fs *fs, const char *path,
}
}
-int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
- off_t off, struct fuse_file_info *fi)
+static void fuse_free_buf(struct fuse_bufvec *buf)
+{
+ if (buf != NULL) {
+ size_t i;
+
+ for (i = 0; i < buf->count; i++)
+ free(buf->buf[i].mem);
+ free(buf);
+ }
+}
+
+int fuse_fs_read_buf(struct fuse_fs *fs, const char *path,
+ struct fuse_bufvec **bufp, size_t size, off_t off,
+ struct fuse_file_info *fi)
{
fuse_get_context()->private_data = fs->user_data;
- if (fs->op.read) {
+ if (fs->op.read || fs->op.read_buf) {
int res;
if (fs->debug)
fprintf(stderr,
- "read[%llu] %lu bytes from %llu flags: 0x%x\n",
+ "read[%llu] %zu bytes from %llu flags: 0x%x\n",
(unsigned long long) fi->fh,
- (unsigned long) size, (unsigned long long) off,
- fi->flags);
+ size, (unsigned long long) off, fi->flags);
+
+ if (fs->op.read_buf) {
+ res = fs->op.read_buf(path, bufp, size, off, fi);
+ } else {
+ struct fuse_bufvec *buf;
+ void *mem;
- res = fs->op.read(path, buf, size, off, fi);
+ buf = malloc(sizeof(struct fuse_bufvec));
+ if (buf == NULL)
+ return -ENOMEM;
+
+ mem = malloc(size);
+ if (mem == NULL) {
+ free(buf);
+ return -ENOMEM;
+ }
+ *buf = FUSE_BUFVEC_INIT(size);
+ buf->buf[0].mem = mem;
+ *bufp = buf;
+
+ res = fs->op.read(path, mem, size, off, fi);
+ if (res >= 0)
+ buf->buf[0].size = res;
+ }
if (fs->debug && res >= 0)
- fprintf(stderr, " read[%llu] %u bytes from %llu\n",
- (unsigned long long) fi->fh, res,
+ fprintf(stderr, " read[%llu] %zu bytes from %llu\n",
+ (unsigned long long) fi->fh,
+ fuse_buf_size(*bufp),
(unsigned long long) off);
- if (res > (int) size)
+ if (res >= 0 && fuse_buf_size(*bufp) > (int) size)
fprintf(stderr, "fuse: read too many bytes\n");
- return res;
+ if (res < 0)
+ return res;
+
+ return 0;
} else {
return -ENOSYS;
}
}
+int fuse_fs_read(struct fuse_fs *fs, const char *path, char *mem, size_t size,
+ off_t off, struct fuse_file_info *fi)
+{
+ int res;
+ struct fuse_bufvec *buf = NULL;
+
+ res = fuse_fs_read_buf(fs, path, &buf, size, off, fi);
+ if (res == 0) {
+ struct fuse_bufvec dst = FUSE_BUFVEC_INIT(size);
+
+ dst.buf[0].mem = mem;
+ res = fuse_buf_copy(&dst, buf, 0);
+ }
+ fuse_free_buf(buf);
+
+ return res;
+}
+
int fuse_fs_write_buf(struct fuse_fs *fs, const char *path,
struct fuse_bufvec *buf, off_t off,
struct fuse_file_info *fi)
@@ -1282,7 +1337,7 @@ int fuse_fs_write_buf(struct fuse_fs *fs, const char *path,
int res;
size_t size = fuse_buf_size(buf);
- assert(buf->idx = 0 && buf->off == 0);
+ assert(buf->idx == 0 && buf->off == 0);
if (fs->debug)
fprintf(stderr,
"write%s[%llu] %zu bytes to %llu flags: 0x%x\n",
@@ -1303,6 +1358,7 @@ int fuse_fs_write_buf(struct fuse_fs *fs, const char *path,
!(buf->buf[0].flags & FUSE_BUF_IS_FD)) {
flatbuf = &buf->buf[0];
} else {
+ res = -ENOMEM;
mem = malloc(size);
if (mem == NULL)
goto out;
@@ -2604,32 +2660,26 @@ static void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size,
off_t off, struct fuse_file_info *fi)
{
struct fuse *f = req_fuse_prepare(req);
+ struct fuse_bufvec *buf = NULL;
char *path;
- char *buf;
int res;
- buf = (char *) malloc(size);
- if (buf == NULL) {
- reply_err(req, -ENOMEM);
- return;
- }
-
res = get_path_nullok(f, ino, &path);
if (res == 0) {
struct fuse_intr_data d;
fuse_prepare_interrupt(f, req, &d);
- res = fuse_fs_read(f->fs, path, buf, size, off, fi);
+ res = fuse_fs_read_buf(f->fs, path, &buf, size, off, fi);
fuse_finish_interrupt(f, req, &d);
free_path(f, ino, path);
}
- if (res >= 0)
- fuse_reply_buf(req, buf, res);
+ if (res == 0)
+ fuse_reply_data(req, buf, FUSE_BUF_SPLICE_MOVE);
else
reply_err(req, res);
- free(buf);
+ fuse_free_buf(buf);
}
static void fuse_lib_write_buf(fuse_req_t req, fuse_ino_t ino,
diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript
index 7c754e9..4694575 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_read_buf;
fuse_fs_write_buf;
fuse_lowlevel_notify_retrieve;
fuse_lowlevel_notify_store;
diff --git a/lib/modules/iconv.c b/lib/modules/iconv.c
index fa777a7..ca62c82 100644
--- a/lib/modules/iconv.c
+++ b/lib/modules/iconv.c
@@ -397,14 +397,14 @@ static int iconv_open_file(const char *path, struct fuse_file_info *fi)
return err;
}
-static int iconv_read(const char *path, char *buf, size_t size, off_t offset,
- struct fuse_file_info *fi)
+static int iconv_read_buf(const char *path, struct fuse_bufvec **bufp,
+ size_t size, 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_read(ic->next, newpath, buf, size, offset, fi);
+ err = fuse_fs_read_buf(ic->next, newpath, bufp, size, offset, fi);
free(newpath);
}
return err;
@@ -604,7 +604,7 @@ static struct fuse_operations iconv_oper = {
.utimens = iconv_utimens,
.create = iconv_create,
.open = iconv_open_file,
- .read = iconv_read,
+ .read_buf = iconv_read_buf,
.write_buf = iconv_write_buf,
.statfs = iconv_statfs,
.flush = iconv_flush,
diff --git a/lib/modules/subdir.c b/lib/modules/subdir.c
index 788765c..6d9ac89 100644
--- a/lib/modules/subdir.c
+++ b/lib/modules/subdir.c
@@ -384,14 +384,14 @@ static int subdir_open(const char *path, struct fuse_file_info *fi)
return err;
}
-static int subdir_read(const char *path, char *buf, size_t size, off_t offset,
- struct fuse_file_info *fi)
+static int subdir_read_buf(const char *path, struct fuse_bufvec **bufp,
+ size_t size, 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_read(d->next, newpath, buf, size, offset, fi);
+ err = fuse_fs_read_buf(d->next, newpath, bufp, size, offset, fi);
free(newpath);
}
return err;
@@ -587,7 +587,7 @@ static struct fuse_operations subdir_oper = {
.utimens = subdir_utimens,
.create = subdir_create,
.open = subdir_open,
- .read = subdir_read,
+ .read_buf = subdir_read_buf,
.write_buf = subdir_write_buf,
.statfs = subdir_statfs,
.flush = subdir_flush,