Blame view

fs/afs/dir.c 51.8 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
  /* dir.c: AFS filesystem directory handling
   *
f3ddee8dc   David Howells   afs: Fix director...
4
   * Copyright (C) 2002, 2018 Red Hat, Inc. All Rights Reserved.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
   * Written by David Howells (dhowells@redhat.com)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
   */
  
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
  #include <linux/fs.h>
34286d666   Nick Piggin   fs: rcu-walk awar...
10
  #include <linux/namei.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
  #include <linux/pagemap.h>
f3ddee8dc   David Howells   afs: Fix director...
12
  #include <linux/swap.h>
00d3b7a45   David Howells   [AFS]: Add securi...
13
  #include <linux/ctype.h>
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
14
  #include <linux/sched.h>
f3ddee8dc   David Howells   afs: Fix director...
15
  #include <linux/task_io_accounting_ops.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  #include "internal.h"
a58823ac4   David Howells   afs: Fix applicat...
17
  #include "afs_fs.h"
4ea219a83   David Howells   afs: Split the di...
18
  #include "xdr_fs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19

260a98031   David Howells   [AFS]: Add "direc...
20
  static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
00cd8dd3b   Al Viro   stop passing name...
21
  				 unsigned int flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  static int afs_dir_open(struct inode *inode, struct file *file);
1bbae9f81   Al Viro   [readdir] convert...
23
  static int afs_readdir(struct file *file, struct dir_context *ctx);
0b728e191   Al Viro   stop passing name...
24
  static int afs_d_revalidate(struct dentry *dentry, unsigned int flags);
fe15ce446   Nick Piggin   fs: change d_dele...
25
  static int afs_d_delete(const struct dentry *dentry);
79ddbfa50   David Howells   afs: Implement si...
26
  static void afs_d_iput(struct dentry *dentry, struct inode *inode);
5cf9dd55a   David Howells   afs: Prospectivel...
27
  static int afs_lookup_one_filldir(struct dir_context *ctx, const char *name, int nlen,
afefdbb28   David Howells   [PATCH] VFS: Make...
28
  				  loff_t fpos, u64 ino, unsigned dtype);
5cf9dd55a   David Howells   afs: Prospectivel...
29
30
  static int afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen,
  			      loff_t fpos, u64 ino, unsigned dtype);
4acdaf27e   Al Viro   switch ->create()...
31
  static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
ebfc3b49a   Al Viro   don't pass nameid...
32
  		      bool excl);
18bb1db3e   Al Viro   switch vfs_mkdir(...
33
  static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
260a98031   David Howells   [AFS]: Add "direc...
34
35
36
37
38
39
40
  static int afs_rmdir(struct inode *dir, struct dentry *dentry);
  static int afs_unlink(struct inode *dir, struct dentry *dentry);
  static int afs_link(struct dentry *from, struct inode *dir,
  		    struct dentry *dentry);
  static int afs_symlink(struct inode *dir, struct dentry *dentry,
  		       const char *content);
  static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
1cd66c93b   Miklos Szeredi   fs: make remainin...
41
42
  		      struct inode *new_dir, struct dentry *new_dentry,
  		      unsigned int flags);
f3ddee8dc   David Howells   afs: Fix director...
43
44
45
46
47
48
49
50
  static int afs_dir_releasepage(struct page *page, gfp_t gfp_flags);
  static void afs_dir_invalidatepage(struct page *page, unsigned int offset,
  				   unsigned int length);
  
  static int afs_dir_set_page_dirty(struct page *page)
  {
  	BUG(); /* This should never happen. */
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51

4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
52
  const struct file_operations afs_dir_file_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  	.open		= afs_dir_open,
00d3b7a45   David Howells   [AFS]: Add securi...
54
  	.release	= afs_release,
29884eff1   Al Viro   afs: switch to ->...
55
  	.iterate_shared	= afs_readdir,
e8d6c5541   David Howells   AFS: implement fi...
56
  	.lock		= afs_lock,
3222a3e55   Christoph Hellwig   [PATCH] fix ->lls...
57
  	.llseek		= generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  };
754661f14   Arjan van de Ven   [PATCH] mark stru...
59
  const struct inode_operations afs_dir_inode_operations = {
260a98031   David Howells   [AFS]: Add "direc...
60
61
62
63
64
65
66
  	.create		= afs_create,
  	.lookup		= afs_lookup,
  	.link		= afs_link,
  	.unlink		= afs_unlink,
  	.symlink	= afs_symlink,
  	.mkdir		= afs_mkdir,
  	.rmdir		= afs_rmdir,
2773bf00a   Miklos Szeredi   fs: rename "renam...
67
  	.rename		= afs_rename,
00d3b7a45   David Howells   [AFS]: Add securi...
68
  	.permission	= afs_permission,
416351f28   David Howells   AFS: AFS fixups
69
  	.getattr	= afs_getattr,
31143d5d5   David Howells   AFS: implement ba...
70
  	.setattr	= afs_setattr,
d3e3b7eac   David Howells   afs: Add metadata...
71
  	.listxattr	= afs_listxattr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
  };
f3ddee8dc   David Howells   afs: Fix director...
73
74
75
76
77
  const struct address_space_operations afs_dir_aops = {
  	.set_page_dirty	= afs_dir_set_page_dirty,
  	.releasepage	= afs_dir_releasepage,
  	.invalidatepage	= afs_dir_invalidatepage,
  };
d61dcce29   Al Viro   switch afs
78
  const struct dentry_operations afs_fs_dentry_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
  	.d_revalidate	= afs_d_revalidate,
  	.d_delete	= afs_d_delete,
260a98031   David Howells   [AFS]: Add "direc...
81
  	.d_release	= afs_d_release,
d18610b0c   David Howells   AFS: Use d_automo...
82
  	.d_automount	= afs_d_automount,
79ddbfa50   David Howells   afs: Implement si...
83
  	.d_iput		= afs_d_iput,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
  };
5cf9dd55a   David Howells   afs: Prospectivel...
85
86
87
88
89
90
  struct afs_lookup_one_cookie {
  	struct dir_context	ctx;
  	struct qstr		name;
  	bool			found;
  	struct afs_fid		fid;
  };
