xref: /linux/fs/fuse/readdir.c (revision 4f6b838c378a52ea3ae0b15f12ca8a20849072fa)
1d123d8e1SMiklos Szeredi /*
2d123d8e1SMiklos Szeredi   FUSE: Filesystem in Userspace
3d123d8e1SMiklos Szeredi   Copyright (C) 2001-2018  Miklos Szeredi <miklos@szeredi.hu>
4d123d8e1SMiklos Szeredi 
5d123d8e1SMiklos Szeredi   This program can be distributed under the terms of the GNU GPL.
6d123d8e1SMiklos Szeredi   See the file COPYING.
7d123d8e1SMiklos Szeredi */
8d123d8e1SMiklos Szeredi 
9d123d8e1SMiklos Szeredi 
10d123d8e1SMiklos Szeredi #include "fuse_i.h"
11261aaba7SMiklos Szeredi #include <linux/iversion.h>
12d123d8e1SMiklos Szeredi #include <linux/posix_acl.h>
1369e34551SMiklos Szeredi #include <linux/pagemap.h>
1469e34551SMiklos Szeredi #include <linux/highmem.h>
15d123d8e1SMiklos Szeredi 
16d123d8e1SMiklos Szeredi static bool fuse_use_readdirplus(struct inode *dir, struct dir_context *ctx)
17d123d8e1SMiklos Szeredi {
18d123d8e1SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
19d123d8e1SMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(dir);
20d123d8e1SMiklos Szeredi 
21d123d8e1SMiklos Szeredi 	if (!fc->do_readdirplus)
22d123d8e1SMiklos Szeredi 		return false;
23d123d8e1SMiklos Szeredi 	if (!fc->readdirplus_auto)
24d123d8e1SMiklos Szeredi 		return true;
25d123d8e1SMiklos Szeredi 	if (test_and_clear_bit(FUSE_I_ADVISE_RDPLUS, &fi->state))
26d123d8e1SMiklos Szeredi 		return true;
27d123d8e1SMiklos Szeredi 	if (ctx->pos == 0)
28d123d8e1SMiklos Szeredi 		return true;
29d123d8e1SMiklos Szeredi 	return false;
30d123d8e1SMiklos Szeredi }
31d123d8e1SMiklos Szeredi 
3269e34551SMiklos Szeredi static void fuse_add_dirent_to_cache(struct file *file,
3369e34551SMiklos Szeredi 				     struct fuse_dirent *dirent, loff_t pos)
3469e34551SMiklos Szeredi {
3569e34551SMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(file_inode(file));
3669e34551SMiklos Szeredi 	size_t reclen = FUSE_DIRENT_SIZE(dirent);
3769e34551SMiklos Szeredi 	pgoff_t index;
3869e34551SMiklos Szeredi 	struct page *page;
3969e34551SMiklos Szeredi 	loff_t size;
403494927eSMiklos Szeredi 	u64 version;
4169e34551SMiklos Szeredi 	unsigned int offset;
4269e34551SMiklos Szeredi 	void *addr;
4369e34551SMiklos Szeredi 
4469e34551SMiklos Szeredi 	spin_lock(&fi->rdc.lock);
4569e34551SMiklos Szeredi 	/*
4669e34551SMiklos Szeredi 	 * Is cache already completed?  Or this entry does not go at the end of
4769e34551SMiklos Szeredi 	 * cache?
4869e34551SMiklos Szeredi 	 */
4969e34551SMiklos Szeredi 	if (fi->rdc.cached || pos != fi->rdc.pos) {
5069e34551SMiklos Szeredi 		spin_unlock(&fi->rdc.lock);
5169e34551SMiklos Szeredi 		return;
5269e34551SMiklos Szeredi 	}
533494927eSMiklos Szeredi 	version = fi->rdc.version;
5469e34551SMiklos Szeredi 	size = fi->rdc.size;
5569e34551SMiklos Szeredi 	offset = size & ~PAGE_MASK;
5669e34551SMiklos Szeredi 	index = size >> PAGE_SHIFT;
5769e34551SMiklos Szeredi 	/* Dirent doesn't fit in current page?  Jump to next page. */
5869e34551SMiklos Szeredi 	if (offset + reclen > PAGE_SIZE) {
5969e34551SMiklos Szeredi 		index++;
6069e34551SMiklos Szeredi 		offset = 0;
6169e34551SMiklos Szeredi 	}
6269e34551SMiklos Szeredi 	spin_unlock(&fi->rdc.lock);
6369e34551SMiklos Szeredi 
6469e34551SMiklos Szeredi 	if (offset) {
6569e34551SMiklos Szeredi 		page = find_lock_page(file->f_mapping, index);
6669e34551SMiklos Szeredi 	} else {
6769e34551SMiklos Szeredi 		page = find_or_create_page(file->f_mapping, index,
6869e34551SMiklos Szeredi 					   mapping_gfp_mask(file->f_mapping));
6969e34551SMiklos Szeredi 	}
7069e34551SMiklos Szeredi 	if (!page)
7169e34551SMiklos Szeredi 		return;
7269e34551SMiklos Szeredi 
7369e34551SMiklos Szeredi 	spin_lock(&fi->rdc.lock);
7469e34551SMiklos Szeredi 	/* Raced with another readdir */
753494927eSMiklos Szeredi 	if (fi->rdc.version != version || fi->rdc.size != size ||
763494927eSMiklos Szeredi 	    WARN_ON(fi->rdc.pos != pos))
7769e34551SMiklos Szeredi 		goto unlock;
7869e34551SMiklos Szeredi 
7969e34551SMiklos Szeredi 	addr = kmap_atomic(page);
8069e34551SMiklos Szeredi 	if (!offset)
8169e34551SMiklos Szeredi 		clear_page(addr);
8269e34551SMiklos Szeredi 	memcpy(addr + offset, dirent, reclen);
8369e34551SMiklos Szeredi 	kunmap_atomic(addr);
8469e34551SMiklos Szeredi 	fi->rdc.size = (index << PAGE_SHIFT) + offset + reclen;
8569e34551SMiklos Szeredi 	fi->rdc.pos = dirent->off;
8669e34551SMiklos Szeredi unlock:
8769e34551SMiklos Szeredi 	spin_unlock(&fi->rdc.lock);
8869e34551SMiklos Szeredi 	unlock_page(page);
8969e34551SMiklos Szeredi 	put_page(page);
9069e34551SMiklos Szeredi }
9169e34551SMiklos Szeredi 
9269e34551SMiklos Szeredi static void fuse_readdir_cache_end(struct file *file, loff_t pos)
9369e34551SMiklos Szeredi {
9469e34551SMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(file_inode(file));
9569e34551SMiklos Szeredi 	loff_t end;
9669e34551SMiklos Szeredi 
9769e34551SMiklos Szeredi 	spin_lock(&fi->rdc.lock);
9869e34551SMiklos Szeredi 	/* does cache end position match current position? */
9969e34551SMiklos Szeredi 	if (fi->rdc.pos != pos) {
10069e34551SMiklos Szeredi 		spin_unlock(&fi->rdc.lock);
10169e34551SMiklos Szeredi 		return;
10269e34551SMiklos Szeredi 	}
10369e34551SMiklos Szeredi 
10469e34551SMiklos Szeredi 	fi->rdc.cached = true;
10569e34551SMiklos Szeredi 	end = ALIGN(fi->rdc.size, PAGE_SIZE);
10669e34551SMiklos Szeredi 	spin_unlock(&fi->rdc.lock);
10769e34551SMiklos Szeredi 
10869e34551SMiklos Szeredi 	/* truncate unused tail of cache */
10969e34551SMiklos Szeredi 	truncate_inode_pages(file->f_mapping, end);
11069e34551SMiklos Szeredi }
11169e34551SMiklos Szeredi 
11218172b10SMiklos Szeredi static bool fuse_emit(struct file *file, struct dir_context *ctx,
11318172b10SMiklos Szeredi 		      struct fuse_dirent *dirent)
11418172b10SMiklos Szeredi {
11569e34551SMiklos Szeredi 	struct fuse_file *ff = file->private_data;
11669e34551SMiklos Szeredi 
11769e34551SMiklos Szeredi 	if (ff->open_flags & FOPEN_CACHE_DIR)
11869e34551SMiklos Szeredi 		fuse_add_dirent_to_cache(file, dirent, ctx->pos);
11969e34551SMiklos Szeredi 
12018172b10SMiklos Szeredi 	return dir_emit(ctx, dirent->name, dirent->namelen, dirent->ino,
12118172b10SMiklos Szeredi 			dirent->type);
12218172b10SMiklos Szeredi }
12318172b10SMiklos Szeredi 
124d123d8e1SMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
125d123d8e1SMiklos Szeredi 			 struct dir_context *ctx)
126d123d8e1SMiklos Szeredi {
127d123d8e1SMiklos Szeredi 	while (nbytes >= FUSE_NAME_OFFSET) {
128d123d8e1SMiklos Szeredi 		struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
129d123d8e1SMiklos Szeredi 		size_t reclen = FUSE_DIRENT_SIZE(dirent);
130d123d8e1SMiklos Szeredi 		if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
131d123d8e1SMiklos Szeredi 			return -EIO;
132d123d8e1SMiklos Szeredi 		if (reclen > nbytes)
133d123d8e1SMiklos Szeredi 			break;
134d123d8e1SMiklos Szeredi 		if (memchr(dirent->name, '/', dirent->namelen) != NULL)
135d123d8e1SMiklos Szeredi 			return -EIO;
136d123d8e1SMiklos Szeredi 
13718172b10SMiklos Szeredi 		if (!fuse_emit(file, ctx, dirent))
138d123d8e1SMiklos Szeredi 			break;
139d123d8e1SMiklos Szeredi 
140d123d8e1SMiklos Szeredi 		buf += reclen;
141d123d8e1SMiklos Szeredi 		nbytes -= reclen;
142d123d8e1SMiklos Szeredi 		ctx->pos = dirent->off;
143d123d8e1SMiklos Szeredi 	}
144d123d8e1SMiklos Szeredi 
145d123d8e1SMiklos Szeredi 	return 0;
146d123d8e1SMiklos Szeredi }
147d123d8e1SMiklos Szeredi 
148d123d8e1SMiklos Szeredi static int fuse_direntplus_link(struct file *file,
149d123d8e1SMiklos Szeredi 				struct fuse_direntplus *direntplus,
150d123d8e1SMiklos Szeredi 				u64 attr_version)
151d123d8e1SMiklos Szeredi {
152d123d8e1SMiklos Szeredi 	struct fuse_entry_out *o = &direntplus->entry_out;
153d123d8e1SMiklos Szeredi 	struct fuse_dirent *dirent = &direntplus->dirent;
154d123d8e1SMiklos Szeredi 	struct dentry *parent = file->f_path.dentry;
155d123d8e1SMiklos Szeredi 	struct qstr name = QSTR_INIT(dirent->name, dirent->namelen);
156d123d8e1SMiklos Szeredi 	struct dentry *dentry;
157d123d8e1SMiklos Szeredi 	struct dentry *alias;
158d123d8e1SMiklos Szeredi 	struct inode *dir = d_inode(parent);
159d123d8e1SMiklos Szeredi 	struct fuse_conn *fc;
160d123d8e1SMiklos Szeredi 	struct inode *inode;
161d123d8e1SMiklos Szeredi 	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
162d123d8e1SMiklos Szeredi 
163d123d8e1SMiklos Szeredi 	if (!o->nodeid) {
164d123d8e1SMiklos Szeredi 		/*
165d123d8e1SMiklos Szeredi 		 * Unlike in the case of fuse_lookup, zero nodeid does not mean
166d123d8e1SMiklos Szeredi 		 * ENOENT. Instead, it only means the userspace filesystem did
167d123d8e1SMiklos Szeredi 		 * not want to return attributes/handle for this entry.
168d123d8e1SMiklos Szeredi 		 *
169d123d8e1SMiklos Szeredi 		 * So do nothing.
170d123d8e1SMiklos Szeredi 		 */
171d123d8e1SMiklos Szeredi 		return 0;
172d123d8e1SMiklos Szeredi 	}
173d123d8e1SMiklos Szeredi 
174d123d8e1SMiklos Szeredi 	if (name.name[0] == '.') {
175d123d8e1SMiklos Szeredi 		/*
176d123d8e1SMiklos Szeredi 		 * We could potentially refresh the attributes of the directory
177d123d8e1SMiklos Szeredi 		 * and its parent?
178d123d8e1SMiklos Szeredi 		 */
179d123d8e1SMiklos Szeredi 		if (name.len == 1)
180d123d8e1SMiklos Szeredi 			return 0;
181d123d8e1SMiklos Szeredi 		if (name.name[1] == '.' && name.len == 2)
182d123d8e1SMiklos Szeredi 			return 0;
183d123d8e1SMiklos Szeredi 	}
184d123d8e1SMiklos Szeredi 
185d123d8e1SMiklos Szeredi 	if (invalid_nodeid(o->nodeid))
186d123d8e1SMiklos Szeredi 		return -EIO;
187eb59bd17SMiklos Szeredi 	if (fuse_invalid_attr(&o->attr))
188d123d8e1SMiklos Szeredi 		return -EIO;
189d123d8e1SMiklos Szeredi 
190d123d8e1SMiklos Szeredi 	fc = get_fuse_conn(dir);
191d123d8e1SMiklos Szeredi 
192d123d8e1SMiklos Szeredi 	name.hash = full_name_hash(parent, name.name, name.len);
193d123d8e1SMiklos Szeredi 	dentry = d_lookup(parent, &name);
194d123d8e1SMiklos Szeredi 	if (!dentry) {
195d123d8e1SMiklos Szeredi retry:
196d123d8e1SMiklos Szeredi 		dentry = d_alloc_parallel(parent, &name, &wq);
197d123d8e1SMiklos Szeredi 		if (IS_ERR(dentry))
198d123d8e1SMiklos Szeredi 			return PTR_ERR(dentry);
199d123d8e1SMiklos Szeredi 	}
200d123d8e1SMiklos Szeredi 	if (!d_in_lookup(dentry)) {
201d123d8e1SMiklos Szeredi 		struct fuse_inode *fi;
202d123d8e1SMiklos Szeredi 		inode = d_inode(dentry);
203d123d8e1SMiklos Szeredi 		if (!inode ||
204d123d8e1SMiklos Szeredi 		    get_node_id(inode) != o->nodeid ||
205d123d8e1SMiklos Szeredi 		    ((o->attr.mode ^ inode->i_mode) & S_IFMT)) {
206d123d8e1SMiklos Szeredi 			d_invalidate(dentry);
207d123d8e1SMiklos Szeredi 			dput(dentry);
208d123d8e1SMiklos Szeredi 			goto retry;
209d123d8e1SMiklos Szeredi 		}
210d123d8e1SMiklos Szeredi 		if (is_bad_inode(inode)) {
211d123d8e1SMiklos Szeredi 			dput(dentry);
212d123d8e1SMiklos Szeredi 			return -EIO;
213d123d8e1SMiklos Szeredi 		}
214d123d8e1SMiklos Szeredi 
215d123d8e1SMiklos Szeredi 		fi = get_fuse_inode(inode);
216c9d8f5f0SKirill Tkhai 		spin_lock(&fi->lock);
217d123d8e1SMiklos Szeredi 		fi->nlookup++;
218c9d8f5f0SKirill Tkhai 		spin_unlock(&fi->lock);
219d123d8e1SMiklos Szeredi 
220d123d8e1SMiklos Szeredi 		forget_all_cached_acls(inode);
221d123d8e1SMiklos Szeredi 		fuse_change_attributes(inode, &o->attr,
222d123d8e1SMiklos Szeredi 				       entry_attr_timeout(o),
223d123d8e1SMiklos Szeredi 				       attr_version);
224d123d8e1SMiklos Szeredi 		/*
225d123d8e1SMiklos Szeredi 		 * The other branch comes via fuse_iget()
226d123d8e1SMiklos Szeredi 		 * which bumps nlookup inside
227d123d8e1SMiklos Szeredi 		 */
228d123d8e1SMiklos Szeredi 	} else {
229d123d8e1SMiklos Szeredi 		inode = fuse_iget(dir->i_sb, o->nodeid, o->generation,
230d123d8e1SMiklos Szeredi 				  &o->attr, entry_attr_timeout(o),
231d123d8e1SMiklos Szeredi 				  attr_version);
232d123d8e1SMiklos Szeredi 		if (!inode)
233d123d8e1SMiklos Szeredi 			inode = ERR_PTR(-ENOMEM);
234d123d8e1SMiklos Szeredi 
235d123d8e1SMiklos Szeredi 		alias = d_splice_alias(inode, dentry);
236d123d8e1SMiklos Szeredi 		d_lookup_done(dentry);
237d123d8e1SMiklos Szeredi 		if (alias) {
238d123d8e1SMiklos Szeredi 			dput(dentry);
239d123d8e1SMiklos Szeredi 			dentry = alias;
240d123d8e1SMiklos Szeredi 		}
241d123d8e1SMiklos Szeredi 		if (IS_ERR(dentry))
242d123d8e1SMiklos Szeredi 			return PTR_ERR(dentry);
243d123d8e1SMiklos Szeredi 	}
244d123d8e1SMiklos Szeredi 	if (fc->readdirplus_auto)
245d123d8e1SMiklos Szeredi 		set_bit(FUSE_I_INIT_RDPLUS, &get_fuse_inode(inode)->state);
246d123d8e1SMiklos Szeredi 	fuse_change_entry_timeout(dentry, o);
247d123d8e1SMiklos Szeredi 
248d123d8e1SMiklos Szeredi 	dput(dentry);
249d123d8e1SMiklos Szeredi 	return 0;
250d123d8e1SMiklos Szeredi }
251d123d8e1SMiklos Szeredi 
2523545fe21SMiklos Szeredi static void fuse_force_forget(struct file *file, u64 nodeid)
2533545fe21SMiklos Szeredi {
2543545fe21SMiklos Szeredi 	struct inode *inode = file_inode(file);
255*fcee216bSMax Reitz 	struct fuse_mount *fm = get_fuse_mount(inode);
2563545fe21SMiklos Szeredi 	struct fuse_forget_in inarg;
2573545fe21SMiklos Szeredi 	FUSE_ARGS(args);
2583545fe21SMiklos Szeredi 
2593545fe21SMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
2603545fe21SMiklos Szeredi 	inarg.nlookup = 1;
2613545fe21SMiklos Szeredi 	args.opcode = FUSE_FORGET;
2623545fe21SMiklos Szeredi 	args.nodeid = nodeid;
2633545fe21SMiklos Szeredi 	args.in_numargs = 1;
2643545fe21SMiklos Szeredi 	args.in_args[0].size = sizeof(inarg);
2653545fe21SMiklos Szeredi 	args.in_args[0].value = &inarg;
2663545fe21SMiklos Szeredi 	args.force = true;
2673545fe21SMiklos Szeredi 	args.noreply = true;
2683545fe21SMiklos Szeredi 
269*fcee216bSMax Reitz 	fuse_simple_request(fm, &args);
2703545fe21SMiklos Szeredi 	/* ignore errors */
2713545fe21SMiklos Szeredi }
2723545fe21SMiklos Szeredi 
273d123d8e1SMiklos Szeredi static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file,
274d123d8e1SMiklos Szeredi 			     struct dir_context *ctx, u64 attr_version)
275d123d8e1SMiklos Szeredi {
276d123d8e1SMiklos Szeredi 	struct fuse_direntplus *direntplus;
277d123d8e1SMiklos Szeredi 	struct fuse_dirent *dirent;
278d123d8e1SMiklos Szeredi 	size_t reclen;
279d123d8e1SMiklos Szeredi 	int over = 0;
280d123d8e1SMiklos Szeredi 	int ret;
281d123d8e1SMiklos Szeredi 
282d123d8e1SMiklos Szeredi 	while (nbytes >= FUSE_NAME_OFFSET_DIRENTPLUS) {
283d123d8e1SMiklos Szeredi 		direntplus = (struct fuse_direntplus *) buf;
284d123d8e1SMiklos Szeredi 		dirent = &direntplus->dirent;
285d123d8e1SMiklos Szeredi 		reclen = FUSE_DIRENTPLUS_SIZE(direntplus);
286d123d8e1SMiklos Szeredi 
287d123d8e1SMiklos Szeredi 		if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
288d123d8e1SMiklos Szeredi 			return -EIO;
289d123d8e1SMiklos Szeredi 		if (reclen > nbytes)
290d123d8e1SMiklos Szeredi 			break;
291d123d8e1SMiklos Szeredi 		if (memchr(dirent->name, '/', dirent->namelen) != NULL)
292d123d8e1SMiklos Szeredi 			return -EIO;
293d123d8e1SMiklos Szeredi 
294d123d8e1SMiklos Szeredi 		if (!over) {
295d123d8e1SMiklos Szeredi 			/* We fill entries into dstbuf only as much as
296d123d8e1SMiklos Szeredi 			   it can hold. But we still continue iterating
297d123d8e1SMiklos Szeredi 			   over remaining entries to link them. If not,
298d123d8e1SMiklos Szeredi 			   we need to send a FORGET for each of those
299d123d8e1SMiklos Szeredi 			   which we did not link.
300d123d8e1SMiklos Szeredi 			*/
30118172b10SMiklos Szeredi 			over = !fuse_emit(file, ctx, dirent);
302d123d8e1SMiklos Szeredi 			if (!over)
303d123d8e1SMiklos Szeredi 				ctx->pos = dirent->off;
304d123d8e1SMiklos Szeredi 		}
305d123d8e1SMiklos Szeredi 
306d123d8e1SMiklos Szeredi 		buf += reclen;
307d123d8e1SMiklos Szeredi 		nbytes -= reclen;
308d123d8e1SMiklos Szeredi 
309d123d8e1SMiklos Szeredi 		ret = fuse_direntplus_link(file, direntplus, attr_version);
310d123d8e1SMiklos Szeredi 		if (ret)
311d123d8e1SMiklos Szeredi 			fuse_force_forget(file, direntplus->entry_out.nodeid);
312d123d8e1SMiklos Szeredi 	}
313d123d8e1SMiklos Szeredi 
314d123d8e1SMiklos Szeredi 	return 0;
315d123d8e1SMiklos Szeredi }
316d123d8e1SMiklos Szeredi 
3175d7bc7e8SMiklos Szeredi static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx)
318d123d8e1SMiklos Szeredi {
31943f5098eSMiklos Szeredi 	int plus;
32043f5098eSMiklos Szeredi 	ssize_t res;
321d123d8e1SMiklos Szeredi 	struct page *page;
322d123d8e1SMiklos Szeredi 	struct inode *inode = file_inode(file);
323*fcee216bSMax Reitz 	struct fuse_mount *fm = get_fuse_mount(inode);
32443f5098eSMiklos Szeredi 	struct fuse_io_args ia = {};
32543f5098eSMiklos Szeredi 	struct fuse_args_pages *ap = &ia.ap;
32643f5098eSMiklos Szeredi 	struct fuse_page_desc desc = { .length = PAGE_SIZE };
327d123d8e1SMiklos Szeredi 	u64 attr_version = 0;
328d123d8e1SMiklos Szeredi 	bool locked;
329d123d8e1SMiklos Szeredi 
330d123d8e1SMiklos Szeredi 	page = alloc_page(GFP_KERNEL);
33143f5098eSMiklos Szeredi 	if (!page)
332d123d8e1SMiklos Szeredi 		return -ENOMEM;
333d123d8e1SMiklos Szeredi 
334d123d8e1SMiklos Szeredi 	plus = fuse_use_readdirplus(inode, ctx);
335cabdb4faSzhengbin 	ap->args.out_pages = true;
33643f5098eSMiklos Szeredi 	ap->num_pages = 1;
33743f5098eSMiklos Szeredi 	ap->pages = &page;
33843f5098eSMiklos Szeredi 	ap->descs = &desc;
339d123d8e1SMiklos Szeredi 	if (plus) {
340*fcee216bSMax Reitz 		attr_version = fuse_get_attr_version(fm->fc);
34143f5098eSMiklos Szeredi 		fuse_read_args_fill(&ia, file, ctx->pos, PAGE_SIZE,
342d123d8e1SMiklos Szeredi 				    FUSE_READDIRPLUS);
343d123d8e1SMiklos Szeredi 	} else {
34443f5098eSMiklos Szeredi 		fuse_read_args_fill(&ia, file, ctx->pos, PAGE_SIZE,
345d123d8e1SMiklos Szeredi 				    FUSE_READDIR);
346d123d8e1SMiklos Szeredi 	}
347d123d8e1SMiklos Szeredi 	locked = fuse_lock_inode(inode);
348*fcee216bSMax Reitz 	res = fuse_simple_request(fm, &ap->args);
349d123d8e1SMiklos Szeredi 	fuse_unlock_inode(inode, locked);
35043f5098eSMiklos Szeredi 	if (res >= 0) {
35143f5098eSMiklos Szeredi 		if (!res) {
35269e34551SMiklos Szeredi 			struct fuse_file *ff = file->private_data;
35369e34551SMiklos Szeredi 
35469e34551SMiklos Szeredi 			if (ff->open_flags & FOPEN_CACHE_DIR)
35569e34551SMiklos Szeredi 				fuse_readdir_cache_end(file, ctx->pos);
35669e34551SMiklos Szeredi 		} else if (plus) {
35743f5098eSMiklos Szeredi 			res = parse_dirplusfile(page_address(page), res,
358d123d8e1SMiklos Szeredi 						file, ctx, attr_version);
359d123d8e1SMiklos Szeredi 		} else {
36043f5098eSMiklos Szeredi 			res = parse_dirfile(page_address(page), res, file,
361d123d8e1SMiklos Szeredi 					    ctx);
362d123d8e1SMiklos Szeredi 		}
363d123d8e1SMiklos Szeredi 	}
364d123d8e1SMiklos Szeredi 
365d123d8e1SMiklos Szeredi 	__free_page(page);
366d123d8e1SMiklos Szeredi 	fuse_invalidate_atime(inode);
36743f5098eSMiklos Szeredi 	return res;
368d123d8e1SMiklos Szeredi }
3695d7bc7e8SMiklos Szeredi 
3705d7bc7e8SMiklos Szeredi enum fuse_parse_result {
3715d7bc7e8SMiklos Szeredi 	FOUND_ERR = -1,
3725d7bc7e8SMiklos Szeredi 	FOUND_NONE = 0,
3735d7bc7e8SMiklos Szeredi 	FOUND_SOME,
3745d7bc7e8SMiklos Szeredi 	FOUND_ALL,
3755d7bc7e8SMiklos Szeredi };
3765d7bc7e8SMiklos Szeredi 
3775d7bc7e8SMiklos Szeredi static enum fuse_parse_result fuse_parse_cache(struct fuse_file *ff,
3785d7bc7e8SMiklos Szeredi 					       void *addr, unsigned int size,
3795d7bc7e8SMiklos Szeredi 					       struct dir_context *ctx)
3805d7bc7e8SMiklos Szeredi {
3815d7bc7e8SMiklos Szeredi 	unsigned int offset = ff->readdir.cache_off & ~PAGE_MASK;
3825d7bc7e8SMiklos Szeredi 	enum fuse_parse_result res = FOUND_NONE;
3835d7bc7e8SMiklos Szeredi 
3845d7bc7e8SMiklos Szeredi 	WARN_ON(offset >= size);
3855d7bc7e8SMiklos Szeredi 
3865d7bc7e8SMiklos Szeredi 	for (;;) {
3875d7bc7e8SMiklos Szeredi 		struct fuse_dirent *dirent = addr + offset;
3885d7bc7e8SMiklos Szeredi 		unsigned int nbytes = size - offset;
389e5854b1cSTejun Heo 		size_t reclen;
3905d7bc7e8SMiklos Szeredi 
3915d7bc7e8SMiklos Szeredi 		if (nbytes < FUSE_NAME_OFFSET || !dirent->namelen)
3925d7bc7e8SMiklos Szeredi 			break;
3935d7bc7e8SMiklos Szeredi 
394e5854b1cSTejun Heo 		reclen = FUSE_DIRENT_SIZE(dirent); /* derefs ->namelen */
395e5854b1cSTejun Heo 
3965d7bc7e8SMiklos Szeredi 		if (WARN_ON(dirent->namelen > FUSE_NAME_MAX))
3975d7bc7e8SMiklos Szeredi 			return FOUND_ERR;
3985d7bc7e8SMiklos Szeredi 		if (WARN_ON(reclen > nbytes))
3995d7bc7e8SMiklos Szeredi 			return FOUND_ERR;
4005d7bc7e8SMiklos Szeredi 		if (WARN_ON(memchr(dirent->name, '/', dirent->namelen) != NULL))
4015d7bc7e8SMiklos Szeredi 			return FOUND_ERR;
4025d7bc7e8SMiklos Szeredi 
4035d7bc7e8SMiklos Szeredi 		if (ff->readdir.pos == ctx->pos) {
4045d7bc7e8SMiklos Szeredi 			res = FOUND_SOME;
4055d7bc7e8SMiklos Szeredi 			if (!dir_emit(ctx, dirent->name, dirent->namelen,
4065d7bc7e8SMiklos Szeredi 				      dirent->ino, dirent->type))
4075d7bc7e8SMiklos Szeredi 				return FOUND_ALL;
4085d7bc7e8SMiklos Szeredi 			ctx->pos = dirent->off;
4095d7bc7e8SMiklos Szeredi 		}
4105d7bc7e8SMiklos Szeredi 		ff->readdir.pos = dirent->off;
4115d7bc7e8SMiklos Szeredi 		ff->readdir.cache_off += reclen;
4125d7bc7e8SMiklos Szeredi 
4135d7bc7e8SMiklos Szeredi 		offset += reclen;
4145d7bc7e8SMiklos Szeredi 	}
4155d7bc7e8SMiklos Szeredi 
4165d7bc7e8SMiklos Szeredi 	return res;
4175d7bc7e8SMiklos Szeredi }
4185d7bc7e8SMiklos Szeredi 
4197118883bSMiklos Szeredi static void fuse_rdc_reset(struct inode *inode)
4203494927eSMiklos Szeredi {
4217118883bSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
4227118883bSMiklos Szeredi 
4233494927eSMiklos Szeredi 	fi->rdc.cached = false;
4243494927eSMiklos Szeredi 	fi->rdc.version++;
4253494927eSMiklos Szeredi 	fi->rdc.size = 0;
4263494927eSMiklos Szeredi 	fi->rdc.pos = 0;
4273494927eSMiklos Szeredi }
4283494927eSMiklos Szeredi 
4295d7bc7e8SMiklos Szeredi #define UNCACHED 1
4305d7bc7e8SMiklos Szeredi 
4315d7bc7e8SMiklos Szeredi static int fuse_readdir_cached(struct file *file, struct dir_context *ctx)
4325d7bc7e8SMiklos Szeredi {
4335d7bc7e8SMiklos Szeredi 	struct fuse_file *ff = file->private_data;
4345d7bc7e8SMiklos Szeredi 	struct inode *inode = file_inode(file);
4357118883bSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
4365d7bc7e8SMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
4375d7bc7e8SMiklos Szeredi 	enum fuse_parse_result res;
4385d7bc7e8SMiklos Szeredi 	pgoff_t index;
4395d7bc7e8SMiklos Szeredi 	unsigned int size;
4405d7bc7e8SMiklos Szeredi 	struct page *page;
4415d7bc7e8SMiklos Szeredi 	void *addr;
4425d7bc7e8SMiklos Szeredi 
4435d7bc7e8SMiklos Szeredi 	/* Seeked?  If so, reset the cache stream */
4445d7bc7e8SMiklos Szeredi 	if (ff->readdir.pos != ctx->pos) {
4455d7bc7e8SMiklos Szeredi 		ff->readdir.pos = 0;
4465d7bc7e8SMiklos Szeredi 		ff->readdir.cache_off = 0;
4475d7bc7e8SMiklos Szeredi 	}
4485d7bc7e8SMiklos Szeredi 
4497118883bSMiklos Szeredi 	/*
4507118883bSMiklos Szeredi 	 * We're just about to start reading into the cache or reading the
4517118883bSMiklos Szeredi 	 * cache; both cases require an up-to-date mtime value.
4527118883bSMiklos Szeredi 	 */
4537118883bSMiklos Szeredi 	if (!ctx->pos && fc->auto_inval_data) {
4547118883bSMiklos Szeredi 		int err = fuse_update_attributes(inode, file);
4557118883bSMiklos Szeredi 
4567118883bSMiklos Szeredi 		if (err)
4577118883bSMiklos Szeredi 			return err;
4587118883bSMiklos Szeredi 	}
4597118883bSMiklos Szeredi 
4605d7bc7e8SMiklos Szeredi retry:
4615d7bc7e8SMiklos Szeredi 	spin_lock(&fi->rdc.lock);
4627118883bSMiklos Szeredi retry_locked:
4635d7bc7e8SMiklos Szeredi 	if (!fi->rdc.cached) {
4647118883bSMiklos Szeredi 		/* Starting cache? Set cache mtime. */
4657118883bSMiklos Szeredi 		if (!ctx->pos && !fi->rdc.size) {
4667118883bSMiklos Szeredi 			fi->rdc.mtime = inode->i_mtime;
467261aaba7SMiklos Szeredi 			fi->rdc.iversion = inode_query_iversion(inode);
4687118883bSMiklos Szeredi 		}
4695d7bc7e8SMiklos Szeredi 		spin_unlock(&fi->rdc.lock);
4705d7bc7e8SMiklos Szeredi 		return UNCACHED;
4715d7bc7e8SMiklos Szeredi 	}
4723494927eSMiklos Szeredi 	/*
4737118883bSMiklos Szeredi 	 * When at the beginning of the directory (i.e. just after opendir(3) or
4747118883bSMiklos Szeredi 	 * rewinddir(3)), then need to check whether directory contents have
4757118883bSMiklos Szeredi 	 * changed, and reset the cache if so.
4767118883bSMiklos Szeredi 	 */
4777118883bSMiklos Szeredi 	if (!ctx->pos) {
478261aaba7SMiklos Szeredi 		if (inode_peek_iversion(inode) != fi->rdc.iversion ||
479261aaba7SMiklos Szeredi 		    !timespec64_equal(&fi->rdc.mtime, &inode->i_mtime)) {
4807118883bSMiklos Szeredi 			fuse_rdc_reset(inode);
4817118883bSMiklos Szeredi 			goto retry_locked;
4827118883bSMiklos Szeredi 		}
4837118883bSMiklos Szeredi 	}
4847118883bSMiklos Szeredi 
4857118883bSMiklos Szeredi 	/*
4863494927eSMiklos Szeredi 	 * If cache version changed since the last getdents() call, then reset
4873494927eSMiklos Szeredi 	 * the cache stream.
4883494927eSMiklos Szeredi 	 */
4893494927eSMiklos Szeredi 	if (ff->readdir.version != fi->rdc.version) {
4903494927eSMiklos Szeredi 		ff->readdir.pos = 0;
4913494927eSMiklos Szeredi 		ff->readdir.cache_off = 0;
4923494927eSMiklos Szeredi 	}
4933494927eSMiklos Szeredi 	/*
4943494927eSMiklos Szeredi 	 * If at the beginning of the cache, than reset version to
4953494927eSMiklos Szeredi 	 * current.
4963494927eSMiklos Szeredi 	 */
4973494927eSMiklos Szeredi 	if (ff->readdir.pos == 0)
4983494927eSMiklos Szeredi 		ff->readdir.version = fi->rdc.version;
4993494927eSMiklos Szeredi 
5005d7bc7e8SMiklos Szeredi 	WARN_ON(fi->rdc.size < ff->readdir.cache_off);
5015d7bc7e8SMiklos Szeredi 
5025d7bc7e8SMiklos Szeredi 	index = ff->readdir.cache_off >> PAGE_SHIFT;
5035d7bc7e8SMiklos Szeredi 
5045d7bc7e8SMiklos Szeredi 	if (index == (fi->rdc.size >> PAGE_SHIFT))
5055d7bc7e8SMiklos Szeredi 		size = fi->rdc.size & ~PAGE_MASK;
5065d7bc7e8SMiklos Szeredi 	else
5075d7bc7e8SMiklos Szeredi 		size = PAGE_SIZE;
5085d7bc7e8SMiklos Szeredi 	spin_unlock(&fi->rdc.lock);
5095d7bc7e8SMiklos Szeredi 
5105d7bc7e8SMiklos Szeredi 	/* EOF? */
5115d7bc7e8SMiklos Szeredi 	if ((ff->readdir.cache_off & ~PAGE_MASK) == size)
5125d7bc7e8SMiklos Szeredi 		return 0;
5135d7bc7e8SMiklos Szeredi 
5145d7bc7e8SMiklos Szeredi 	page = find_get_page_flags(file->f_mapping, index,
5155d7bc7e8SMiklos Szeredi 				   FGP_ACCESSED | FGP_LOCK);
5163494927eSMiklos Szeredi 	spin_lock(&fi->rdc.lock);
5175d7bc7e8SMiklos Szeredi 	if (!page) {
5185d7bc7e8SMiklos Szeredi 		/*
5195d7bc7e8SMiklos Szeredi 		 * Uh-oh: page gone missing, cache is useless
5205d7bc7e8SMiklos Szeredi 		 */
5213494927eSMiklos Szeredi 		if (fi->rdc.version == ff->readdir.version)
5227118883bSMiklos Szeredi 			fuse_rdc_reset(inode);
5237118883bSMiklos Szeredi 		goto retry_locked;
5245d7bc7e8SMiklos Szeredi 	}
5255d7bc7e8SMiklos Szeredi 
5263494927eSMiklos Szeredi 	/* Make sure it's still the same version after getting the page. */
5273494927eSMiklos Szeredi 	if (ff->readdir.version != fi->rdc.version) {
5283494927eSMiklos Szeredi 		spin_unlock(&fi->rdc.lock);
5293494927eSMiklos Szeredi 		unlock_page(page);
5303494927eSMiklos Szeredi 		put_page(page);
5313494927eSMiklos Szeredi 		goto retry;
5323494927eSMiklos Szeredi 	}
5333494927eSMiklos Szeredi 	spin_unlock(&fi->rdc.lock);
5343494927eSMiklos Szeredi 
5353494927eSMiklos Szeredi 	/*
5363494927eSMiklos Szeredi 	 * Contents of the page are now protected against changing by holding
5373494927eSMiklos Szeredi 	 * the page lock.
5383494927eSMiklos Szeredi 	 */
5395d7bc7e8SMiklos Szeredi 	addr = kmap(page);
5405d7bc7e8SMiklos Szeredi 	res = fuse_parse_cache(ff, addr, size, ctx);
5415d7bc7e8SMiklos Szeredi 	kunmap(page);
5425d7bc7e8SMiklos Szeredi 	unlock_page(page);
5435d7bc7e8SMiklos Szeredi 	put_page(page);
5445d7bc7e8SMiklos Szeredi 
5455d7bc7e8SMiklos Szeredi 	if (res == FOUND_ERR)
5465d7bc7e8SMiklos Szeredi 		return -EIO;
5475d7bc7e8SMiklos Szeredi 
5485d7bc7e8SMiklos Szeredi 	if (res == FOUND_ALL)
5495d7bc7e8SMiklos Szeredi 		return 0;
5505d7bc7e8SMiklos Szeredi 
5515d7bc7e8SMiklos Szeredi 	if (size == PAGE_SIZE) {
5525d7bc7e8SMiklos Szeredi 		/* We hit end of page: skip to next page. */
5535d7bc7e8SMiklos Szeredi 		ff->readdir.cache_off = ALIGN(ff->readdir.cache_off, PAGE_SIZE);
5545d7bc7e8SMiklos Szeredi 		goto retry;
5555d7bc7e8SMiklos Szeredi 	}
5565d7bc7e8SMiklos Szeredi 
5575d7bc7e8SMiklos Szeredi 	/*
5585d7bc7e8SMiklos Szeredi 	 * End of cache reached.  If found position, then we are done, otherwise
5595d7bc7e8SMiklos Szeredi 	 * need to fall back to uncached, since the position we were looking for
5605d7bc7e8SMiklos Szeredi 	 * wasn't in the cache.
5615d7bc7e8SMiklos Szeredi 	 */
5625d7bc7e8SMiklos Szeredi 	return res == FOUND_SOME ? 0 : UNCACHED;
5635d7bc7e8SMiklos Szeredi }
5645d7bc7e8SMiklos Szeredi 
5655d7bc7e8SMiklos Szeredi int fuse_readdir(struct file *file, struct dir_context *ctx)
5665d7bc7e8SMiklos Szeredi {
5675d7bc7e8SMiklos Szeredi 	struct fuse_file *ff = file->private_data;
5685d7bc7e8SMiklos Szeredi 	struct inode *inode = file_inode(file);
5695d7bc7e8SMiklos Szeredi 	int err;
5705d7bc7e8SMiklos Szeredi 
5715d7bc7e8SMiklos Szeredi 	if (is_bad_inode(inode))
5725d7bc7e8SMiklos Szeredi 		return -EIO;
5735d7bc7e8SMiklos Szeredi 
5745d7bc7e8SMiklos Szeredi 	mutex_lock(&ff->readdir.lock);
5755d7bc7e8SMiklos Szeredi 
5765d7bc7e8SMiklos Szeredi 	err = UNCACHED;
5775d7bc7e8SMiklos Szeredi 	if (ff->open_flags & FOPEN_CACHE_DIR)
5785d7bc7e8SMiklos Szeredi 		err = fuse_readdir_cached(file, ctx);
5795d7bc7e8SMiklos Szeredi 	if (err == UNCACHED)
5805d7bc7e8SMiklos Szeredi 		err = fuse_readdir_uncached(file, ctx);
5815d7bc7e8SMiklos Szeredi 
5825d7bc7e8SMiklos Szeredi 	mutex_unlock(&ff->readdir.lock);
5835d7bc7e8SMiklos Szeredi 
5845d7bc7e8SMiklos Szeredi 	return err;
5855d7bc7e8SMiklos Szeredi }
586