Blame view

fs/fuse/readdir.c 13.6 KB
d123d8e18   Miklos Szeredi   fuse: split out r...
1
2
3
4
5
6
7
8
9
10
  /*
    FUSE: Filesystem in Userspace
    Copyright (C) 2001-2018  Miklos Szeredi <miklos@szeredi.hu>
  
    This program can be distributed under the terms of the GNU GPL.
    See the file COPYING.
  */
  
  
  #include "fuse_i.h"
261aaba72   Miklos Szeredi   fuse: use iversio...
11
  #include <linux/iversion.h>
d123d8e18   Miklos Szeredi   fuse: split out r...
12
  #include <linux/posix_acl.h>
69e345511   Miklos Szeredi   fuse: allow cachi...
13
14
  #include <linux/pagemap.h>
  #include <linux/highmem.h>
d123d8e18   Miklos Szeredi   fuse: split out r...
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  
  static bool fuse_use_readdirplus(struct inode *dir, struct dir_context *ctx)
  {
  	struct fuse_conn *fc = get_fuse_conn(dir);
  	struct fuse_inode *fi = get_fuse_inode(dir);
  
  	if (!fc->do_readdirplus)
  		return false;
  	if (!fc->readdirplus_auto)
  		return true;
  	if (test_and_clear_bit(FUSE_I_ADVISE_RDPLUS, &fi->state))
  		return true;
  	if (ctx->pos == 0)
  		return true;
  	return false;
  }
69e345511   Miklos Szeredi   fuse: allow cachi...
31
32
33
34
35
36
37
38
  static void fuse_add_dirent_to_cache(struct file *file,
  				     struct fuse_dirent *dirent, loff_t pos)
  {
  	struct fuse_inode *fi = get_fuse_inode(file_inode(file));
  	size_t reclen = FUSE_DIRENT_SIZE(dirent);
  	pgoff_t index;
  	struct page *page;
  	loff_t size;
3494927e0   Miklos Szeredi   fuse: add readdir...
39
  	u64 version;
69e345511   Miklos Szeredi   fuse: allow cachi...
40
41
42
43
44
45
46
47
48
49
50
51
  	unsigned int offset;
  	void *addr;
  
  	spin_lock(&fi->rdc.lock);
  	/*
  	 * Is cache already completed?  Or this entry does not go at the end of
  	 * cache?
  	 */
  	if (fi->rdc.cached || pos != fi->rdc.pos) {
  		spin_unlock(&fi->rdc.lock);
  		return;
  	}
3494927e0   Miklos Szeredi   fuse: add readdir...
52
  	version = fi->rdc.version;
69e345511   Miklos Szeredi   fuse: allow cachi...
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
  	size = fi->rdc.size;
  	offset = size & ~PAGE_MASK;
  	index = size >> PAGE_SHIFT;
  	/* Dirent doesn't fit in current page?  Jump to next page. */
  	if (offset + reclen > PAGE_SIZE) {
  		index++;
  		offset = 0;
  	}
  	spin_unlock(&fi->rdc.lock);
  
  	if (offset) {
  		page = find_lock_page(file->f_mapping, index);
  	} else {
  		page = find_or_create_page(file->f_mapping, index,
  					   mapping_gfp_mask(file->f_mapping));
  	}
  	if (!page)
  		return;
  
  	spin_lock(&fi->rdc.lock);
  	/* Raced with another readdir */
3494927e0   Miklos Szeredi   fuse: add readdir...
74
75
  	if (fi->rdc.version != version || fi->rdc.size != size ||
  	    WARN_ON(fi->rdc.pos != pos))
69e345511   Miklos Szeredi   fuse: allow cachi...
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  		goto unlock;
  
  	addr = kmap_atomic(page);
  	if (!offset)
  		clear_page(addr);
  	memcpy(addr + offset, dirent, reclen);
  	kunmap_atomic(addr);
  	fi->rdc.size = (index << PAGE_SHIFT) + offset + reclen;
  	fi->rdc.pos = dirent->off;
  unlock:
  	spin_unlock(&fi->rdc.lock);
  	unlock_page(page);
  	put_page(page);
  }
  
  static void fuse_readdir_cache_end(struct file *file, loff_t pos)
  {
  	struct fuse_inode *fi = get_fuse_inode(file_inode(file));
  	loff_t end;
  
  	spin_lock(&fi->rdc.lock);
  	/* does cache end position match current position? */
  	if (fi->rdc.pos != pos) {
  		spin_unlock(&fi->rdc.lock);
  		return;
  	}
  
  	fi->rdc.cached = true;
  	end = ALIGN(fi->rdc.size, PAGE_SIZE);
  	spin_unlock(&fi->rdc.lock);
  
  	/* truncate unused tail of cache */
  	truncate_inode_pages(file->f_mapping, end);
  }
