aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/dir.c
diff options
context:
space:
mode:
authorFeng Shuo <steve.shuo.feng@gmail.com>2013-01-14 22:23:28 -0500
committerMiklos Szeredi <mszeredi@suse.cz>2013-01-31 11:08:11 -0500
commit4582a4ab2a0e7218449fb2e895d0aae9ea753c94 (patch)
tree20e4bf90709bf369665c3261753fcf32ff0d1b78 /fs/fuse/dir.c
parentc2132c1bc73d9a279cec148f74ea709c960b3d89 (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.c31
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
17static 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
31static 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
18static inline void fuse_dentry_settime(struct dentry *entry, u64 time) 39static 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
1291static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) 1314static 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);