aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorGravatar Feng Shuo <steve.shuo.feng@gmail.com>2013-01-04 16:23:31 +0800
committerGravatar Miklos Szeredi <mszeredi@suse.cz>2013-02-07 14:58:50 +0100
commitf448ac69d1791f4b5c1ce2771624e261cb1797b4 (patch)
tree4c8348915460af579afab632b87887d17d561377 /lib
parent914871b20a901e3e1e981c92bc42b1c93b7ab81b (diff)
libfuse: add readdirplus support in fuse_lowlevel_ops
This patch implements readdirplus support in FUSE usersapce. It adds a new fuse lowlevel operations fuse_lowleve_ops::readdir_plus, corespoding mount options and helper functions to maintain buffer. [From: Eric Wong <normalperson@yhbt.net>] This makes our terminology consistent with NFS and our kernel module, as well as reducing user/developer confusion in the command-line. Note: I'm keeping "fuse_add_direntry_plus" since that is less standardized in its use than "readdirplus" for now. Signed-off-by: Feng Shuo <steve.shuo.feng@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/fuse_i.h1
-rw-r--r--lib/fuse_lowlevel.c48
-rw-r--r--lib/fuse_versionscript1
3 files changed, 49 insertions, 1 deletions
diff --git a/lib/fuse_i.h b/lib/fuse_i.h
index 225ff7d..02e7af1 100644
--- a/lib/fuse_i.h
+++ b/lib/fuse_i.h
@@ -73,6 +73,7 @@ struct fuse_ll {
int no_splice_read;
int auto_inval_data;
int no_auto_inval_data;
+ int no_readdirplus;
struct fuse_lowlevel_ops op;
int got_init;
struct cuse_data *cuse_data;
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index 568cf47..feaa076 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -339,6 +339,25 @@ static void fill_entry(struct fuse_entry_out *arg,
convert_stat(&e->attr, &arg->attr);
}
+size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
+ const char *name,
+ const struct fuse_entry_param *e, off_t off)
+{
+ struct fuse_entry_out *argp;
+ size_t entsize;
+
+ (void) req;
+ entsize = FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET_DIRENTPLUS +
+ fuse_dirent_size(strlen(name)));
+ if (entsize <= bufsize && buf){
+ argp = (struct fuse_entry_out *)buf;
+ memset(argp, 0, sizeof(*argp));
+ fill_entry(argp, e);
+ fuse_add_dirent(buf + sizeof(*argp), name, &(e->attr), off);
+ }
+ return entsize;
+}
+
static void fill_open(struct fuse_open_out *arg,
const struct fuse_file_info *f)
{
@@ -1406,6 +1425,21 @@ static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
fuse_reply_err(req, ENOSYS);
}
+static void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+{
+ struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
+ struct fuse_file_info fi;
+
+ memset(&fi, 0, sizeof(fi));
+ fi.fh = arg->fh;
+ fi.fh_old = fi.fh;
+
+ if (req->f->op.readdirplus)
+ req->f->op.readdirplus(req, nodeid, arg->size, arg->offset, &fi);
+ else
+ fuse_reply_err(req, ENOSYS);
+}
+
static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
@@ -1806,6 +1840,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
f->conn.capable |= FUSE_CAP_FLOCK_LOCKS;
if (arg->flags & FUSE_AUTO_INVAL_DATA)
f->conn.capable |= FUSE_CAP_AUTO_INVAL_DATA;
+ if (arg->flags & FUSE_DO_READDIRPLUS)
+ f->conn.capable |= FUSE_CAP_READDIRPLUS;
} else {
f->conn.async_read = 0;
f->conn.max_readahead = 0;
@@ -1838,6 +1874,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
f->conn.want |= FUSE_CAP_BIG_WRITES;
if (f->auto_inval_data)
f->conn.want |= FUSE_CAP_AUTO_INVAL_DATA;
+ if (f->op.readdirplus && !f->no_readdirplus)
+ f->conn.want |= FUSE_CAP_READDIRPLUS;
if (bufsize < FUSE_MIN_READ_BUFFER) {
fprintf(stderr, "fuse: warning: buffer size too small: %zu\n",
@@ -1861,6 +1899,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
f->conn.want &= ~FUSE_CAP_SPLICE_MOVE;
if (f->no_auto_inval_data)
f->conn.want &= ~FUSE_CAP_AUTO_INVAL_DATA;
+ if (f->no_readdirplus)
+ f->conn.want &= ~FUSE_CAP_READDIRPLUS;
if (f->conn.async_read || (f->conn.want & FUSE_CAP_ASYNC_READ))
outarg.flags |= FUSE_ASYNC_READ;
@@ -1878,6 +1918,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
outarg.flags |= FUSE_FLOCK_LOCKS;
if (f->conn.want & FUSE_CAP_AUTO_INVAL_DATA)
outarg.flags |= FUSE_AUTO_INVAL_DATA;
+ if (f->conn.want & FUSE_CAP_READDIRPLUS)
+ outarg.flags |= FUSE_DO_READDIRPLUS;
outarg.max_readahead = f->conn.max_readahead;
outarg.max_write = f->conn.max_write;
if (f->conn.proto_minor >= 13) {
@@ -2294,6 +2336,7 @@ static struct {
[FUSE_DESTROY] = { do_destroy, "DESTROY" },
[FUSE_NOTIFY_REPLY] = { (void *) 1, "NOTIFY_REPLY" },
[FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" },
+ [FUSE_READDIRPLUS] = { do_readdirplus, "READDIRPLUS"},
[CUSE_INIT] = { cuse_lowlevel_init, "CUSE_INIT" },
};
@@ -2402,7 +2445,8 @@ static void fuse_ll_process_buf(void *data, const struct fuse_buf *buf,
in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR &&
- in->opcode != FUSE_NOTIFY_REPLY)
+ in->opcode != FUSE_NOTIFY_REPLY &&
+ in->opcode != FUSE_READDIRPLUS)
goto reply_err;
err = ENOSYS;
@@ -2501,6 +2545,7 @@ static const struct fuse_opt fuse_ll_opts[] = {
{ "no_splice_read", offsetof(struct fuse_ll, no_splice_read), 1},
{ "auto_inval_data", offsetof(struct fuse_ll, auto_inval_data), 1},
{ "no_auto_inval_data", offsetof(struct fuse_ll, no_auto_inval_data), 1},
+ { "no_readdirplus", offsetof(struct fuse_ll, no_readdirplus), 1},
FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD),
FUSE_OPT_KEY("-h", KEY_HELP),
FUSE_OPT_KEY("--help", KEY_HELP),
@@ -2533,6 +2578,7 @@ static void fuse_ll_help(void)
" -o [no_]splice_move move data while splicing to the fuse device\n"
" -o [no_]splice_read use splice to read from the fuse device\n"
" -o [no_]auto_inval_data use automatic kernel cache invalidation logic\n"
+" -o [no_]readdirplus use readdirplus if possible.\n"
);
}
diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript
index ea2a1c8..ad5a940 100644
--- a/lib/fuse_versionscript
+++ b/lib/fuse_versionscript
@@ -51,6 +51,7 @@ FUSE_3.0 {
fuse_reply_statfs;
fuse_set_signal_handlers;
fuse_add_direntry;
+ fuse_add_direntry_plus;
fuse_chan_new;
fuse_chan_recv;
fuse_daemonize;