18172b10b   Miklos Szeredi   fuse: extract fus...
110
111
112
  static bool fuse_emit(struct file *file, struct dir_context *ctx,
  		      struct fuse_dirent *dirent)
  {
69e345511   Miklos Szeredi   fuse: allow cachi...
113
114
115
116
  	struct fuse_file *ff = file->private_data;
  
  	if (ff->open_flags & FOPEN_CACHE_DIR)
  		fuse_add_dirent_to_cache(file, dirent, ctx->pos);
18172b10b   Miklos Szeredi   fuse: extract fus...
117
118
119
  	return dir_emit(ctx, dirent->name, dirent->namelen, dirent->ino,
  			dirent->type);
  }
d123d8e18   Miklos Szeredi   fuse: split out r...
120
121
122
123
124
125
126
127
128
129
130
131
  static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
  			 struct dir_context *ctx)
  {
  	while (nbytes >= FUSE_NAME_OFFSET) {
  		struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
  		size_t reclen = FUSE_DIRENT_SIZE(dirent);
  		if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
  			return -EIO;
  		if (reclen > nbytes)
  			break;
  		if (memchr(dirent->name, '/', dirent->namelen) != NULL)
  			return -EIO;
18172b10b   Miklos Szeredi   fuse: extract fus...
132
  		if (!fuse_emit(file, ctx, dirent))
d123d8e18   Miklos Szeredi   fuse: split out r...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
  			break;
  
  		buf += reclen;
  		nbytes -= reclen;
  		ctx->pos = dirent->off;
  	}
  
  	return 0;
  }
  
  static int fuse_direntplus_link(struct file *file,
  				struct fuse_direntplus *direntplus,
  				u64 attr_version)
  {
  	struct fuse_entry_out *o = &direntplus->entry_out;
  	struct fuse_dirent *dirent = &direntplus->dirent;
  	struct dentry *parent = file->f_path.dentry;
  	struct qstr name = QSTR_INIT(dirent->name, dirent->namelen);
  	struct dentry *dentry;
  	struct dentry *alias;
  	struct inode *dir = d_inode(parent);
  	struct fuse_conn *fc;
  	struct inode *inode;
  	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
  
  	if (!o->nodeid) {
  		/*
  		 * Unlike in the case of fuse_lookup, zero nodeid does not mean
  		 * ENOENT. Instead, it only means the userspace filesystem did
  		 * not want to return attributes/handle for this entry.
  		 *
  		 * So do nothing.
  		 */
  		return 0;
  	}
  
  	if (name.name[0] == '.') {
  		/*
  		 * We could potentially refresh the attributes of the directory
  		 * and its parent?
  		 */
  		if (name.len == 1)
  			return 0;
  		if (name.name[1] == '.' && name.len == 2)
  			return 0;
  	}
  
  	if (invalid_nodeid(o->nodeid))
  		return -EIO;
eb59bd17d   Miklos Szeredi   fuse: verify attr...
182
  	if (fuse_invalid_attr(&o->attr))
d123d8e18   Miklos Szeredi   fuse: split out r...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
  		return -EIO;
  
  	fc = get_fuse_conn(dir);
  
  	name.hash = full_name_hash(parent, name.name, name.len);
  	dentry = d_lookup(parent, &name);
  	if (!dentry) {
  retry:
  		dentry = d_alloc_parallel(parent, &name, &wq);
  		if (IS_ERR(dentry))
  			return PTR_ERR(dentry);
  	}
  	if (!d_in_lookup(dentry)) {
  		struct fuse_inode *fi;
  		inode = d_inode(dentry);
  		if (!inode ||
  		    get_node_id(inode) != o->nodeid ||
  		    ((o->attr.mode ^ inode->i_mode) & S_IFMT)) {
  			d_invalidate(dentry);
  			dput(dentry);
  			goto retry;
  		}
36cf9ae54   Miklos Szeredi   fuse: fix bad inode
205
  		if (fuse_is_bad(inode)) {
d123d8e18   Miklos Szeredi   fuse: split out r...
206
207
208
209
210
  			dput(dentry);
  			return -EIO;
  		}
  
  		fi = get_fuse_inode(inode);
c9d8f5f06   Kirill Tkhai   fuse: Protect fi-...
211
  		spin_lock(&fi->lock);
d123d8e18   Miklos Szeredi   fuse: split out r...
212
  		fi->nlookup++;
c9d8f5f06   Kirill Tkhai   fuse: Protect fi-...
213
  		spin_unlock(&fi->lock);
d123d8e18   Miklos Szeredi   fuse: split out r...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
  
  		forget_all_cached_acls(inode);
  		fuse_change_attributes(inode, &o->attr,
  				       entry_attr_timeout(o),
  				       attr_version);
  		/*
  		 * The other branch comes via fuse_iget()
  		 * which bumps nlookup inside
  		 */
  	} else {
  		inode = fuse_iget(dir->i_sb, o->nodeid, o->generation,
  				  &o->attr, entry_attr_timeout(o),
  				  attr_version);
  		if (!inode)
  			inode = ERR_PTR(-ENOMEM);
  
  		alias = d_splice_alias(inode, dentry);
  		d_lookup_done(dentry);
  		if (alias) {
  			dput(dentry);
  			dentry = alias;
  		}
  		if (IS_ERR(dentry))
  			return PTR_ERR(dentry);
  	}
  	if (fc->readdirplus_auto)
  		set_bit(FUSE_I_INIT_RDPLUS, &get_fuse_inode(inode)->state);
  	fuse_change_entry_timeout(dentry, o);
  
  	dput(dentry);
  	return 0;
  }
