Blame view

fs/afs/dir.c 25.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /* dir.c: AFS filesystem directory handling
   *
   * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells (dhowells@redhat.com)
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; either version
   * 2 of the License, or (at your option) any later version.
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/init.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include <linux/fs.h>
34286d666   Nick Piggin   fs: rcu-walk awar...
16
  #include <linux/namei.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
  #include <linux/pagemap.h>
00d3b7a45   David Howells   [AFS]: Add securi...
18
  #include <linux/ctype.h>
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
19
  #include <linux/sched.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
  #include "internal.h"
260a98031   David Howells   [AFS]: Add "direc...
21
  static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
00cd8dd3b   Al Viro   stop passing name...
22
  				 unsigned int flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
  static int afs_dir_open(struct inode *inode, struct file *file);
1bbae9f81   Al Viro   [readdir] convert...
24
  static int afs_readdir(struct file *file, struct dir_context *ctx);
0b728e191   Al Viro   stop passing name...
25
  static int afs_d_revalidate(struct dentry *dentry, unsigned int flags);
fe15ce446   Nick Piggin   fs: change d_dele...
26
  static int afs_d_delete(const struct dentry *dentry);
260a98031   David Howells   [AFS]: Add "direc...
27
  static void afs_d_release(struct dentry *dentry);
ac7576f4b   Miklos Szeredi   vfs: make first a...
28
  static int afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen,
afefdbb28   David Howells   [PATCH] VFS: Make...
29
  				  loff_t fpos, u64 ino, unsigned dtype);
4acdaf27e   Al Viro   switch ->create()...
30
  static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
ebfc3b49a   Al Viro   don't pass nameid...
31
  		      bool excl);
18bb1db3e   Al Viro   switch vfs_mkdir(...
32
  static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
260a98031   David Howells   [AFS]: Add "direc...
33
34
35
36
37
38
39
  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...
40
41
  		      struct inode *new_dir, struct dentry *new_dentry,
  		      unsigned int flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42

4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
43
  const struct file_operations afs_dir_file_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  	.open		= afs_dir_open,
00d3b7a45   David Howells   [AFS]: Add securi...
45
  	.release	= afs_release,
29884eff1   Al Viro   afs: switch to ->...
46
  	.iterate_shared	= afs_readdir,
e8d6c5541   David Howells   AFS: implement fi...
47
  	.lock		= afs_lock,
3222a3e55   Christoph Hellwig   [PATCH] fix ->lls...
48
  	.llseek		= generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
  };
754661f14   Arjan van de Ven   [PATCH] mark stru...
50
  const struct inode_operations afs_dir_inode_operations = {
260a98031   David Howells   [AFS]: Add "direc...
51
52
53
54
55
56
57
  	.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...
58
  	.rename		= afs_rename,
00d3b7a45   David Howells   [AFS]: Add securi...
59
  	.permission	= afs_permission,
416351f28   David Howells   AFS: AFS fixups
60
  	.getattr	= afs_getattr,
31143d5d5   David Howells   AFS: implement ba...
61
  	.setattr	= afs_setattr,
d3e3b7eac   David Howells   afs: Add metadata...
62
  	.listxattr	= afs_listxattr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
  };
d61dcce29   Al Viro   switch afs
64
  const struct dentry_operations afs_fs_dentry_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
  	.d_revalidate	= afs_d_revalidate,
  	.d_delete	= afs_d_delete,
260a98031   David Howells   [AFS]: Add "direc...
67
  	.d_release	= afs_d_release,
d18610b0c   David Howells   AFS: Use d_automo...
68
  	.d_automount	= afs_d_automount,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
  };
  
  #define AFS_DIR_HASHTBL_SIZE	128
  #define AFS_DIR_DIRENT_SIZE	32
  #define AFS_DIRENT_PER_BLOCK	64
  
  union afs_dirent {
  	struct {
  		uint8_t		valid;
  		uint8_t		unused[1];
  		__be16		hash_next;
  		__be32		vnode;
  		__be32		unique;
  		uint8_t		name[16];
  		uint8_t		overflow[4];	/* if any char of the name (inc
  						 * NUL) reaches here, consume
  						 * the next dirent too */
  	} u;
  	uint8_t	extended_name[32];
  };
  
  /* AFS directory page header (one at the beginning of every 2048-byte chunk) */
  struct afs_dir_pagehdr {
  	__be16		npages;
  	__be16		magic;
  #define AFS_DIR_MAGIC htons(1234)
  	uint8_t		nentries;
  	uint8_t		bitmap[8];
  	uint8_t		pad[19];
  };
  
  /* directory block layout */
  union afs_dir_block {
  
  	struct afs_dir_pagehdr pagehdr;
  
  	struct {
  		struct afs_dir_pagehdr	pagehdr;
  		uint8_t			alloc_ctrs[128];
  		/* dir hash table */
  		uint16_t		hashtable[AFS_DIR_HASHTBL_SIZE];
  	} hdr;
  
  	union afs_dirent dirents[AFS_DIRENT_PER_BLOCK];
  };
  
  /* layout on a linux VM page */
  struct afs_dir_page {
  	union afs_dir_block blocks[PAGE_SIZE / sizeof(union afs_dir_block)];
  };
