Blame view

fs/afs/super.c 13.6 KB
ec26815ad   David Howells   [AFS]: Clean up t...
1
2
  /* AFS superblock handling
   *
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
3
   * Copyright (c) 2002, 2007 Red Hat, Inc. All rights reserved.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
9
10
11
12
   *
   * This software may be freely redistributed under the terms of the
   * GNU General Public License.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   *
   * Authors: David Howells <dhowells@redhat.com>
44d1b980c   David Woodhouse   Fix various old e...
13
   *          David Woodhouse <dwmw2@infradead.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
   *
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
bec5eb614   wanglei   AFS: Implement an...
19
  #include <linux/mount.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
22
23
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/fs.h>
  #include <linux/pagemap.h>
80c72fe41   David Howells   [AFS/AF_RXRPC]: M...
24
  #include <linux/parser.h>
45222b9e0   David Howells   AFS: implement st...
25
  #include <linux/statfs.h>
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
26
  #include <linux/sched.h>
f74f70f8b   Eric W. Biederman   afs: Only allow m...
27
28
  #include <linux/nsproxy.h>
  #include <net/net_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
  #include "internal.h"
  
  #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */
51cc50685   Alexey Dobriyan   SL*B: drop kmem c...
32
  static void afs_i_init_once(void *foo);
f7442b3be   Al Viro   convert afs
33
34
  static struct dentry *afs_mount(struct file_system_type *fs_type,
  		      int flags, const char *dev_name, void *data);