3545fe211   Miklos Szeredi   fuse: convert fus...
246
247
248
  static void fuse_force_forget(struct file *file, u64 nodeid)
  {
  	struct inode *inode = file_inode(file);
fcee216be   Max Reitz   fuse: split fuse_...
249
  	struct fuse_mount *fm = get_fuse_mount(inode);
3545fe211   Miklos Szeredi   fuse: convert fus...
250
251
252
253
254
255
256
257
258
259
260
261
  	struct fuse_forget_in inarg;
  	FUSE_ARGS(args);
  
  	memset(&inarg, 0, sizeof(inarg));
  	inarg.nlookup = 1;
  	args.opcode = FUSE_FORGET;
  	args.nodeid = nodeid;
  	args.in_numargs = 1;
  	args.in_args[0].size = sizeof(inarg);
  	args.in_args[0].value = &inarg;
  	args.force = true;
  	args.noreply = true;
fcee216be   Max Reitz   fuse: split fuse_...
262
  	fuse_simple_request(fm, &args);
3545fe211   Miklos Szeredi   fuse: convert fus...
263
264
  	/* ignore errors */
  }
d123d8e18   Miklos Szeredi   fuse: split out r...
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
  static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file,
  			     struct dir_context *ctx, u64 attr_version)
  {
  	struct fuse_direntplus *direntplus;
  	struct fuse_dirent *dirent;
  	size_t reclen;
  	int over = 0;
  	int ret;
  
  	while (nbytes >= FUSE_NAME_OFFSET_DIRENTPLUS) {
  		direntplus = (struct fuse_direntplus *) buf;
  		dirent = &direntplus->dirent;
  		reclen = FUSE_DIRENTPLUS_SIZE(direntplus);
  
  		if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
  			return -EIO;
  		if (reclen > nbytes)
  			break;
  		if (memchr(dirent->name, '/', dirent->namelen) != NULL)
  			return -EIO;
  
  		if (!over) {
  			/* We fill entries into dstbuf only as much as
  			   it can hold. But we still continue iterating
  			   over remaining entries to link them. If not,
  			   we need to send a FORGET for each of those
  			   which we did not link.
  			*/
18172b10b   Miklos Szeredi   fuse: extract fus...
293
  			over = !fuse_emit(file, ctx, dirent);
d123d8e18   Miklos Szeredi   fuse: split out r...
294
295
296
297
298
299
300
301
302
303
304
305
306
307
  			if (!over)
  				ctx->pos = dirent->off;
  		}
  
  		buf += reclen;
  		nbytes -= reclen;
  
  		ret = fuse_direntplus_link(file, direntplus, attr_version);
  		if (ret)
  			fuse_force_forget(file, direntplus->entry_out.nodeid);
  	}
  
  	return 0;
  }