260a98031   David Howells   [AFS]: Add "direc...
119
  struct afs_lookup_cookie {
1bbae9f81   Al Viro   [readdir] convert...
120
  	struct dir_context ctx;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
  	struct afs_fid	fid;
1bbae9f81   Al Viro   [readdir] convert...
122
  	struct qstr name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
  	int		found;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
127
  /*
   * check that a directory page is valid
   */
be5b82dbf   Al Viro   make ext2_get_pag...
128
  static inline bool afs_dir_check_page(struct inode *dir, struct page *page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
131
132
133
134
135
136
137
138
  {
  	struct afs_dir_page *dbuf;
  	loff_t latter;
  	int tmp, qty;
  
  #if 0
  	/* check the page count */
  	qty = desc.size / sizeof(dbuf->blocks[0]);
  	if (qty == 0)
  		goto error;
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
139
  	if (page->index == 0 && qty != ntohs(dbuf->blocks[0].pagehdr.npages)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
  		printk("kAFS: %s(%lu): wrong number of dir blocks %d!=%hu
  ",
530b64127   Harvey Harrison   afs: replace rema...
142
  		       __func__, dir->i_ino, qty,
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
143
  		       ntohs(dbuf->blocks[0].pagehdr.npages));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
147
148
  		goto error;
  	}
  #endif
  
  	/* determine how many magic numbers there should be in this page */
54b21a799   Andrew Morton   [PATCH] fix possi...
149
  	latter = dir->i_size - page_offset(page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
152
153
154
155
156
157
158
159
160
161
  	if (latter >= PAGE_SIZE)
  		qty = PAGE_SIZE;
  	else
  		qty = latter;
  	qty /= sizeof(union afs_dir_block);
  
  	/* check them */
  	dbuf = page_address(page);
  	for (tmp = 0; tmp < qty; tmp++) {
  		if (dbuf->blocks[tmp].pagehdr.magic != AFS_DIR_MAGIC) {
  			printk("kAFS: %s(%lu): bad magic %d/%d is %04hx
  ",
530b64127   Harvey Harrison   afs: replace rema...
162
  			       __func__, dir->i_ino, tmp, qty,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
166
167
168
  			       ntohs(dbuf->blocks[tmp].pagehdr.magic));
  			goto error;
  		}
  	}
  
  	SetPageChecked(page);
be5b82dbf   Al Viro   make ext2_get_pag...
169
  	return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170

ec26815ad   David Howells   [AFS]: Clean up t...
171
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
  	SetPageError(page);
be5b82dbf   Al Viro   make ext2_get_pag...
173
  	return false;
ec26815ad   David Howells   [AFS]: Clean up t...
174
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
178
179
180
181
  /*
   * discard a page cached in the pagecache
   */
  static inline void afs_dir_put_page(struct page *page)
  {
  	kunmap(page);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
182
  	put_page(page);
ec26815ad   David Howells   [AFS]: Clean up t...
183
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
187
  /*
   * get a page into the pagecache
   */
00d3b7a45   David Howells   [AFS]: Add securi...
188
189
  static struct page *afs_dir_get_page(struct inode *dir, unsigned long index,
  				     struct key *key)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
  {
  	struct page *page;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
  	_enter("{%lu},%lu", dir->i_ino, index);
f6d335c08   Al Viro   AFS: Don't put st...
193
  	page = read_cache_page(dir->i_mapping, index, afs_page_filler, key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
  	if (!IS_ERR(page)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
  		kmap(page);
be5b82dbf   Al Viro   make ext2_get_pag...
196
197
198
199
  		if (unlikely(!PageChecked(page))) {
  			if (PageError(page) || !afs_dir_check_page(dir, page))
  				goto fail;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
201
  	}
  	return page;
ec26815ad   David Howells   [AFS]: Clean up t...
202
  fail:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
  	afs_dir_put_page(page);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
204
  	_leave(" = -EIO");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
  	return ERR_PTR(-EIO);
ec26815ad   David Howells   [AFS]: Clean up t...
206
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
211
212
213
  /*
   * open an AFS directory file
   */
  static int afs_dir_open(struct inode *inode, struct file *file)
  {
  	_enter("{%lu}", inode->i_ino);
2ecd05ae6   Alexey Dobriyan   [PATCH] fs/*: use...
214
215
  	BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);
  	BUILD_BUG_ON(sizeof(union afs_dirent) != 32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
224
  /*
   * deal with one block in an AFS directory
   */
1bbae9f81   Al Viro   [readdir] convert...
225
  static int afs_dir_iterate_block(struct dir_context *ctx,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
  				 union afs_dir_block *block,
1bbae9f81   Al Viro   [readdir] convert...
227
  				 unsigned blkoff)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
230
231
  {
  	union afs_dirent *dire;
  	unsigned offset, next, curr;
  	size_t nlen;
1bbae9f81   Al Viro   [readdir] convert...
232
  	int tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233

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

1bbae9f81   Al Viro   [readdir] convert...
236
  	curr = (ctx->pos - blkoff) / sizeof(union afs_dirent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
239
240
241
242
243
244
245
246
247
  
  	/* walk through the block, an entry at a time */
  	for (offset = AFS_DIRENT_PER_BLOCK - block->pagehdr.nentries;
  	     offset < AFS_DIRENT_PER_BLOCK;
  	     offset = next
  	     ) {
  		next = offset + 1;
  
  		/* skip entries marked unused in the bitmap */
  		if (!(block->pagehdr.bitmap[offset / 8] &
  		      (1 << (offset % 8)))) {
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
248
  			_debug("ENT[%zu.%u]: unused",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
  			       blkoff / sizeof(union afs_dir_block), offset);
  			if (offset >= curr)
1bbae9f81   Al Viro   [readdir] convert...
251
  				ctx->pos = blkoff +
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
254
255
256
257
258
259
260
  					next * sizeof(union afs_dirent);
  			continue;
  		}
  
  		/* got a valid entry */
  		dire = &block->dirents[offset];
  		nlen = strnlen(dire->u.name,
  			       sizeof(*block) -
  			       offset * sizeof(union afs_dirent));
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
261
  		_debug("ENT[%zu.%u]: %s %zu \"%s\"",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
264
265
266
267
268
  		       blkoff / sizeof(union afs_dir_block), offset,
  		       (offset < curr ? "skip" : "fill"),
  		       nlen, dire->u.name);
  
  		/* work out where the next possible entry is */
  		for (tmp = nlen; tmp > 15; tmp -= sizeof(union afs_dirent)) {
  			if (next >= AFS_DIRENT_PER_BLOCK) {
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
269
  				_debug("ENT[%zu.%u]:"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
  				       " %u travelled beyond end dir block"
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
271
  				       " (len %u/%zu)",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
273
274
275
276
277
  				       blkoff / sizeof(union afs_dir_block),
  				       offset, next, tmp, nlen);
  				return -EIO;
  			}
  			if (!(block->pagehdr.bitmap[next / 8] &
  			      (1 << (next % 8)))) {
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
278
279
  				_debug("ENT[%zu.%u]:"
  				       " %u unmarked extension (len %u/%zu)",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
281
282
283
  				       blkoff / sizeof(union afs_dir_block),
  				       offset, next, tmp, nlen);
  				return -EIO;
  			}
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
284
  			_debug("ENT[%zu.%u]: ext %u/%zu",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
287
288
289
290
291
292
293
294
  			       blkoff / sizeof(union afs_dir_block),
  			       next, tmp, nlen);
  			next++;
  		}
  
  		/* skip if starts before the current position */
  		if (offset < curr)
  			continue;
  
  		/* found the next entry */
1bbae9f81   Al Viro   [readdir] convert...
295
  		if (!dir_emit(ctx, dire->u.name, nlen,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
  			      ntohl(dire->u.vnode),
1bbae9f81   Al Viro   [readdir] convert...
297
298
  			      ctx->actor == afs_lookup_filldir ?
  			      ntohl(dire->u.unique) : DT_UNKNOWN)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
300
301
  			_leave(" = 0 [full]");
  			return 0;
  		}
1bbae9f81   Al Viro   [readdir] convert...
302
  		ctx->pos = blkoff + next * sizeof(union afs_dirent);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
304
305
306
  	}
  
  	_leave(" = 1 [more]");
  	return 1;
ec26815ad   David Howells   [AFS]: Clean up t...
307
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
  /*
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
310
   * iterate through the data blob that lists the contents of an AFS directory
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
   */
1bbae9f81   Al Viro   [readdir] convert...
312
313
  static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx,
  			   struct key *key)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  {
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
315
  	union afs_dir_block *dblock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
318
319
  	struct afs_dir_page *dbuf;
  	struct page *page;
  	unsigned blkoff, limit;
  	int ret;
1bbae9f81   Al Viro   [readdir] convert...
320
  	_enter("{%lu},%u,,", dir->i_ino, (unsigned)ctx->pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
322
  	if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dir)->flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
325
326
327
  		_leave(" = -ESTALE");
  		return -ESTALE;
  	}
  
  	/* round the file position up to the next entry boundary */
1bbae9f81   Al Viro   [readdir] convert...
328
329
  	ctx->pos += sizeof(union afs_dirent) - 1;
  	ctx->pos &= ~(sizeof(union afs_dirent) - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
332
  
  	/* walk through the blocks in sequence */
  	ret = 0;
1bbae9f81   Al Viro   [readdir] convert...
333
334
  	while (ctx->pos < dir->i_size) {
  		blkoff = ctx->pos & ~(sizeof(union afs_dir_block) - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
336
  
  		/* fetch the appropriate page from the directory */
00d3b7a45   David Howells   [AFS]: Add securi...
337
  		page = afs_dir_get_page(dir, blkoff / PAGE_SIZE, key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
339
340
341
342
343
344
345
346
347
348
349
350
  		if (IS_ERR(page)) {
  			ret = PTR_ERR(page);
  			break;
  		}
  
  		limit = blkoff & ~(PAGE_SIZE - 1);
  
  		dbuf = page_address(page);
  
  		/* deal with the individual blocks stashed on this page */
  		do {
  			dblock = &dbuf->blocks[(blkoff % PAGE_SIZE) /
  					       sizeof(union afs_dir_block)];
1bbae9f81   Al Viro   [readdir] convert...
351
  			ret = afs_dir_iterate_block(ctx, dblock, blkoff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
354
355
356
357
  			if (ret != 1) {
  				afs_dir_put_page(page);
  				goto out;
  			}
  
  			blkoff += sizeof(union afs_dir_block);
1bbae9f81   Al Viro   [readdir] convert...
358
  		} while (ctx->pos < dir->i_size && blkoff < limit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
361
362
  
  		afs_dir_put_page(page);
  		ret = 0;
  	}
ec26815ad   David Howells   [AFS]: Clean up t...
363
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
  	_leave(" = %d", ret);
  	return ret;
ec26815ad   David Howells   [AFS]: Clean up t...
366
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
370
  /*
   * read an AFS directory
   */
1bbae9f81   Al Viro   [readdir] convert...
371
  static int afs_readdir(struct file *file, struct dir_context *ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
  {
1bbae9f81   Al Viro   [readdir] convert...
373
374
  	return afs_dir_iterate(file_inode(file), 
  			      ctx, file->private_data);
ec26815ad   David Howells   [AFS]: Clean up t...
375
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
379
380
381
  /*
   * search the directory for a name
   * - if afs_dir_iterate_block() spots this function, it'll pass the FID
   *   uniquifier through dtype
   */
ac7576f4b   Miklos Szeredi   vfs: make first a...
382
383
  static int afs_lookup_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
384
  {
ac7576f4b   Miklos Szeredi   vfs: make first a...
385
386
  	struct afs_lookup_cookie *cookie =
  		container_of(ctx, struct afs_lookup_cookie, ctx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387

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

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
392
393
394
  	/* insanity checks first */
  	BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);
  	BUILD_BUG_ON(sizeof(union afs_dirent) != 32);
1bbae9f81   Al Viro   [readdir] convert...
395
396
  	if (cookie->name.len != nlen ||
  	    memcmp(cookie->name.name, name, nlen) != 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
399
400
401
402
403
404
405
406
  		_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...
407
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
  /*
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
410
   * do a lookup in a directory
260a98031   David Howells   [AFS]: Add "direc...
411
   * - just returns the FID the dentry name maps to if found
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
   */
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
413
  static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
00d3b7a45   David Howells   [AFS]: Add securi...
414
  			 struct afs_fid *fid, struct key *key)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
  {
1bbae9f81   Al Viro   [readdir] convert...
416
417
418
419
420
421
  	struct afs_super_info *as = dir->i_sb->s_fs_info;
  	struct afs_lookup_cookie cookie = {
  		.ctx.actor = afs_lookup_filldir,
  		.name = dentry->d_name,
  		.fid.vid = as->volume->vid
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
  	int ret;
a455589f1   Al Viro   assorted conversi...
423
  	_enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
  	/* search the directory */
1bbae9f81   Al Viro   [readdir] convert...
426
  	ret = afs_dir_iterate(dir, &cookie.ctx, key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
  	if (ret < 0) {
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
428
429
  		_leave(" = %d [iter]", ret);
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
432
433
  	}
  
  	ret = -ENOENT;
  	if (!cookie.found) {
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
434
435
  		_leave(" = -ENOENT [not found]");
  		return -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
  	}
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
437
438
439
440
441
442
  	*fid = cookie.fid;
  	_leave(" = 0 { vn=%u u=%u }", fid->vnode, fid->unique);
  	return 0;
  }
  
  /*
bec5eb614   wanglei   AFS: Implement an...
443
444
445
446
447
448
449
450
451
452
   * Try to auto mount the mountpoint with pseudo directory, if the autocell
   * operation is setted.
   */
  static struct inode *afs_try_auto_mntpt(
  	int ret, struct dentry *dentry, struct inode *dir, struct key *key,
  	struct afs_fid *fid)
  {
  	const char *devname = dentry->d_name.name;
  	struct afs_vnode *vnode = AFS_FS_I(dir);
  	struct inode *inode;
a455589f1   Al Viro   assorted conversi...
453
454
  	_enter("%d, %p{%pd}, {%x:%u}, %p",
  	       ret, dentry, dentry, vnode->fid.vid, vnode->fid.vnode, key);
bec5eb614   wanglei   AFS: Implement an...
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
  
  	if (ret != -ENOENT ||
  	    !test_bit(AFS_VNODE_AUTOCELL, &vnode->flags))
  		goto out;
  
  	inode = afs_iget_autocell(dir, devname, strlen(devname), key);
  	if (IS_ERR(inode)) {
  		ret = PTR_ERR(inode);
  		goto out;
  	}
  
  	*fid = AFS_FS_I(inode)->fid;
  	_leave("= %p", inode);
  	return inode;
  
  out:
  	_leave("= %d", ret);
  	return ERR_PTR(ret);
  }
  
  /*
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
476
477
   * look up an entry in a directory
   */
260a98031   David Howells   [AFS]: Add "direc...
478
  static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
00cd8dd3b   Al Viro   stop passing name...
479
  				 unsigned int flags)
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
480
481
482
483
  {
  	struct afs_vnode *vnode;
  	struct afs_fid fid;
  	struct inode *inode;
00d3b7a45   David Howells   [AFS]: Add securi...
484
  	struct key *key;
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
485
  	int ret;
260a98031   David Howells   [AFS]: Add "direc...
486
  	vnode = AFS_FS_I(dir);
a455589f1   Al Viro   assorted conversi...
487
488
  	_enter("{%x:%u},%p{%pd},",
  	       vnode->fid.vid, vnode->fid.vnode, dentry, dentry);
260a98031   David Howells   [AFS]: Add "direc...
489

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

45222b9e0   David Howells   AFS: implement st...
492
  	if (dentry->d_name.len >= AFSNAMEMAX) {
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
493
494
495
  		_leave(" = -ENAMETOOLONG");
  		return ERR_PTR(-ENAMETOOLONG);
  	}
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
496
497
498
499
  	if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
  		_leave(" = -ESTALE");
  		return ERR_PTR(-ESTALE);
  	}
00d3b7a45   David Howells   [AFS]: Add securi...
500
501
502
  	key = afs_request_key(vnode->volume->cell);
  	if (IS_ERR(key)) {
  		_leave(" = %ld [key]", PTR_ERR(key));
e231c2ee6   David Howells   Convert ERR_PTR(P...
503
  		return ERR_CAST(key);
00d3b7a45   David Howells   [AFS]: Add securi...
504
  	}
260a98031   David Howells   [AFS]: Add "direc...
505
506
507
508
509
510
  	ret = afs_validate(vnode, key);
  	if (ret < 0) {
  		key_put(key);
  		_leave(" = %d [val]", ret);
  		return ERR_PTR(ret);
  	}
00d3b7a45   David Howells   [AFS]: Add securi...
511
  	ret = afs_do_lookup(dir, dentry, &fid, key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
  	if (ret < 0) {
bec5eb614   wanglei   AFS: Implement an...
513
514
515
516
517
518
519
  		inode = afs_try_auto_mntpt(ret, dentry, dir, key, &fid);
  		if (!IS_ERR(inode)) {
  			key_put(key);
  			goto success;
  		}
  
  		ret = PTR_ERR(inode);
00d3b7a45   David Howells   [AFS]: Add securi...
520
  		key_put(key);
260a98031   David Howells   [AFS]: Add "direc...
521
522
523
524
525
  		if (ret == -ENOENT) {
  			d_add(dentry, NULL);
  			_leave(" = NULL [negative]");
  			return NULL;
  		}
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
526
  		_leave(" = %d [do]", ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
528
  		return ERR_PTR(ret);
  	}
260a98031   David Howells   [AFS]: Add "direc...
529
  	dentry->d_fsdata = (void *)(unsigned long) vnode->status.data_version;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
531
  	/* instantiate the dentry */
260a98031   David Howells   [AFS]: Add "direc...
532
  	inode = afs_iget(dir->i_sb, key, &fid, NULL, NULL);
00d3b7a45   David Howells   [AFS]: Add securi...
533
  	key_put(key);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
534
535
  	if (IS_ERR(inode)) {
  		_leave(" = %ld", PTR_ERR(inode));
e231c2ee6   David Howells   Convert ERR_PTR(P...
536
  		return ERR_CAST(inode);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
537
  	}
bec5eb614   wanglei   AFS: Implement an...
538
  success:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
  	d_add(dentry, inode);
d6e43f751   David Howells   AFS: Use i_genera...
540
  	_leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%u }",
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
541
542
  	       fid.vnode,
  	       fid.unique,
2b0143b5c   David Howells   VFS: normal files...
543
544
  	       d_inode(dentry)->i_ino,
  	       d_inode(dentry)->i_generation);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
546
  
  	return NULL;
ec26815ad   David Howells   [AFS]: Clean up t...
547
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
550
551
552
  /*
   * 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
553
   */
0b728e191   Al Viro   stop passing name...
554
  static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
  {
260a98031   David Howells   [AFS]: Add "direc...
556
  	struct afs_vnode *vnode, *dir;
dd0d9a46f   Artem Bityutskiy   AFS: Fix compilat...
557
  	struct afs_fid uninitialized_var(fid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
  	struct dentry *parent;
00d3b7a45   David Howells   [AFS]: Add securi...
559
  	struct key *key;
260a98031   David Howells   [AFS]: Add "direc...
560
  	void *dir_version;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
  	int ret;
0b728e191   Al Viro   stop passing name...
562
  	if (flags & LOOKUP_RCU)
34286d666   Nick Piggin   fs: rcu-walk awar...
563
  		return -ECHILD;
2b0143b5c   David Howells   VFS: normal files...
564
  	vnode = AFS_FS_I(d_inode(dentry));
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
565

2b0143b5c   David Howells   VFS: normal files...
566
  	if (d_really_is_positive(dentry))
a455589f1   Al Viro   assorted conversi...
567
568
  		_enter("{v={%x:%u} n=%pd fl=%lx},",
  		       vnode->fid.vid, vnode->fid.vnode, dentry,
260a98031   David Howells   [AFS]: Add "direc...
569
570
  		       vnode->flags);
  	else
a455589f1   Al Viro   assorted conversi...
571
  		_enter("{neg n=%pd}", dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572

260a98031   David Howells   [AFS]: Add "direc...
573
  	key = afs_request_key(AFS_FS_S(dentry->d_sb)->volume->cell);
00d3b7a45   David Howells   [AFS]: Add securi...
574
575
  	if (IS_ERR(key))
  		key = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
  	/* lock down the parent dentry so we can peer at it */
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
577
  	parent = dget_parent(dentry);
2b0143b5c   David Howells   VFS: normal files...
578
  	dir = AFS_FS_I(d_inode(parent));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579

260a98031   David Howells   [AFS]: Add "direc...
580
581
582
583
584
  	/* validate the parent directory */
  	if (test_bit(AFS_VNODE_MODIFIED, &dir->flags))
  		afs_validate(dir, key);
  
  	if (test_bit(AFS_VNODE_DELETED, &dir->flags)) {
a455589f1   Al Viro   assorted conversi...
585
  		_debug("%pd: parent dir deleted", dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
587
  		goto out_bad;
  	}
260a98031   David Howells   [AFS]: Add "direc...
588
589
590
  	dir_version = (void *) (unsigned long) dir->status.data_version;
  	if (dentry->d_fsdata == dir_version)
  		goto out_valid; /* the dir contents are unchanged */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591

260a98031   David Howells   [AFS]: Add "direc...
592
593
594
595
596
597
598
  	_debug("dir modified");
  
  	/* search the directory for this vnode */
  	ret = afs_do_lookup(&dir->vfs_inode, dentry, &fid, key);
  	switch (ret) {
  	case 0:
  		/* the filename maps to something */
2b0143b5c   David Howells   VFS: normal files...
599
  		if (d_really_is_negative(dentry))
260a98031   David Howells   [AFS]: Add "direc...
600
  			goto out_bad;
2b0143b5c   David Howells   VFS: normal files...
601
  		if (is_bad_inode(d_inode(dentry))) {
a455589f1   Al Viro   assorted conversi...
602
603
604
  			printk("kAFS: afs_d_revalidate: %pd2 has bad inode
  ",
  			       dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
606
  			goto out_bad;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
608
  		/* if the vnode ID has changed, then the dirent points to a
  		 * different file */
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
609
  		if (fid.vnode != vnode->fid.vnode) {
a455589f1   Al Viro   assorted conversi...
610
611
  			_debug("%pd: dirent changed [%u != %u]",
  			       dentry, fid.vnode,
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
612
  			       vnode->fid.vnode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
614
615
616
  			goto not_found;
  		}
  
  		/* if the vnode ID uniqifier has changed, then the file has
260a98031   David Howells   [AFS]: Add "direc...
617
618
  		 * been deleted and replaced, and the original vnode ID has
  		 * been reused */
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
619
  		if (fid.unique != vnode->fid.unique) {
a455589f1   Al Viro   assorted conversi...
620
621
  			_debug("%pd: file deleted (uq %u -> %u I:%u)",
  			       dentry, fid.unique,
7a224228e   Jean Noel Cordenner   vfs: Add 64 bit i...
622
  			       vnode->fid.unique,
2b0143b5c   David Howells   VFS: normal files...
623
  			       d_inode(dentry)->i_generation);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
624
625
626
  			spin_lock(&vnode->lock);
  			set_bit(AFS_VNODE_DELETED, &vnode->flags);
  			spin_unlock(&vnode->lock);
260a98031   David Howells   [AFS]: Add "direc...
627
  			goto not_found;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
  		}
260a98031   David Howells   [AFS]: Add "direc...
629
  		goto out_valid;
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
630

260a98031   David Howells   [AFS]: Add "direc...
631
632
  	case -ENOENT:
  		/* the filename is unknown */
a455589f1   Al Viro   assorted conversi...
633
  		_debug("%pd: dirent not found", dentry);
2b0143b5c   David Howells   VFS: normal files...
634
  		if (d_really_is_positive(dentry))
260a98031   David Howells   [AFS]: Add "direc...
635
636
  			goto not_found;
  		goto out_valid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637

260a98031   David Howells   [AFS]: Add "direc...
638
  	default:
a455589f1   Al Viro   assorted conversi...
639
640
  		_debug("failed to iterate dir %pd: %d",
  		       parent, ret);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
641
642
  		goto out_bad;
  	}
ec26815ad   David Howells   [AFS]: Clean up t...
643
  out_valid:
260a98031   David Howells   [AFS]: Add "direc...
644
  	dentry->d_fsdata = dir_version;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
  	dput(parent);
00d3b7a45   David Howells   [AFS]: Add securi...
646
  	key_put(key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
649
650
  	_leave(" = 1 [valid]");
  	return 1;
  
  	/* the dirent, if it exists, now points to a different vnode */
ec26815ad   David Howells   [AFS]: Clean up t...
651
  not_found:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
652
653
654
  	spin_lock(&dentry->d_lock);
  	dentry->d_flags |= DCACHE_NFSFS_RENAMED;
  	spin_unlock(&dentry->d_lock);
ec26815ad   David Howells   [AFS]: Clean up t...
655
  out_bad:
a455589f1   Al Viro   assorted conversi...
656
  	_debug("dropping dentry %pd2", dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
  	dput(parent);
00d3b7a45   David Howells   [AFS]: Add securi...
658
  	key_put(key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
661
  
  	_leave(" = 0 [bad]");
  	return 0;
ec26815ad   David Howells   [AFS]: Clean up t...
662
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
666
667
668
669
  /*
   * 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...
670
  static int afs_d_delete(const struct dentry *dentry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
  {
a455589f1   Al Viro   assorted conversi...
672
  	_enter("%pd", dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
674
675
  
  	if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
  		goto zap;
2b0143b5c   David Howells   VFS: normal files...
676
677
678
  	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...
679
  		goto zap;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
681
682
  
  	_leave(" = 0 [keep]");
  	return 0;
ec26815ad   David Howells   [AFS]: Clean up t...
683
  zap:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
685
  	_leave(" = 1 [zap]");
  	return 1;
ec26815ad   David Howells   [AFS]: Clean up t...
686
  }
260a98031   David Howells   [AFS]: Add "direc...
687
688
689
690
691
692
  
  /*
   * handle dentry release
   */
  static void afs_d_release(struct dentry *dentry)
  {
a455589f1   Al Viro   assorted conversi...
693
  	_enter("%pd", dentry);
260a98031   David Howells   [AFS]: Add "direc...
694
695
696
697
698
  }
  
  /*
   * create a directory on an AFS filesystem
   */
18bb1db3e   Al Viro   switch vfs_mkdir(...
699
  static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
260a98031   David Howells   [AFS]: Add "direc...
700
701
702
703
704
705
706
707
708
709
710
  {
  	struct afs_file_status status;
  	struct afs_callback cb;
  	struct afs_server *server;
  	struct afs_vnode *dvnode, *vnode;
  	struct afs_fid fid;
  	struct inode *inode;
  	struct key *key;
  	int ret;
  
  	dvnode = AFS_FS_I(dir);
a455589f1   Al Viro   assorted conversi...
711
712
  	_enter("{%x:%u},{%pd},%ho",
  	       dvnode->fid.vid, dvnode->fid.vnode, dentry, mode);
260a98031   David Howells   [AFS]: Add "direc...
713

260a98031   David Howells   [AFS]: Add "direc...
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
  	key = afs_request_key(dvnode->volume->cell);
  	if (IS_ERR(key)) {
  		ret = PTR_ERR(key);
  		goto error;
  	}
  
  	mode |= S_IFDIR;
  	ret = afs_vnode_create(dvnode, key, dentry->d_name.name,
  			       mode, &fid, &status, &cb, &server);
  	if (ret < 0)
  		goto mkdir_error;
  
  	inode = afs_iget(dir->i_sb, key, &fid, &status, &cb);
  	if (IS_ERR(inode)) {
  		/* ENOMEM at a really inconvenient time - just abandon the new
  		 * directory on the server */
  		ret = PTR_ERR(inode);
  		goto iget_error;
  	}
  
  	/* apply the status report we've got for the new vnode */
  	vnode = AFS_FS_I(inode);
  	spin_lock(&vnode->lock);
  	vnode->update_cnt++;
  	spin_unlock(&vnode->lock);
  	afs_vnode_finalise_status_update(vnode, server);
  	afs_put_server(server);
  
  	d_instantiate(dentry, inode);
  	if (d_unhashed(dentry)) {
  		_debug("not hashed");
  		d_rehash(dentry);
  	}
  	key_put(key);
  	_leave(" = 0");
  	return 0;
  
  iget_error:
  	afs_put_server(server);
  mkdir_error:
  	key_put(key);
  error:
  	d_drop(dentry);
  	_leave(" = %d", ret);
  	return ret;
  }
  
  /*
   * remove a directory from an AFS filesystem
   */
  static int afs_rmdir(struct inode *dir, struct dentry *dentry)
  {
  	struct afs_vnode *dvnode, *vnode;
  	struct key *key;
  	int ret;
  
  	dvnode = AFS_FS_I(dir);
a455589f1   Al Viro   assorted conversi...
771
772
  	_enter("{%x:%u},{%pd}",
  	       dvnode->fid.vid, dvnode->fid.vnode, dentry);
260a98031   David Howells   [AFS]: Add "direc...
773

260a98031   David Howells   [AFS]: Add "direc...
774
775
776
777
778
779
780
781
782
  	key = afs_request_key(dvnode->volume->cell);
  	if (IS_ERR(key)) {
  		ret = PTR_ERR(key);
  		goto error;
  	}
  
  	ret = afs_vnode_remove(dvnode, key, dentry->d_name.name, true);
  	if (ret < 0)
  		goto rmdir_error;
2b0143b5c   David Howells   VFS: normal files...
783
784
  	if (d_really_is_positive(dentry)) {
  		vnode = AFS_FS_I(d_inode(dentry));
260a98031   David Howells   [AFS]: Add "direc...
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
  		clear_nlink(&vnode->vfs_inode);
  		set_bit(AFS_VNODE_DELETED, &vnode->flags);
  		afs_discard_callback_on_delete(vnode);
  	}
  
  	key_put(key);
  	_leave(" = 0");
  	return 0;
  
  rmdir_error:
  	key_put(key);
  error:
  	_leave(" = %d", ret);
  	return ret;
  }
  
  /*
   * remove a file from an AFS filesystem
   */
  static int afs_unlink(struct inode *dir, struct dentry *dentry)
  {
  	struct afs_vnode *dvnode, *vnode;
  	struct key *key;
  	int ret;
  
  	dvnode = AFS_FS_I(dir);
a455589f1   Al Viro   assorted conversi...
811
812
  	_enter("{%x:%u},{%pd}",
  	       dvnode->fid.vid, dvnode->fid.vnode, dentry);
260a98031   David Howells   [AFS]: Add "direc...
813
814
  
  	ret = -ENAMETOOLONG;
45222b9e0   David Howells   AFS: implement st...
815
  	if (dentry->d_name.len >= AFSNAMEMAX)
260a98031   David Howells   [AFS]: Add "direc...
816
817
818
819
820
821
822
  		goto error;
  
  	key = afs_request_key(dvnode->volume->cell);
  	if (IS_ERR(key)) {
  		ret = PTR_ERR(key);
  		goto error;
  	}
2b0143b5c   David Howells   VFS: normal files...
823
824
  	if (d_really_is_positive(dentry)) {
  		vnode = AFS_FS_I(d_inode(dentry));
260a98031   David Howells   [AFS]: Add "direc...
825
826
827
828
829
830
831
832
833
834
  
  		/* make sure we have a callback promise on the victim */
  		ret = afs_validate(vnode, key);
  		if (ret < 0)
  			goto error;
  	}
  
  	ret = afs_vnode_remove(dvnode, key, dentry->d_name.name, false);
  	if (ret < 0)
  		goto remove_error;
2b0143b5c   David Howells   VFS: normal files...
835
  	if (d_really_is_positive(dentry)) {
260a98031   David Howells   [AFS]: Add "direc...
836
837
838
839
840
841
842
843
844
  		/* if the file wasn't 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...
  		 */
2b0143b5c   David Howells   VFS: normal files...
845
  		vnode = AFS_FS_I(d_inode(dentry));
260a98031   David Howells   [AFS]: Add "direc...
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
  		if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
  			_debug("AFS_VNODE_DELETED");
  		if (test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags))
  			_debug("AFS_VNODE_CB_BROKEN");
  		set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
  		ret = afs_validate(vnode, key);
  		_debug("nlink %d [val %d]", vnode->vfs_inode.i_nlink, ret);
  	}
  
  	key_put(key);
  	_leave(" = 0");
  	return 0;
  
  remove_error:
  	key_put(key);
  error:
  	_leave(" = %d", ret);
  	return ret;
  }
  
  /*
   * create a regular file on an AFS filesystem
   */
4acdaf27e   Al Viro   switch ->create()...
869
  static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
ebfc3b49a   Al Viro   don't pass nameid...
870
  		      bool excl)
260a98031   David Howells   [AFS]: Add "direc...
871
872
873
874
875
876
877
878
879
880
881
  {
  	struct afs_file_status status;
  	struct afs_callback cb;
  	struct afs_server *server;
  	struct afs_vnode *dvnode, *vnode;
  	struct afs_fid fid;
  	struct inode *inode;
  	struct key *key;
  	int ret;
  
  	dvnode = AFS_FS_I(dir);
a455589f1   Al Viro   assorted conversi...
882
883
  	_enter("{%x:%u},{%pd},%ho,",
  	       dvnode->fid.vid, dvnode->fid.vnode, dentry, mode);
260a98031   David Howells   [AFS]: Add "direc...
884

260a98031   David Howells   [AFS]: Add "direc...
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
  	key = afs_request_key(dvnode->volume->cell);
  	if (IS_ERR(key)) {
  		ret = PTR_ERR(key);
  		goto error;
  	}
  
  	mode |= S_IFREG;
  	ret = afs_vnode_create(dvnode, key, dentry->d_name.name,
  			       mode, &fid, &status, &cb, &server);
  	if (ret < 0)
  		goto create_error;
  
  	inode = afs_iget(dir->i_sb, key, &fid, &status, &cb);
  	if (IS_ERR(inode)) {
  		/* ENOMEM at a really inconvenient time - just abandon the new
  		 * directory on the server */
  		ret = PTR_ERR(inode);
  		goto iget_error;
  	}
  
  	/* apply the status report we've got for the new vnode */
  	vnode = AFS_FS_I(inode);
  	spin_lock(&vnode->lock);
  	vnode->update_cnt++;
  	spin_unlock(&vnode->lock);
  	afs_vnode_finalise_status_update(vnode, server);
  	afs_put_server(server);
  
  	d_instantiate(dentry, inode);
  	if (d_unhashed(dentry)) {
  		_debug("not hashed");
  		d_rehash(dentry);
  	}
  	key_put(key);
  	_leave(" = 0");
  	return 0;
  
  iget_error:
  	afs_put_server(server);
  create_error:
  	key_put(key);
  error:
  	d_drop(dentry);
  	_leave(" = %d", ret);
  	return ret;
  }
  
  /*
   * create a hard link between files in an AFS filesystem
   */
  static int afs_link(struct dentry *from, struct inode *dir,
  		    struct dentry *dentry)
  {
  	struct afs_vnode *dvnode, *vnode;
  	struct key *key;
  	int ret;
2b0143b5c   David Howells   VFS: normal files...
941
  	vnode = AFS_FS_I(d_inode(from));
260a98031   David Howells   [AFS]: Add "direc...
942
  	dvnode = AFS_FS_I(dir);
a455589f1   Al Viro   assorted conversi...
943
  	_enter("{%x:%u},{%x:%u},{%pd}",
260a98031   David Howells   [AFS]: Add "direc...
944
945
  	       vnode->fid.vid, vnode->fid.vnode,
  	       dvnode->fid.vid, dvnode->fid.vnode,
a455589f1   Al Viro   assorted conversi...
946
  	       dentry);
260a98031   David Howells   [AFS]: Add "direc...
947

260a98031   David Howells   [AFS]: Add "direc...
948
949
950
951
952
953
954
955
956
  	key = afs_request_key(dvnode->volume->cell);
  	if (IS_ERR(key)) {
  		ret = PTR_ERR(key);
  		goto error;
  	}
  
  	ret = afs_vnode_link(dvnode, vnode, key, dentry->d_name.name);
  	if (ret < 0)
  		goto link_error;
7de9c6ee3   Al Viro   new helper: ihold()
957
  	ihold(&vnode->vfs_inode);
260a98031   David Howells   [AFS]: Add "direc...
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
  	d_instantiate(dentry, &vnode->vfs_inode);
  	key_put(key);
  	_leave(" = 0");
  	return 0;
  
  link_error:
  	key_put(key);
  error:
  	d_drop(dentry);
  	_leave(" = %d", ret);
  	return ret;
  }
  
  /*
   * create a symlink in an AFS filesystem
   */
  static int afs_symlink(struct inode *dir, struct dentry *dentry,
  		       const char *content)
  {
  	struct afs_file_status status;
  	struct afs_server *server;
  	struct afs_vnode *dvnode, *vnode;
  	struct afs_fid fid;
  	struct inode *inode;
  	struct key *key;
  	int ret;
  
  	dvnode = AFS_FS_I(dir);
a455589f1   Al Viro   assorted conversi...
986
987
  	_enter("{%x:%u},{%pd},%s",
  	       dvnode->fid.vid, dvnode->fid.vnode, dentry,
260a98031   David Howells   [AFS]: Add "direc...
988
  	       content);
260a98031   David Howells   [AFS]: Add "direc...
989
  	ret = -EINVAL;
45222b9e0   David Howells   AFS: implement st...
990
  	if (strlen(content) >= AFSPATHMAX)
260a98031   David Howells   [AFS]: Add "direc...
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
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
  		goto error;
  
  	key = afs_request_key(dvnode->volume->cell);
  	if (IS_ERR(key)) {
  		ret = PTR_ERR(key);
  		goto error;
  	}
  
  	ret = afs_vnode_symlink(dvnode, key, dentry->d_name.name, content,
  				&fid, &status, &server);
  	if (ret < 0)
  		goto create_error;
  
  	inode = afs_iget(dir->i_sb, key, &fid, &status, NULL);
  	if (IS_ERR(inode)) {
  		/* ENOMEM at a really inconvenient time - just abandon the new
  		 * directory on the server */
  		ret = PTR_ERR(inode);
  		goto iget_error;
  	}
  
  	/* apply the status report we've got for the new vnode */
  	vnode = AFS_FS_I(inode);
  	spin_lock(&vnode->lock);
  	vnode->update_cnt++;
  	spin_unlock(&vnode->lock);
  	afs_vnode_finalise_status_update(vnode, server);
  	afs_put_server(server);
  
  	d_instantiate(dentry, inode);
  	if (d_unhashed(dentry)) {
  		_debug("not hashed");
  		d_rehash(dentry);
  	}
  	key_put(key);
  	_leave(" = 0");
  	return 0;
  
  iget_error:
  	afs_put_server(server);
  create_error:
  	key_put(key);
  error:
  	d_drop(dentry);
  	_leave(" = %d", ret);
  	return ret;
  }
  
  /*
   * 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...
1043
1044
  		      struct inode *new_dir, struct dentry *new_dentry,
  		      unsigned int flags)
260a98031   David Howells   [AFS]: Add "direc...
1045
1046
1047
1048
  {
  	struct afs_vnode *orig_dvnode, *new_dvnode, *vnode;
  	struct key *key;
  	int ret;
1cd66c93b   Miklos Szeredi   fs: make remainin...
1049
1050
  	if (flags)
  		return -EINVAL;
2b0143b5c   David Howells   VFS: normal files...
1051
  	vnode = AFS_FS_I(d_inode(old_dentry));
260a98031   David Howells   [AFS]: Add "direc...
1052
1053
  	orig_dvnode = AFS_FS_I(old_dir);
  	new_dvnode = AFS_FS_I(new_dir);
a455589f1   Al Viro   assorted conversi...
1054
  	_enter("{%x:%u},{%x:%u},{%x:%u},{%pd}",
260a98031   David Howells   [AFS]: Add "direc...
1055
1056
1057
  	       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...
1058
  	       new_dentry);
260a98031   David Howells   [AFS]: Add "direc...
1059

260a98031   David Howells   [AFS]: Add "direc...
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
  	key = afs_request_key(orig_dvnode->volume->cell);
  	if (IS_ERR(key)) {
  		ret = PTR_ERR(key);
  		goto error;
  	}
  
  	ret = afs_vnode_rename(orig_dvnode, new_dvnode, key,
  			       old_dentry->d_name.name,
  			       new_dentry->d_name.name);
  	if (ret < 0)
  		goto rename_error;
  	key_put(key);
  	_leave(" = 0");
  	return 0;
  
  rename_error:
  	key_put(key);
  error:
  	d_drop(new_dentry);
  	_leave(" = %d", ret);
  	return ret;
  }