260a98031   David Howells   [AFS]: Add "direc...
91
  struct afs_lookup_cookie {
5cf9dd55a   David Howells   afs: Prospectivel...
92
93
94
95
96
  	struct dir_context	ctx;
  	struct qstr		name;
  	bool			found;
  	bool			one_only;
  	unsigned short		nr_fids;
5cf9dd55a   David Howells   afs: Prospectivel...
97
  	struct afs_fid		fids[50];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
101
  /*
   * check that a directory page is valid
   */
f3ddee8dc   David Howells   afs: Fix director...
102
103
  static bool afs_dir_check_page(struct afs_vnode *dvnode, struct page *page,
  			       loff_t i_size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
  {
003176369   David Howells   afs: Adjust the d...
105
  	struct afs_xdr_dir_page *dbuf;
f3ddee8dc   David Howells   afs: Fix director...
106
  	loff_t latter, off;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
  	int tmp, qty;
dab17c1ad   David Howells   afs: Fix director...
108
109
110
111
  	/* Determine how many magic numbers there should be in this page, but
  	 * we must take care because the directory may change size under us.
  	 */
  	off = page_offset(page);
dab17c1ad   David Howells   afs: Fix director...
112
113
114
115
  	if (i_size <= off)
  		goto checked;
  
  	latter = i_size - off;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
119
  	if (latter >= PAGE_SIZE)
  		qty = PAGE_SIZE;
  	else
  		qty = latter;
003176369   David Howells   afs: Adjust the d...
120
  	qty /= sizeof(union afs_xdr_dir_block);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
  
  	/* check them */
63a4681ff   David Howells   afs: Locally edit...
123
  	dbuf = kmap(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
  	for (tmp = 0; tmp < qty; tmp++) {
003176369   David Howells   afs: Adjust the d...
125
  		if (dbuf->blocks[tmp].hdr.magic != AFS_DIR_MAGIC) {
dab17c1ad   David Howells   afs: Fix director...
126
127
  			printk("kAFS: %s(%lx): bad magic %d/%d is %04hx
  ",
f3ddee8dc   David Howells   afs: Fix director...
128
  			       __func__, dvnode->vfs_inode.i_ino, tmp, qty,
003176369   David Howells   afs: Adjust the d...
129
  			       ntohs(dbuf->blocks[tmp].hdr.magic));
f3ddee8dc   David Howells   afs: Fix director...
130
  			trace_afs_dir_check_failed(dvnode, off, i_size);
63a4681ff   David Howells   afs: Locally edit...
131
  			kunmap(page);
f51375cd9   David Howells   afs: Add a couple...
132
  			trace_afs_file_error(dvnode, -EIO, afs_file_error_dir_bad_magic);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
134
  			goto error;
  		}
63a4681ff   David Howells   afs: Locally edit...
135
136
137
138
139
140
  
  		/* Make sure each block is NUL terminated so we can reasonably
  		 * use string functions on it.  The filenames in the page
  		 * *should* be NUL-terminated anyway.
  		 */
  		((u8 *)&dbuf->blocks[tmp])[AFS_DIR_BLOCK_SIZE - 1] = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
  	}
63a4681ff   David Howells   afs: Locally edit...
142
  	kunmap(page);
dab17c1ad   David Howells   afs: Fix director...
143
  checked:
f3ddee8dc   David Howells   afs: Fix director...
144
  	afs_stat_v(dvnode, n_read_dir);
be5b82dbf   Al Viro   make ext2_get_pag...
145
  	return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146

ec26815ad   David Howells   [AFS]: Clean up t...
147
  error:
be5b82dbf   Al Viro   make ext2_get_pag...
148
  	return false;
ec26815ad   David Howells   [AFS]: Clean up t...
149
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
  /*
445b10289   David Howells   afs: Improve dir ...
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
182
183
184
185
186
   * Check the contents of a directory that we've just read.
   */
  static bool afs_dir_check_pages(struct afs_vnode *dvnode, struct afs_read *req)
  {
  	struct afs_xdr_dir_page *dbuf;
  	unsigned int i, j, qty = PAGE_SIZE / sizeof(union afs_xdr_dir_block);
  
  	for (i = 0; i < req->nr_pages; i++)
  		if (!afs_dir_check_page(dvnode, req->pages[i], req->actual_len))
  			goto bad;
  	return true;
  
  bad:
  	pr_warn("DIR %llx:%llx f=%llx l=%llx al=%llx r=%llx
  ",
  		dvnode->fid.vid, dvnode->fid.vnode,
  		req->file_size, req->len, req->actual_len, req->remain);
  	pr_warn("DIR %llx %x %x %x
  ",
  		req->pos, req->index, req->nr_pages, req->offset);
  
  	for (i = 0; i < req->nr_pages; i++) {
  		dbuf = kmap(req->pages[i]);
  		for (j = 0; j < qty; j++) {
  			union afs_xdr_dir_block *block = &dbuf->blocks[j];
  
  			pr_warn("[%02x] %32phN
  ", i * qty + j, block);
  		}
  		kunmap(req->pages[i]);
  	}
  	return false;
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
188
189
190
191
   * open an AFS directory file
   */
  static int afs_dir_open(struct inode *inode, struct file *file)
  {
  	_enter("{%lu}", inode->i_ino);
003176369   David Howells   afs: Adjust the d...
192
193
  	BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048);
  	BUILD_BUG_ON(sizeof(union afs_xdr_dirent) != 32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
195
  	if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(inode)->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
  		return -ENOENT;
00d3b7a45   David Howells   [AFS]: Add securi...
197
  	return afs_open(inode, file);
ec26815ad   David Howells   [AFS]: Clean up t...
198
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
  /*
f3ddee8dc   David Howells   afs: Fix director...
201
202
203
204
205
   * Read the directory into the pagecache in one go, scrubbing the previous
   * contents.  The list of pages is returned, pinning them so that they don't
   * get reclaimed during the iteration.
   */
  static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key)
b61f7dcf4   David Howells   afs: Fix director...
206
  	__acquires(&dvnode->validate_lock)
f3ddee8dc   David Howells   afs: Fix director...
207
208
209
210
211
212
213
214
215
  {
  	struct afs_read *req;
  	loff_t i_size;
  	int nr_pages, nr_inline, i, n;
  	int ret = -ENOMEM;
  
  retry:
  	i_size = i_size_read(&dvnode->vfs_inode);
  	if (i_size < 2048)
f51375cd9   David Howells   afs: Add a couple...
216
217
218
  		return ERR_PTR(afs_bad(dvnode, afs_file_error_dir_small));
  	if (i_size > 2048 * 1024) {
  		trace_afs_file_error(dvnode, -EFBIG, afs_file_error_dir_big);
f3ddee8dc   David Howells   afs: Fix director...
219
  		return ERR_PTR(-EFBIG);
f51375cd9   David Howells   afs: Add a couple...
220
  	}
f3ddee8dc   David Howells   afs: Fix director...
221
222
223
224
225
226
227
228
229
230
  
  	_enter("%llu", i_size);
  
  	/* Get a request record to hold the page list.  We want to hold it
  	 * inline if we can, but we don't want to make an order 1 allocation.
  	 */
  	nr_pages = (i_size + PAGE_SIZE - 1) / PAGE_SIZE;
  	nr_inline = nr_pages;
  	if (nr_inline > (PAGE_SIZE - sizeof(*req)) / sizeof(struct page *))
  		nr_inline = 0;
ee102584e   Zhengyuan Liu   fs/afs: use struc...
231
  	req = kzalloc(struct_size(req, array, nr_inline), GFP_KERNEL);
f3ddee8dc   David Howells   afs: Fix director...
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
  	if (!req)
  		return ERR_PTR(-ENOMEM);
  
  	refcount_set(&req->usage, 1);
  	req->nr_pages = nr_pages;
  	req->actual_len = i_size; /* May change */
  	req->len = nr_pages * PAGE_SIZE; /* We can ask for more than there is */
  	req->data_version = dvnode->status.data_version; /* May change */
  	if (nr_inline > 0) {
  		req->pages = req->array;
  	} else {
  		req->pages = kcalloc(nr_pages, sizeof(struct page *),
  				     GFP_KERNEL);
  		if (!req->pages)
  			goto error;
  	}
  
  	/* Get a list of all the pages that hold or will hold the directory
  	 * content.  We need to fill in any gaps that we might find where the
  	 * memory reclaimer has been at work.  If there are any gaps, we will
  	 * need to reread the entire directory contents.
  	 */
  	i = 0;
  	do {
  		n = find_get_pages_contig(dvnode->vfs_inode.i_mapping, i,
  					  req->nr_pages - i,
  					  req->pages + i);
  		_debug("find %u at %u/%u", n, i, req->nr_pages);
  		if (n == 0) {
  			gfp_t gfp = dvnode->vfs_inode.i_mapping->gfp_mask;
  
  			if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
  				afs_stat_v(dvnode, n_inval);
  
  			ret = -ENOMEM;
  			req->pages[i] = __page_cache_alloc(gfp);
  			if (!req->pages[i])
  				goto error;
  			ret = add_to_page_cache_lru(req->pages[i],
  						    dvnode->vfs_inode.i_mapping,
  						    i, gfp);
  			if (ret < 0)
  				goto error;
fa04a40b1   David Howells   afs: Fix to take ...
275
  			attach_page_private(req->pages[i], (void *)1);
f3ddee8dc   David Howells   afs: Fix director...
276
277
278
279
280
281
282
283
284
285
  			unlock_page(req->pages[i]);
  			i++;
  		} else {
  			i += n;
  		}
  	} while (i < req->nr_pages);
  
  	/* If we're going to reload, we need to lock all the pages to prevent
  	 * races.
  	 */
b61f7dcf4   David Howells   afs: Fix director...
286
287
288
  	ret = -ERESTARTSYS;
  	if (down_read_killable(&dvnode->validate_lock) < 0)
  		goto error;
f3ddee8dc   David Howells   afs: Fix director...
289

b61f7dcf4   David Howells   afs: Fix director...
290
291
  	if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
  		goto success;
f3ddee8dc   David Howells   afs: Fix director...
292

b61f7dcf4   David Howells   afs: Fix director...
293
294
295
296
297
  	up_read(&dvnode->validate_lock);
  	if (down_write_killable(&dvnode->validate_lock) < 0)
  		goto error;
  
  	if (!test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) {
99987c560   David Howells   afs: Add director...
298
  		trace_afs_reload_dir(dvnode);
f3ddee8dc   David Howells   afs: Fix director...
299
300
  		ret = afs_fetch_data(dvnode, key, req);
  		if (ret < 0)
b61f7dcf4   David Howells   afs: Fix director...
301
  			goto error_unlock;
f3ddee8dc   David Howells   afs: Fix director...
302
303
304
305
306
307
308
309
  
  		task_io_account_read(PAGE_SIZE * req->nr_pages);
  
  		if (req->len < req->file_size)
  			goto content_has_grown;
  
  		/* Validate the data we just read. */
  		ret = -EIO;
445b10289   David Howells   afs: Improve dir ...
310
311
  		if (!afs_dir_check_pages(dvnode, req))
  			goto error_unlock;
f3ddee8dc   David Howells   afs: Fix director...
312
313
314
315
316
  
  		// TODO: Trim excess pages
  
  		set_bit(AFS_VNODE_DIR_VALID, &dvnode->flags);
  	}
b61f7dcf4   David Howells   afs: Fix director...
317
  	downgrade_write(&dvnode->validate_lock);
f3ddee8dc   David Howells   afs: Fix director...
318
  success:
f3ddee8dc   David Howells   afs: Fix director...
319
  	return req;
f3ddee8dc   David Howells   afs: Fix director...
320
  error_unlock:
b61f7dcf4   David Howells   afs: Fix director...
321
  	up_write(&dvnode->validate_lock);
f3ddee8dc   David Howells   afs: Fix director...
322
323
324
325
326
327
  error:
  	afs_put_read(req);
  	_leave(" = %d", ret);
  	return ERR_PTR(ret);
  
  content_has_grown:
b61f7dcf4   David Howells   afs: Fix director...
328
  	up_write(&dvnode->validate_lock);
f3ddee8dc   David Howells   afs: Fix director...
329
330
331
332
333
  	afs_put_read(req);
  	goto retry;
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
   * deal with one block in an AFS directory
   */
f51375cd9   David Howells   afs: Add a couple...
336
337
  static int afs_dir_iterate_block(struct afs_vnode *dvnode,
  				 struct dir_context *ctx,
003176369   David Howells   afs: Adjust the d...
338
  				 union afs_xdr_dir_block *block,
1bbae9f81   Al Viro   [readdir] convert...
339
  				 unsigned blkoff)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
  {
003176369   David Howells   afs: Adjust the d...
341
  	union afs_xdr_dirent *dire;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
343
  	unsigned offset, next, curr;
  	size_t nlen;
1bbae9f81   Al Viro   [readdir] convert...
344
  	int tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345

1bbae9f81   Al Viro   [readdir] convert...
346
  	_enter("%u,%x,%p,,",(unsigned)ctx->pos,blkoff,block);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347

003176369   David Howells   afs: Adjust the d...
348
  	curr = (ctx->pos - blkoff) / sizeof(union afs_xdr_dirent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
  
  	/* walk through the block, an entry at a time */
4ea219a83   David Howells   afs: Split the di...
351
352
  	for (offset = (blkoff == 0 ? AFS_DIR_RESV_BLOCKS0 : AFS_DIR_RESV_BLOCKS);
  	     offset < AFS_DIR_SLOTS_PER_BLOCK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
355
356
357
  	     offset = next
  	     ) {
  		next = offset + 1;
  
  		/* skip entries marked unused in the bitmap */
003176369   David Howells   afs: Adjust the d...
358
  		if (!(block->hdr.bitmap[offset / 8] &
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
  		      (1 << (offset % 8)))) {
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
360
  			_debug("ENT[%zu.%u]: unused",
003176369   David Howells   afs: Adjust the d...
361
  			       blkoff / sizeof(union afs_xdr_dir_block), offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
  			if (offset >= curr)
1bbae9f81   Al Viro   [readdir] convert...
363
  				ctx->pos = blkoff +
003176369   David Howells   afs: Adjust the d...
364
  					next * sizeof(union afs_xdr_dirent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
366
367
368
369
370
371
  			continue;
  		}
  
  		/* got a valid entry */
  		dire = &block->dirents[offset];
  		nlen = strnlen(dire->u.name,
  			       sizeof(*block) -
003176369   David Howells   afs: Adjust the d...
372
  			       offset * sizeof(union afs_xdr_dirent));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373

5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
374
  		_debug("ENT[%zu.%u]: %s %zu \"%s\"",
003176369   David Howells   afs: Adjust the d...
375
  		       blkoff / sizeof(union afs_xdr_dir_block), offset,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
377
378
379
  		       (offset < curr ? "skip" : "fill"),
  		       nlen, dire->u.name);
  
  		/* work out where the next possible entry is */
003176369   David Howells   afs: Adjust the d...
380
  		for (tmp = nlen; tmp > 15; tmp -= sizeof(union afs_xdr_dirent)) {
4ea219a83   David Howells   afs: Split the di...
381
  			if (next >= AFS_DIR_SLOTS_PER_BLOCK) {
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
382
  				_debug("ENT[%zu.%u]:"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
  				       " %u travelled beyond end dir block"
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
384
  				       " (len %u/%zu)",
003176369   David Howells   afs: Adjust the d...
385
  				       blkoff / sizeof(union afs_xdr_dir_block),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
  				       offset, next, tmp, nlen);
f51375cd9   David Howells   afs: Add a couple...
387
  				return afs_bad(dvnode, afs_file_error_dir_over_end);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
  			}
003176369   David Howells   afs: Adjust the d...
389
  			if (!(block->hdr.bitmap[next / 8] &
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
  			      (1 << (next % 8)))) {
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
391
392
  				_debug("ENT[%zu.%u]:"
  				       " %u unmarked extension (len %u/%zu)",
003176369   David Howells   afs: Adjust the d...
393
  				       blkoff / sizeof(union afs_xdr_dir_block),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
  				       offset, next, tmp, nlen);
f51375cd9   David Howells   afs: Add a couple...
395
  				return afs_bad(dvnode, afs_file_error_dir_unmarked_ext);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
  			}
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
397
  			_debug("ENT[%zu.%u]: ext %u/%zu",
003176369   David Howells   afs: Adjust the d...
398
  			       blkoff / sizeof(union afs_xdr_dir_block),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
400
401
402
403
404
405
406
407
  			       next, tmp, nlen);
  			next++;
  		}
  
  		/* skip if starts before the current position */
  		if (offset < curr)
  			continue;
  
  		/* found the next entry */
1bbae9f81   Al Viro   [readdir] convert...
408
  		if (!dir_emit(ctx, dire->u.name, nlen,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
  			      ntohl(dire->u.vnode),
5cf9dd55a   David Howells   afs: Prospectivel...
410
411
  			      (ctx->actor == afs_lookup_filldir ||
  			       ctx->actor == afs_lookup_one_filldir)?
1bbae9f81   Al Viro   [readdir] convert...
412
  			      ntohl(dire->u.unique) : DT_UNKNOWN)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
414
415
  			_leave(" = 0 [full]");
  			return 0;
  		}
003176369   David Howells   afs: Adjust the d...
416
  		ctx->pos = blkoff + next * sizeof(union afs_xdr_dirent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
418
419
420
  	}
  
  	_leave(" = 1 [more]");
  	return 1;
ec26815ad   David Howells   [AFS]: Clean up t...
421
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  /*
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
424
   * iterate through the data blob that lists the contents of an AFS directory
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
   */
1bbae9f81   Al Viro   [readdir] convert...
426
  static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx,
9dd0b82ef   David Howells   afs: Fix missing ...
427
  			   struct key *key, afs_dataversion_t *_dir_version)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  {
f3ddee8dc   David Howells   afs: Fix director...
429
  	struct afs_vnode *dvnode = AFS_FS_I(dir);
003176369   David Howells   afs: Adjust the d...
430
431
  	struct afs_xdr_dir_page *dbuf;
  	union afs_xdr_dir_block *dblock;
f3ddee8dc   David Howells   afs: Fix director...
432
  	struct afs_read *req;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
435
  	struct page *page;
  	unsigned blkoff, limit;
  	int ret;
1bbae9f81   Al Viro   [readdir] convert...
436
  	_enter("{%lu},%u,,", dir->i_ino, (unsigned)ctx->pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
438
  	if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dir)->flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
441
  		_leave(" = -ESTALE");
  		return -ESTALE;
  	}
f3ddee8dc   David Howells   afs: Fix director...
442
443
444
  	req = afs_read_dir(dvnode, key);
  	if (IS_ERR(req))
  		return PTR_ERR(req);
9dd0b82ef   David Howells   afs: Fix missing ...
445
  	*_dir_version = req->data_version;
f3ddee8dc   David Howells   afs: Fix director...
446

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
  	/* round the file position up to the next entry boundary */
003176369   David Howells   afs: Adjust the d...
448
449
  	ctx->pos += sizeof(union afs_xdr_dirent) - 1;
  	ctx->pos &= ~(sizeof(union afs_xdr_dirent) - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
451
452
  
  	/* walk through the blocks in sequence */
  	ret = 0;
f3ddee8dc   David Howells   afs: Fix director...
453
  	while (ctx->pos < req->actual_len) {
003176369   David Howells   afs: Adjust the d...
454
  		blkoff = ctx->pos & ~(sizeof(union afs_xdr_dir_block) - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455

f3ddee8dc   David Howells   afs: Fix director...
456
457
458
459
460
  		/* Fetch the appropriate page from the directory and re-add it
  		 * to the LRU.
  		 */
  		page = req->pages[blkoff / PAGE_SIZE];
  		if (!page) {
f51375cd9   David Howells   afs: Add a couple...
461
  			ret = afs_bad(dvnode, afs_file_error_dir_missing_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
463
  			break;
  		}
f3ddee8dc   David Howells   afs: Fix director...
464
  		mark_page_accessed(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
466
  
  		limit = blkoff & ~(PAGE_SIZE - 1);
f3ddee8dc   David Howells   afs: Fix director...
467
  		dbuf = kmap(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
470
471
  
  		/* deal with the individual blocks stashed on this page */
  		do {
  			dblock = &dbuf->blocks[(blkoff % PAGE_SIZE) /
003176369   David Howells   afs: Adjust the d...
472
  					       sizeof(union afs_xdr_dir_block)];
f51375cd9   David Howells   afs: Add a couple...
473
  			ret = afs_dir_iterate_block(dvnode, ctx, dblock, blkoff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
  			if (ret != 1) {
f3ddee8dc   David Howells   afs: Fix director...
475
  				kunmap(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
477
  				goto out;
  			}
003176369   David Howells   afs: Adjust the d...
478
  			blkoff += sizeof(union afs_xdr_dir_block);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479

1bbae9f81   Al Viro   [readdir] convert...
480
  		} while (ctx->pos < dir->i_size && blkoff < limit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481

f3ddee8dc   David Howells   afs: Fix director...
482
  		kunmap(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
  		ret = 0;
  	}
ec26815ad   David Howells   [AFS]: Clean up t...
485
  out:
b61f7dcf4   David Howells   afs: Fix director...
486
  	up_read(&dvnode->validate_lock);
f3ddee8dc   David Howells   afs: Fix director...
487
  	afs_put_read(req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
489
  	_leave(" = %d", ret);
  	return ret;
ec26815ad   David Howells   [AFS]: Clean up t...
490
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
493
494
  /*
   * read an AFS directory
   */
1bbae9f81   Al Viro   [readdir] convert...
495
  static int afs_readdir(struct file *file, struct dir_context *ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
  {
9dd0b82ef   David Howells   afs: Fix missing ...
497
498
499
500
  	afs_dataversion_t dir_version;
  
  	return afs_dir_iterate(file_inode(file), ctx, afs_file_key(file),
  			       &dir_version);
ec26815ad   David Howells   [AFS]: Clean up t...
501
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
  /*
5cf9dd55a   David Howells   afs: Prospectivel...
504
   * Search the directory for a single name
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
506
507
   * - if afs_dir_iterate_block() spots this function, it'll pass the FID
   *   uniquifier through dtype
   */
5cf9dd55a   David Howells   afs: Prospectivel...
508
509
  static int afs_lookup_one_filldir(struct dir_context *ctx, const char *name,
  				  int nlen, loff_t fpos, u64 ino, unsigned dtype)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
  {
5cf9dd55a   David Howells   afs: Prospectivel...
511
512
  	struct afs_lookup_one_cookie *cookie =
  		container_of(ctx, struct afs_lookup_one_cookie, ctx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513

1bbae9f81   Al Viro   [readdir] convert...
514
515
  	_enter("{%s,%u},%s,%u,,%llu,%u",
  	       cookie->name.name, cookie->name.len, name, nlen,
ba3e0e1ac   David S. Miller   [AFS]: Fix u64 pr...
516
  	       (unsigned long long) ino, dtype);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
518
  	/* insanity checks first */
003176369   David Howells   afs: Adjust the d...
519
520
  	BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048);
  	BUILD_BUG_ON(sizeof(union afs_xdr_dirent) != 32);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
521

1bbae9f81   Al Viro   [readdir] convert...
522
523
  	if (cookie->name.len != nlen ||
  	    memcmp(cookie->name.name, name, nlen) != 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
525
526
527
528
529
530
531
532
533
  		_leave(" = 0 [no]");
  		return 0;
  	}
  
  	cookie->fid.vnode = ino;
  	cookie->fid.unique = dtype;
  	cookie->found = 1;
  
  	_leave(" = -1 [found]");
  	return -1;
ec26815ad   David Howells   [AFS]: Clean up t...
534
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
  /*
5cf9dd55a   David Howells   afs: Prospectivel...
537
   * Do a lookup of a single name in a directory
260a98031   David Howells   [AFS]: Add "direc...
538
   * - just returns the FID the dentry name maps to if found
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
   */
5cf9dd55a   David Howells   afs: Prospectivel...
540
  static int afs_do_lookup_one(struct inode *dir, struct dentry *dentry,
9dd0b82ef   David Howells   afs: Fix missing ...
541
542
  			     struct afs_fid *fid, struct key *key,
  			     afs_dataversion_t *_dir_version)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
  {
1bbae9f81   Al Viro   [readdir] convert...
544
  	struct afs_super_info *as = dir->i_sb->s_fs_info;
5cf9dd55a   David Howells   afs: Prospectivel...
545
546
  	struct afs_lookup_one_cookie cookie = {
  		.ctx.actor = afs_lookup_one_filldir,
1bbae9f81   Al Viro   [readdir] convert...
547
548
549
  		.name = dentry->d_name,
  		.fid.vid = as->volume->vid
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
  	int ret;
a455589f1   Al Viro   assorted conversi...
551
  	_enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  	/* search the directory */
9dd0b82ef   David Howells   afs: Fix missing ...
554
  	ret = afs_dir_iterate(dir, &cookie.ctx, key, _dir_version);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
  	if (ret < 0) {
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
556
557
  		_leave(" = %d [iter]", ret);
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
559
560
561
  	}
  
  	ret = -ENOENT;
  	if (!cookie.found) {
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
562
563
  		_leave(" = -ENOENT [not found]");
  		return -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
  	}
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
565
  	*fid = cookie.fid;
3b6492df4   David Howells   afs: Increase to ...
566
  	_leave(" = 0 { vn=%llu u=%u }", fid->vnode, fid->unique);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
567
568
569
570
  	return 0;
  }
  
  /*
5cf9dd55a   David Howells   afs: Prospectivel...
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
   * search the directory for a name
   * - if afs_dir_iterate_block() spots this function, it'll pass the FID
   *   uniquifier through dtype
   */
  static int afs_lookup_filldir(struct dir_context *ctx, const char *name,
  			      int nlen, loff_t fpos, u64 ino, unsigned dtype)
  {
  	struct afs_lookup_cookie *cookie =
  		container_of(ctx, struct afs_lookup_cookie, ctx);
  	int ret;
  
  	_enter("{%s,%u},%s,%u,,%llu,%u",
  	       cookie->name.name, cookie->name.len, name, nlen,
  	       (unsigned long long) ino, dtype);
  
  	/* insanity checks first */
003176369   David Howells   afs: Adjust the d...
587
588
  	BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048);
  	BUILD_BUG_ON(sizeof(union afs_xdr_dirent) != 32);
5cf9dd55a   David Howells   afs: Prospectivel...
589
590
591
592
593
594
595
596
597
  
  	if (cookie->found) {
  		if (cookie->nr_fids < 50) {
  			cookie->fids[cookie->nr_fids].vnode	= ino;
  			cookie->fids[cookie->nr_fids].unique	= dtype;
  			cookie->nr_fids++;
  		}
  	} else if (cookie->name.len == nlen &&
  		   memcmp(cookie->name.name, name, nlen) == 0) {
e49c7b2f6   David Howells   afs: Build an abs...
598
599
  		cookie->fids[1].vnode	= ino;
  		cookie->fids[1].unique	= dtype;
5cf9dd55a   David Howells   afs: Prospectivel...
600
601
602
603
604
605
606
607
608
609
610
  		cookie->found = 1;
  		if (cookie->one_only)
  			return -1;
  	}
  
  	ret = cookie->nr_fids >= 50 ? -1 : 0;
  	_leave(" = %d", ret);
  	return ret;
  }
  
  /*
e49c7b2f6   David Howells   afs: Build an abs...
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
   * Deal with the result of a successful lookup operation.  Turn all the files
   * into inodes and save the first one - which is the one we actually want.
   */
  static void afs_do_lookup_success(struct afs_operation *op)
  {
  	struct afs_vnode_param *vp;
  	struct afs_vnode *vnode;
  	struct inode *inode;
  	u32 abort_code;
  	int i;
  
  	_enter("");
  
  	for (i = 0; i < op->nr_files; i++) {
  		switch (i) {
  		case 0:
  			vp = &op->file[0];
  			abort_code = vp->scb.status.abort_code;
  			if (abort_code != 0) {
44767c353   David Howells   afs: Remove afs_o...
630
  				op->ac.abort_code = abort_code;
e49c7b2f6   David Howells   afs: Build an abs...
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
  				op->error = afs_abort_to_error(abort_code);
  			}
  			break;
  
  		case 1:
  			vp = &op->file[1];
  			break;
  
  		default:
  			vp = &op->more_files[i - 2];
  			break;
  		}
  
  		if (!vp->scb.have_status && !vp->scb.have_error)
  			continue;
  
  		_debug("do [%u]", i);
  		if (vp->vnode) {
  			if (!test_bit(AFS_VNODE_UNSET, &vp->vnode->flags))
  				afs_vnode_commit_status(op, vp);
  		} else if (vp->scb.status.abort_code == 0) {
  			inode = afs_iget(op, vp);
  			if (!IS_ERR(inode)) {
  				vnode = AFS_FS_I(inode);
  				afs_cache_permit(vnode, op->key,
  						 0 /* Assume vnode->cb_break is 0 */ +
  						 op->cb_v_break,
  						 &vp->scb);
  				vp->vnode = vnode;
  				vp->put_vnode = true;
  			}
  		} else {
  			_debug("- abort %d %llx:%llx.%x",
  			       vp->scb.status.abort_code,
  			       vp->fid.vid, vp->fid.vnode, vp->fid.unique);
  		}
  	}
  
  	_leave("");
  }
  
  static const struct afs_operation_ops afs_inline_bulk_status_operation = {
  	.issue_afs_rpc	= afs_fs_inline_bulk_status,
  	.issue_yfs_rpc	= yfs_fs_inline_bulk_status,
  	.success	= afs_do_lookup_success,
  };
b6489a49f   David Howells   afs: Fix silly re...
677
  static const struct afs_operation_ops afs_lookup_fetch_status_operation = {
e49c7b2f6   David Howells   afs: Build an abs...
678
679
680
  	.issue_afs_rpc	= afs_fs_fetch_status,
  	.issue_yfs_rpc	= yfs_fs_fetch_status,
  	.success	= afs_do_lookup_success,
728279a5a   David Howells   afs: Fix use of a...
681
  	.aborted	= afs_check_for_remote_deletion,
e49c7b2f6   David Howells   afs: Build an abs...
682
683
684
  };
  
  /*
20325960f   David Howells   afs: Reorganise v...
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
   * See if we know that the server we expect to use doesn't support
   * FS.InlineBulkStatus.
   */
  static bool afs_server_supports_ibulk(struct afs_vnode *dvnode)
  {
  	struct afs_server_list *slist;
  	struct afs_volume *volume = dvnode->volume;
  	struct afs_server *server;
  	bool ret = true;
  	int i;
  
  	if (!test_bit(AFS_VOLUME_MAYBE_NO_IBULK, &volume->flags))
  		return true;
  
  	rcu_read_lock();
  	slist = rcu_dereference(volume->servers);
  
  	for (i = 0; i < slist->nr_servers; i++) {
  		server = slist->servers[i].server;
  		if (server == dvnode->cb_server) {
  			if (test_bit(AFS_SERVER_FL_NO_IBULK, &server->flags))
  				ret = false;
  			break;
  		}
  	}
  
  	rcu_read_unlock();
  	return ret;
  }
  
  /*
5cf9dd55a   David Howells   afs: Prospectivel...
716
717
718
719
720
721
722
723
   * Do a lookup in a directory.  We make use of bulk lookup to query a slew of
   * files in one go and create inodes for them.  The inode of the file we were
   * asked for is returned.
   */
  static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry,
  				   struct key *key)
  {
  	struct afs_lookup_cookie *cookie;
e49c7b2f6   David Howells   afs: Build an abs...
724
725
  	struct afs_vnode_param *vp;
  	struct afs_operation *op;
39db9815d   David Howells   afs: Fix applicat...
726
727
  	struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode;
  	struct inode *inode = NULL, *ti;
9dd0b82ef   David Howells   afs: Fix missing ...
728
  	afs_dataversion_t data_version = READ_ONCE(dvnode->status.data_version);
e49c7b2f6   David Howells   afs: Build an abs...
729
730
  	long ret;
  	int i;
5cf9dd55a   David Howells   afs: Prospectivel...
731
732
733
734
735
736
  
  	_enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry);
  
  	cookie = kzalloc(sizeof(struct afs_lookup_cookie), GFP_KERNEL);
  	if (!cookie)
  		return ERR_PTR(-ENOMEM);
e49c7b2f6   David Howells   afs: Build an abs...
737
738
  	for (i = 0; i < ARRAY_SIZE(cookie->fids); i++)
  		cookie->fids[i].vid = dvnode->fid.vid;
5cf9dd55a   David Howells   afs: Prospectivel...
739
740
  	cookie->ctx.actor = afs_lookup_filldir;
  	cookie->name = dentry->d_name;
13fcc6356   David Howells   afs: Always inclu...
741
742
  	cookie->nr_fids = 2; /* slot 0 is saved for the fid we actually want
  			      * and slot 1 for the directory */
5cf9dd55a   David Howells   afs: Prospectivel...
743

20325960f   David Howells   afs: Reorganise v...
744
745
  	if (!afs_server_supports_ibulk(dvnode))
  		cookie->one_only = true;
5cf9dd55a   David Howells   afs: Prospectivel...
746

5cf9dd55a   David Howells   afs: Prospectivel...
747
  	/* search the directory */
9dd0b82ef   David Howells   afs: Fix missing ...
748
  	ret = afs_dir_iterate(dir, &cookie->ctx, key, &data_version);
e49c7b2f6   David Howells   afs: Build an abs...
749
  	if (ret < 0)
5cf9dd55a   David Howells   afs: Prospectivel...
750
  		goto out;
5cf9dd55a   David Howells   afs: Prospectivel...
751

9dd0b82ef   David Howells   afs: Fix missing ...
752
  	dentry->d_fsdata = (void *)(unsigned long)data_version;
e49c7b2f6   David Howells   afs: Build an abs...
753
  	ret = -ENOENT;
5cf9dd55a   David Howells   afs: Prospectivel...
754
755
756
757
  	if (!cookie->found)
  		goto out;
  
  	/* Check to see if we already have an inode for the primary fid. */
e49c7b2f6   David Howells   afs: Build an abs...
758
759
  	inode = ilookup5(dir->i_sb, cookie->fids[1].vnode,
  			 afs_ilookup5_test_by_fid, &cookie->fids[1]);
5cf9dd55a   David Howells   afs: Prospectivel...
760
  	if (inode)
e49c7b2f6   David Howells   afs: Build an abs...
761
  		goto out; /* We do */
5cf9dd55a   David Howells   afs: Prospectivel...
762

e49c7b2f6   David Howells   afs: Build an abs...
763
764
765
766
767
768
769
  	/* Okay, we didn't find it.  We need to query the server - and whilst
  	 * we're doing that, we're going to attempt to look up a bunch of other
  	 * vnodes also.
  	 */
  	op = afs_alloc_operation(NULL, dvnode->volume);
  	if (IS_ERR(op)) {
  		ret = PTR_ERR(op);
5cf9dd55a   David Howells   afs: Prospectivel...
770
  		goto out;
e49c7b2f6   David Howells   afs: Build an abs...
771
  	}
5cf9dd55a   David Howells   afs: Prospectivel...
772

e49c7b2f6   David Howells   afs: Build an abs...
773
774
  	afs_op_set_vnode(op, 0, dvnode);
  	afs_op_set_fid(op, 1, &cookie->fids[1]);
13fcc6356   David Howells   afs: Always inclu...
775

e49c7b2f6   David Howells   afs: Build an abs...
776
777
  	op->nr_files = cookie->nr_fids;
  	_debug("nr_files %u", op->nr_files);
39db9815d   David Howells   afs: Fix applicat...
778

e49c7b2f6   David Howells   afs: Build an abs...
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
  	/* Need space for examining all the selected files */
  	op->error = -ENOMEM;
  	if (op->nr_files > 2) {
  		op->more_files = kvcalloc(op->nr_files - 2,
  					  sizeof(struct afs_vnode_param),
  					  GFP_KERNEL);
  		if (!op->more_files)
  			goto out_op;
  
  		for (i = 2; i < op->nr_files; i++) {
  			vp = &op->more_files[i - 2];
  			vp->fid = cookie->fids[i];
  
  			/* Find any inodes that already exist and get their
  			 * callback counters.
  			 */
  			ti = ilookup5_nowait(dir->i_sb, vp->fid.vnode,
  					     afs_ilookup5_test_by_fid, &vp->fid);
  			if (!IS_ERR_OR_NULL(ti)) {
  				vnode = AFS_FS_I(ti);
  				vp->dv_before = vnode->status.data_version;
  				vp->cb_break_before = afs_calc_vnode_cb_break(vnode);
  				vp->vnode = vnode;
  				vp->put_vnode = true;
a9e5c87ca   David Howells   afs: Fix speculat...
803
  				vp->speculative = true; /* vnode not locked */
e49c7b2f6   David Howells   afs: Build an abs...
804
  			}
39db9815d   David Howells   afs: Fix applicat...
805
806
  		}
  	}
5cf9dd55a   David Howells   afs: Prospectivel...
807
808
809
810
  	/* Try FS.InlineBulkStatus first.  Abort codes for the individual
  	 * lookups contained therein are stored in the reply without aborting
  	 * the whole operation.
  	 */
e49c7b2f6   David Howells   afs: Build an abs...
811
812
813
814
815
  	op->error = -ENOTSUPP;
  	if (!cookie->one_only) {
  		op->ops = &afs_inline_bulk_status_operation;
  		afs_begin_vnode_operation(op);
  		afs_wait_for_operation(op);
5cf9dd55a   David Howells   afs: Prospectivel...
816
  	}
e49c7b2f6   David Howells   afs: Build an abs...
817
818
819
820
821
822
  	if (op->error == -ENOTSUPP) {
  		/* We could try FS.BulkStatus next, but this aborts the entire
  		 * op if any of the lookups fails - so, for the moment, revert
  		 * to FS.FetchStatus for op->file[1].
  		 */
  		op->fetch_status.which = 1;
f8ea5c7bc   David Howells   afs: Fix afs_do_l...
823
  		op->ops = &afs_lookup_fetch_status_operation;
e49c7b2f6   David Howells   afs: Build an abs...
824
825
  		afs_begin_vnode_operation(op);
  		afs_wait_for_operation(op);
5cf9dd55a   David Howells   afs: Prospectivel...
826
  	}
e49c7b2f6   David Howells   afs: Build an abs...
827
  	inode = ERR_PTR(op->error);
5cf9dd55a   David Howells   afs: Prospectivel...
828

e49c7b2f6   David Howells   afs: Build an abs...
829
830
831
832
  out_op:
  	if (op->error == 0) {
  		inode = &op->file[1].vnode->vfs_inode;
  		op->file[1].vnode = NULL;
5cf9dd55a   David Howells   afs: Prospectivel...
833
  	}
e49c7b2f6   David Howells   afs: Build an abs...
834
835
836
837
838
  	if (op->file[0].scb.have_status)
  		dentry->d_fsdata = (void *)(unsigned long)op->file[0].scb.status.data_version;
  	else
  		dentry->d_fsdata = (void *)(unsigned long)op->file[0].dv_before;
  	ret = afs_put_operation(op);
5cf9dd55a   David Howells   afs: Prospectivel...
839
840
  out:
  	kfree(cookie);
e49c7b2f6   David Howells   afs: Build an abs...
841
842
  	_leave("");
  	return inode ?: ERR_PTR(ret);
5cf9dd55a   David Howells   afs: Prospectivel...
843
844
845
  }
  
  /*
6f8880d8e   David Howells   afs: Implement @s...
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
   * Look up an entry in a directory with @sys substitution.
   */
  static struct dentry *afs_lookup_atsys(struct inode *dir, struct dentry *dentry,
  				       struct key *key)
  {
  	struct afs_sysnames *subs;
  	struct afs_net *net = afs_i2net(dir);
  	struct dentry *ret;
  	char *buf, *p, *name;
  	int len, i;
  
  	_enter("");
  
  	ret = ERR_PTR(-ENOMEM);
  	p = buf = kmalloc(AFSNAMEMAX, GFP_KERNEL);
  	if (!buf)
  		goto out_p;
  	if (dentry->d_name.len > 4) {
  		memcpy(p, dentry->d_name.name, dentry->d_name.len - 4);
  		p += dentry->d_name.len - 4;
  	}
  
  	/* There is an ordered list of substitutes that we have to try. */
  	read_lock(&net->sysnames_lock);
  	subs = net->sysnames;
  	refcount_inc(&subs->usage);
  	read_unlock(&net->sysnames_lock);
  
  	for (i = 0; i < subs->nr; i++) {
  		name = subs->subs[i];
  		len = dentry->d_name.len - 4 + strlen(name);
  		if (len >= AFSNAMEMAX) {
  			ret = ERR_PTR(-ENAMETOOLONG);
  			goto out_s;
  		}
  
  		strcpy(p, name);
  		ret = lookup_one_len(buf, dentry->d_parent, len);
  		if (IS_ERR(ret) || d_is_positive(ret))
  			goto out_s;
  		dput(ret);
  	}
  
  	/* We don't want to d_add() the @sys dentry here as we don't want to
  	 * the cached dentry to hide changes to the sysnames list.
  	 */
  	ret = NULL;
  out_s:
  	afs_put_sysnames(subs);
  	kfree(buf);
  out_p:
  	key_put(key);
  	return ret;
  }
  
  /*
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
902
903
   * look up an entry in a directory
   */
260a98031   David Howells   [AFS]: Add "direc...
904
  static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
00cd8dd3b   Al Viro   stop passing name...
905
  				 unsigned int flags)
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
906
  {
5cf9dd55a   David Howells   afs: Prospectivel...
907
  	struct afs_vnode *dvnode = AFS_FS_I(dir);
40a708bd6   David Howells   afs: Fix use-afte...
908
  	struct afs_fid fid = {};
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
909
  	struct inode *inode;
34b2a88fb   Al Viro   afs_lookup(): swi...
910
  	struct dentry *d;
00d3b7a45   David Howells   [AFS]: Add securi...
911
  	struct key *key;
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
912
  	int ret;
3b6492df4   David Howells   afs: Increase to ...
913
  	_enter("{%llx:%llu},%p{%pd},",
5cf9dd55a   David Howells   afs: Prospectivel...
914
  	       dvnode->fid.vid, dvnode->fid.vnode, dentry, dentry);
260a98031   David Howells   [AFS]: Add "direc...
915

2b0143b5c   David Howells   VFS: normal files...
916
  	ASSERTCMP(d_inode(dentry), ==, NULL);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
917

45222b9e0   David Howells   AFS: implement st...
918
  	if (dentry->d_name.len >= AFSNAMEMAX) {
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
919
920
921
  		_leave(" = -ENAMETOOLONG");
  		return ERR_PTR(-ENAMETOOLONG);
  	}
5cf9dd55a   David Howells   afs: Prospectivel...
922
  	if (test_bit(AFS_VNODE_DELETED, &dvnode->flags)) {
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
923
924
925
  		_leave(" = -ESTALE");
  		return ERR_PTR(-ESTALE);
  	}
5cf9dd55a   David Howells   afs: Prospectivel...
926
  	key = afs_request_key(dvnode->volume->cell);
00d3b7a45   David Howells   [AFS]: Add securi...
927
928
  	if (IS_ERR(key)) {
  		_leave(" = %ld [key]", PTR_ERR(key));
e231c2ee6   David Howells   Convert ERR_PTR(P...
929
  		return ERR_CAST(key);
00d3b7a45   David Howells   [AFS]: Add securi...
930
  	}
5cf9dd55a   David Howells   afs: Prospectivel...
931
  	ret = afs_validate(dvnode, key);
260a98031   David Howells   [AFS]: Add "direc...
932
933
934
935
936
  	if (ret < 0) {
  		key_put(key);
  		_leave(" = %d [val]", ret);
  		return ERR_PTR(ret);
  	}
6f8880d8e   David Howells   afs: Implement @s...
937
938
939
940
941
942
  	if (dentry->d_name.len >= 4 &&
  	    dentry->d_name.name[dentry->d_name.len - 4] == '@' &&
  	    dentry->d_name.name[dentry->d_name.len - 3] == 's' &&
  	    dentry->d_name.name[dentry->d_name.len - 2] == 'y' &&
  	    dentry->d_name.name[dentry->d_name.len - 1] == 's')
  		return afs_lookup_atsys(dir, dentry, key);
d55b4da43   David Howells   afs: Introduce a ...
943
  	afs_stat_v(dvnode, n_lookup);
5cf9dd55a   David Howells   afs: Prospectivel...
944
  	inode = afs_do_lookup(dir, dentry, key);
00d3b7a45   David Howells   [AFS]: Add securi...
945
  	key_put(key);
f52b83b0b   David Howells   afs: Fix afs_look...
946
  	if (inode == ERR_PTR(-ENOENT))
34b2a88fb   Al Viro   afs_lookup(): swi...
947
  		inode = afs_try_auto_mntpt(dentry, dir);
40a708bd6   David Howells   afs: Fix use-afte...
948
949
950
  
  	if (!IS_ERR_OR_NULL(inode))
  		fid = AFS_FS_I(inode)->fid;
fed79fd78   David Howells   afs: Fix debuggin...
951
  	_debug("splice %p", dentry->d_inode);
34b2a88fb   Al Viro   afs_lookup(): swi...
952
  	d = d_splice_alias(inode, dentry);
80548b039   David Howells   afs: Add more tra...
953
  	if (!IS_ERR_OR_NULL(d)) {
34b2a88fb   Al Viro   afs_lookup(): swi...
954
  		d->d_fsdata = dentry->d_fsdata;
40a708bd6   David Howells   afs: Fix use-afte...
955
  		trace_afs_lookup(dvnode, &d->d_name, &fid);
80548b039   David Howells   afs: Add more tra...
956
  	} else {
40a708bd6   David Howells   afs: Fix use-afte...
957
  		trace_afs_lookup(dvnode, &dentry->d_name, &fid);
80548b039   David Howells   afs: Add more tra...
958
  	}
e49c7b2f6   David Howells   afs: Build an abs...
959
  	_leave("");
34b2a88fb   Al Viro   afs_lookup(): swi...
960
  	return d;
ec26815ad   David Howells   [AFS]: Clean up t...
961
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
963
  /*
a0753c290   David Howells   afs: Support RCU ...
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
   * Check the validity of a dentry under RCU conditions.
   */
  static int afs_d_revalidate_rcu(struct dentry *dentry)
  {
  	struct afs_vnode *dvnode, *vnode;
  	struct dentry *parent;
  	struct inode *dir, *inode;
  	long dir_version, de_version;
  
  	_enter("%p", dentry);
  
  	/* Check the parent directory is still valid first. */
  	parent = READ_ONCE(dentry->d_parent);
  	dir = d_inode_rcu(parent);
  	if (!dir)
  		return -ECHILD;
  	dvnode = AFS_FS_I(dir);
  	if (test_bit(AFS_VNODE_DELETED, &dvnode->flags))
  		return -ECHILD;
  
  	if (!afs_check_validity(dvnode))
  		return -ECHILD;
  
  	/* We only need to invalidate a dentry if the server's copy changed
  	 * behind our back.  If we made the change, it's no problem.  Note that
  	 * on a 32-bit system, we only have 32 bits in the dentry to store the
  	 * version.
  	 */
  	dir_version = (long)READ_ONCE(dvnode->status.data_version);
  	de_version = (long)READ_ONCE(dentry->d_fsdata);
  	if (de_version != dir_version) {
  		dir_version = (long)READ_ONCE(dvnode->invalid_before);
  		if (de_version - dir_version < 0)
  			return -ECHILD;
  	}
  
  	/* Check to see if the vnode referred to by the dentry still
  	 * has a callback.
  	 */
  	if (d_really_is_positive(dentry)) {
  		inode = d_inode_rcu(dentry);
  		if (inode) {
  			vnode = AFS_FS_I(inode);
  			if (!afs_check_validity(vnode))
  				return -ECHILD;
  		}
  	}
  
  	return 1; /* Still valid */
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1016
1017
1018
   * check that a dentry lookup hit has found a valid entry
   * - NOTE! the hit can be a negative hit too, so we can't assume we have an
   *   inode
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1019
   */
0b728e191   Al Viro   stop passing name...
1020
  static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1021
  {
260a98031   David Howells   [AFS]: Add "direc...
1022
  	struct afs_vnode *vnode, *dir;
3f649ab72   Kees Cook   treewide: Remove ...
1023
  	struct afs_fid fid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1024
  	struct dentry *parent;
c435ee345   David Howells   afs: Overhaul the...
1025
  	struct inode *inode;
00d3b7a45   David Howells   [AFS]: Add securi...
1026
  	struct key *key;
40fc81027   David Howells   afs: Fix afs_d_va...
1027
  	afs_dataversion_t dir_version, invalid_before;
9dd0b82ef   David Howells   afs: Fix missing ...
1028
  	long de_version;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1029
  	int ret;
0b728e191   Al Viro   stop passing name...
1030
  	if (flags & LOOKUP_RCU)
a0753c290   David Howells   afs: Support RCU ...
1031
  		return afs_d_revalidate_rcu(dentry);
34286d666   Nick Piggin   fs: rcu-walk awar...
1032

c435ee345   David Howells   afs: Overhaul the...
1033
1034
  	if (d_really_is_positive(dentry)) {
  		vnode = AFS_FS_I(d_inode(dentry));
3b6492df4   David Howells   afs: Increase to ...
1035
  		_enter("{v={%llx:%llu} n=%pd fl=%lx},",
a455589f1   Al Viro   assorted conversi...
1036
  		       vnode->fid.vid, vnode->fid.vnode, dentry,
260a98031   David Howells   [AFS]: Add "direc...
1037
  		       vnode->flags);
c435ee345   David Howells   afs: Overhaul the...
1038
  	} else {
a455589f1   Al Viro   assorted conversi...
1039
  		_enter("{neg n=%pd}", dentry);
c435ee345   David Howells   afs: Overhaul the...
1040
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041

260a98031   David Howells   [AFS]: Add "direc...
1042
  	key = afs_request_key(AFS_FS_S(dentry->d_sb)->volume->cell);
00d3b7a45   David Howells   [AFS]: Add securi...
1043
1044
  	if (IS_ERR(key))
  		key = NULL;
c435ee345   David Howells   afs: Overhaul the...
1045
1046
1047
1048
1049
1050
1051
1052
1053
  	if (d_really_is_positive(dentry)) {
  		inode = d_inode(dentry);
  		if (inode) {
  			vnode = AFS_FS_I(inode);
  			afs_validate(vnode, key);
  			if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
  				goto out_bad;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1054
  	/* lock down the parent dentry so we can peer at it */
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
1055
  	parent = dget_parent(dentry);
2b0143b5c   David Howells   VFS: normal files...
1056
  	dir = AFS_FS_I(d_inode(parent));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1057

260a98031   David Howells   [AFS]: Add "direc...
1058
  	/* validate the parent directory */
c435ee345   David Howells   afs: Overhaul the...
1059
  	afs_validate(dir, key);
260a98031   David Howells   [AFS]: Add "direc...
1060
1061
  
  	if (test_bit(AFS_VNODE_DELETED, &dir->flags)) {
a455589f1   Al Viro   assorted conversi...
1062
  		_debug("%pd: parent dir deleted", dentry);
c435ee345   David Howells   afs: Overhaul the...
1063
  		goto out_bad_parent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1064
  	}
a4ff7401f   David Howells   afs: Keep track o...
1065
1066
1067
1068
1069
  	/* We only need to invalidate a dentry if the server's copy changed
  	 * behind our back.  If we made the change, it's no problem.  Note that
  	 * on a 32-bit system, we only have 32 bits in the dentry to store the
  	 * version.
  	 */
9dd0b82ef   David Howells   afs: Fix missing ...
1070
  	dir_version = dir->status.data_version;
a4ff7401f   David Howells   afs: Keep track o...
1071
  	de_version = (long)dentry->d_fsdata;
9dd0b82ef   David Howells   afs: Fix missing ...
1072
  	if (de_version == (long)dir_version)
5dc84855b   David Howells   afs: Only update ...
1073
  		goto out_valid_noupdate;
a4ff7401f   David Howells   afs: Keep track o...
1074

40fc81027   David Howells   afs: Fix afs_d_va...
1075
1076
  	invalid_before = dir->invalid_before;
  	if (de_version - (long)invalid_before >= 0)
a4ff7401f   David Howells   afs: Keep track o...
1077
  		goto out_valid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1078

260a98031   David Howells   [AFS]: Add "direc...
1079
  	_debug("dir modified");
d55b4da43   David Howells   afs: Introduce a ...
1080
  	afs_stat_v(dir, n_reval);
260a98031   David Howells   [AFS]: Add "direc...
1081
1082
  
  	/* search the directory for this vnode */
9dd0b82ef   David Howells   afs: Fix missing ...
1083
  	ret = afs_do_lookup_one(&dir->vfs_inode, dentry, &fid, key, &dir_version);
260a98031   David Howells   [AFS]: Add "direc...
1084
1085
1086
  	switch (ret) {
  	case 0:
  		/* the filename maps to something */
2b0143b5c   David Howells   VFS: normal files...
1087
  		if (d_really_is_negative(dentry))
c435ee345   David Howells   afs: Overhaul the...
1088
1089
1090
  			goto out_bad_parent;
  		inode = d_inode(dentry);
  		if (is_bad_inode(inode)) {
a455589f1   Al Viro   assorted conversi...
1091
1092
1093
  			printk("kAFS: afs_d_revalidate: %pd2 has bad inode
  ",
  			       dentry);
c435ee345   David Howells   afs: Overhaul the...
1094
  			goto out_bad_parent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095
  		}
c435ee345   David Howells   afs: Overhaul the...
1096
  		vnode = AFS_FS_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1097
1098
  		/* if the vnode ID has changed, then the dirent points to a
  		 * different file */
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
1099
  		if (fid.vnode != vnode->fid.vnode) {
3b6492df4   David Howells   afs: Increase to ...
1100
  			_debug("%pd: dirent changed [%llu != %llu]",
a455589f1   Al Viro   assorted conversi...
1101
  			       dentry, fid.vnode,
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
1102
  			       vnode->fid.vnode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1103
1104
1105
1106
  			goto not_found;
  		}
  
  		/* if the vnode ID uniqifier has changed, then the file has
260a98031   David Howells   [AFS]: Add "direc...
1107
1108
  		 * been deleted and replaced, and the original vnode ID has
  		 * been reused */
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
1109
  		if (fid.unique != vnode->fid.unique) {
a455589f1   Al Viro   assorted conversi...
1110
1111
  			_debug("%pd: file deleted (uq %u -> %u I:%u)",
  			       dentry, fid.unique,
7a224228e   Jean Noel Cordenner   vfs: Add 64 bit i...
1112
  			       vnode->fid.unique,
c435ee345   David Howells   afs: Overhaul the...
1113
1114
  			       vnode->vfs_inode.i_generation);
  			write_seqlock(&vnode->cb_lock);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
1115
  			set_bit(AFS_VNODE_DELETED, &vnode->flags);
c435ee345   David Howells   afs: Overhaul the...
1116
  			write_sequnlock(&vnode->cb_lock);
260a98031   David Howells   [AFS]: Add "direc...
1117
  			goto not_found;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
  		}
260a98031   David Howells   [AFS]: Add "direc...
1119
  		goto out_valid;
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
1120

260a98031   David Howells   [AFS]: Add "direc...
1121
1122
  	case -ENOENT:
  		/* the filename is unknown */
a455589f1   Al Viro   assorted conversi...
1123
  		_debug("%pd: dirent not found", dentry);
2b0143b5c   David Howells   VFS: normal files...
1124
  		if (d_really_is_positive(dentry))
260a98031   David Howells   [AFS]: Add "direc...
1125
1126
  			goto not_found;
  		goto out_valid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1127

260a98031   David Howells   [AFS]: Add "direc...
1128
  	default:
a455589f1   Al Viro   assorted conversi...
1129
1130
  		_debug("failed to iterate dir %pd: %d",
  		       parent, ret);
c435ee345   David Howells   afs: Overhaul the...
1131
  		goto out_bad_parent;
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
1132
  	}
ec26815ad   David Howells   [AFS]: Clean up t...
1133
  out_valid:
9dd0b82ef   David Howells   afs: Fix missing ...
1134
  	dentry->d_fsdata = (void *)(unsigned long)dir_version;
5dc84855b   David Howells   afs: Only update ...
1135
  out_valid_noupdate:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1136
  	dput(parent);
00d3b7a45   David Howells   [AFS]: Add securi...
1137
  	key_put(key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1138
1139
1140
1141
  	_leave(" = 1 [valid]");
  	return 1;
  
  	/* the dirent, if it exists, now points to a different vnode */
ec26815ad   David Howells   [AFS]: Clean up t...
1142
  not_found:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1143
1144
1145
  	spin_lock(&dentry->d_lock);
  	dentry->d_flags |= DCACHE_NFSFS_RENAMED;
  	spin_unlock(&dentry->d_lock);
c435ee345   David Howells   afs: Overhaul the...
1146
  out_bad_parent:
a455589f1   Al Viro   assorted conversi...
1147
  	_debug("dropping dentry %pd2", dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1148
  	dput(parent);
c435ee345   David Howells   afs: Overhaul the...
1149
  out_bad:
00d3b7a45   David Howells   [AFS]: Add securi...
1150
  	key_put(key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1151
1152
1153
  
  	_leave(" = 0 [bad]");
  	return 0;
ec26815ad   David Howells   [AFS]: Clean up t...
1154
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1155

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1156
1157
1158
1159
1160
1161
  /*
   * allow the VFS to enquire as to whether a dentry should be unhashed (mustn't
   * sleep)
   * - called from dput() when d_count is going to 0.
   * - return 1 to request dentry be unhashed, 0 otherwise
   */
fe15ce446   Nick Piggin   fs: change d_dele...
1162
  static int afs_d_delete(const struct dentry *dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1163
  {
a455589f1   Al Viro   assorted conversi...
1164
  	_enter("%pd", dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165
1166
1167
  
  	if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
  		goto zap;
2b0143b5c   David Howells   VFS: normal files...
1168
1169
1170
  	if (d_really_is_positive(dentry) &&
  	    (test_bit(AFS_VNODE_DELETED,   &AFS_FS_I(d_inode(dentry))->flags) ||
  	     test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(d_inode(dentry))->flags)))
bec5eb614   wanglei   AFS: Implement an...
1171
  		goto zap;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1172
1173
1174
  
  	_leave(" = 0 [keep]");
  	return 0;
ec26815ad   David Howells   [AFS]: Clean up t...
1175
  zap:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1176
1177
  	_leave(" = 1 [zap]");
  	return 1;
ec26815ad   David Howells   [AFS]: Clean up t...
1178
  }
260a98031   David Howells   [AFS]: Add "direc...
1179
1180
  
  /*
79ddbfa50   David Howells   afs: Implement si...
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
   * Clean up sillyrename files on dentry removal.
   */
  static void afs_d_iput(struct dentry *dentry, struct inode *inode)
  {
  	if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
  		afs_silly_iput(dentry, inode);
  	iput(inode);
  }
  
  /*
260a98031   David Howells   [AFS]: Add "direc...
1191
1192
   * handle dentry release
   */
66c7e1d31   David Howells   afs: Split the dy...
1193
  void afs_d_release(struct dentry *dentry)
260a98031   David Howells   [AFS]: Add "direc...
1194
  {
a455589f1   Al Viro   assorted conversi...
1195
  	_enter("%pd", dentry);
260a98031   David Howells   [AFS]: Add "direc...
1196
  }
728279a5a   David Howells   afs: Fix use of a...
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
  void afs_check_for_remote_deletion(struct afs_operation *op)
  {
  	struct afs_vnode *vnode = op->file[0].vnode;
  
  	switch (op->ac.abort_code) {
  	case VNOVNODE:
  		set_bit(AFS_VNODE_DELETED, &vnode->flags);
  		afs_break_callback(vnode, afs_cb_break_for_deleted);
  	}
  }
260a98031   David Howells   [AFS]: Add "direc...
1207
  /*
d2ddc776a   David Howells   afs: Overhaul vol...
1208
1209
   * Create a new inode for create/mkdir/symlink
   */
e49c7b2f6   David Howells   afs: Build an abs...
1210
  static void afs_vnode_new_inode(struct afs_operation *op)
d2ddc776a   David Howells   afs: Overhaul vol...
1211
  {
e49c7b2f6   David Howells   afs: Build an abs...
1212
  	struct afs_vnode_param *vp = &op->file[1];
5a8132761   David Howells   afs: Do better ac...
1213
  	struct afs_vnode *vnode;
d2ddc776a   David Howells   afs: Overhaul vol...
1214
  	struct inode *inode;
e49c7b2f6   David Howells   afs: Build an abs...
1215
1216
1217
  	_enter("");
  
  	ASSERTCMP(op->error, ==, 0);
d2ddc776a   David Howells   afs: Overhaul vol...
1218

e49c7b2f6   David Howells   afs: Build an abs...
1219
  	inode = afs_iget(op, vp);
d2ddc776a   David Howells   afs: Overhaul vol...
1220
1221
1222
1223
  	if (IS_ERR(inode)) {
  		/* ENOMEM or EINTR at a really inconvenient time - just abandon
  		 * the new directory on the server.
  		 */
e49c7b2f6   David Howells   afs: Build an abs...
1224
  		op->error = PTR_ERR(inode);
d2ddc776a   David Howells   afs: Overhaul vol...
1225
1226
  		return;
  	}
5a8132761   David Howells   afs: Do better ac...
1227
1228
  	vnode = AFS_FS_I(inode);
  	set_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags);
e49c7b2f6   David Howells   afs: Build an abs...
1229
1230
1231
  	if (!op->error)
  		afs_cache_permit(vnode, op->key, vnode->cb_break, &vp->scb);
  	d_instantiate(op->dentry, inode);
d2ddc776a   David Howells   afs: Overhaul vol...
1232
  }
e49c7b2f6   David Howells   afs: Build an abs...
1233
  static void afs_create_success(struct afs_operation *op)
b83591532   David Howells   afs: Pass pre-fet...
1234
  {
e49c7b2f6   David Howells   afs: Build an abs...
1235
  	_enter("op=%08x", op->debug_id);
da8d07551   David Howells   afs: Concoct ctimes
1236
  	op->ctime = op->file[0].scb.status.mtime_client;
e49c7b2f6   David Howells   afs: Build an abs...
1237
1238
1239
  	afs_vnode_commit_status(op, &op->file[0]);
  	afs_update_dentry_version(op, &op->file[0], op->dentry);
  	afs_vnode_new_inode(op);
b83591532   David Howells   afs: Pass pre-fet...
1240
  }
e49c7b2f6   David Howells   afs: Build an abs...
1241
  static void afs_create_edit_dir(struct afs_operation *op)
9dd0b82ef   David Howells   afs: Fix missing ...
1242
  {
e49c7b2f6   David Howells   afs: Build an abs...
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
  	struct afs_vnode_param *dvp = &op->file[0];
  	struct afs_vnode_param *vp = &op->file[1];
  	struct afs_vnode *dvnode = dvp->vnode;
  
  	_enter("op=%08x", op->debug_id);
  
  	down_write(&dvnode->validate_lock);
  	if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
  	    dvnode->status.data_version == dvp->dv_before + dvp->dv_delta)
  		afs_edit_dir_add(dvnode, &op->dentry->d_name, &vp->fid,
  				 op->create.reason);
  	up_write(&dvnode->validate_lock);
9dd0b82ef   David Howells   afs: Fix missing ...
1255
  }
e49c7b2f6   David Howells   afs: Build an abs...
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
  static void afs_create_put(struct afs_operation *op)
  {
  	_enter("op=%08x", op->debug_id);
  
  	if (op->error)
  		d_drop(op->dentry);
  }
  
  static const struct afs_operation_ops afs_mkdir_operation = {
  	.issue_afs_rpc	= afs_fs_make_dir,
  	.issue_yfs_rpc	= yfs_fs_make_dir,
  	.success	= afs_create_success,
728279a5a   David Howells   afs: Fix use of a...
1268
  	.aborted	= afs_check_for_remote_deletion,
e49c7b2f6   David Howells   afs: Build an abs...
1269
1270
1271
  	.edit_dir	= afs_create_edit_dir,
  	.put		= afs_create_put,
  };
9dd0b82ef   David Howells   afs: Fix missing ...
1272
  /*
260a98031   David Howells   [AFS]: Add "direc...
1273
1274
   * create a directory on an AFS filesystem
   */
18bb1db3e   Al Viro   switch vfs_mkdir(...
1275
  static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
260a98031   David Howells   [AFS]: Add "direc...
1276
  {
e49c7b2f6   David Howells   afs: Build an abs...
1277
  	struct afs_operation *op;
d2ddc776a   David Howells   afs: Overhaul vol...
1278
  	struct afs_vnode *dvnode = AFS_FS_I(dir);
260a98031   David Howells   [AFS]: Add "direc...
1279

3b6492df4   David Howells   afs: Increase to ...
1280
  	_enter("{%llx:%llu},{%pd},%ho",
a455589f1   Al Viro   assorted conversi...
1281
  	       dvnode->fid.vid, dvnode->fid.vnode, dentry, mode);
260a98031   David Howells   [AFS]: Add "direc...
1282

e49c7b2f6   David Howells   afs: Build an abs...
1283
1284
1285
1286
  	op = afs_alloc_operation(NULL, dvnode->volume);
  	if (IS_ERR(op)) {
  		d_drop(dentry);
  		return PTR_ERR(op);
2105c2820   David Howells   afs: Fix race bet...
1287
  	}
63a4681ff   David Howells   afs: Locally edit...
1288

e49c7b2f6   David Howells   afs: Build an abs...
1289
1290
  	afs_op_set_vnode(op, 0, dvnode);
  	op->file[0].dv_delta = 1;
da8d07551   David Howells   afs: Concoct ctimes
1291
  	op->file[0].update_ctime = true;
e49c7b2f6   David Howells   afs: Build an abs...
1292
1293
1294
1295
1296
  	op->dentry	= dentry;
  	op->create.mode	= S_IFDIR | mode;
  	op->create.reason = afs_edit_dir_for_mkdir;
  	op->ops		= &afs_mkdir_operation;
  	return afs_do_sync_operation(op);
260a98031   David Howells   [AFS]: Add "direc...
1297
1298
1299
  }
  
  /*
d2ddc776a   David Howells   afs: Overhaul vol...
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
   * Remove a subdir from a directory.
   */
  static void afs_dir_remove_subdir(struct dentry *dentry)
  {
  	if (d_really_is_positive(dentry)) {
  		struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));
  
  		clear_nlink(&vnode->vfs_inode);
  		set_bit(AFS_VNODE_DELETED, &vnode->flags);
  		clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
63a4681ff   David Howells   afs: Locally edit...
1310
  		clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags);
d2ddc776a   David Howells   afs: Overhaul vol...
1311
1312
  	}
  }
e49c7b2f6   David Howells   afs: Build an abs...
1313
1314
1315
  static void afs_rmdir_success(struct afs_operation *op)
  {
  	_enter("op=%08x", op->debug_id);
da8d07551   David Howells   afs: Concoct ctimes
1316
  	op->ctime = op->file[0].scb.status.mtime_client;
e49c7b2f6   David Howells   afs: Build an abs...
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
  	afs_vnode_commit_status(op, &op->file[0]);
  	afs_update_dentry_version(op, &op->file[0], op->dentry);
  }
  
  static void afs_rmdir_edit_dir(struct afs_operation *op)
  {
  	struct afs_vnode_param *dvp = &op->file[0];
  	struct afs_vnode *dvnode = dvp->vnode;
  
  	_enter("op=%08x", op->debug_id);
  	afs_dir_remove_subdir(op->dentry);
  
  	down_write(&dvnode->validate_lock);
  	if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
  	    dvnode->status.data_version == dvp->dv_before + dvp->dv_delta)
  		afs_edit_dir_remove(dvnode, &op->dentry->d_name,
  				    afs_edit_dir_for_rmdir);
  	up_write(&dvnode->validate_lock);
  }
  
  static void afs_rmdir_put(struct afs_operation *op)
  {
  	_enter("op=%08x", op->debug_id);
  	if (op->file[1].vnode)
  		up_write(&op->file[1].vnode->rmdir_lock);
  }
  
  static const struct afs_operation_ops afs_rmdir_operation = {
  	.issue_afs_rpc	= afs_fs_remove_dir,
  	.issue_yfs_rpc	= yfs_fs_remove_dir,
  	.success	= afs_rmdir_success,
728279a5a   David Howells   afs: Fix use of a...
1348
  	.aborted	= afs_check_for_remote_deletion,
e49c7b2f6   David Howells   afs: Build an abs...
1349
1350
1351
  	.edit_dir	= afs_rmdir_edit_dir,
  	.put		= afs_rmdir_put,
  };
d2ddc776a   David Howells   afs: Overhaul vol...
1352
  /*
260a98031   David Howells   [AFS]: Add "direc...
1353
1354
1355
1356
   * remove a directory from an AFS filesystem
   */
  static int afs_rmdir(struct inode *dir, struct dentry *dentry)
  {
e49c7b2f6   David Howells   afs: Build an abs...
1357
  	struct afs_operation *op;
f58db83fd   David Howells   afs: Get the targ...
1358
  	struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode = NULL;
260a98031   David Howells   [AFS]: Add "direc...
1359
  	int ret;
3b6492df4   David Howells   afs: Increase to ...
1360
  	_enter("{%llx:%llu},{%pd}",
a455589f1   Al Viro   assorted conversi...
1361
  	       dvnode->fid.vid, dvnode->fid.vnode, dentry);
260a98031   David Howells   [AFS]: Add "direc...
1362

e49c7b2f6   David Howells   afs: Build an abs...
1363
1364
1365
  	op = afs_alloc_operation(NULL, dvnode->volume);
  	if (IS_ERR(op))
  		return PTR_ERR(op);
a58823ac4   David Howells   afs: Fix applicat...
1366

e49c7b2f6   David Howells   afs: Build an abs...
1367
1368
  	afs_op_set_vnode(op, 0, dvnode);
  	op->file[0].dv_delta = 1;
da8d07551   David Howells   afs: Concoct ctimes
1369
  	op->file[0].update_ctime = true;
e49c7b2f6   David Howells   afs: Build an abs...
1370
1371
1372
  
  	op->dentry	= dentry;
  	op->ops		= &afs_rmdir_operation;
260a98031   David Howells   [AFS]: Add "direc...
1373

f58db83fd   David Howells   afs: Get the targ...
1374
1375
1376
  	/* Try to make sure we have a callback promise on the victim. */
  	if (d_really_is_positive(dentry)) {
  		vnode = AFS_FS_I(d_inode(dentry));
e49c7b2f6   David Howells   afs: Build an abs...
1377
  		ret = afs_validate(vnode, op->key);
f58db83fd   David Howells   afs: Get the targ...
1378
  		if (ret < 0)
e49c7b2f6   David Howells   afs: Build an abs...
1379
  			goto error;
f58db83fd   David Howells   afs: Get the targ...
1380
  	}
79ddbfa50   David Howells   afs: Implement si...
1381
1382
1383
  	if (vnode) {
  		ret = down_write_killable(&vnode->rmdir_lock);
  		if (ret < 0)
e49c7b2f6   David Howells   afs: Build an abs...
1384
1385
  			goto error;
  		op->file[1].vnode = vnode;
79ddbfa50   David Howells   afs: Implement si...
1386
  	}
e49c7b2f6   David Howells   afs: Build an abs...
1387
  	return afs_do_sync_operation(op);
260a98031   David Howells   [AFS]: Add "direc...
1388

260a98031   David Howells   [AFS]: Add "direc...
1389
  error:
e49c7b2f6   David Howells   afs: Build an abs...
1390
  	return afs_put_operation(op);
260a98031   David Howells   [AFS]: Add "direc...
1391
1392
1393
  }
  
  /*
d2ddc776a   David Howells   afs: Overhaul vol...
1394
1395
1396
1397
1398
1399
1400
1401
1402
   * Remove a link to a file or symlink from a directory.
   *
   * If the file was not deleted due to excess hard links, the fileserver will
   * break the callback promise on the file - if it had one - before it returns
   * to us, and if it was deleted, it won't
   *
   * However, if we didn't have a callback promise outstanding, or it was
   * outstanding on a different server, then it won't break it either...
   */
e49c7b2f6   David Howells   afs: Build an abs...
1403
  static void afs_dir_remove_link(struct afs_operation *op)
d2ddc776a   David Howells   afs: Overhaul vol...
1404
  {
e49c7b2f6   David Howells   afs: Build an abs...
1405
1406
1407
1408
  	struct afs_vnode *dvnode = op->file[0].vnode;
  	struct afs_vnode *vnode = op->file[1].vnode;
  	struct dentry *dentry = op->dentry;
  	int ret;
d2ddc776a   David Howells   afs: Overhaul vol...
1409

e49c7b2f6   David Howells   afs: Build an abs...
1410
1411
1412
1413
1414
  	if (op->error != 0 ||
  	    (op->file[1].scb.have_status && op->file[1].scb.have_error))
  		return;
  	if (d_really_is_positive(dentry))
  		return;
d2ddc776a   David Howells   afs: Overhaul vol...
1415

e49c7b2f6   David Howells   afs: Build an abs...
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
  	if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
  		/* Already done */
  	} else if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) {
  		write_seqlock(&vnode->cb_lock);
  		drop_nlink(&vnode->vfs_inode);
  		if (vnode->vfs_inode.i_nlink == 0) {
  			set_bit(AFS_VNODE_DELETED, &vnode->flags);
  			__afs_break_callback(vnode, afs_cb_break_for_unlink);
  		}
  		write_sequnlock(&vnode->cb_lock);
  	} else {
  		afs_break_callback(vnode, afs_cb_break_for_unlink);
440fbc3a8   David Howells   afs: Fix unlink
1428

e49c7b2f6   David Howells   afs: Build an abs...
1429
1430
  		if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
  			_debug("AFS_VNODE_DELETED");
440fbc3a8   David Howells   afs: Fix unlink
1431

e49c7b2f6   David Howells   afs: Build an abs...
1432
1433
1434
  		ret = afs_validate(vnode, op->key);
  		if (ret != -ESTALE)
  			op->error = ret;
d2ddc776a   David Howells   afs: Overhaul vol...
1435
  	}
e49c7b2f6   David Howells   afs: Build an abs...
1436
1437
1438
1439
1440
1441
  	_debug("nlink %d [val %d]", vnode->vfs_inode.i_nlink, op->error);
  }
  
  static void afs_unlink_success(struct afs_operation *op)
  {
  	_enter("op=%08x", op->debug_id);
da8d07551   David Howells   afs: Concoct ctimes
1442
  	op->ctime = op->file[0].scb.status.mtime_client;
b6489a49f   David Howells   afs: Fix silly re...
1443
  	afs_check_dir_conflict(op, &op->file[0]);
e49c7b2f6   David Howells   afs: Build an abs...
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
  	afs_vnode_commit_status(op, &op->file[0]);
  	afs_vnode_commit_status(op, &op->file[1]);
  	afs_update_dentry_version(op, &op->file[0], op->dentry);
  	afs_dir_remove_link(op);
  }
  
  static void afs_unlink_edit_dir(struct afs_operation *op)
  {
  	struct afs_vnode_param *dvp = &op->file[0];
  	struct afs_vnode *dvnode = dvp->vnode;
  
  	_enter("op=%08x", op->debug_id);
  	down_write(&dvnode->validate_lock);
  	if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
  	    dvnode->status.data_version == dvp->dv_before + dvp->dv_delta)
  		afs_edit_dir_remove(dvnode, &op->dentry->d_name,
  				    afs_edit_dir_for_unlink);
  	up_write(&dvnode->validate_lock);
d2ddc776a   David Howells   afs: Overhaul vol...
1462
  }
e49c7b2f6   David Howells   afs: Build an abs...
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
  static void afs_unlink_put(struct afs_operation *op)
  {
  	_enter("op=%08x", op->debug_id);
  	if (op->unlink.need_rehash && op->error < 0 && op->error != -ENOENT)
  		d_rehash(op->dentry);
  }
  
  static const struct afs_operation_ops afs_unlink_operation = {
  	.issue_afs_rpc	= afs_fs_remove_file,
  	.issue_yfs_rpc	= yfs_fs_remove_file,
  	.success	= afs_unlink_success,
728279a5a   David Howells   afs: Fix use of a...
1474
  	.aborted	= afs_check_for_remote_deletion,
e49c7b2f6   David Howells   afs: Build an abs...
1475
1476
1477
  	.edit_dir	= afs_unlink_edit_dir,
  	.put		= afs_unlink_put,
  };
d2ddc776a   David Howells   afs: Overhaul vol...
1478
1479
  /*
   * Remove a file or symlink from an AFS filesystem.
260a98031   David Howells   [AFS]: Add "direc...
1480
1481
1482
   */
  static int afs_unlink(struct inode *dir, struct dentry *dentry)
  {
e49c7b2f6   David Howells   afs: Build an abs...
1483
  	struct afs_operation *op;
fa59f52f5   David Howells   afs: afs_unlink()...
1484
1485
  	struct afs_vnode *dvnode = AFS_FS_I(dir);
  	struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));
260a98031   David Howells   [AFS]: Add "direc...
1486
  	int ret;
3b6492df4   David Howells   afs: Increase to ...
1487
  	_enter("{%llx:%llu},{%pd}",
a455589f1   Al Viro   assorted conversi...
1488
  	       dvnode->fid.vid, dvnode->fid.vnode, dentry);
260a98031   David Howells   [AFS]: Add "direc...
1489

45222b9e0   David Howells   AFS: implement st...
1490
  	if (dentry->d_name.len >= AFSNAMEMAX)
d2ddc776a   David Howells   afs: Overhaul vol...
1491
  		return -ENAMETOOLONG;
260a98031   David Howells   [AFS]: Add "direc...
1492

e49c7b2f6   David Howells   afs: Build an abs...
1493
1494
1495
  	op = afs_alloc_operation(NULL, dvnode->volume);
  	if (IS_ERR(op))
  		return PTR_ERR(op);
a58823ac4   David Howells   afs: Fix applicat...
1496

e49c7b2f6   David Howells   afs: Build an abs...
1497
1498
  	afs_op_set_vnode(op, 0, dvnode);
  	op->file[0].dv_delta = 1;
da8d07551   David Howells   afs: Concoct ctimes
1499
  	op->file[0].update_ctime = true;
260a98031   David Howells   [AFS]: Add "direc...
1500

d2ddc776a   David Howells   afs: Overhaul vol...
1501
  	/* Try to make sure we have a callback promise on the victim. */
e49c7b2f6   David Howells   afs: Build an abs...
1502
1503
1504
1505
1506
  	ret = afs_validate(vnode, op->key);
  	if (ret < 0) {
  		op->error = ret;
  		goto error;
  	}
260a98031   David Howells   [AFS]: Add "direc...
1507

79ddbfa50   David Howells   afs: Implement si...
1508
  	spin_lock(&dentry->d_lock);
fa59f52f5   David Howells   afs: afs_unlink()...
1509
  	if (d_count(dentry) > 1) {
79ddbfa50   David Howells   afs: Implement si...
1510
1511
1512
  		spin_unlock(&dentry->d_lock);
  		/* Start asynchronous writeout of the inode */
  		write_inode_now(d_inode(dentry), 0);
e49c7b2f6   David Howells   afs: Build an abs...
1513
1514
  		op->error = afs_sillyrename(dvnode, vnode, dentry, op->key);
  		goto error;
79ddbfa50   David Howells   afs: Implement si...
1515
1516
1517
1518
  	}
  	if (!d_unhashed(dentry)) {
  		/* Prevent a race with RCU lookup. */
  		__d_drop(dentry);
e49c7b2f6   David Howells   afs: Build an abs...
1519
  		op->unlink.need_rehash = true;
79ddbfa50   David Howells   afs: Implement si...
1520
1521
  	}
  	spin_unlock(&dentry->d_lock);
e49c7b2f6   David Howells   afs: Build an abs...
1522
  	op->file[1].vnode = vnode;
da8d07551   David Howells   afs: Concoct ctimes
1523
  	op->file[1].update_ctime = true;
b6489a49f   David Howells   afs: Fix silly re...
1524
  	op->file[1].op_unlinked = true;
e49c7b2f6   David Howells   afs: Build an abs...
1525
1526
  	op->dentry	= dentry;
  	op->ops		= &afs_unlink_operation;
b6489a49f   David Howells   afs: Fix silly re...
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
  	afs_begin_vnode_operation(op);
  	afs_wait_for_operation(op);
  
  	/* If there was a conflict with a third party, check the status of the
  	 * unlinked vnode.
  	 */
  	if (op->error == 0 && (op->flags & AFS_OPERATION_DIR_CONFLICT)) {
  		op->file[1].update_ctime = false;
  		op->fetch_status.which = 1;
  		op->ops = &afs_fetch_status_operation;
  		afs_begin_vnode_operation(op);
  		afs_wait_for_operation(op);
  	}
  
  	return afs_put_operation(op);
79ddbfa50   David Howells   afs: Implement si...
1542

260a98031   David Howells   [AFS]: Add "direc...
1543
  error:
e49c7b2f6   David Howells   afs: Build an abs...
1544
  	return afs_put_operation(op);
260a98031   David Howells   [AFS]: Add "direc...
1545
  }
e49c7b2f6   David Howells   afs: Build an abs...
1546
1547
1548
1549
  static const struct afs_operation_ops afs_create_operation = {
  	.issue_afs_rpc	= afs_fs_create_file,
  	.issue_yfs_rpc	= yfs_fs_create_file,
  	.success	= afs_create_success,
728279a5a   David Howells   afs: Fix use of a...
1550
  	.aborted	= afs_check_for_remote_deletion,
e49c7b2f6   David Howells   afs: Build an abs...
1551
1552
1553
  	.edit_dir	= afs_create_edit_dir,
  	.put		= afs_create_put,
  };
260a98031   David Howells   [AFS]: Add "direc...
1554
1555
1556
  /*
   * create a regular file on an AFS filesystem
   */
4acdaf27e   Al Viro   switch ->create()...
1557
  static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
ebfc3b49a   Al Viro   don't pass nameid...
1558
  		      bool excl)
260a98031   David Howells   [AFS]: Add "direc...
1559
  {
e49c7b2f6   David Howells   afs: Build an abs...
1560
  	struct afs_operation *op;
43dd388b2   Colin Ian King   afs: remove redun...
1561
  	struct afs_vnode *dvnode = AFS_FS_I(dir);
e49c7b2f6   David Howells   afs: Build an abs...
1562
  	int ret = -ENAMETOOLONG;
260a98031   David Howells   [AFS]: Add "direc...
1563

e49c7b2f6   David Howells   afs: Build an abs...
1564
  	_enter("{%llx:%llu},{%pd},%ho",
a455589f1   Al Viro   assorted conversi...
1565
  	       dvnode->fid.vid, dvnode->fid.vnode, dentry, mode);
260a98031   David Howells   [AFS]: Add "direc...
1566

d2ddc776a   David Howells   afs: Overhaul vol...
1567
1568
  	if (dentry->d_name.len >= AFSNAMEMAX)
  		goto error;
e49c7b2f6   David Howells   afs: Build an abs...
1569
1570
1571
  	op = afs_alloc_operation(NULL, dvnode->volume);
  	if (IS_ERR(op)) {
  		ret = PTR_ERR(op);
260a98031   David Howells   [AFS]: Add "direc...
1572
1573
  		goto error;
  	}
e49c7b2f6   David Howells   afs: Build an abs...
1574
1575
  	afs_op_set_vnode(op, 0, dvnode);
  	op->file[0].dv_delta = 1;
da8d07551   David Howells   afs: Concoct ctimes
1576
  	op->file[0].update_ctime = true;
63a4681ff   David Howells   afs: Locally edit...
1577

e49c7b2f6   David Howells   afs: Build an abs...
1578
1579
1580
1581
1582
  	op->dentry	= dentry;
  	op->create.mode	= S_IFREG | mode;
  	op->create.reason = afs_edit_dir_for_create;
  	op->ops		= &afs_create_operation;
  	return afs_do_sync_operation(op);
260a98031   David Howells   [AFS]: Add "direc...
1583

260a98031   David Howells   [AFS]: Add "direc...
1584
1585
1586
1587
1588
  error:
  	d_drop(dentry);
  	_leave(" = %d", ret);
  	return ret;
  }
e49c7b2f6   David Howells   afs: Build an abs...
1589
1590
1591
1592
1593
1594
  static void afs_link_success(struct afs_operation *op)
  {
  	struct afs_vnode_param *dvp = &op->file[0];
  	struct afs_vnode_param *vp = &op->file[1];
  
  	_enter("op=%08x", op->debug_id);
da8d07551   David Howells   afs: Concoct ctimes
1595
  	op->ctime = dvp->scb.status.mtime_client;
e49c7b2f6   David Howells   afs: Build an abs...
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
  	afs_vnode_commit_status(op, dvp);
  	afs_vnode_commit_status(op, vp);
  	afs_update_dentry_version(op, dvp, op->dentry);
  	if (op->dentry_2->d_parent == op->dentry->d_parent)
  		afs_update_dentry_version(op, dvp, op->dentry_2);
  	ihold(&vp->vnode->vfs_inode);
  	d_instantiate(op->dentry, &vp->vnode->vfs_inode);
  }
  
  static void afs_link_put(struct afs_operation *op)
  {
  	_enter("op=%08x", op->debug_id);
  	if (op->error)
  		d_drop(op->dentry);
  }
  
  static const struct afs_operation_ops afs_link_operation = {
  	.issue_afs_rpc	= afs_fs_link,
  	.issue_yfs_rpc	= yfs_fs_link,
  	.success	= afs_link_success,
728279a5a   David Howells   afs: Fix use of a...
1616
  	.aborted	= afs_check_for_remote_deletion,
e49c7b2f6   David Howells   afs: Build an abs...
1617
1618
1619
  	.edit_dir	= afs_create_edit_dir,
  	.put		= afs_link_put,
  };
260a98031   David Howells   [AFS]: Add "direc...
1620
1621
1622
1623
1624
1625
  /*
   * create a hard link between files in an AFS filesystem
   */
  static int afs_link(struct dentry *from, struct inode *dir,
  		    struct dentry *dentry)
  {
e49c7b2f6   David Howells   afs: Build an abs...
1626
  	struct afs_operation *op;
a58823ac4   David Howells   afs: Fix applicat...
1627
1628
  	struct afs_vnode *dvnode = AFS_FS_I(dir);
  	struct afs_vnode *vnode = AFS_FS_I(d_inode(from));
e49c7b2f6   David Howells   afs: Build an abs...
1629
  	int ret = -ENAMETOOLONG;
260a98031   David Howells   [AFS]: Add "direc...
1630

3b6492df4   David Howells   afs: Increase to ...
1631
  	_enter("{%llx:%llu},{%llx:%llu},{%pd}",
260a98031   David Howells   [AFS]: Add "direc...
1632
1633
  	       vnode->fid.vid, vnode->fid.vnode,
  	       dvnode->fid.vid, dvnode->fid.vnode,
a455589f1   Al Viro   assorted conversi...
1634
  	       dentry);
260a98031   David Howells   [AFS]: Add "direc...
1635

d2ddc776a   David Howells   afs: Overhaul vol...
1636
1637
  	if (dentry->d_name.len >= AFSNAMEMAX)
  		goto error;
e49c7b2f6   David Howells   afs: Build an abs...
1638
1639
1640
  	op = afs_alloc_operation(NULL, dvnode->volume);
  	if (IS_ERR(op)) {
  		ret = PTR_ERR(op);
a58823ac4   David Howells   afs: Fix applicat...
1641
  		goto error;
260a98031   David Howells   [AFS]: Add "direc...
1642
  	}
e49c7b2f6   David Howells   afs: Build an abs...
1643
1644
1645
  	afs_op_set_vnode(op, 0, dvnode);
  	afs_op_set_vnode(op, 1, vnode);
  	op->file[0].dv_delta = 1;
da8d07551   David Howells   afs: Concoct ctimes
1646
1647
  	op->file[0].update_ctime = true;
  	op->file[1].update_ctime = true;
260a98031   David Howells   [AFS]: Add "direc...
1648

e49c7b2f6   David Howells   afs: Build an abs...
1649
1650
1651
1652
1653
  	op->dentry		= dentry;
  	op->dentry_2		= from;
  	op->ops			= &afs_link_operation;
  	op->create.reason	= afs_edit_dir_for_link;
  	return afs_do_sync_operation(op);
63a4681ff   David Howells   afs: Locally edit...
1654

260a98031   David Howells   [AFS]: Add "direc...
1655
1656
1657
1658
1659
  error:
  	d_drop(dentry);
  	_leave(" = %d", ret);
  	return ret;
  }
e49c7b2f6   David Howells   afs: Build an abs...
1660
1661
1662
1663
  static const struct afs_operation_ops afs_symlink_operation = {
  	.issue_afs_rpc	= afs_fs_symlink,
  	.issue_yfs_rpc	= yfs_fs_symlink,
  	.success	= afs_create_success,
728279a5a   David Howells   afs: Fix use of a...
1664
  	.aborted	= afs_check_for_remote_deletion,
e49c7b2f6   David Howells   afs: Build an abs...
1665
1666
1667
  	.edit_dir	= afs_create_edit_dir,
  	.put		= afs_create_put,
  };
260a98031   David Howells   [AFS]: Add "direc...
1668
1669
1670
1671
1672
1673
  /*
   * create a symlink in an AFS filesystem
   */
  static int afs_symlink(struct inode *dir, struct dentry *dentry,
  		       const char *content)
  {
e49c7b2f6   David Howells   afs: Build an abs...
1674
  	struct afs_operation *op;
d2ddc776a   David Howells   afs: Overhaul vol...
1675
  	struct afs_vnode *dvnode = AFS_FS_I(dir);
260a98031   David Howells   [AFS]: Add "direc...
1676
  	int ret;
3b6492df4   David Howells   afs: Increase to ...
1677
  	_enter("{%llx:%llu},{%pd},%s",
a455589f1   Al Viro   assorted conversi...
1678
  	       dvnode->fid.vid, dvnode->fid.vnode, dentry,
260a98031   David Howells   [AFS]: Add "direc...
1679
  	       content);
d2ddc776a   David Howells   afs: Overhaul vol...
1680
1681
1682
  	ret = -ENAMETOOLONG;
  	if (dentry->d_name.len >= AFSNAMEMAX)
  		goto error;
260a98031   David Howells   [AFS]: Add "direc...
1683
  	ret = -EINVAL;
45222b9e0   David Howells   AFS: implement st...
1684
  	if (strlen(content) >= AFSPATHMAX)
260a98031   David Howells   [AFS]: Add "direc...
1685
  		goto error;
e49c7b2f6   David Howells   afs: Build an abs...
1686
1687
1688
  	op = afs_alloc_operation(NULL, dvnode->volume);
  	if (IS_ERR(op)) {
  		ret = PTR_ERR(op);
a58823ac4   David Howells   afs: Fix applicat...
1689
  		goto error;
260a98031   David Howells   [AFS]: Add "direc...
1690
  	}
e49c7b2f6   David Howells   afs: Build an abs...
1691
1692
  	afs_op_set_vnode(op, 0, dvnode);
  	op->file[0].dv_delta = 1;
260a98031   David Howells   [AFS]: Add "direc...
1693

e49c7b2f6   David Howells   afs: Build an abs...
1694
1695
1696
1697
1698
  	op->dentry		= dentry;
  	op->ops			= &afs_symlink_operation;
  	op->create.reason	= afs_edit_dir_for_symlink;
  	op->create.symlink	= content;
  	return afs_do_sync_operation(op);
260a98031   David Howells   [AFS]: Add "direc...
1699

260a98031   David Howells   [AFS]: Add "direc...
1700
1701
1702
1703
1704
  error:
  	d_drop(dentry);
  	_leave(" = %d", ret);
  	return ret;
  }
e49c7b2f6   David Howells   afs: Build an abs...
1705
1706
1707
  static void afs_rename_success(struct afs_operation *op)
  {
  	_enter("op=%08x", op->debug_id);
da8d07551   David Howells   afs: Concoct ctimes
1708
  	op->ctime = op->file[0].scb.status.mtime_client;
b6489a49f   David Howells   afs: Fix silly re...
1709
  	afs_check_dir_conflict(op, &op->file[1]);
e49c7b2f6   David Howells   afs: Build an abs...
1710
  	afs_vnode_commit_status(op, &op->file[0]);
da8d07551   David Howells   afs: Concoct ctimes
1711
1712
  	if (op->file[1].vnode != op->file[0].vnode) {
  		op->ctime = op->file[1].scb.status.mtime_client;
e49c7b2f6   David Howells   afs: Build an abs...
1713
  		afs_vnode_commit_status(op, &op->file[1]);
da8d07551   David Howells   afs: Concoct ctimes
1714
  	}
e49c7b2f6   David Howells   afs: Build an abs...
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
  }
  
  static void afs_rename_edit_dir(struct afs_operation *op)
  {
  	struct afs_vnode_param *orig_dvp = &op->file[0];
  	struct afs_vnode_param *new_dvp = &op->file[1];
  	struct afs_vnode *orig_dvnode = orig_dvp->vnode;
  	struct afs_vnode *new_dvnode = new_dvp->vnode;
  	struct afs_vnode *vnode = AFS_FS_I(d_inode(op->dentry));
  	struct dentry *old_dentry = op->dentry;
  	struct dentry *new_dentry = op->dentry_2;
  	struct inode *new_inode;
  
  	_enter("op=%08x", op->debug_id);
  
  	if (op->rename.rehash) {
  		d_rehash(op->rename.rehash);
  		op->rename.rehash = NULL;
  	}
  
  	down_write(&orig_dvnode->validate_lock);
  	if (test_bit(AFS_VNODE_DIR_VALID, &orig_dvnode->flags) &&
  	    orig_dvnode->status.data_version == orig_dvp->dv_before + orig_dvp->dv_delta)
  		afs_edit_dir_remove(orig_dvnode, &old_dentry->d_name,
  				    afs_edit_dir_for_rename_0);
  
  	if (new_dvnode != orig_dvnode) {
  		up_write(&orig_dvnode->validate_lock);
  		down_write(&new_dvnode->validate_lock);
  	}
  
  	if (test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags) &&
  	    new_dvnode->status.data_version == new_dvp->dv_before + new_dvp->dv_delta) {
  		if (!op->rename.new_negative)
  			afs_edit_dir_remove(new_dvnode, &new_dentry->d_name,
  					    afs_edit_dir_for_rename_1);
  
  		afs_edit_dir_add(new_dvnode, &new_dentry->d_name,
  				 &vnode->fid, afs_edit_dir_for_rename_2);
  	}
  
  	new_inode = d_inode(new_dentry);
  	if (new_inode) {
  		spin_lock(&new_inode->i_lock);
  		if (new_inode->i_nlink > 0)
  			drop_nlink(new_inode);
  		spin_unlock(&new_inode->i_lock);
  	}
  
  	/* Now we can update d_fsdata on the dentries to reflect their
  	 * new parent's data_version.
  	 *
  	 * Note that if we ever implement RENAME_EXCHANGE, we'll have
  	 * to update both dentries with opposing dir versions.
  	 */
  	afs_update_dentry_version(op, new_dvp, op->dentry);
  	afs_update_dentry_version(op, new_dvp, op->dentry_2);
  
  	d_move(old_dentry, new_dentry);
  
  	up_write(&new_dvnode->validate_lock);
  }
  
  static void afs_rename_put(struct afs_operation *op)
  {
  	_enter("op=%08x", op->debug_id);
  	if (op->rename.rehash)
  		d_rehash(op->rename.rehash);
  	dput(op->rename.tmp);
  	if (op->error)
  		d_rehash(op->dentry);
  }
  
  static const struct afs_operation_ops afs_rename_operation = {
  	.issue_afs_rpc	= afs_fs_rename,
  	.issue_yfs_rpc	= yfs_fs_rename,
  	.success	= afs_rename_success,
  	.edit_dir	= afs_rename_edit_dir,
  	.put		= afs_rename_put,
  };
260a98031   David Howells   [AFS]: Add "direc...
1795
1796
1797
1798
  /*
   * rename a file in an AFS filesystem and/or move it between directories
   */
  static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
1cd66c93b   Miklos Szeredi   fs: make remainin...
1799
1800
  		      struct inode *new_dir, struct dentry *new_dentry,
  		      unsigned int flags)
260a98031   David Howells   [AFS]: Add "direc...
1801
  {
e49c7b2f6   David Howells   afs: Build an abs...
1802
  	struct afs_operation *op;
260a98031   David Howells   [AFS]: Add "direc...
1803
  	struct afs_vnode *orig_dvnode, *new_dvnode, *vnode;
260a98031   David Howells   [AFS]: Add "direc...
1804
  	int ret;
1cd66c93b   Miklos Szeredi   fs: make remainin...
1805
1806
  	if (flags)
  		return -EINVAL;
79ddbfa50   David Howells   afs: Implement si...
1807
1808
1809
  	/* Don't allow silly-rename files be moved around. */
  	if (old_dentry->d_flags & DCACHE_NFSFS_RENAMED)
  		return -EINVAL;
2b0143b5c   David Howells   VFS: normal files...
1810
  	vnode = AFS_FS_I(d_inode(old_dentry));
260a98031   David Howells   [AFS]: Add "direc...
1811
1812
  	orig_dvnode = AFS_FS_I(old_dir);
  	new_dvnode = AFS_FS_I(new_dir);
3b6492df4   David Howells   afs: Increase to ...
1813
  	_enter("{%llx:%llu},{%llx:%llu},{%llx:%llu},{%pd}",
260a98031   David Howells   [AFS]: Add "direc...
1814
1815
1816
  	       orig_dvnode->fid.vid, orig_dvnode->fid.vnode,
  	       vnode->fid.vid, vnode->fid.vnode,
  	       new_dvnode->fid.vid, new_dvnode->fid.vnode,
a455589f1   Al Viro   assorted conversi...
1817
  	       new_dentry);
260a98031   David Howells   [AFS]: Add "direc...
1818

e49c7b2f6   David Howells   afs: Build an abs...
1819
1820
1821
  	op = afs_alloc_operation(NULL, orig_dvnode->volume);
  	if (IS_ERR(op))
  		return PTR_ERR(op);
a58823ac4   David Howells   afs: Fix applicat...
1822

e49c7b2f6   David Howells   afs: Build an abs...
1823
1824
1825
1826
  	afs_op_set_vnode(op, 0, orig_dvnode);
  	afs_op_set_vnode(op, 1, new_dvnode); /* May be same as orig_dvnode */
  	op->file[0].dv_delta = 1;
  	op->file[1].dv_delta = 1;
da8d07551   David Howells   afs: Concoct ctimes
1827
1828
  	op->file[0].update_ctime = true;
  	op->file[1].update_ctime = true;
e49c7b2f6   David Howells   afs: Build an abs...
1829
1830
1831
1832
1833
  
  	op->dentry		= old_dentry;
  	op->dentry_2		= new_dentry;
  	op->rename.new_negative	= d_is_negative(new_dentry);
  	op->ops			= &afs_rename_operation;
260a98031   David Howells   [AFS]: Add "direc...
1834

79ddbfa50   David Howells   afs: Implement si...
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
  	/* For non-directories, check whether the target is busy and if so,
  	 * make a copy of the dentry and then do a silly-rename.  If the
  	 * silly-rename succeeds, the copied dentry is hashed and becomes the
  	 * new target.
  	 */
  	if (d_is_positive(new_dentry) && !d_is_dir(new_dentry)) {
  		/* To prevent any new references to the target during the
  		 * rename, we unhash the dentry in advance.
  		 */
  		if (!d_unhashed(new_dentry)) {
  			d_drop(new_dentry);
e49c7b2f6   David Howells   afs: Build an abs...
1846
  			op->rename.rehash = new_dentry;
79ddbfa50   David Howells   afs: Implement si...
1847
1848
1849
1850
1851
  		}
  
  		if (d_count(new_dentry) > 2) {
  			/* copy the target dentry's name */
  			ret = -ENOMEM;
e49c7b2f6   David Howells   afs: Build an abs...
1852
1853
1854
1855
  			op->rename.tmp = d_alloc(new_dentry->d_parent,
  						 &new_dentry->d_name);
  			if (!op->rename.tmp)
  				goto error;
79ddbfa50   David Howells   afs: Implement si...
1856
1857
1858
  
  			ret = afs_sillyrename(new_dvnode,
  					      AFS_FS_I(d_inode(new_dentry)),
e49c7b2f6   David Howells   afs: Build an abs...
1859
  					      new_dentry, op->key);
79ddbfa50   David Howells   afs: Implement si...
1860
  			if (ret)
e49c7b2f6   David Howells   afs: Build an abs...
1861
  				goto error;
79ddbfa50   David Howells   afs: Implement si...
1862

e49c7b2f6   David Howells   afs: Build an abs...
1863
1864
1865
  			op->dentry_2 = op->rename.tmp;
  			op->rename.rehash = NULL;
  			op->rename.new_negative = true;
79ddbfa50   David Howells   afs: Implement si...
1866
1867
  		}
  	}
9dd0b82ef   David Howells   afs: Fix missing ...
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
  	/* This bit is potentially nasty as there's a potential race with
  	 * afs_d_revalidate{,_rcu}().  We have to change d_fsdata on the dentry
  	 * to reflect it's new parent's new data_version after the op, but
  	 * d_revalidate may see old_dentry between the op having taken place
  	 * and the version being updated.
  	 *
  	 * So drop the old_dentry for now to make other threads go through
  	 * lookup instead - which we hold a lock against.
  	 */
  	d_drop(old_dentry);
e49c7b2f6   David Howells   afs: Build an abs...
1878
  	return afs_do_sync_operation(op);
63a4681ff   David Howells   afs: Locally edit...
1879

260a98031   David Howells   [AFS]: Add "direc...
1880
  error:
e49c7b2f6   David Howells   afs: Build an abs...
1881
  	return afs_put_operation(op);
260a98031   David Howells   [AFS]: Add "direc...
1882
  }
f3ddee8dc   David Howells   afs: Fix director...
1883
1884
1885
1886
1887
1888
1889
1890
  
  /*
   * Release a directory page and clean up its private state if it's not busy
   * - return true if the page can now be released, false if not
   */
  static int afs_dir_releasepage(struct page *page, gfp_t gfp_flags)
  {
  	struct afs_vnode *dvnode = AFS_FS_I(page->mapping->host);
3b6492df4   David Howells   afs: Increase to ...
1891
  	_enter("{{%llx:%llu}[%lu]}", dvnode->fid.vid, dvnode->fid.vnode, page->index);
f3ddee8dc   David Howells   afs: Fix director...
1892

fa04a40b1   David Howells   afs: Fix to take ...
1893
  	detach_page_private(page);
f3ddee8dc   David Howells   afs: Fix director...
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
  
  	/* The directory will need reloading. */
  	if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
  		afs_stat_v(dvnode, n_relpg);
  	return 1;
  }
  
  /*
   * invalidate part or all of a page
   * - release a page and clean up its private data if offset is 0 (indicating
   *   the entire page)
   */
  static void afs_dir_invalidatepage(struct page *page, unsigned int offset,
  				   unsigned int length)
  {
  	struct afs_vnode *dvnode = AFS_FS_I(page->mapping->host);
  
  	_enter("{%lu},%u,%u", page->index, offset, length);
  
  	BUG_ON(!PageLocked(page));
  
  	/* The directory will need reloading. */
  	if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
  		afs_stat_v(dvnode, n_inval);
  
  	/* we clean up only if the entire page is being invalidated */
fa04a40b1   David Howells   afs: Fix to take ...
1920
1921
  	if (offset == 0 && length == PAGE_SIZE)
  		detach_page_private(page);
f3ddee8dc   David Howells   afs: Fix director...
1922
  }