5d7bc7e86   Miklos Szeredi   fuse: allow using...
308
  static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx)
d123d8e18   Miklos Szeredi   fuse: split out r...
309
  {
43f5098eb   Miklos Szeredi   fuse: convert rea...
310
311
  	int plus;
  	ssize_t res;
d123d8e18   Miklos Szeredi   fuse: split out r...
312
313
  	struct page *page;
  	struct inode *inode = file_inode(file);
fcee216be   Max Reitz   fuse: split fuse_...
314
  	struct fuse_mount *fm = get_fuse_mount(inode);
43f5098eb   Miklos Szeredi   fuse: convert rea...
315
316
317
  	struct fuse_io_args ia = {};
  	struct fuse_args_pages *ap = &ia.ap;
  	struct fuse_page_desc desc = { .length = PAGE_SIZE };
d123d8e18   Miklos Szeredi   fuse: split out r...
318
319
  	u64 attr_version = 0;
  	bool locked;
d123d8e18   Miklos Szeredi   fuse: split out r...
320
  	page = alloc_page(GFP_KERNEL);
43f5098eb   Miklos Szeredi   fuse: convert rea...
321
  	if (!page)
d123d8e18   Miklos Szeredi   fuse: split out r...
322
  		return -ENOMEM;
d123d8e18   Miklos Szeredi   fuse: split out r...
323
324
  
  	plus = fuse_use_readdirplus(inode, ctx);
cabdb4fa2   zhengbin   fuse: use true,fa...
325
  	ap->args.out_pages = true;
43f5098eb   Miklos Szeredi   fuse: convert rea...
326
327
328
  	ap->num_pages = 1;
  	ap->pages = &page;
  	ap->descs = &desc;
d123d8e18   Miklos Szeredi   fuse: split out r...
329
  	if (plus) {
fcee216be   Max Reitz   fuse: split fuse_...
330
  		attr_version = fuse_get_attr_version(fm->fc);
43f5098eb   Miklos Szeredi   fuse: convert rea...
331
332
  		fuse_read_args_fill(&ia, file, ctx->pos, PAGE_SIZE,
  				    FUSE_READDIRPLUS);
d123d8e18   Miklos Szeredi   fuse: split out r...
333
  	} else {
43f5098eb   Miklos Szeredi   fuse: convert rea...
334
335
  		fuse_read_args_fill(&ia, file, ctx->pos, PAGE_SIZE,
  				    FUSE_READDIR);
d123d8e18   Miklos Szeredi   fuse: split out r...
336
337
  	}
  	locked = fuse_lock_inode(inode);
fcee216be   Max Reitz   fuse: split fuse_...
338
  	res = fuse_simple_request(fm, &ap->args);
d123d8e18   Miklos Szeredi   fuse: split out r...
339
  	fuse_unlock_inode(inode, locked);
43f5098eb   Miklos Szeredi   fuse: convert rea...
340
341
  	if (res >= 0) {
  		if (!res) {
69e345511   Miklos Szeredi   fuse: allow cachi...
342
343
344
345
346
  			struct fuse_file *ff = file->private_data;
  
  			if (ff->open_flags & FOPEN_CACHE_DIR)
  				fuse_readdir_cache_end(file, ctx->pos);
  		} else if (plus) {
43f5098eb   Miklos Szeredi   fuse: convert rea...
347
  			res = parse_dirplusfile(page_address(page), res,
d123d8e18   Miklos Szeredi   fuse: split out r...
348
349
  						file, ctx, attr_version);
  		} else {
43f5098eb   Miklos Szeredi   fuse: convert rea...
350
  			res = parse_dirfile(page_address(page), res, file,
d123d8e18   Miklos Szeredi   fuse: split out r...
351
352
353
354
355
356
  					    ctx);
  		}
  	}
  
  	__free_page(page);
  	fuse_invalidate_atime(inode);
43f5098eb   Miklos Szeredi   fuse: convert rea...
357
  	return res;
d123d8e18   Miklos Szeredi   fuse: split out r...
358
  }
