Commit | Line | Data |
---|---|---|
ec26815a DH |
1 | /* AFS superblock handling |
2 | * | |
08e0e7c8 | 3 | * Copyright (c) 2002, 2007 Red Hat, Inc. All rights reserved. |
1da177e4 LT |
4 | * |
5 | * This software may be freely redistributed under the terms of the | |
6 | * GNU General Public License. | |
7 | * | |
8 | * You should have received a copy of the GNU General Public License | |
9 | * along with this program; if not, write to the Free Software | |
10 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
11 | * | |
12 | * Authors: David Howells <dhowells@redhat.com> | |
44d1b980 | 13 | * David Woodhouse <dwmw2@infradead.org> |
1da177e4 LT |
14 | * |
15 | */ | |
16 | ||
17 | #include <linux/kernel.h> | |
18 | #include <linux/module.h> | |
bec5eb61 | 19 | #include <linux/mount.h> |
1da177e4 LT |
20 | #include <linux/init.h> |
21 | #include <linux/slab.h> | |
22 | #include <linux/fs.h> | |
23 | #include <linux/pagemap.h> | |
80c72fe4 | 24 | #include <linux/parser.h> |
45222b9e | 25 | #include <linux/statfs.h> |
e8edc6e0 | 26 | #include <linux/sched.h> |
f74f70f8 | 27 | #include <linux/nsproxy.h> |
f044c884 | 28 | #include <linux/magic.h> |
f74f70f8 | 29 | #include <net/net_namespace.h> |
1da177e4 LT |
30 | #include "internal.h" |
31 | ||
51cc5068 | 32 | static void afs_i_init_once(void *foo); |
f7442b3b AV |
33 | static struct dentry *afs_mount(struct file_system_type *fs_type, |
34 | int flags, const char *dev_name, void *data); | |
dde194a6 | 35 | static void afs_kill_super(struct super_block *sb); |
1da177e4 | 36 | static struct inode *afs_alloc_inode(struct super_block *sb); |
1da177e4 | 37 | static void afs_destroy_inode(struct inode *inode); |
45222b9e | 38 | static int afs_statfs(struct dentry *dentry, struct kstatfs *buf); |
677018a6 DH |
39 | static int afs_show_devname(struct seq_file *m, struct dentry *root); |
40 | static int afs_show_options(struct seq_file *m, struct dentry *root); | |
1da177e4 | 41 | |
1f5ce9e9 | 42 | struct file_system_type afs_fs_type = { |
1da177e4 LT |
43 | .owner = THIS_MODULE, |
44 | .name = "afs", | |
f7442b3b | 45 | .mount = afs_mount, |
dde194a6 | 46 | .kill_sb = afs_kill_super, |
80c72fe4 | 47 | .fs_flags = 0, |
1da177e4 | 48 | }; |
7f78e035 | 49 | MODULE_ALIAS_FS("afs"); |
1da177e4 | 50 | |
ee9b6d61 | 51 | static const struct super_operations afs_super_ops = { |
45222b9e | 52 | .statfs = afs_statfs, |
1da177e4 | 53 | .alloc_inode = afs_alloc_inode, |
bec5eb61 | 54 | .drop_inode = afs_drop_inode, |
1da177e4 | 55 | .destroy_inode = afs_destroy_inode, |
b57922d9 | 56 | .evict_inode = afs_evict_inode, |
677018a6 DH |
57 | .show_devname = afs_show_devname, |
58 | .show_options = afs_show_options, | |
1da177e4 LT |
59 | }; |
60 | ||
e18b890b | 61 | static struct kmem_cache *afs_inode_cachep; |
1da177e4 LT |
62 | static atomic_t afs_count_active_inodes; |
63 | ||
80c72fe4 DH |
64 | enum { |
65 | afs_no_opt, | |
66 | afs_opt_cell, | |
4d673da1 | 67 | afs_opt_dyn, |
80c72fe4 DH |
68 | afs_opt_rwpath, |
69 | afs_opt_vol, | |
bec5eb61 | 70 | afs_opt_autocell, |
80c72fe4 DH |
71 | }; |
72 | ||
a447c093 | 73 | static const match_table_t afs_options_list = { |
80c72fe4 | 74 | { afs_opt_cell, "cell=%s" }, |
4d673da1 | 75 | { afs_opt_dyn, "dyn" }, |
80c72fe4 DH |
76 | { afs_opt_rwpath, "rwpath" }, |
77 | { afs_opt_vol, "vol=%s" }, | |
bec5eb61 | 78 | { afs_opt_autocell, "autocell" }, |
80c72fe4 DH |
79 | { afs_no_opt, NULL }, |
80 | }; | |
81 | ||
1da177e4 LT |
82 | /* |
83 | * initialise the filesystem | |
84 | */ | |
85 | int __init afs_fs_init(void) | |
86 | { | |
87 | int ret; | |
88 | ||
89 | _enter(""); | |
90 | ||
1da177e4 LT |
91 | /* create ourselves an inode cache */ |
92 | atomic_set(&afs_count_active_inodes, 0); | |
93 | ||
94 | ret = -ENOMEM; | |
95 | afs_inode_cachep = kmem_cache_create("afs_inode_cache", | |
96 | sizeof(struct afs_vnode), | |
97 | 0, | |
5d097056 | 98 | SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT, |
20c2df83 | 99 | afs_i_init_once); |
1da177e4 LT |
100 | if (!afs_inode_cachep) { |
101 | printk(KERN_NOTICE "kAFS: Failed to allocate inode cache\n"); | |
102 | return ret; | |
103 | } | |
104 | ||
105 | /* now export our filesystem to lesser mortals */ | |
106 | ret = register_filesystem(&afs_fs_type); | |
107 | if (ret < 0) { | |
108 | kmem_cache_destroy(afs_inode_cachep); | |
08e0e7c8 | 109 | _leave(" = %d", ret); |
1da177e4 LT |
110 | return ret; |
111 | } | |
112 | ||
08e0e7c8 | 113 | _leave(" = 0"); |
1da177e4 | 114 | return 0; |
ec26815a | 115 | } |
1da177e4 | 116 | |
1da177e4 LT |
117 | /* |
118 | * clean up the filesystem | |
119 | */ | |
120 | void __exit afs_fs_exit(void) | |
121 | { | |
08e0e7c8 DH |
122 | _enter(""); |
123 | ||
124 | afs_mntpt_kill_timer(); | |
1da177e4 LT |
125 | unregister_filesystem(&afs_fs_type); |
126 | ||
127 | if (atomic_read(&afs_count_active_inodes) != 0) { | |
128 | printk("kAFS: %d active inode objects still present\n", | |
129 | atomic_read(&afs_count_active_inodes)); | |
130 | BUG(); | |
131 | } | |
132 | ||
8c0a8537 KS |
133 | /* |
134 | * Make sure all delayed rcu free inodes are flushed before we | |
135 | * destroy cache. | |
136 | */ | |
137 | rcu_barrier(); | |
1da177e4 | 138 | kmem_cache_destroy(afs_inode_cachep); |
08e0e7c8 | 139 | _leave(""); |
ec26815a | 140 | } |
1da177e4 | 141 | |
677018a6 DH |
142 | /* |
143 | * Display the mount device name in /proc/mounts. | |
144 | */ | |
145 | static int afs_show_devname(struct seq_file *m, struct dentry *root) | |
146 | { | |
d2ddc776 | 147 | struct afs_super_info *as = AFS_FS_S(root->d_sb); |
677018a6 | 148 | struct afs_volume *volume = as->volume; |
d2ddc776 | 149 | struct afs_cell *cell = as->cell; |
677018a6 DH |
150 | const char *suf = ""; |
151 | char pref = '%'; | |
152 | ||
4d673da1 DH |
153 | if (as->dyn_root) { |
154 | seq_puts(m, "none"); | |
155 | return 0; | |
156 | } | |
157 | ||
677018a6 DH |
158 | switch (volume->type) { |
159 | case AFSVL_RWVOL: | |
160 | break; | |
161 | case AFSVL_ROVOL: | |
162 | pref = '#'; | |
163 | if (volume->type_force) | |
164 | suf = ".readonly"; | |
165 | break; | |
166 | case AFSVL_BACKVOL: | |
167 | pref = '#'; | |
168 | suf = ".backup"; | |
169 | break; | |
170 | } | |
171 | ||
d2ddc776 | 172 | seq_printf(m, "%c%s:%s%s", pref, cell->name, volume->name, suf); |
677018a6 DH |
173 | return 0; |
174 | } | |
175 | ||
176 | /* | |
177 | * Display the mount options in /proc/mounts. | |
178 | */ | |
179 | static int afs_show_options(struct seq_file *m, struct dentry *root) | |
180 | { | |
4d673da1 DH |
181 | struct afs_super_info *as = AFS_FS_S(root->d_sb); |
182 | ||
183 | if (as->dyn_root) | |
184 | seq_puts(m, ",dyn"); | |
677018a6 | 185 | if (test_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(d_inode(root))->flags)) |
4d673da1 | 186 | seq_puts(m, ",autocell"); |
677018a6 DH |
187 | return 0; |
188 | } | |
189 | ||
1da177e4 LT |
190 | /* |
191 | * parse the mount options | |
192 | * - this function has been shamelessly adapted from the ext3 fs which | |
193 | * shamelessly adapted it from the msdos fs | |
194 | */ | |
00d3b7a4 DH |
195 | static int afs_parse_options(struct afs_mount_params *params, |
196 | char *options, const char **devname) | |
1da177e4 | 197 | { |
08e0e7c8 | 198 | struct afs_cell *cell; |
80c72fe4 DH |
199 | substring_t args[MAX_OPT_ARGS]; |
200 | char *p; | |
201 | int token; | |
1da177e4 LT |
202 | |
203 | _enter("%s", options); | |
204 | ||
205 | options[PAGE_SIZE - 1] = 0; | |
206 | ||
80c72fe4 DH |
207 | while ((p = strsep(&options, ","))) { |
208 | if (!*p) | |
209 | continue; | |
1da177e4 | 210 | |
80c72fe4 DH |
211 | token = match_token(p, afs_options_list, args); |
212 | switch (token) { | |
213 | case afs_opt_cell: | |
989782dc DH |
214 | rcu_read_lock(); |
215 | cell = afs_lookup_cell_rcu(params->net, | |
216 | args[0].from, | |
217 | args[0].to - args[0].from); | |
218 | rcu_read_unlock(); | |
08e0e7c8 DH |
219 | if (IS_ERR(cell)) |
220 | return PTR_ERR(cell); | |
9ed900b1 | 221 | afs_put_cell(params->net, params->cell); |
00d3b7a4 | 222 | params->cell = cell; |
80c72fe4 DH |
223 | break; |
224 | ||
225 | case afs_opt_rwpath: | |
4d673da1 | 226 | params->rwpath = true; |
80c72fe4 DH |
227 | break; |
228 | ||
229 | case afs_opt_vol: | |
230 | *devname = args[0].from; | |
231 | break; | |
232 | ||
bec5eb61 | 233 | case afs_opt_autocell: |
4d673da1 DH |
234 | params->autocell = true; |
235 | break; | |
236 | ||
237 | case afs_opt_dyn: | |
238 | params->dyn_root = true; | |
bec5eb61 | 239 | break; |
240 | ||
80c72fe4 DH |
241 | default: |
242 | printk(KERN_ERR "kAFS:" | |
243 | " Unknown or invalid mount option: '%s'\n", p); | |
244 | return -EINVAL; | |
1da177e4 | 245 | } |
1da177e4 LT |
246 | } |
247 | ||
80c72fe4 DH |
248 | _leave(" = 0"); |
249 | return 0; | |
ec26815a | 250 | } |
1da177e4 | 251 | |
00d3b7a4 DH |
252 | /* |
253 | * parse a device name to get cell name, volume name, volume type and R/W | |
254 | * selector | |
255 | * - this can be one of the following: | |
256 | * "%[cell:]volume[.]" R/W volume | |
257 | * "#[cell:]volume[.]" R/O or R/W volume (rwpath=0), | |
258 | * or R/W (rwpath=1) volume | |
259 | * "%[cell:]volume.readonly" R/O volume | |
260 | * "#[cell:]volume.readonly" R/O volume | |
261 | * "%[cell:]volume.backup" Backup volume | |
262 | * "#[cell:]volume.backup" Backup volume | |
263 | */ | |
264 | static int afs_parse_device_name(struct afs_mount_params *params, | |
265 | const char *name) | |
266 | { | |
267 | struct afs_cell *cell; | |
268 | const char *cellname, *suffix; | |
269 | int cellnamesz; | |
270 | ||
271 | _enter(",%s", name); | |
4d673da1 | 272 | |
00d3b7a4 DH |
273 | if (!name) { |
274 | printk(KERN_ERR "kAFS: no volume name specified\n"); | |
275 | return -EINVAL; | |
276 | } | |
277 | ||
278 | if ((name[0] != '%' && name[0] != '#') || !name[1]) { | |
279 | printk(KERN_ERR "kAFS: unparsable volume name\n"); | |
280 | return -EINVAL; | |
281 | } | |
282 | ||
283 | /* determine the type of volume we're looking for */ | |
284 | params->type = AFSVL_ROVOL; | |
285 | params->force = false; | |
286 | if (params->rwpath || name[0] == '%') { | |
287 | params->type = AFSVL_RWVOL; | |
288 | params->force = true; | |
289 | } | |
290 | name++; | |
291 | ||
292 | /* split the cell name out if there is one */ | |
293 | params->volname = strchr(name, ':'); | |
294 | if (params->volname) { | |
295 | cellname = name; | |
296 | cellnamesz = params->volname - name; | |
297 | params->volname++; | |
298 | } else { | |
299 | params->volname = name; | |
300 | cellname = NULL; | |
301 | cellnamesz = 0; | |
302 | } | |
303 | ||
304 | /* the volume type is further affected by a possible suffix */ | |
305 | suffix = strrchr(params->volname, '.'); | |
306 | if (suffix) { | |
307 | if (strcmp(suffix, ".readonly") == 0) { | |
308 | params->type = AFSVL_ROVOL; | |
309 | params->force = true; | |
310 | } else if (strcmp(suffix, ".backup") == 0) { | |
311 | params->type = AFSVL_BACKVOL; | |
312 | params->force = true; | |
313 | } else if (suffix[1] == 0) { | |
314 | } else { | |
315 | suffix = NULL; | |
316 | } | |
317 | } | |
318 | ||
319 | params->volnamesz = suffix ? | |
320 | suffix - params->volname : strlen(params->volname); | |
321 | ||
322 | _debug("cell %*.*s [%p]", | |
323 | cellnamesz, cellnamesz, cellname ?: "", params->cell); | |
324 | ||
325 | /* lookup the cell record */ | |
326 | if (cellname || !params->cell) { | |
989782dc DH |
327 | cell = afs_lookup_cell(params->net, cellname, cellnamesz, |
328 | NULL, false); | |
00d3b7a4 | 329 | if (IS_ERR(cell)) { |
bec5eb61 | 330 | printk(KERN_ERR "kAFS: unable to lookup cell '%*.*s'\n", |
331 | cellnamesz, cellnamesz, cellname ?: ""); | |
00d3b7a4 DH |
332 | return PTR_ERR(cell); |
333 | } | |
9ed900b1 | 334 | afs_put_cell(params->net, params->cell); |
00d3b7a4 DH |
335 | params->cell = cell; |
336 | } | |
337 | ||
338 | _debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s", | |
339 | params->cell->name, params->cell, | |
340 | params->volnamesz, params->volnamesz, params->volname, | |
341 | suffix ?: "-", params->type, params->force ? " FORCE" : ""); | |
342 | ||
343 | return 0; | |
344 | } | |
345 | ||
1da177e4 LT |
346 | /* |
347 | * check a superblock to see if it's the one we're looking for | |
348 | */ | |
349 | static int afs_test_super(struct super_block *sb, void *data) | |
350 | { | |
dde194a6 | 351 | struct afs_super_info *as1 = data; |
d2ddc776 | 352 | struct afs_super_info *as = AFS_FS_S(sb); |
1da177e4 | 353 | |
4d673da1 DH |
354 | return (as->net == as1->net && |
355 | as->volume && | |
356 | as->volume->vid == as1->volume->vid); | |
357 | } | |
358 | ||
359 | static int afs_dynroot_test_super(struct super_block *sb, void *data) | |
360 | { | |
361 | return false; | |
dde194a6 AV |
362 | } |
363 | ||
364 | static int afs_set_super(struct super_block *sb, void *data) | |
365 | { | |
d2ddc776 DH |
366 | struct afs_super_info *as = data; |
367 | ||
368 | sb->s_fs_info = as; | |
dde194a6 | 369 | return set_anon_super(sb, NULL); |
ec26815a | 370 | } |
1da177e4 | 371 | |
1da177e4 LT |
372 | /* |
373 | * fill in the superblock | |
374 | */ | |
dde194a6 AV |
375 | static int afs_fill_super(struct super_block *sb, |
376 | struct afs_mount_params *params) | |
1da177e4 | 377 | { |
d2ddc776 | 378 | struct afs_super_info *as = AFS_FS_S(sb); |
1da177e4 | 379 | struct afs_fid fid; |
1da177e4 LT |
380 | struct inode *inode = NULL; |
381 | int ret; | |
382 | ||
08e0e7c8 | 383 | _enter(""); |
1da177e4 | 384 | |
1da177e4 | 385 | /* fill in the superblock */ |
09cbfeaf KS |
386 | sb->s_blocksize = PAGE_SIZE; |
387 | sb->s_blocksize_bits = PAGE_SHIFT; | |
1da177e4 LT |
388 | sb->s_magic = AFS_FS_MAGIC; |
389 | sb->s_op = &afs_super_ops; | |
4d673da1 DH |
390 | if (!as->dyn_root) |
391 | sb->s_xattr = afs_xattr_handlers; | |
edd3ba94 JK |
392 | ret = super_setup_bdi(sb); |
393 | if (ret) | |
394 | return ret; | |
395 | sb->s_bdi->ra_pages = VM_MAX_READAHEAD * 1024 / PAGE_SIZE; | |
1da177e4 LT |
396 | |
397 | /* allocate the root inode and dentry */ | |
4d673da1 DH |
398 | if (as->dyn_root) { |
399 | inode = afs_iget_pseudo_dir(sb, true); | |
400 | sb->s_flags |= SB_RDONLY; | |
401 | } else { | |
402 | sprintf(sb->s_id, "%u", as->volume->vid); | |
403 | afs_activate_volume(as->volume); | |
404 | fid.vid = as->volume->vid; | |
405 | fid.vnode = 1; | |
406 | fid.unique = 1; | |
407 | inode = afs_iget(sb, params->key, &fid, NULL, NULL, NULL); | |
408 | } | |
409 | ||
08e0e7c8 | 410 | if (IS_ERR(inode)) |
dde194a6 | 411 | return PTR_ERR(inode); |
1da177e4 | 412 | |
4d673da1 | 413 | if (params->autocell || params->dyn_root) |
bec5eb61 | 414 | set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); |
415 | ||
1da177e4 | 416 | ret = -ENOMEM; |
48fde701 AV |
417 | sb->s_root = d_make_root(inode); |
418 | if (!sb->s_root) | |
1da177e4 LT |
419 | goto error; |
420 | ||
d61dcce2 | 421 | sb->s_d_op = &afs_fs_dentry_operations; |
1da177e4 | 422 | |
08e0e7c8 | 423 | _leave(" = 0"); |
1da177e4 LT |
424 | return 0; |
425 | ||
ec26815a | 426 | error: |
08e0e7c8 | 427 | _leave(" = %d", ret); |
1da177e4 | 428 | return ret; |
ec26815a | 429 | } |
1da177e4 | 430 | |
49566f6f DH |
431 | static struct afs_super_info *afs_alloc_sbi(struct afs_mount_params *params) |
432 | { | |
433 | struct afs_super_info *as; | |
434 | ||
435 | as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); | |
436 | if (as) { | |
437 | as->net = afs_get_net(params->net); | |
4d673da1 DH |
438 | if (params->dyn_root) |
439 | as->dyn_root = true; | |
440 | else | |
441 | as->cell = afs_get_cell(params->cell); | |
49566f6f DH |
442 | } |
443 | return as; | |
444 | } | |
445 | ||
446 | static void afs_destroy_sbi(struct afs_super_info *as) | |
447 | { | |
448 | if (as) { | |
9ed900b1 DH |
449 | afs_put_volume(as->cell, as->volume); |
450 | afs_put_cell(as->net, as->cell); | |
49566f6f DH |
451 | afs_put_net(as->net); |
452 | kfree(as); | |
453 | } | |
454 | } | |
455 | ||
1da177e4 LT |
456 | /* |
457 | * get an AFS superblock | |
1da177e4 | 458 | */ |
f7442b3b | 459 | static struct dentry *afs_mount(struct file_system_type *fs_type, |
49566f6f | 460 | int flags, const char *dev_name, void *options) |
1da177e4 LT |
461 | { |
462 | struct afs_mount_params params; | |
463 | struct super_block *sb; | |
d2ddc776 | 464 | struct afs_volume *candidate; |
00d3b7a4 | 465 | struct key *key; |
dde194a6 | 466 | struct afs_super_info *as; |
1da177e4 LT |
467 | int ret; |
468 | ||
469 | _enter(",,%s,%p", dev_name, options); | |
470 | ||
471 | memset(¶ms, 0, sizeof(params)); | |
f044c884 | 472 | params.net = &__afs_net; |
1da177e4 | 473 | |
f74f70f8 EB |
474 | ret = -EINVAL; |
475 | if (current->nsproxy->net_ns != &init_net) | |
476 | goto error; | |
477 | ||
00d3b7a4 | 478 | /* parse the options and device name */ |
1da177e4 | 479 | if (options) { |
00d3b7a4 | 480 | ret = afs_parse_options(¶ms, options, &dev_name); |
1da177e4 LT |
481 | if (ret < 0) |
482 | goto error; | |
1da177e4 LT |
483 | } |
484 | ||
4d673da1 DH |
485 | if (!params.dyn_root) { |
486 | ret = afs_parse_device_name(¶ms, dev_name); | |
487 | if (ret < 0) | |
488 | goto error; | |
00d3b7a4 | 489 | |
4d673da1 DH |
490 | /* try and do the mount securely */ |
491 | key = afs_request_key(params.cell); | |
492 | if (IS_ERR(key)) { | |
493 | _leave(" = %ld [key]", PTR_ERR(key)); | |
494 | ret = PTR_ERR(key); | |
495 | goto error; | |
496 | } | |
497 | params.key = key; | |
00d3b7a4 | 498 | } |
00d3b7a4 | 499 | |
49566f6f DH |
500 | /* allocate a superblock info record */ |
501 | ret = -ENOMEM; | |
502 | as = afs_alloc_sbi(¶ms); | |
503 | if (!as) | |
d2ddc776 | 504 | goto error_key; |
49566f6f | 505 | |
4d673da1 DH |
506 | if (!params.dyn_root) { |
507 | /* Assume we're going to need a volume record; at the very | |
508 | * least we can use it to update the volume record if we have | |
509 | * one already. This checks that the volume exists within the | |
510 | * cell. | |
511 | */ | |
512 | candidate = afs_create_volume(¶ms); | |
513 | if (IS_ERR(candidate)) { | |
514 | ret = PTR_ERR(candidate); | |
515 | goto error_as; | |
516 | } | |
d2ddc776 | 517 | |
4d673da1 DH |
518 | as->volume = candidate; |
519 | } | |
1da177e4 LT |
520 | |
521 | /* allocate a deviceless superblock */ | |
4d673da1 DH |
522 | sb = sget(fs_type, |
523 | as->dyn_root ? afs_dynroot_test_super : afs_test_super, | |
524 | afs_set_super, flags, as); | |
08e0e7c8 DH |
525 | if (IS_ERR(sb)) { |
526 | ret = PTR_ERR(sb); | |
f044c884 | 527 | goto error_as; |
08e0e7c8 | 528 | } |
1da177e4 | 529 | |
436058a4 DH |
530 | if (!sb->s_root) { |
531 | /* initial superblock/root creation */ | |
532 | _debug("create"); | |
436058a4 | 533 | ret = afs_fill_super(sb, ¶ms); |
f044c884 DH |
534 | if (ret < 0) |
535 | goto error_sb; | |
49566f6f | 536 | as = NULL; |
1751e8a6 | 537 | sb->s_flags |= SB_ACTIVE; |
436058a4 DH |
538 | } else { |
539 | _debug("reuse"); | |
1751e8a6 | 540 | ASSERTCMP(sb->s_flags, &, SB_ACTIVE); |
49566f6f DH |
541 | afs_destroy_sbi(as); |
542 | as = NULL; | |
1da177e4 | 543 | } |
1da177e4 | 544 | |
9ed900b1 | 545 | afs_put_cell(params.net, params.cell); |
49566f6f | 546 | key_put(params.key); |
08e0e7c8 | 547 | _leave(" = 0 [%p]", sb); |
f7442b3b | 548 | return dget(sb->s_root); |
1da177e4 | 549 | |
f044c884 DH |
550 | error_sb: |
551 | deactivate_locked_super(sb); | |
d2ddc776 | 552 | goto error_key; |
f044c884 | 553 | error_as: |
49566f6f | 554 | afs_destroy_sbi(as); |
d2ddc776 DH |
555 | error_key: |
556 | key_put(params.key); | |
ec26815a | 557 | error: |
9ed900b1 | 558 | afs_put_cell(params.net, params.cell); |
1da177e4 | 559 | _leave(" = %d", ret); |
f7442b3b | 560 | return ERR_PTR(ret); |
ec26815a | 561 | } |
1da177e4 | 562 | |
dde194a6 | 563 | static void afs_kill_super(struct super_block *sb) |
1da177e4 | 564 | { |
c435ee34 | 565 | struct afs_super_info *as = AFS_FS_S(sb); |
f044c884 | 566 | |
c435ee34 DH |
567 | /* Clear the callback interests (which will do ilookup5) before |
568 | * deactivating the superblock. | |
569 | */ | |
4d673da1 DH |
570 | if (as->volume) |
571 | afs_clear_callback_interests(as->net, as->volume->servers); | |
dde194a6 | 572 | kill_anon_super(sb); |
4d673da1 DH |
573 | if (as->volume) |
574 | afs_deactivate_volume(as->volume); | |
49566f6f | 575 | afs_destroy_sbi(as); |
ec26815a | 576 | } |
1da177e4 | 577 | |
1da177e4 | 578 | /* |
f8de483e DH |
579 | * Initialise an inode cache slab element prior to any use. Note that |
580 | * afs_alloc_inode() *must* reset anything that could incorrectly leak from one | |
581 | * inode to another. | |
1da177e4 | 582 | */ |
51cc5068 | 583 | static void afs_i_init_once(void *_vnode) |
1da177e4 | 584 | { |
ec26815a | 585 | struct afs_vnode *vnode = _vnode; |
1da177e4 | 586 | |
a35afb83 CL |
587 | memset(vnode, 0, sizeof(*vnode)); |
588 | inode_init_once(&vnode->vfs_inode); | |
d2ddc776 | 589 | mutex_init(&vnode->io_lock); |
a35afb83 | 590 | mutex_init(&vnode->validate_lock); |
4343d008 | 591 | spin_lock_init(&vnode->wb_lock); |
a35afb83 | 592 | spin_lock_init(&vnode->lock); |
4343d008 | 593 | INIT_LIST_HEAD(&vnode->wb_keys); |
e8d6c554 DH |
594 | INIT_LIST_HEAD(&vnode->pending_locks); |
595 | INIT_LIST_HEAD(&vnode->granted_locks); | |
596 | INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work); | |
c435ee34 | 597 | seqlock_init(&vnode->cb_lock); |
ec26815a | 598 | } |
1da177e4 | 599 | |
1da177e4 LT |
600 | /* |
601 | * allocate an AFS inode struct from our slab cache | |
602 | */ | |
603 | static struct inode *afs_alloc_inode(struct super_block *sb) | |
604 | { | |
605 | struct afs_vnode *vnode; | |
606 | ||
ec26815a | 607 | vnode = kmem_cache_alloc(afs_inode_cachep, GFP_KERNEL); |
1da177e4 LT |
608 | if (!vnode) |
609 | return NULL; | |
610 | ||
611 | atomic_inc(&afs_count_active_inodes); | |
612 | ||
f8de483e | 613 | /* Reset anything that shouldn't leak from one inode to the next. */ |
1da177e4 LT |
614 | memset(&vnode->fid, 0, sizeof(vnode->fid)); |
615 | memset(&vnode->status, 0, sizeof(vnode->status)); | |
616 | ||
617 | vnode->volume = NULL; | |
f8de483e DH |
618 | vnode->lock_key = NULL; |
619 | vnode->permit_cache = NULL; | |
620 | vnode->cb_interest = NULL; | |
621 | #ifdef CONFIG_AFS_FSCACHE | |
622 | vnode->cache = NULL; | |
623 | #endif | |
624 | ||
260a9803 | 625 | vnode->flags = 1 << AFS_VNODE_UNSET; |
f8de483e DH |
626 | vnode->cb_type = 0; |
627 | vnode->lock_state = AFS_VNODE_LOCK_NONE; | |
1da177e4 | 628 | |
0f300ca9 | 629 | _leave(" = %p", &vnode->vfs_inode); |
1da177e4 | 630 | return &vnode->vfs_inode; |
ec26815a | 631 | } |
1da177e4 | 632 | |
fa0d7e3d NP |
633 | static void afs_i_callback(struct rcu_head *head) |
634 | { | |
635 | struct inode *inode = container_of(head, struct inode, i_rcu); | |
636 | struct afs_vnode *vnode = AFS_FS_I(inode); | |
fa0d7e3d NP |
637 | kmem_cache_free(afs_inode_cachep, vnode); |
638 | } | |
639 | ||
1da177e4 LT |
640 | /* |
641 | * destroy an AFS inode struct | |
642 | */ | |
643 | static void afs_destroy_inode(struct inode *inode) | |
644 | { | |
08e0e7c8 DH |
645 | struct afs_vnode *vnode = AFS_FS_I(inode); |
646 | ||
0f300ca9 | 647 | _enter("%p{%x:%u}", inode, vnode->fid.vid, vnode->fid.vnode); |
1da177e4 | 648 | |
08e0e7c8 DH |
649 | _debug("DESTROY INODE %p", inode); |
650 | ||
c435ee34 | 651 | ASSERTCMP(vnode->cb_interest, ==, NULL); |
08e0e7c8 | 652 | |
fa0d7e3d | 653 | call_rcu(&inode->i_rcu, afs_i_callback); |
1da177e4 | 654 | atomic_dec(&afs_count_active_inodes); |
ec26815a | 655 | } |
45222b9e DH |
656 | |
657 | /* | |
658 | * return information about an AFS volume | |
659 | */ | |
660 | static int afs_statfs(struct dentry *dentry, struct kstatfs *buf) | |
661 | { | |
4d673da1 | 662 | struct afs_super_info *as = AFS_FS_S(dentry->d_sb); |
d2ddc776 | 663 | struct afs_fs_cursor fc; |
45222b9e | 664 | struct afs_volume_status vs; |
2b0143b5 | 665 | struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); |
45222b9e DH |
666 | struct key *key; |
667 | int ret; | |
668 | ||
4d673da1 DH |
669 | buf->f_type = dentry->d_sb->s_magic; |
670 | buf->f_bsize = AFS_BLOCK_SIZE; | |
671 | buf->f_namelen = AFSNAMEMAX - 1; | |
672 | ||
673 | if (as->dyn_root) { | |
674 | buf->f_blocks = 1; | |
675 | buf->f_bavail = 0; | |
676 | buf->f_bfree = 0; | |
677 | return 0; | |
678 | } | |
679 | ||
45222b9e DH |
680 | key = afs_request_key(vnode->volume->cell); |
681 | if (IS_ERR(key)) | |
682 | return PTR_ERR(key); | |
683 | ||
d2ddc776 DH |
684 | ret = -ERESTARTSYS; |
685 | if (afs_begin_vnode_operation(&fc, vnode, key)) { | |
686 | fc.flags |= AFS_FS_CURSOR_NO_VSLEEP; | |
687 | while (afs_select_fileserver(&fc)) { | |
688 | fc.cb_break = vnode->cb_break + vnode->cb_s_break; | |
689 | afs_fs_get_volume_status(&fc, &vs); | |
690 | } | |
691 | ||
692 | afs_check_for_remote_deletion(&fc, fc.vnode); | |
693 | afs_vnode_commit_status(&fc, vnode, fc.cb_break); | |
694 | ret = afs_end_vnode_operation(&fc); | |
45222b9e DH |
695 | } |
696 | ||
d2ddc776 | 697 | key_put(key); |
45222b9e | 698 | |
d2ddc776 | 699 | if (ret == 0) { |
d2ddc776 DH |
700 | if (vs.max_quota == 0) |
701 | buf->f_blocks = vs.part_max_blocks; | |
702 | else | |
703 | buf->f_blocks = vs.max_quota; | |
704 | buf->f_bavail = buf->f_bfree = buf->f_blocks - vs.blocks_in_use; | |
705 | } | |
706 | ||
707 | return ret; | |
45222b9e | 708 | } |