dde194a64   Al Viro   afs: fix sget() r...
35
  static void afs_kill_super(struct super_block *sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  static struct inode *afs_alloc_inode(struct super_block *sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  static void afs_destroy_inode(struct inode *inode);
45222b9e0   David Howells   AFS: implement st...
38
  static int afs_statfs(struct dentry *dentry, struct kstatfs *buf);
677018a6c   David Howells   afs: Implement sh...
39
40
  static int afs_show_devname(struct seq_file *m, struct dentry *root);
  static int afs_show_options(struct seq_file *m, struct dentry *root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41

1f5ce9e93   Trond Myklebust   VFS: Unexport do_...
42
  struct file_system_type afs_fs_type = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
  	.owner		= THIS_MODULE,
  	.name		= "afs",
f7442b3be   Al Viro   convert afs
45
  	.mount		= afs_mount,
dde194a64   Al Viro   afs: fix sget() r...
46
  	.kill_sb	= afs_kill_super,
80c72fe41   David Howells   [AFS/AF_RXRPC]: M...
47
  	.fs_flags	= 0,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
  };
7f78e0351   Eric W. Biederman   fs: Limit sys_mou...
49
  MODULE_ALIAS_FS("afs");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50

ee9b6d61a   Josef 'Jeff' Sipek   [PATCH] Mark stru...
51
  static const struct super_operations afs_super_ops = {
45222b9e0   David Howells   AFS: implement st...
52
  	.statfs		= afs_statfs,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  	.alloc_inode	= afs_alloc_inode,
bec5eb614   wanglei   AFS: Implement an...
54
  	.drop_inode	= afs_drop_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  	.destroy_inode	= afs_destroy_inode,
b57922d97   Al Viro   convert remaining...
56
  	.evict_inode	= afs_evict_inode,
677018a6c   David Howells   afs: Implement sh...
57
58
  	.show_devname	= afs_show_devname,
  	.show_options	= afs_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
  };
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
60
  static struct kmem_cache *afs_inode_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
  static atomic_t afs_count_active_inodes;
80c72fe41   David Howells   [AFS/AF_RXRPC]: M...
62
63
64
65
66
  enum {
  	afs_no_opt,
  	afs_opt_cell,
  	afs_opt_rwpath,
  	afs_opt_vol,
bec5eb614   wanglei   AFS: Implement an...
67
  	afs_opt_autocell,
80c72fe41   David Howells   [AFS/AF_RXRPC]: M...
68
  };
a447c0932   Steven Whitehouse   vfs: Use const fo...
69
  static const match_table_t afs_options_list = {
80c72fe41   David Howells   [AFS/AF_RXRPC]: M...
70
71
72
  	{ afs_opt_cell,		"cell=%s"	},
  	{ afs_opt_rwpath,	"rwpath"	},
  	{ afs_opt_vol,		"vol=%s"	},
bec5eb614   wanglei   AFS: Implement an...
73
  	{ afs_opt_autocell,	"autocell"	},
80c72fe41   David Howells   [AFS/AF_RXRPC]: M...
74
75
  	{ afs_no_opt,		NULL		},
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
78
79
80
81
82
83
  /*
   * initialise the filesystem
   */
  int __init afs_fs_init(void)
  {
  	int ret;
  
  	_enter("");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
86
87
88
89
90
  	/* create ourselves an inode cache */
  	atomic_set(&afs_count_active_inodes, 0);
  
  	ret = -ENOMEM;
  	afs_inode_cachep = kmem_cache_create("afs_inode_cache",
  					     sizeof(struct afs_vnode),
  					     0,
5d097056c   Vladimir Davydov   kmemcg: account c...
91
  					     SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT,
20c2df83d   Paul Mundt   mm: Remove slab d...
92
  					     afs_i_init_once);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
95
96
97
98
99
100
101
102
  	if (!afs_inode_cachep) {
  		printk(KERN_NOTICE "kAFS: Failed to allocate inode cache
  ");
  		return ret;
  	}
  
  	/* now export our filesystem to lesser mortals */
  	ret = register_filesystem(&afs_fs_type);
  	if (ret < 0) {
  		kmem_cache_destroy(afs_inode_cachep);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
103
  		_leave(" = %d", ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
  		return ret;
  	}
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
106
  	_leave(" = 0");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
  	return 0;
ec26815ad   David Howells   [AFS]: Clean up t...
108
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
114
  /*
   * clean up the filesystem
   */
  void __exit afs_fs_exit(void)
  {
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
115
116
117
  	_enter("");
  
  	afs_mntpt_kill_timer();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
120
121
122
123
124
125
  	unregister_filesystem(&afs_fs_type);
  
  	if (atomic_read(&afs_count_active_inodes) != 0) {
  		printk("kAFS: %d active inode objects still present
  ",
  		       atomic_read(&afs_count_active_inodes));
  		BUG();
  	}
8c0a85377   Kirill A. Shutemov   fs: push rcu_barr...
126
127
128
129
130
  	/*
  	 * Make sure all delayed rcu free inodes are flushed before we
  	 * destroy cache.
  	 */
  	rcu_barrier();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  	kmem_cache_destroy(afs_inode_cachep);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
132
  	_leave("");
ec26815ad   David Howells   [AFS]: Clean up t...
133
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
  /*
677018a6c   David Howells   afs: Implement sh...
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
   * Display the mount device name in /proc/mounts.
   */
  static int afs_show_devname(struct seq_file *m, struct dentry *root)
  {
  	struct afs_super_info *as = root->d_sb->s_fs_info;
  	struct afs_volume *volume = as->volume;
  	struct afs_cell *cell = volume->cell;
  	const char *suf = "";
  	char pref = '%';
  
  	switch (volume->type) {
  	case AFSVL_RWVOL:
  		break;
  	case AFSVL_ROVOL:
  		pref = '#';
  		if (volume->type_force)
  			suf = ".readonly";
  		break;
  	case AFSVL_BACKVOL:
  		pref = '#';
  		suf = ".backup";
  		break;
  	}
  
  	seq_printf(m, "%c%s:%s%s", pref, cell->name, volume->vlocation->vldb.name, suf);
  	return 0;
  }
  
  /*
   * Display the mount options in /proc/mounts.
   */
  static int afs_show_options(struct seq_file *m, struct dentry *root)
  {
  	if (test_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(d_inode(root))->flags))
  		seq_puts(m, "autocell");
  	return 0;
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
178
   * parse the mount options
   * - this function has been shamelessly adapted from the ext3 fs which
   *   shamelessly adapted it from the msdos fs
   */
00d3b7a45   David Howells   [AFS]: Add securi...
179
180
  static int afs_parse_options(struct afs_mount_params *params,
  			     char *options, const char **devname)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
  {
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
182
  	struct afs_cell *cell;
80c72fe41   David Howells   [AFS/AF_RXRPC]: M...
183
184
185
  	substring_t args[MAX_OPT_ARGS];
  	char *p;
  	int token;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
188
189
  
  	_enter("%s", options);
  
  	options[PAGE_SIZE - 1] = 0;
80c72fe41   David Howells   [AFS/AF_RXRPC]: M...
190
191
192
  	while ((p = strsep(&options, ","))) {
  		if (!*p)
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193

80c72fe41   David Howells   [AFS/AF_RXRPC]: M...
194
195
196
197
  		token = match_token(p, afs_options_list, args);
  		switch (token) {
  		case afs_opt_cell:
  			cell = afs_cell_lookup(args[0].from,
bec5eb614   wanglei   AFS: Implement an...
198
199
  					       args[0].to - args[0].from,
  					       false);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
200
201
  			if (IS_ERR(cell))
  				return PTR_ERR(cell);
00d3b7a45   David Howells   [AFS]: Add securi...
202
203
  			afs_put_cell(params->cell);
  			params->cell = cell;
80c72fe41   David Howells   [AFS/AF_RXRPC]: M...
204
205
206
207
208
209
210
211
212
  			break;
  
  		case afs_opt_rwpath:
  			params->rwpath = 1;
  			break;
  
  		case afs_opt_vol:
  			*devname = args[0].from;
  			break;
bec5eb614   wanglei   AFS: Implement an...
213
214
215
  		case afs_opt_autocell:
  			params->autocell = 1;
  			break;
80c72fe41   David Howells   [AFS/AF_RXRPC]: M...
216
217
218
219
220
  		default:
  			printk(KERN_ERR "kAFS:"
  			       " Unknown or invalid mount option: '%s'
  ", p);
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
  	}
80c72fe41   David Howells   [AFS/AF_RXRPC]: M...
223
224
  	_leave(" = 0");
  	return 0;
ec26815ad   David Howells   [AFS]: Clean up t...
225
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
  /*
00d3b7a45   David Howells   [AFS]: Add securi...
228
229
230
231
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
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
   * parse a device name to get cell name, volume name, volume type and R/W
   * selector
   * - this can be one of the following:
   *	"%[cell:]volume[.]"		R/W volume
   *	"#[cell:]volume[.]"		R/O or R/W volume (rwpath=0),
   *					 or R/W (rwpath=1) volume
   *	"%[cell:]volume.readonly"	R/O volume
   *	"#[cell:]volume.readonly"	R/O volume
   *	"%[cell:]volume.backup"		Backup volume
   *	"#[cell:]volume.backup"		Backup volume
   */
  static int afs_parse_device_name(struct afs_mount_params *params,
  				 const char *name)
  {
  	struct afs_cell *cell;
  	const char *cellname, *suffix;
  	int cellnamesz;
  
  	_enter(",%s", name);
  
  	if (!name) {
  		printk(KERN_ERR "kAFS: no volume name specified
  ");
  		return -EINVAL;
  	}
  
  	if ((name[0] != '%' && name[0] != '#') || !name[1]) {
  		printk(KERN_ERR "kAFS: unparsable volume name
  ");
  		return -EINVAL;
  	}
  
  	/* determine the type of volume we're looking for */
  	params->type = AFSVL_ROVOL;
  	params->force = false;
  	if (params->rwpath || name[0] == '%') {
  		params->type = AFSVL_RWVOL;
  		params->force = true;
  	}
  	name++;
  
  	/* split the cell name out if there is one */
  	params->volname = strchr(name, ':');
  	if (params->volname) {
  		cellname = name;
  		cellnamesz = params->volname - name;
  		params->volname++;
  	} else {
  		params->volname = name;
  		cellname = NULL;
  		cellnamesz = 0;
  	}
  
  	/* the volume type is further affected by a possible suffix */
  	suffix = strrchr(params->volname, '.');
  	if (suffix) {
  		if (strcmp(suffix, ".readonly") == 0) {
  			params->type = AFSVL_ROVOL;
  			params->force = true;
  		} else if (strcmp(suffix, ".backup") == 0) {
  			params->type = AFSVL_BACKVOL;
  			params->force = true;
  		} else if (suffix[1] == 0) {
  		} else {
  			suffix = NULL;
  		}
  	}
  
  	params->volnamesz = suffix ?
  		suffix - params->volname : strlen(params->volname);
  
  	_debug("cell %*.*s [%p]",
  	       cellnamesz, cellnamesz, cellname ?: "", params->cell);
  
  	/* lookup the cell record */
  	if (cellname || !params->cell) {
bec5eb614   wanglei   AFS: Implement an...
304
  		cell = afs_cell_lookup(cellname, cellnamesz, true);
00d3b7a45   David Howells   [AFS]: Add securi...
305
  		if (IS_ERR(cell)) {
bec5eb614   wanglei   AFS: Implement an...
306
307
308
  			printk(KERN_ERR "kAFS: unable to lookup cell '%*.*s'
  ",
  			       cellnamesz, cellnamesz, cellname ?: "");
00d3b7a45   David Howells   [AFS]: Add securi...
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
  			return PTR_ERR(cell);
  		}
  		afs_put_cell(params->cell);
  		params->cell = cell;
  	}
  
  	_debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s",
  	       params->cell->name, params->cell,
  	       params->volnamesz, params->volnamesz, params->volname,
  	       suffix ?: "-", params->type, params->force ? " FORCE" : "");
  
  	return 0;
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
325
326
327
   * check a superblock to see if it's the one we're looking for
   */
  static int afs_test_super(struct super_block *sb, void *data)
  {
dde194a64   Al Viro   afs: fix sget() r...
328
  	struct afs_super_info *as1 = data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
  	struct afs_super_info *as = sb->s_fs_info;
dde194a64   Al Viro   afs: fix sget() r...
330
331
332
333
334
335
336
  	return as->volume == as1->volume;
  }
  
  static int afs_set_super(struct super_block *sb, void *data)
  {
  	sb->s_fs_info = data;
  	return set_anon_super(sb, NULL);
ec26815ad   David Howells   [AFS]: Clean up t...
337
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
341
  /*
   * fill in the superblock
   */
dde194a64   Al Viro   afs: fix sget() r...
342
343
  static int afs_fill_super(struct super_block *sb,
  			  struct afs_mount_params *params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
  {
dde194a64   Al Viro   afs: fix sget() r...
345
  	struct afs_super_info *as = sb->s_fs_info;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
  	struct afs_fid fid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
348
  	struct inode *inode = NULL;
  	int ret;
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
349
  	_enter("");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
  	/* fill in the superblock */
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
352
353
  	sb->s_blocksize		= PAGE_SIZE;
  	sb->s_blocksize_bits	= PAGE_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
355
  	sb->s_magic		= AFS_FS_MAGIC;
  	sb->s_op		= &afs_super_ops;
d3e3b7eac   David Howells   afs: Add metadata...
356
  	sb->s_xattr		= afs_xattr_handlers;
edd3ba94c   Jan Kara   afs: Convert to s...
357
358
359
360
  	ret = super_setup_bdi(sb);
  	if (ret)
  		return ret;
  	sb->s_bdi->ra_pages	= VM_MAX_READAHEAD * 1024 / PAGE_SIZE;
2e41ae225   David Howells   AFS: Set s_id in ...
361
  	strlcpy(sb->s_id, as->volume->vlocation->vldb.name, sizeof(sb->s_id));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
365
366
  
  	/* allocate the root inode and dentry */
  	fid.vid		= as->volume->vid;
  	fid.vnode	= 1;
  	fid.unique	= 1;
260a98031   David Howells   [AFS]: Add "direc...
367
  	inode = afs_iget(sb, params->key, &fid, NULL, NULL);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
368
  	if (IS_ERR(inode))
dde194a64   Al Viro   afs: fix sget() r...
369
  		return PTR_ERR(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370

bec5eb614   wanglei   AFS: Implement an...
371
372
  	if (params->autocell)
  		set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
  	ret = -ENOMEM;
48fde701a   Al Viro   switch open-coded...
374
375
  	sb->s_root = d_make_root(inode);
  	if (!sb->s_root)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  		goto error;
d61dcce29   Al Viro   switch afs
377
  	sb->s_d_op = &afs_fs_dentry_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
379
  	_leave(" = 0");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
  	return 0;
ec26815ad   David Howells   [AFS]: Clean up t...
381
  error:
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
382
  	_leave(" = %d", ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
  	return ret;
ec26815ad   David Howells   [AFS]: Clean up t...
384
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
387
  /*
   * get an AFS superblock
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
   */
f7442b3be   Al Viro   convert afs
389
390
  static struct dentry *afs_mount(struct file_system_type *fs_type,
  		      int flags, const char *dev_name, void *options)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
392
393
  {
  	struct afs_mount_params params;
  	struct super_block *sb;
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
394
  	struct afs_volume *vol;
00d3b7a45   David Howells   [AFS]: Add securi...
395
  	struct key *key;
969729d56   Miklos Szeredi   mount options: fi...
396
  	char *new_opts = kstrdup(options, GFP_KERNEL);
dde194a64   Al Viro   afs: fix sget() r...
397
  	struct afs_super_info *as;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
399
400
401
402
  	int ret;
  
  	_enter(",,%s,%p", dev_name, options);
  
  	memset(&params, 0, sizeof(params));
f74f70f8b   Eric W. Biederman   afs: Only allow m...
403
404
405
  	ret = -EINVAL;
  	if (current->nsproxy->net_ns != &init_net)
  		goto error;
00d3b7a45   David Howells   [AFS]: Add securi...
406
  	/* parse the options and device name */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
  	if (options) {
00d3b7a45   David Howells   [AFS]: Add securi...
408
  		ret = afs_parse_options(&params, options, &dev_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
  		if (ret < 0)
  			goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
  	}
00d3b7a45   David Howells   [AFS]: Add securi...
412
413
414
415
416
417
418
419
420
421
422
423
  	ret = afs_parse_device_name(&params, dev_name);
  	if (ret < 0)
  		goto error;
  
  	/* try and do the mount securely */
  	key = afs_request_key(params.cell);
  	if (IS_ERR(key)) {
  		_leave(" = %ld [key]", PTR_ERR(key));
  		ret = PTR_ERR(key);
  		goto error;
  	}
  	params.key = key;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
  	/* parse the device name */
00d3b7a45   David Howells   [AFS]: Add securi...
425
  	vol = afs_volume_lookup(&params);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
426
427
  	if (IS_ERR(vol)) {
  		ret = PTR_ERR(vol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  		goto error;
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
429
  	}
dde194a64   Al Viro   afs: fix sget() r...
430
431
432
433
434
435
436
437
438
  
  	/* allocate a superblock info record */
  	as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL);
  	if (!as) {
  		ret = -ENOMEM;
  		afs_put_volume(vol);
  		goto error;
  	}
  	as->volume = vol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
  
  	/* allocate a deviceless superblock */
9249e17fe   David Howells   VFS: Pass mount f...
441
  	sb = sget(fs_type, afs_test_super, afs_set_super, flags, as);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
442
443
  	if (IS_ERR(sb)) {
  		ret = PTR_ERR(sb);
dde194a64   Al Viro   afs: fix sget() r...
444
445
  		afs_put_volume(vol);
  		kfree(as);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
446
  		goto error;
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
447
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448

436058a49   David Howells   [AFS]: Handle mul...
449
450
451
  	if (!sb->s_root) {
  		/* initial superblock/root creation */
  		_debug("create");
436058a49   David Howells   [AFS]: Handle mul...
452
453
  		ret = afs_fill_super(sb, &params);
  		if (ret < 0) {
6f5bbff9a   Al Viro   Convert obvious p...
454
  			deactivate_locked_super(sb);
436058a49   David Howells   [AFS]: Handle mul...
455
456
457
458
459
460
  			goto error;
  		}
  		sb->s_flags |= MS_ACTIVE;
  	} else {
  		_debug("reuse");
  		ASSERTCMP(sb->s_flags, &, MS_ACTIVE);
dde194a64   Al Viro   afs: fix sget() r...
461
462
  		afs_put_volume(vol);
  		kfree(as);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464

00d3b7a45   David Howells   [AFS]: Add securi...
465
  	afs_put_cell(params.cell);
2a32cebd6   Al Viro   Fix races around ...
466
  	kfree(new_opts);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
467
  	_leave(" = 0 [%p]", sb);
f7442b3be   Al Viro   convert afs
468
  	return dget(sb->s_root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469

ec26815ad   David Howells   [AFS]: Clean up t...
470
  error:
00d3b7a45   David Howells   [AFS]: Add securi...
471
472
  	afs_put_cell(params.cell);
  	key_put(params.key);
969729d56   Miklos Szeredi   mount options: fi...
473
  	kfree(new_opts);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
  	_leave(" = %d", ret);
f7442b3be   Al Viro   convert afs
475
  	return ERR_PTR(ret);
ec26815ad   David Howells   [AFS]: Clean up t...
476
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477

dde194a64   Al Viro   afs: fix sget() r...
478
  static void afs_kill_super(struct super_block *sb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
  {
  	struct afs_super_info *as = sb->s_fs_info;
dde194a64   Al Viro   afs: fix sget() r...
481
  	kill_anon_super(sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  	afs_put_volume(as->volume);
dde194a64   Al Viro   afs: fix sget() r...
483
  	kfree(as);
ec26815ad   David Howells   [AFS]: Clean up t...
484
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
487
488
  /*
   * initialise an inode cache slab element prior to any use
   */
51cc50685   Alexey Dobriyan   SL*B: drop kmem c...
489
  static void afs_i_init_once(void *_vnode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
  {
ec26815ad   David Howells   [AFS]: Clean up t...
491
  	struct afs_vnode *vnode = _vnode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492

a35afb830   Christoph Lameter   Remove SLAB_CTOR_...
493
494
495
496
497
498
499
500
  	memset(vnode, 0, sizeof(*vnode));
  	inode_init_once(&vnode->vfs_inode);
  	init_waitqueue_head(&vnode->update_waitq);
  	mutex_init(&vnode->permits_lock);
  	mutex_init(&vnode->validate_lock);
  	spin_lock_init(&vnode->writeback_lock);
  	spin_lock_init(&vnode->lock);
  	INIT_LIST_HEAD(&vnode->writebacks);
e8d6c5541   David Howells   AFS: implement fi...
501
502
503
  	INIT_LIST_HEAD(&vnode->pending_locks);
  	INIT_LIST_HEAD(&vnode->granted_locks);
  	INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work);
a35afb830   Christoph Lameter   Remove SLAB_CTOR_...
504
  	INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work);
ec26815ad   David Howells   [AFS]: Clean up t...
505
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
508
509
510
511
512
  /*
   * allocate an AFS inode struct from our slab cache
   */
  static struct inode *afs_alloc_inode(struct super_block *sb)
  {
  	struct afs_vnode *vnode;
ec26815ad   David Howells   [AFS]: Clean up t...
513
  	vnode = kmem_cache_alloc(afs_inode_cachep, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
516
517
518
519
520
521
522
523
  	if (!vnode)
  		return NULL;
  
  	atomic_inc(&afs_count_active_inodes);
  
  	memset(&vnode->fid, 0, sizeof(vnode->fid));
  	memset(&vnode->status, 0, sizeof(vnode->status));
  
  	vnode->volume		= NULL;
  	vnode->update_cnt	= 0;
260a98031   David Howells   [AFS]: Add "direc...
524
  	vnode->flags		= 1 << AFS_VNODE_UNSET;
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
525
  	vnode->cb_promised	= false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526

0f300ca92   David Howells   AFS: fix a couple...
527
  	_leave(" = %p", &vnode->vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
  	return &vnode->vfs_inode;
ec26815ad   David Howells   [AFS]: Clean up t...
529
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530

fa0d7e3de   Nick Piggin   fs: icache RCU fr...
531
532
533
534
  static void afs_i_callback(struct rcu_head *head)
  {
  	struct inode *inode = container_of(head, struct inode, i_rcu);
  	struct afs_vnode *vnode = AFS_FS_I(inode);
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
535
536
  	kmem_cache_free(afs_inode_cachep, vnode);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
539
540
541
  /*
   * destroy an AFS inode struct
   */
  static void afs_destroy_inode(struct inode *inode)
  {
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
542
  	struct afs_vnode *vnode = AFS_FS_I(inode);
0f300ca92   David Howells   AFS: fix a couple...
543
  	_enter("%p{%x:%u}", inode, vnode->fid.vid, vnode->fid.vnode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
545
546
547
  	_debug("DESTROY INODE %p", inode);
  
  	ASSERTCMP(vnode->server, ==, NULL);
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
548
  	call_rcu(&inode->i_rcu, afs_i_callback);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
  	atomic_dec(&afs_count_active_inodes);
ec26815ad   David Howells   [AFS]: Clean up t...
550
  }
45222b9e0   David Howells   AFS: implement st...
551
552
553
554
555
556
557
  
  /*
   * return information about an AFS volume
   */
  static int afs_statfs(struct dentry *dentry, struct kstatfs *buf)
  {
  	struct afs_volume_status vs;
2b0143b5c   David Howells   VFS: normal files...
558
  	struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));
45222b9e0   David Howells   AFS: implement st...
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
  	struct key *key;
  	int ret;
  
  	key = afs_request_key(vnode->volume->cell);
  	if (IS_ERR(key))
  		return PTR_ERR(key);
  
  	ret = afs_vnode_get_volume_status(vnode, key, &vs);
  	key_put(key);
  	if (ret < 0) {
  		_leave(" = %d", ret);
  		return ret;
  	}
  
  	buf->f_type	= dentry->d_sb->s_magic;
  	buf->f_bsize	= AFS_BLOCK_SIZE;
  	buf->f_namelen	= AFSNAMEMAX - 1;
  
  	if (vs.max_quota == 0)
  		buf->f_blocks = vs.part_max_blocks;
  	else
  		buf->f_blocks = vs.max_quota;
  	buf->f_bavail = buf->f_bfree = buf->f_blocks - vs.blocks_in_use;
  	return 0;
  }