5d7bc7e86   Miklos Szeredi   fuse: allow using...
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  
  enum fuse_parse_result {
  	FOUND_ERR = -1,
  	FOUND_NONE = 0,
  	FOUND_SOME,
  	FOUND_ALL,
  };
  
  static enum fuse_parse_result fuse_parse_cache(struct fuse_file *ff,
  					       void *addr, unsigned int size,
  					       struct dir_context *ctx)
  {
  	unsigned int offset = ff->readdir.cache_off & ~PAGE_MASK;
  	enum fuse_parse_result res = FOUND_NONE;
  
  	WARN_ON(offset >= size);
  
  	for (;;) {
  		struct fuse_dirent *dirent = addr + offset;
  		unsigned int nbytes = size - offset;
e5854b1cd   Tejun Heo   fuse: fix beyond-...
379
  		size_t reclen;
5d7bc7e86   Miklos Szeredi   fuse: allow using...
380
381
382
  
  		if (nbytes < FUSE_NAME_OFFSET || !dirent->namelen)
  			break;
e5854b1cd   Tejun Heo   fuse: fix beyond-...
383
  		reclen = FUSE_DIRENT_SIZE(dirent); /* derefs ->namelen */
5d7bc7e86   Miklos Szeredi   fuse: allow using...
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
  		if (WARN_ON(dirent->namelen > FUSE_NAME_MAX))
  			return FOUND_ERR;
  		if (WARN_ON(reclen > nbytes))
  			return FOUND_ERR;
  		if (WARN_ON(memchr(dirent->name, '/', dirent->namelen) != NULL))
  			return FOUND_ERR;
  
  		if (ff->readdir.pos == ctx->pos) {
  			res = FOUND_SOME;
  			if (!dir_emit(ctx, dirent->name, dirent->namelen,
  				      dirent->ino, dirent->type))
  				return FOUND_ALL;
  			ctx->pos = dirent->off;
  		}
  		ff->readdir.pos = dirent->off;
  		ff->readdir.cache_off += reclen;
  
  		offset += reclen;
  	}
  
  	return res;
  }
7118883b4   Miklos Szeredi   fuse: use mtime f...
406
  static void fuse_rdc_reset(struct inode *inode)
