diff options
author | Feng Shuo <steve.shuo.feng@gmail.com> | 2013-01-14 22:23:28 -0500 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2013-01-31 11:08:11 -0500 |
commit | 4582a4ab2a0e7218449fb2e895d0aae9ea753c94 (patch) | |
tree | 20e4bf90709bf369665c3261753fcf32ff0d1b78 /fs/fuse/dir.c | |
parent | c2132c1bc73d9a279cec148f74ea709c960b3d89 (diff) |
FUSE: Adapt readdirplus to application usage patterns
Use the same adaptive readdirplus mechanism as NFS:
http://permalink.gmane.org/gmane.linux.nfs/49299
If the user space implementation wants to disable readdirplus
temporarily, it could just return ENOTSUPP. Then kernel will
recall it with readdir.
Signed-off-by: Feng Shuo <steve.shuo.feng@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r-- | fs/fuse/dir.c | 31 |
1 files changed, 28 insertions, 3 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index aa0b6ade0e68..dc5e64893375 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -14,6 +14,27 @@ | |||
14 | #include <linux/namei.h> | 14 | #include <linux/namei.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | 16 | ||
17 | static bool fuse_use_readdirplus(struct inode *dir, struct file *filp) | ||
18 | { | ||
19 | struct fuse_conn *fc = get_fuse_conn(dir); | ||
20 | struct fuse_inode *fi = get_fuse_inode(dir); | ||
21 | |||
22 | if (!fc->do_readdirplus) | ||
23 | return false; | ||
24 | if (test_and_clear_bit(FUSE_I_ADVISE_RDPLUS, &fi->state)) | ||
25 | return true; | ||
26 | if (filp->f_pos == 0) | ||
27 | return true; | ||
28 | return false; | ||
29 | } | ||
30 | |||
31 | static void fuse_advise_use_readdirplus(struct inode *dir) | ||
32 | { | ||
33 | struct fuse_inode *fi = get_fuse_inode(dir); | ||
34 | |||
35 | set_bit(FUSE_I_ADVISE_RDPLUS, &fi->state); | ||
36 | } | ||
37 | |||
17 | #if BITS_PER_LONG >= 64 | 38 | #if BITS_PER_LONG >= 64 |
18 | static inline void fuse_dentry_settime(struct dentry *entry, u64 time) | 39 | static inline void fuse_dentry_settime(struct dentry *entry, u64 time) |
19 | { | 40 | { |
@@ -219,6 +240,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) | |||
219 | attr_version); | 240 | attr_version); |
220 | fuse_change_entry_timeout(entry, &outarg); | 241 | fuse_change_entry_timeout(entry, &outarg); |
221 | } | 242 | } |
243 | fuse_advise_use_readdirplus(inode); | ||
222 | return 1; | 244 | return 1; |
223 | } | 245 | } |
224 | 246 | ||
@@ -355,6 +377,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
355 | else | 377 | else |
356 | fuse_invalidate_entry_cache(entry); | 378 | fuse_invalidate_entry_cache(entry); |
357 | 379 | ||
380 | fuse_advise_use_readdirplus(dir); | ||
358 | return newent; | 381 | return newent; |
359 | 382 | ||
360 | out_iput: | 383 | out_iput: |
@@ -1290,7 +1313,7 @@ static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file, | |||
1290 | 1313 | ||
1291 | static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) | 1314 | static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) |
1292 | { | 1315 | { |
1293 | int err; | 1316 | int plus, err; |
1294 | size_t nbytes; | 1317 | size_t nbytes; |
1295 | struct page *page; | 1318 | struct page *page; |
1296 | struct inode *inode = file->f_path.dentry->d_inode; | 1319 | struct inode *inode = file->f_path.dentry->d_inode; |
@@ -1310,11 +1333,13 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) | |||
1310 | fuse_put_request(fc, req); | 1333 | fuse_put_request(fc, req); |
1311 | return -ENOMEM; | 1334 | return -ENOMEM; |
1312 | } | 1335 | } |
1336 | |||
1337 | plus = fuse_use_readdirplus(inode, file); | ||
1313 | req->out.argpages = 1; | 1338 | req->out.argpages = 1; |
1314 | req->num_pages = 1; | 1339 | req->num_pages = 1; |
1315 | req->pages[0] = page; | 1340 | req->pages[0] = page; |
1316 | req->page_descs[0].length = PAGE_SIZE; | 1341 | req->page_descs[0].length = PAGE_SIZE; |
1317 | if (fc->do_readdirplus) { | 1342 | if (plus) { |
1318 | attr_version = fuse_get_attr_version(fc); | 1343 | attr_version = fuse_get_attr_version(fc); |
1319 | fuse_read_fill(req, file, file->f_pos, PAGE_SIZE, | 1344 | fuse_read_fill(req, file, file->f_pos, PAGE_SIZE, |
1320 | FUSE_READDIRPLUS); | 1345 | FUSE_READDIRPLUS); |
@@ -1327,7 +1352,7 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) | |||
1327 | err = req->out.h.error; | 1352 | err = req->out.h.error; |
1328 | fuse_put_request(fc, req); | 1353 | fuse_put_request(fc, req); |
1329 | if (!err) { | 1354 | if (!err) { |
1330 | if (fc->do_readdirplus) { | 1355 | if (plus) { |
1331 | err = parse_dirplusfile(page_address(page), nbytes, | 1356 | err = parse_dirplusfile(page_address(page), nbytes, |
1332 | file, dstbuf, filldir, | 1357 | file, dstbuf, filldir, |
1333 | attr_version); | 1358 | attr_version); |