1 | /* AFS superblock handling |
2 | * |
3 | * Copyright (c) 2002, 2007, 2018 Red Hat, Inc. All rights reserved. |
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> |
13 | * David Woodhouse <dwmw2@infradead.org> |
14 | * |
15 | */ |
16 | |
17 | #include <linux/kernel.h> |
18 | #include <linux/module.h> |
19 | #include <linux/mount.h> |
20 | #include <linux/init.h> |
21 | #include <linux/slab.h> |
22 | #include <linux/fs.h> |
23 | #include <linux/pagemap.h> |
24 | #include <linux/fs_parser.h> |
25 | #include <linux/statfs.h> |
26 | #include <linux/sched.h> |
27 | #include <linux/nsproxy.h> |
28 | #include <linux/magic.h> |
29 | #include <net/net_namespace.h> |
30 | #include "internal.h" |
31 | |
32 | static void afs_i_init_once(void *foo); |
33 | static void afs_kill_super(struct super_block *sb); |
34 | static struct inode *afs_alloc_inode(struct super_block *sb); |
35 | static void afs_destroy_inode(struct inode *inode); |
36 | static void afs_free_inode(struct inode *inode); |
37 | static int afs_statfs(struct dentry *dentry, struct kstatfs *buf); |
38 | static int afs_show_devname(struct seq_file *m, struct dentry *root); |
39 | static int afs_show_options(struct seq_file *m, struct dentry *root); |
40 | static int afs_init_fs_context(struct fs_context *fc); |
41 | static const struct fs_parameter_spec afs_fs_parameters[]; |
42 | |
43 | struct file_system_type afs_fs_type = { |
44 | .owner = THIS_MODULE, |
45 | .name = "afs" , |
46 | .init_fs_context = afs_init_fs_context, |
47 | .parameters = afs_fs_parameters, |
48 | .kill_sb = afs_kill_super, |
49 | .fs_flags = FS_RENAME_DOES_D_MOVE, |
50 | }; |
51 | MODULE_ALIAS_FS("afs" ); |
52 | |
53 | int afs_net_id; |
54 | |
55 | static const struct super_operations afs_super_ops = { |
56 | .statfs = afs_statfs, |
57 | .alloc_inode = afs_alloc_inode, |
58 | .write_inode = afs_write_inode, |
59 | .drop_inode = afs_drop_inode, |
60 | .destroy_inode = afs_destroy_inode, |
61 | .free_inode = afs_free_inode, |
62 | .evict_inode = afs_evict_inode, |
63 | .show_devname = afs_show_devname, |
64 | .show_options = afs_show_options, |
65 | }; |
66 | |
67 | static struct kmem_cache *afs_inode_cachep; |
68 | static atomic_t afs_count_active_inodes; |
69 | |
70 | enum afs_param { |
71 | Opt_autocell, |
72 | Opt_dyn, |
73 | Opt_flock, |
74 | Opt_source, |
75 | }; |
76 | |
77 | static const struct constant_table afs_param_flock[] = { |
78 | {"local" , afs_flock_mode_local }, |
79 | {"openafs" , afs_flock_mode_openafs }, |
80 | {"strict" , afs_flock_mode_strict }, |
81 | {"write" , afs_flock_mode_write }, |
82 | {} |
83 | }; |
84 | |
85 | static const struct fs_parameter_spec afs_fs_parameters[] = { |
86 | fsparam_flag ("autocell" , Opt_autocell), |
87 | fsparam_flag ("dyn" , Opt_dyn), |
88 | fsparam_enum ("flock" , Opt_flock, afs_param_flock), |
89 | fsparam_string("source" , Opt_source), |
90 | {} |
91 | }; |
92 | |
93 | /* |
94 | * initialise the filesystem |
95 | */ |
96 | int __init afs_fs_init(void) |
97 | { |
98 | int ret; |
99 | |
100 | _enter("" ); |
101 | |
102 | /* create ourselves an inode cache */ |
103 | atomic_set(v: &afs_count_active_inodes, i: 0); |
104 | |
105 | ret = -ENOMEM; |
106 | afs_inode_cachep = kmem_cache_create(name: "afs_inode_cache" , |
107 | size: sizeof(struct afs_vnode), |
108 | align: 0, |
109 | SLAB_HWCACHE_ALIGN|SLAB_ACCOUNT, |
110 | ctor: afs_i_init_once); |
111 | if (!afs_inode_cachep) { |
112 | printk(KERN_NOTICE "kAFS: Failed to allocate inode cache\n" ); |
113 | return ret; |
114 | } |
115 | |
116 | /* now export our filesystem to lesser mortals */ |
117 | ret = register_filesystem(&afs_fs_type); |
118 | if (ret < 0) { |
119 | kmem_cache_destroy(s: afs_inode_cachep); |
120 | _leave(" = %d" , ret); |
121 | return ret; |
122 | } |
123 | |
124 | _leave(" = 0" ); |
125 | return 0; |
126 | } |
127 | |
128 | /* |
129 | * clean up the filesystem |
130 | */ |
131 | void afs_fs_exit(void) |
132 | { |
133 | _enter("" ); |
134 | |
135 | afs_mntpt_kill_timer(); |
136 | unregister_filesystem(&afs_fs_type); |
137 | |
138 | if (atomic_read(v: &afs_count_active_inodes) != 0) { |
139 | printk("kAFS: %d active inode objects still present\n" , |
140 | atomic_read(&afs_count_active_inodes)); |
141 | BUG(); |
142 | } |
143 | |
144 | /* |
145 | * Make sure all delayed rcu free inodes are flushed before we |
146 | * destroy cache. |
147 | */ |
148 | rcu_barrier(); |
149 | kmem_cache_destroy(s: afs_inode_cachep); |
150 | _leave("" ); |
151 | } |
152 | |
153 | /* |
154 | * Display the mount device name in /proc/mounts. |
155 | */ |
156 | static int afs_show_devname(struct seq_file *m, struct dentry *root) |
157 | { |
158 | struct afs_super_info *as = AFS_FS_S(sb: root->d_sb); |
159 | struct afs_volume *volume = as->volume; |
160 | struct afs_cell *cell = as->cell; |
161 | const char *suf = "" ; |
162 | char pref = '%'; |
163 | |
164 | if (as->dyn_root) { |
165 | seq_puts(m, s: "none" ); |
166 | return 0; |
167 | } |
168 | |
169 | switch (volume->type) { |
170 | case AFSVL_RWVOL: |
171 | break; |
172 | case AFSVL_ROVOL: |
173 | pref = '#'; |
174 | if (volume->type_force) |
175 | suf = ".readonly" ; |
176 | break; |
177 | case AFSVL_BACKVOL: |
178 | pref = '#'; |
179 | suf = ".backup" ; |
180 | break; |
181 | } |
182 | |
183 | seq_printf(m, fmt: "%c%s:%s%s" , pref, cell->name, volume->name, suf); |
184 | return 0; |
185 | } |
186 | |
187 | /* |
188 | * Display the mount options in /proc/mounts. |
189 | */ |
190 | static int afs_show_options(struct seq_file *m, struct dentry *root) |
191 | { |
192 | struct afs_super_info *as = AFS_FS_S(sb: root->d_sb); |
193 | const char *p = NULL; |
194 | |
195 | if (as->dyn_root) |
196 | seq_puts(m, s: ",dyn" ); |
197 | if (test_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(d_inode(root))->flags)) |
198 | seq_puts(m, s: ",autocell" ); |
199 | switch (as->flock_mode) { |
200 | case afs_flock_mode_unset: break; |
201 | case afs_flock_mode_local: p = "local" ; break; |
202 | case afs_flock_mode_openafs: p = "openafs" ; break; |
203 | case afs_flock_mode_strict: p = "strict" ; break; |
204 | case afs_flock_mode_write: p = "write" ; break; |
205 | } |
206 | if (p) |
207 | seq_printf(m, fmt: ",flock=%s" , p); |
208 | |
209 | return 0; |
210 | } |
211 | |
212 | /* |
213 | * Parse the source name to get cell name, volume name, volume type and R/W |
214 | * selector. |
215 | * |
216 | * This can be one of the following: |
217 | * "%[cell:]volume[.]" R/W volume |
218 | * "#[cell:]volume[.]" R/O or R/W volume (R/O parent), |
219 | * or R/W (R/W parent) volume |
220 | * "%[cell:]volume.readonly" R/O volume |
221 | * "#[cell:]volume.readonly" R/O volume |
222 | * "%[cell:]volume.backup" Backup volume |
223 | * "#[cell:]volume.backup" Backup volume |
224 | */ |
225 | static int afs_parse_source(struct fs_context *fc, struct fs_parameter *param) |
226 | { |
227 | struct afs_fs_context *ctx = fc->fs_private; |
228 | struct afs_cell *cell; |
229 | const char *cellname, *suffix, *name = param->string; |
230 | int cellnamesz; |
231 | |
232 | _enter(",%s" , name); |
233 | |
234 | if (fc->source) |
235 | return invalf(fc, "kAFS: Multiple sources not supported" ); |
236 | |
237 | if (!name) { |
238 | printk(KERN_ERR "kAFS: no volume name specified\n" ); |
239 | return -EINVAL; |
240 | } |
241 | |
242 | if ((name[0] != '%' && name[0] != '#') || !name[1]) { |
243 | /* To use dynroot, we don't want to have to provide a source */ |
244 | if (strcmp(name, "none" ) == 0) { |
245 | ctx->no_cell = true; |
246 | return 0; |
247 | } |
248 | printk(KERN_ERR "kAFS: unparsable volume name\n" ); |
249 | return -EINVAL; |
250 | } |
251 | |
252 | /* determine the type of volume we're looking for */ |
253 | if (name[0] == '%') { |
254 | ctx->type = AFSVL_RWVOL; |
255 | ctx->force = true; |
256 | } |
257 | name++; |
258 | |
259 | /* split the cell name out if there is one */ |
260 | ctx->volname = strchr(name, ':'); |
261 | if (ctx->volname) { |
262 | cellname = name; |
263 | cellnamesz = ctx->volname - name; |
264 | ctx->volname++; |
265 | } else { |
266 | ctx->volname = name; |
267 | cellname = NULL; |
268 | cellnamesz = 0; |
269 | } |
270 | |
271 | /* the volume type is further affected by a possible suffix */ |
272 | suffix = strrchr(ctx->volname, '.'); |
273 | if (suffix) { |
274 | if (strcmp(suffix, ".readonly" ) == 0) { |
275 | ctx->type = AFSVL_ROVOL; |
276 | ctx->force = true; |
277 | } else if (strcmp(suffix, ".backup" ) == 0) { |
278 | ctx->type = AFSVL_BACKVOL; |
279 | ctx->force = true; |
280 | } else if (suffix[1] == 0) { |
281 | } else { |
282 | suffix = NULL; |
283 | } |
284 | } |
285 | |
286 | ctx->volnamesz = suffix ? |
287 | suffix - ctx->volname : strlen(ctx->volname); |
288 | |
289 | _debug("cell %*.*s [%p]" , |
290 | cellnamesz, cellnamesz, cellname ?: "" , ctx->cell); |
291 | |
292 | /* lookup the cell record */ |
293 | if (cellname) { |
294 | cell = afs_lookup_cell(ctx->net, cellname, cellnamesz, |
295 | NULL, false); |
296 | if (IS_ERR(ptr: cell)) { |
297 | pr_err("kAFS: unable to lookup cell '%*.*s'\n" , |
298 | cellnamesz, cellnamesz, cellname ?: "" ); |
299 | return PTR_ERR(ptr: cell); |
300 | } |
301 | afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_parse); |
302 | afs_see_cell(cell, afs_cell_trace_see_source); |
303 | ctx->cell = cell; |
304 | } |
305 | |
306 | _debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s" , |
307 | ctx->cell->name, ctx->cell, |
308 | ctx->volnamesz, ctx->volnamesz, ctx->volname, |
309 | suffix ?: "-" , ctx->type, ctx->force ? " FORCE" : "" ); |
310 | |
311 | fc->source = param->string; |
312 | param->string = NULL; |
313 | return 0; |
314 | } |
315 | |
316 | /* |
317 | * Parse a single mount parameter. |
318 | */ |
319 | static int afs_parse_param(struct fs_context *fc, struct fs_parameter *param) |
320 | { |
321 | struct fs_parse_result result; |
322 | struct afs_fs_context *ctx = fc->fs_private; |
323 | int opt; |
324 | |
325 | opt = fs_parse(fc, desc: afs_fs_parameters, param, result: &result); |
326 | if (opt < 0) |
327 | return opt; |
328 | |
329 | switch (opt) { |
330 | case Opt_source: |
331 | return afs_parse_source(fc, param); |
332 | |
333 | case Opt_autocell: |
334 | ctx->autocell = true; |
335 | break; |
336 | |
337 | case Opt_dyn: |
338 | ctx->dyn_root = true; |
339 | break; |
340 | |
341 | case Opt_flock: |
342 | ctx->flock_mode = result.uint_32; |
343 | break; |
344 | |
345 | default: |
346 | return -EINVAL; |
347 | } |
348 | |
349 | _leave(" = 0" ); |
350 | return 0; |
351 | } |
352 | |
353 | /* |
354 | * Validate the options, get the cell key and look up the volume. |
355 | */ |
356 | static int afs_validate_fc(struct fs_context *fc) |
357 | { |
358 | struct afs_fs_context *ctx = fc->fs_private; |
359 | struct afs_volume *volume; |
360 | struct afs_cell *cell; |
361 | struct key *key; |
362 | int ret; |
363 | |
364 | if (!ctx->dyn_root) { |
365 | if (ctx->no_cell) { |
366 | pr_warn("kAFS: Can only specify source 'none' with -o dyn\n" ); |
367 | return -EINVAL; |
368 | } |
369 | |
370 | if (!ctx->cell) { |
371 | pr_warn("kAFS: No cell specified\n" ); |
372 | return -EDESTADDRREQ; |
373 | } |
374 | |
375 | reget_key: |
376 | /* We try to do the mount securely. */ |
377 | key = afs_request_key(ctx->cell); |
378 | if (IS_ERR(ptr: key)) |
379 | return PTR_ERR(ptr: key); |
380 | |
381 | ctx->key = key; |
382 | |
383 | if (ctx->volume) { |
384 | afs_put_volume(ctx->net, ctx->volume, |
385 | afs_volume_trace_put_validate_fc); |
386 | ctx->volume = NULL; |
387 | } |
388 | |
389 | if (test_bit(AFS_CELL_FL_CHECK_ALIAS, &ctx->cell->flags)) { |
390 | ret = afs_cell_detect_alias(ctx->cell, key); |
391 | if (ret < 0) |
392 | return ret; |
393 | if (ret == 1) { |
394 | _debug("switch to alias" ); |
395 | key_put(key: ctx->key); |
396 | ctx->key = NULL; |
397 | cell = afs_use_cell(ctx->cell->alias_of, |
398 | afs_cell_trace_use_fc_alias); |
399 | afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_fc); |
400 | ctx->cell = cell; |
401 | goto reget_key; |
402 | } |
403 | } |
404 | |
405 | volume = afs_create_volume(ctx); |
406 | if (IS_ERR(ptr: volume)) |
407 | return PTR_ERR(ptr: volume); |
408 | |
409 | ctx->volume = volume; |
410 | } |
411 | |
412 | return 0; |
413 | } |
414 | |
415 | /* |
416 | * check a superblock to see if it's the one we're looking for |
417 | */ |
418 | static int afs_test_super(struct super_block *sb, struct fs_context *fc) |
419 | { |
420 | struct afs_fs_context *ctx = fc->fs_private; |
421 | struct afs_super_info *as = AFS_FS_S(sb); |
422 | |
423 | return (as->net_ns == fc->net_ns && |
424 | as->volume && |
425 | as->volume->vid == ctx->volume->vid && |
426 | as->cell == ctx->cell && |
427 | !as->dyn_root); |
428 | } |
429 | |
430 | static int afs_dynroot_test_super(struct super_block *sb, struct fs_context *fc) |
431 | { |
432 | struct afs_super_info *as = AFS_FS_S(sb); |
433 | |
434 | return (as->net_ns == fc->net_ns && |
435 | as->dyn_root); |
436 | } |
437 | |
438 | static int afs_set_super(struct super_block *sb, struct fs_context *fc) |
439 | { |
440 | return set_anon_super(s: sb, NULL); |
441 | } |
442 | |
443 | /* |
444 | * fill in the superblock |
445 | */ |
446 | static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx) |
447 | { |
448 | struct afs_super_info *as = AFS_FS_S(sb); |
449 | struct inode *inode = NULL; |
450 | int ret; |
451 | |
452 | _enter("" ); |
453 | |
454 | /* fill in the superblock */ |
455 | sb->s_blocksize = PAGE_SIZE; |
456 | sb->s_blocksize_bits = PAGE_SHIFT; |
457 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
458 | sb->s_magic = AFS_FS_MAGIC; |
459 | sb->s_op = &afs_super_ops; |
460 | if (!as->dyn_root) |
461 | sb->s_xattr = afs_xattr_handlers; |
462 | ret = super_setup_bdi(sb); |
463 | if (ret) |
464 | return ret; |
465 | |
466 | /* allocate the root inode and dentry */ |
467 | if (as->dyn_root) { |
468 | inode = afs_iget_pseudo_dir(sb, true); |
469 | } else { |
470 | sprintf(buf: sb->s_id, fmt: "%llu" , as->volume->vid); |
471 | afs_activate_volume(as->volume); |
472 | inode = afs_root_iget(sb, ctx->key); |
473 | } |
474 | |
475 | if (IS_ERR(ptr: inode)) |
476 | return PTR_ERR(ptr: inode); |
477 | |
478 | if (ctx->autocell || as->dyn_root) |
479 | set_bit(AFS_VNODE_AUTOCELL, addr: &AFS_FS_I(inode)->flags); |
480 | |
481 | ret = -ENOMEM; |
482 | sb->s_root = d_make_root(inode); |
483 | if (!sb->s_root) |
484 | goto error; |
485 | |
486 | if (as->dyn_root) { |
487 | sb->s_d_op = &afs_dynroot_dentry_operations; |
488 | ret = afs_dynroot_populate(sb); |
489 | if (ret < 0) |
490 | goto error; |
491 | } else { |
492 | sb->s_d_op = &afs_fs_dentry_operations; |
493 | rcu_assign_pointer(as->volume->sb, sb); |
494 | } |
495 | |
496 | _leave(" = 0" ); |
497 | return 0; |
498 | |
499 | error: |
500 | _leave(" = %d" , ret); |
501 | return ret; |
502 | } |
503 | |
504 | static struct afs_super_info *afs_alloc_sbi(struct fs_context *fc) |
505 | { |
506 | struct afs_fs_context *ctx = fc->fs_private; |
507 | struct afs_super_info *as; |
508 | |
509 | as = kzalloc(size: sizeof(struct afs_super_info), GFP_KERNEL); |
510 | if (as) { |
511 | as->net_ns = get_net(net: fc->net_ns); |
512 | as->flock_mode = ctx->flock_mode; |
513 | if (ctx->dyn_root) { |
514 | as->dyn_root = true; |
515 | } else { |
516 | as->cell = afs_use_cell(ctx->cell, afs_cell_trace_use_sbi); |
517 | as->volume = afs_get_volume(ctx->volume, |
518 | afs_volume_trace_get_alloc_sbi); |
519 | } |
520 | } |
521 | return as; |
522 | } |
523 | |
524 | static void afs_destroy_sbi(struct afs_super_info *as) |
525 | { |
526 | if (as) { |
527 | struct afs_net *net = afs_net(net: as->net_ns); |
528 | afs_put_volume(net, as->volume, afs_volume_trace_put_destroy_sbi); |
529 | afs_unuse_cell(net, as->cell, afs_cell_trace_unuse_sbi); |
530 | put_net(net: as->net_ns); |
531 | kfree(objp: as); |
532 | } |
533 | } |
534 | |
535 | static void afs_kill_super(struct super_block *sb) |
536 | { |
537 | struct afs_super_info *as = AFS_FS_S(sb); |
538 | |
539 | if (as->dyn_root) |
540 | afs_dynroot_depopulate(sb); |
541 | |
542 | /* Clear the callback interests (which will do ilookup5) before |
543 | * deactivating the superblock. |
544 | */ |
545 | if (as->volume) |
546 | rcu_assign_pointer(as->volume->sb, NULL); |
547 | kill_anon_super(sb); |
548 | if (as->volume) |
549 | afs_deactivate_volume(as->volume); |
550 | afs_destroy_sbi(as); |
551 | } |
552 | |
553 | /* |
554 | * Get an AFS superblock and root directory. |
555 | */ |
556 | static int afs_get_tree(struct fs_context *fc) |
557 | { |
558 | struct afs_fs_context *ctx = fc->fs_private; |
559 | struct super_block *sb; |
560 | struct afs_super_info *as; |
561 | int ret; |
562 | |
563 | ret = afs_validate_fc(fc); |
564 | if (ret) |
565 | goto error; |
566 | |
567 | _enter("" ); |
568 | |
569 | /* allocate a superblock info record */ |
570 | ret = -ENOMEM; |
571 | as = afs_alloc_sbi(fc); |
572 | if (!as) |
573 | goto error; |
574 | fc->s_fs_info = as; |
575 | |
576 | /* allocate a deviceless superblock */ |
577 | sb = sget_fc(fc, |
578 | test: as->dyn_root ? afs_dynroot_test_super : afs_test_super, |
579 | set: afs_set_super); |
580 | if (IS_ERR(ptr: sb)) { |
581 | ret = PTR_ERR(ptr: sb); |
582 | goto error; |
583 | } |
584 | |
585 | if (!sb->s_root) { |
586 | /* initial superblock/root creation */ |
587 | _debug("create" ); |
588 | ret = afs_fill_super(sb, ctx); |
589 | if (ret < 0) |
590 | goto error_sb; |
591 | sb->s_flags |= SB_ACTIVE; |
592 | } else { |
593 | _debug("reuse" ); |
594 | ASSERTCMP(sb->s_flags, &, SB_ACTIVE); |
595 | } |
596 | |
597 | fc->root = dget(dentry: sb->s_root); |
598 | trace_afs_get_tree(cell: as->cell, volume: as->volume); |
599 | _leave(" = 0 [%p]" , sb); |
600 | return 0; |
601 | |
602 | error_sb: |
603 | deactivate_locked_super(sb); |
604 | error: |
605 | _leave(" = %d" , ret); |
606 | return ret; |
607 | } |
608 | |
609 | static void afs_free_fc(struct fs_context *fc) |
610 | { |
611 | struct afs_fs_context *ctx = fc->fs_private; |
612 | |
613 | afs_destroy_sbi(as: fc->s_fs_info); |
614 | afs_put_volume(ctx->net, ctx->volume, afs_volume_trace_put_free_fc); |
615 | afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_fc); |
616 | key_put(key: ctx->key); |
617 | kfree(objp: ctx); |
618 | } |
619 | |
620 | static const struct fs_context_operations afs_context_ops = { |
621 | .free = afs_free_fc, |
622 | .parse_param = afs_parse_param, |
623 | .get_tree = afs_get_tree, |
624 | }; |
625 | |
626 | /* |
627 | * Set up the filesystem mount context. |
628 | */ |
629 | static int afs_init_fs_context(struct fs_context *fc) |
630 | { |
631 | struct afs_fs_context *ctx; |
632 | struct afs_cell *cell; |
633 | |
634 | ctx = kzalloc(size: sizeof(struct afs_fs_context), GFP_KERNEL); |
635 | if (!ctx) |
636 | return -ENOMEM; |
637 | |
638 | ctx->type = AFSVL_ROVOL; |
639 | ctx->net = afs_net(net: fc->net_ns); |
640 | |
641 | /* Default to the workstation cell. */ |
642 | cell = afs_find_cell(ctx->net, NULL, 0, afs_cell_trace_use_fc); |
643 | if (IS_ERR(ptr: cell)) |
644 | cell = NULL; |
645 | ctx->cell = cell; |
646 | |
647 | fc->fs_private = ctx; |
648 | fc->ops = &afs_context_ops; |
649 | return 0; |
650 | } |
651 | |
652 | /* |
653 | * Initialise an inode cache slab element prior to any use. Note that |
654 | * afs_alloc_inode() *must* reset anything that could incorrectly leak from one |
655 | * inode to another. |
656 | */ |
657 | static void afs_i_init_once(void *_vnode) |
658 | { |
659 | struct afs_vnode *vnode = _vnode; |
660 | |
661 | memset(vnode, 0, sizeof(*vnode)); |
662 | inode_init_once(&vnode->netfs.inode); |
663 | mutex_init(&vnode->io_lock); |
664 | init_rwsem(&vnode->validate_lock); |
665 | spin_lock_init(&vnode->wb_lock); |
666 | spin_lock_init(&vnode->lock); |
667 | INIT_LIST_HEAD(list: &vnode->wb_keys); |
668 | INIT_LIST_HEAD(list: &vnode->pending_locks); |
669 | INIT_LIST_HEAD(list: &vnode->granted_locks); |
670 | INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work); |
671 | INIT_LIST_HEAD(list: &vnode->cb_mmap_link); |
672 | seqlock_init(&vnode->cb_lock); |
673 | } |
674 | |
675 | /* |
676 | * allocate an AFS inode struct from our slab cache |
677 | */ |
678 | static struct inode *afs_alloc_inode(struct super_block *sb) |
679 | { |
680 | struct afs_vnode *vnode; |
681 | |
682 | vnode = alloc_inode_sb(sb, cache: afs_inode_cachep, GFP_KERNEL); |
683 | if (!vnode) |
684 | return NULL; |
685 | |
686 | atomic_inc(v: &afs_count_active_inodes); |
687 | |
688 | /* Reset anything that shouldn't leak from one inode to the next. */ |
689 | memset(&vnode->fid, 0, sizeof(vnode->fid)); |
690 | memset(&vnode->status, 0, sizeof(vnode->status)); |
691 | afs_vnode_set_cache(vnode, NULL); |
692 | |
693 | vnode->volume = NULL; |
694 | vnode->lock_key = NULL; |
695 | vnode->permit_cache = NULL; |
696 | |
697 | vnode->flags = 1 << AFS_VNODE_UNSET; |
698 | vnode->lock_state = AFS_VNODE_LOCK_NONE; |
699 | |
700 | init_rwsem(&vnode->rmdir_lock); |
701 | INIT_WORK(&vnode->cb_work, afs_invalidate_mmap_work); |
702 | |
703 | _leave(" = %p" , &vnode->netfs.inode); |
704 | return &vnode->netfs.inode; |
705 | } |
706 | |
707 | static void afs_free_inode(struct inode *inode) |
708 | { |
709 | kmem_cache_free(s: afs_inode_cachep, objp: AFS_FS_I(inode)); |
710 | } |
711 | |
712 | /* |
713 | * destroy an AFS inode struct |
714 | */ |
715 | static void afs_destroy_inode(struct inode *inode) |
716 | { |
717 | struct afs_vnode *vnode = AFS_FS_I(inode); |
718 | |
719 | _enter("%p{%llx:%llu}" , inode, vnode->fid.vid, vnode->fid.vnode); |
720 | |
721 | _debug("DESTROY INODE %p" , inode); |
722 | |
723 | atomic_dec(v: &afs_count_active_inodes); |
724 | } |
725 | |
726 | static void afs_get_volume_status_success(struct afs_operation *op) |
727 | { |
728 | struct afs_volume_status *vs = &op->volstatus.vs; |
729 | struct kstatfs *buf = op->volstatus.buf; |
730 | |
731 | if (vs->max_quota == 0) |
732 | buf->f_blocks = vs->part_max_blocks; |
733 | else |
734 | buf->f_blocks = vs->max_quota; |
735 | |
736 | if (buf->f_blocks > vs->blocks_in_use) |
737 | buf->f_bavail = buf->f_bfree = |
738 | buf->f_blocks - vs->blocks_in_use; |
739 | } |
740 | |
741 | static const struct afs_operation_ops afs_get_volume_status_operation = { |
742 | .issue_afs_rpc = afs_fs_get_volume_status, |
743 | .issue_yfs_rpc = yfs_fs_get_volume_status, |
744 | .success = afs_get_volume_status_success, |
745 | }; |
746 | |
747 | /* |
748 | * return information about an AFS volume |
749 | */ |
750 | static int afs_statfs(struct dentry *dentry, struct kstatfs *buf) |
751 | { |
752 | struct afs_super_info *as = AFS_FS_S(sb: dentry->d_sb); |
753 | struct afs_operation *op; |
754 | struct afs_vnode *vnode = AFS_FS_I(inode: d_inode(dentry)); |
755 | |
756 | buf->f_type = dentry->d_sb->s_magic; |
757 | buf->f_bsize = AFS_BLOCK_SIZE; |
758 | buf->f_namelen = AFSNAMEMAX - 1; |
759 | |
760 | if (as->dyn_root) { |
761 | buf->f_blocks = 1; |
762 | buf->f_bavail = 0; |
763 | buf->f_bfree = 0; |
764 | return 0; |
765 | } |
766 | |
767 | op = afs_alloc_operation(NULL, as->volume); |
768 | if (IS_ERR(ptr: op)) |
769 | return PTR_ERR(ptr: op); |
770 | |
771 | afs_op_set_vnode(op, n: 0, vnode); |
772 | op->nr_files = 1; |
773 | op->volstatus.buf = buf; |
774 | op->ops = &afs_get_volume_status_operation; |
775 | return afs_do_sync_operation(op); |
776 | } |
777 | |