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 | |
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')
-rw-r--r-- | fs/fuse/dir.c | 31 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 9 | ||||
-rw-r--r-- | fs/fuse/inode.c | 1 |
3 files changed, 38 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); |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index af51c146a9ae..fc55dd33c1e2 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -106,6 +106,15 @@ struct fuse_inode { | |||
106 | 106 | ||
107 | /** List of writepage requestst (pending or sent) */ | 107 | /** List of writepage requestst (pending or sent) */ |
108 | struct list_head writepages; | 108 | struct list_head writepages; |
109 | |||
110 | /** Miscellaneous bits describing inode state */ | ||
111 | unsigned long state; | ||
112 | }; | ||
113 | |||
114 | /** FUSE inode state bits */ | ||
115 | enum { | ||
116 | /** Advise readdirplus */ | ||
117 | FUSE_I_ADVISE_RDPLUS, | ||
109 | }; | 118 | }; |
110 | 119 | ||
111 | struct fuse_conn; | 120 | struct fuse_conn; |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 79b70deb7cd6..9876a87255fe 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -92,6 +92,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) | |||
92 | fi->attr_version = 0; | 92 | fi->attr_version = 0; |
93 | fi->writectr = 0; | 93 | fi->writectr = 0; |
94 | fi->orig_ino = 0; | 94 | fi->orig_ino = 0; |
95 | fi->state = 0; | ||
95 | INIT_LIST_HEAD(&fi->write_files); | 96 | INIT_LIST_HEAD(&fi->write_files); |
96 | INIT_LIST_HEAD(&fi->queued_writes); | 97 | INIT_LIST_HEAD(&fi->queued_writes); |
97 | INIT_LIST_HEAD(&fi->writepages); | 98 | INIT_LIST_HEAD(&fi->writepages); |