Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4582a4ab authored by Feng Shuo's avatar Feng Shuo Committed by Miklos Szeredi
Browse files

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: default avatarFeng Shuo <steve.shuo.feng@gmail.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
parent c2132c1b
Loading
Loading
Loading
Loading
+28 −3
Original line number Diff line number Diff line
@@ -14,6 +14,27 @@
#include <linux/namei.h>
#include <linux/slab.h>

static bool fuse_use_readdirplus(struct inode *dir, struct file *filp)
{
	struct fuse_conn *fc = get_fuse_conn(dir);
	struct fuse_inode *fi = get_fuse_inode(dir);

	if (!fc->do_readdirplus)
		return false;
	if (test_and_clear_bit(FUSE_I_ADVISE_RDPLUS, &fi->state))
		return true;
	if (filp->f_pos == 0)
		return true;
	return false;
}

static void fuse_advise_use_readdirplus(struct inode *dir)
{
	struct fuse_inode *fi = get_fuse_inode(dir);

	set_bit(FUSE_I_ADVISE_RDPLUS, &fi->state);
}

#if BITS_PER_LONG >= 64
static inline void fuse_dentry_settime(struct dentry *entry, u64 time)
{
@@ -219,6 +240,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
				       attr_version);
		fuse_change_entry_timeout(entry, &outarg);
	}
	fuse_advise_use_readdirplus(inode);
	return 1;
}

@@ -355,6 +377,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
	else
		fuse_invalidate_entry_cache(entry);

	fuse_advise_use_readdirplus(dir);
	return newent;

 out_iput:
@@ -1290,7 +1313,7 @@ static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file,

static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
{
	int err;
	int plus, err;
	size_t nbytes;
	struct page *page;
	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)
		fuse_put_request(fc, req);
		return -ENOMEM;
	}

	plus = fuse_use_readdirplus(inode, file);
	req->out.argpages = 1;
	req->num_pages = 1;
	req->pages[0] = page;
	req->page_descs[0].length = PAGE_SIZE;
	if (fc->do_readdirplus) {
	if (plus) {
		attr_version = fuse_get_attr_version(fc);
		fuse_read_fill(req, file, file->f_pos, PAGE_SIZE,
			       FUSE_READDIRPLUS);
@@ -1327,7 +1352,7 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
	err = req->out.h.error;
	fuse_put_request(fc, req);
	if (!err) {
		if (fc->do_readdirplus) {
		if (plus) {
			err = parse_dirplusfile(page_address(page), nbytes,
						file, dstbuf, filldir,
						attr_version);
+9 −0
Original line number Diff line number Diff line
@@ -106,6 +106,15 @@ struct fuse_inode {

	/** List of writepage requestst (pending or sent) */
	struct list_head writepages;

	/** Miscellaneous bits describing inode state */
	unsigned long state;
};

/** FUSE inode state bits */
enum {
	/** Advise readdirplus  */
	FUSE_I_ADVISE_RDPLUS,
};

struct fuse_conn;
+1 −0
Original line number Diff line number Diff line
@@ -92,6 +92,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)
	fi->attr_version = 0;
	fi->writectr = 0;
	fi->orig_ino = 0;
	fi->state = 0;
	INIT_LIST_HEAD(&fi->write_files);
	INIT_LIST_HEAD(&fi->queued_writes);
	INIT_LIST_HEAD(&fi->writepages);