3494927e0   Miklos Szeredi   fuse: add readdir...
407
  {
7118883b4   Miklos Szeredi   fuse: use mtime f...
408
  	struct fuse_inode *fi = get_fuse_inode(inode);
3494927e0   Miklos Szeredi   fuse: add readdir...
409
410
411
412
413
  	fi->rdc.cached = false;
  	fi->rdc.version++;
  	fi->rdc.size = 0;
  	fi->rdc.pos = 0;
  }
5d7bc7e86   Miklos Szeredi   fuse: allow using...
414
415
416
417
418
419
  #define UNCACHED 1
  
  static int fuse_readdir_cached(struct file *file, struct dir_context *ctx)
  {
  	struct fuse_file *ff = file->private_data;
  	struct inode *inode = file_inode(file);
7118883b4   Miklos Szeredi   fuse: use mtime f...
420
  	struct fuse_conn *fc = get_fuse_conn(inode);
5d7bc7e86   Miklos Szeredi   fuse: allow using...
421
422
423
424
425
426
427
428
429
430
431
432
  	struct fuse_inode *fi = get_fuse_inode(inode);
  	enum fuse_parse_result res;
  	pgoff_t index;
  	unsigned int size;
  	struct page *page;
  	void *addr;
  
  	/* Seeked?  If so, reset the cache stream */
  	if (ff->readdir.pos != ctx->pos) {
  		ff->readdir.pos = 0;
  		ff->readdir.cache_off = 0;
  	}
7118883b4   Miklos Szeredi   fuse: use mtime f...
433
434
435
436
437
438
439
440
441
442
  	/*
  	 * We're just about to start reading into the cache or reading the
  	 * cache; both cases require an up-to-date mtime value.
  	 */
  	if (!ctx->pos && fc->auto_inval_data) {
  		int err = fuse_update_attributes(inode, file);
  
  		if (err)
  			return err;
  	}
5d7bc7e86   Miklos Szeredi   fuse: allow using...
443
444
  retry:
  	spin_lock(&fi->rdc.lock);
7118883b4   Miklos Szeredi   fuse: use mtime f...
445
  retry_locked:
5d7bc7e86   Miklos Szeredi   fuse: allow using...
446
  	if (!fi->rdc.cached) {
7118883b4   Miklos Szeredi   fuse: use mtime f...
447
448
449
  		/* Starting cache? Set cache mtime. */
  		if (!ctx->pos && !fi->rdc.size) {
  			fi->rdc.mtime = inode->i_mtime;
261aaba72   Miklos Szeredi   fuse: use iversio...
450
  			fi->rdc.iversion = inode_query_iversion(inode);
7118883b4   Miklos Szeredi   fuse: use mtime f...
451
  		}
5d7bc7e86   Miklos Szeredi   fuse: allow using...
452
453
454
  		spin_unlock(&fi->rdc.lock);
  		return UNCACHED;
  	}
3494927e0   Miklos Szeredi   fuse: add readdir...
455
  	/*
7118883b4   Miklos Szeredi   fuse: use mtime f...
456
457
458
459
460
  	 * When at the beginning of the directory (i.e. just after opendir(3) or
  	 * rewinddir(3)), then need to check whether directory contents have
  	 * changed, and reset the cache if so.
  	 */
  	if (!ctx->pos) {
261aaba72   Miklos Szeredi   fuse: use iversio...
461
462
  		if (inode_peek_iversion(inode) != fi->rdc.iversion ||
  		    !timespec64_equal(&fi->rdc.mtime, &inode->i_mtime)) {
7118883b4   Miklos Szeredi   fuse: use mtime f...
463
464
465
466
467
468
  			fuse_rdc_reset(inode);
  			goto retry_locked;
  		}
  	}
  
  	/*
3494927e0   Miklos Szeredi   fuse: add readdir...
469
470
471
472
473
474
475
476
477
478
479
480
481
  	 * If cache version changed since the last getdents() call, then reset
  	 * the cache stream.
  	 */
  	if (ff->readdir.version != fi->rdc.version) {
  		ff->readdir.pos = 0;
  		ff->readdir.cache_off = 0;
  	}
  	/*
  	 * If at the beginning of the cache, than reset version to
  	 * current.
  	 */
  	if (ff->readdir.pos == 0)
  		ff->readdir.version = fi->rdc.version;
5d7bc7e86   Miklos Szeredi   fuse: allow using...
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
  	WARN_ON(fi->rdc.size < ff->readdir.cache_off);
  
  	index = ff->readdir.cache_off >> PAGE_SHIFT;
  
  	if (index == (fi->rdc.size >> PAGE_SHIFT))
  		size = fi->rdc.size & ~PAGE_MASK;
  	else
  		size = PAGE_SIZE;
  	spin_unlock(&fi->rdc.lock);
  
  	/* EOF? */
  	if ((ff->readdir.cache_off & ~PAGE_MASK) == size)
  		return 0;
  
  	page = find_get_page_flags(file->f_mapping, index,
  				   FGP_ACCESSED | FGP_LOCK);
3494927e0   Miklos Szeredi   fuse: add readdir...
498
  	spin_lock(&fi->rdc.lock);
5d7bc7e86   Miklos Szeredi   fuse: allow using...
499
500
501
502
  	if (!page) {
  		/*
  		 * Uh-oh: page gone missing, cache is useless
  		 */
3494927e0   Miklos Szeredi   fuse: add readdir...
503
  		if (fi->rdc.version == ff->readdir.version)
7118883b4   Miklos Szeredi   fuse: use mtime f...
504
505
  			fuse_rdc_reset(inode);
  		goto retry_locked;
5d7bc7e86   Miklos Szeredi   fuse: allow using...
506
  	}
3494927e0   Miklos Szeredi   fuse: add readdir...
507
508
509
510
511
512
513
514
515
516
517
518
519
  	/* Make sure it's still the same version after getting the page. */
  	if (ff->readdir.version != fi->rdc.version) {
  		spin_unlock(&fi->rdc.lock);
  		unlock_page(page);
  		put_page(page);
  		goto retry;
  	}
  	spin_unlock(&fi->rdc.lock);
  
  	/*
  	 * Contents of the page are now protected against changing by holding
  	 * the page lock.
  	 */
5d7bc7e86   Miklos Szeredi   fuse: allow using...
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
  	addr = kmap(page);
  	res = fuse_parse_cache(ff, addr, size, ctx);
  	kunmap(page);
  	unlock_page(page);
  	put_page(page);
  
  	if (res == FOUND_ERR)
  		return -EIO;
  
  	if (res == FOUND_ALL)
  		return 0;
  
  	if (size == PAGE_SIZE) {
  		/* We hit end of page: skip to next page. */
  		ff->readdir.cache_off = ALIGN(ff->readdir.cache_off, PAGE_SIZE);
  		goto retry;
  	}
  
  	/*
  	 * End of cache reached.  If found position, then we are done, otherwise
  	 * need to fall back to uncached, since the position we were looking for
  	 * wasn't in the cache.
  	 */
  	return res == FOUND_SOME ? 0 : UNCACHED;
  }
  
  int fuse_readdir(struct file *file, struct dir_context *ctx)
  {
  	struct fuse_file *ff = file->private_data;
  	struct inode *inode = file_inode(file);
  	int err;
36cf9ae54   Miklos Szeredi   fuse: fix bad inode
551
  	if (fuse_is_bad(inode))
5d7bc7e86   Miklos Szeredi   fuse: allow using...
552
553
554
555
556
557
558
559
560
561
562
563
564
565
  		return -EIO;
  
  	mutex_lock(&ff->readdir.lock);
  
  	err = UNCACHED;
  	if (ff->open_flags & FOPEN_CACHE_DIR)
  		err = fuse_readdir_cached(file, ctx);
  	if (err == UNCACHED)
  		err = fuse_readdir_uncached(file, ctx);
  
  	mutex_unlock(&ff->readdir.lock);
  
  	return err;
  }