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 = netfs_unpin_writeback, |
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(volume: ctx->volume, reason: afs_volume_trace_put_validate_fc); |
385 | ctx->volume = NULL; |
386 | } |
387 | |
388 | if (test_bit(AFS_CELL_FL_CHECK_ALIAS, &ctx->cell->flags)) { |
389 | ret = afs_cell_detect_alias(ctx->cell, key); |
390 | if (ret < 0) |
391 | return ret; |
392 | if (ret == 1) { |
393 | _debug("switch to alias" ); |
394 | key_put(key: ctx->key); |
395 | ctx->key = NULL; |
396 | cell = afs_use_cell(ctx->cell->alias_of, |
397 | afs_cell_trace_use_fc_alias); |
398 | afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_fc); |
399 | ctx->cell = cell; |
400 | goto reget_key; |
401 | } |
402 | } |
403 | |
404 | volume = afs_create_volume(ctx); |
405 | if (IS_ERR(ptr: volume)) |
406 | return PTR_ERR(ptr: volume); |
407 | |
408 | ctx->volume = volume; |
409 | if (volume->type != AFSVL_RWVOL) { |
410 | ctx->flock_mode = afs_flock_mode_local; |
411 | fc->sb_flags |= SB_RDONLY; |
412 | } |
413 | } |
414 | |
415 | return 0; |
416 | } |
417 | |
418 | /* |
419 | * check a superblock to see if it's the one we're looking for |
420 | */ |
421 | static int afs_test_super(struct super_block *sb, struct fs_context *fc) |
422 | { |
423 | struct afs_fs_context *ctx = fc->fs_private; |
424 | struct afs_super_info *as = AFS_FS_S(sb); |
425 | |
426 | return (as->net_ns == fc->net_ns && |
427 | as->volume && |
428 | as->volume->vid == ctx->volume->vid && |
429 | as->cell == ctx->cell && |
430 | !as->dyn_root); |
431 | } |
432 | |
433 | static int afs_dynroot_test_super(struct super_block *sb, struct fs_context *fc) |
434 | { |
435 | struct afs_super_info *as = AFS_FS_S(sb); |
436 | |
437 | return (as->net_ns == fc->net_ns && |
438 | as->dyn_root); |
439 | } |
440 | |
441 | static int afs_set_super(struct super_block *sb, struct fs_context *fc) |
442 | { |
443 | return set_anon_super(s: sb, NULL); |
444 | } |
445 | |
446 | /* |
447 | * fill in the superblock |
448 | */ |
449 | static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx) |
450 | { |
451 | struct afs_super_info *as = AFS_FS_S(sb); |
452 | struct inode *inode = NULL; |
453 | int ret; |
454 | |
455 | _enter("" ); |
456 | |
457 | /* fill in the superblock */ |
458 | sb->s_blocksize = PAGE_SIZE; |
459 | sb->s_blocksize_bits = PAGE_SHIFT; |
460 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
461 | sb->s_magic = AFS_FS_MAGIC; |
462 | sb->s_op = &afs_super_ops; |
463 | if (!as->dyn_root) |
464 | sb->s_xattr = afs_xattr_handlers; |
465 | ret = super_setup_bdi(sb); |
466 | if (ret) |
467 | return ret; |
468 | |
469 | /* allocate the root inode and dentry */ |
470 | if (as->dyn_root) { |
471 | inode = afs_iget_pseudo_dir(sb, true); |
472 | } else { |
473 | sprintf(buf: sb->s_id, fmt: "%llu" , as->volume->vid); |
474 | afs_activate_volume(as->volume); |
475 | inode = afs_root_iget(sb, ctx->key); |
476 | } |
477 | |
478 | if (IS_ERR(ptr: inode)) |
479 | return PTR_ERR(ptr: inode); |
480 | |
481 | if (ctx->autocell || as->dyn_root) |
482 | set_bit(AFS_VNODE_AUTOCELL, addr: &AFS_FS_I(inode)->flags); |
483 | |
484 | ret = -ENOMEM; |
485 | sb->s_root = d_make_root(inode); |
486 | if (!sb->s_root) |
487 | goto error; |
488 | |
489 | if (as->dyn_root) { |
490 | sb->s_d_op = &afs_dynroot_dentry_operations; |
491 | ret = afs_dynroot_populate(sb); |
492 | if (ret < 0) |
493 | goto error; |
494 | } else { |
495 | sb->s_d_op = &afs_fs_dentry_operations; |
496 | rcu_assign_pointer(as->volume->sb, sb); |
497 | } |
498 | |
499 | _leave(" = 0" ); |
500 | return 0; |
501 | |
502 | error: |
503 | _leave(" = %d" , ret); |
504 | return ret; |
505 | } |
506 | |
507 | static struct afs_super_info *afs_alloc_sbi(struct fs_context *fc) |
508 | { |
509 | struct afs_fs_context *ctx = fc->fs_private; |
510 | struct afs_super_info *as; |
511 | |
512 | as = kzalloc(size: sizeof(struct afs_super_info), GFP_KERNEL); |
513 | if (as) { |
514 | as->net_ns = get_net(net: fc->net_ns); |
515 | as->flock_mode = ctx->flock_mode; |
516 | if (ctx->dyn_root) { |
517 | as->dyn_root = true; |
518 | } else { |
519 | as->cell = afs_use_cell(ctx->cell, afs_cell_trace_use_sbi); |
520 | as->volume = afs_get_volume(ctx->volume, |
521 | afs_volume_trace_get_alloc_sbi); |
522 | } |
523 | } |
524 | return as; |
525 | } |
526 | |
527 | static void afs_destroy_sbi(struct afs_super_info *as) |
528 | { |
529 | if (as) { |
530 | struct afs_net *net = afs_net(net: as->net_ns); |
531 | afs_put_volume(volume: as->volume, reason: afs_volume_trace_put_destroy_sbi); |
532 | afs_unuse_cell(net, as->cell, afs_cell_trace_unuse_sbi); |
533 | put_net(net: as->net_ns); |
534 | kfree(objp: as); |
535 | } |
536 | } |
537 | |
538 | static void afs_kill_super(struct super_block *sb) |
539 | { |
540 | struct afs_super_info *as = AFS_FS_S(sb); |
541 | |
542 | if (as->dyn_root) |
543 | afs_dynroot_depopulate(sb); |
544 | |
545 | /* Clear the callback interests (which will do ilookup5) before |
546 | * deactivating the superblock. |
547 | */ |
548 | if (as->volume) |
549 | rcu_assign_pointer(as->volume->sb, NULL); |
550 | kill_anon_super(sb); |
551 | if (as->volume) |
552 | afs_deactivate_volume(as->volume); |
553 | afs_destroy_sbi(as); |
554 | } |
555 | |
556 | /* |
557 | * Get an AFS superblock and root directory. |
558 | */ |
559 | static int afs_get_tree(struct fs_context *fc) |
560 | { |
561 | struct afs_fs_context *ctx = fc->fs_private; |
562 | struct super_block *sb; |
563 | struct afs_super_info *as; |
564 | int ret; |
565 | |
566 | ret = afs_validate_fc(fc); |
567 | if (ret) |
568 | goto error; |
569 | |
570 | _enter("" ); |
571 | |
572 | /* allocate a superblock info record */ |
573 | ret = -ENOMEM; |
574 | as = afs_alloc_sbi(fc); |
575 | if (!as) |
576 | goto error; |
577 | fc->s_fs_info = as; |
578 | |
579 | /* allocate a deviceless superblock */ |
580 | sb = sget_fc(fc, |
581 | test: as->dyn_root ? afs_dynroot_test_super : afs_test_super, |
582 | set: afs_set_super); |
583 | if (IS_ERR(ptr: sb)) { |
584 | ret = PTR_ERR(ptr: sb); |
585 | goto error; |
586 | } |
587 | |
588 | if (!sb->s_root) { |
589 | /* initial superblock/root creation */ |
590 | _debug("create" ); |
591 | ret = afs_fill_super(sb, ctx); |
592 | if (ret < 0) |
593 | goto error_sb; |
594 | sb->s_flags |= SB_ACTIVE; |
595 | } else { |
596 | _debug("reuse" ); |
597 | ASSERTCMP(sb->s_flags, &, SB_ACTIVE); |
598 | } |
599 | |
600 | fc->root = dget(dentry: sb->s_root); |
601 | trace_afs_get_tree(cell: as->cell, volume: as->volume); |
602 | _leave(" = 0 [%p]" , sb); |
603 | return 0; |
604 | |
605 | error_sb: |
606 | deactivate_locked_super(sb); |
607 | error: |
608 | _leave(" = %d" , ret); |
609 | return ret; |
610 | } |
611 | |
612 | static void afs_free_fc(struct fs_context *fc) |
613 | { |
614 | struct afs_fs_context *ctx = fc->fs_private; |
615 | |
616 | afs_destroy_sbi(as: fc->s_fs_info); |
617 | afs_put_volume(volume: ctx->volume, reason: afs_volume_trace_put_free_fc); |
618 | afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_fc); |
619 | key_put(key: ctx->key); |
620 | kfree(objp: ctx); |
621 | } |
622 | |
623 | static const struct fs_context_operations afs_context_ops = { |
624 | .free = afs_free_fc, |
625 | .parse_param = afs_parse_param, |
626 | .get_tree = afs_get_tree, |
627 | }; |
628 | |
629 | /* |
630 | * Set up the filesystem mount context. |
631 | */ |
632 | static int afs_init_fs_context(struct fs_context *fc) |
633 | { |
634 | struct afs_fs_context *ctx; |
635 | struct afs_cell *cell; |
636 | |
637 | ctx = kzalloc(size: sizeof(struct afs_fs_context), GFP_KERNEL); |
638 | if (!ctx) |
639 | return -ENOMEM; |
640 | |
641 | ctx->type = AFSVL_ROVOL; |
642 | ctx->net = afs_net(net: fc->net_ns); |
643 | |
644 | /* Default to the workstation cell. */ |
645 | cell = afs_find_cell(ctx->net, NULL, 0, afs_cell_trace_use_fc); |
646 | if (IS_ERR(ptr: cell)) |
647 | cell = NULL; |
648 | ctx->cell = cell; |
649 | |
650 | fc->fs_private = ctx; |
651 | fc->ops = &afs_context_ops; |
652 | return 0; |
653 | } |
654 | |
655 | /* |
656 | * Initialise an inode cache slab element prior to any use. Note that |
657 | * afs_alloc_inode() *must* reset anything that could incorrectly leak from one |
658 | * inode to another. |
659 | */ |
660 | static void afs_i_init_once(void *_vnode) |
661 | { |
662 | struct afs_vnode *vnode = _vnode; |
663 | |
664 | memset(vnode, 0, sizeof(*vnode)); |
665 | inode_init_once(&vnode->netfs.inode); |
666 | mutex_init(&vnode->io_lock); |
667 | init_rwsem(&vnode->validate_lock); |
668 | spin_lock_init(&vnode->wb_lock); |
669 | spin_lock_init(&vnode->lock); |
670 | INIT_LIST_HEAD(list: &vnode->wb_keys); |
671 | INIT_LIST_HEAD(list: &vnode->pending_locks); |
672 | INIT_LIST_HEAD(list: &vnode->granted_locks); |
673 | INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work); |
674 | INIT_LIST_HEAD(list: &vnode->cb_mmap_link); |
675 | seqlock_init(&vnode->cb_lock); |
676 | } |
677 | |
678 | /* |
679 | * allocate an AFS inode struct from our slab cache |
680 | */ |
681 | static struct inode *afs_alloc_inode(struct super_block *sb) |
682 | { |
683 | struct afs_vnode *vnode; |
684 | |
685 | vnode = alloc_inode_sb(sb, cache: afs_inode_cachep, GFP_KERNEL); |
686 | if (!vnode) |
687 | return NULL; |
688 | |
689 | atomic_inc(v: &afs_count_active_inodes); |
690 | |
691 | /* Reset anything that shouldn't leak from one inode to the next. */ |
692 | memset(&vnode->fid, 0, sizeof(vnode->fid)); |
693 | memset(&vnode->status, 0, sizeof(vnode->status)); |
694 | afs_vnode_set_cache(vnode, NULL); |
695 | |
696 | vnode->volume = NULL; |
697 | vnode->lock_key = NULL; |
698 | vnode->permit_cache = NULL; |
699 | |
700 | vnode->flags = 1 << AFS_VNODE_UNSET; |
701 | vnode->lock_state = AFS_VNODE_LOCK_NONE; |
702 | |
703 | init_rwsem(&vnode->rmdir_lock); |
704 | INIT_WORK(&vnode->cb_work, afs_invalidate_mmap_work); |
705 | |
706 | _leave(" = %p" , &vnode->netfs.inode); |
707 | return &vnode->netfs.inode; |
708 | } |
709 | |
710 | static void afs_free_inode(struct inode *inode) |
711 | { |
712 | kmem_cache_free(s: afs_inode_cachep, objp: AFS_FS_I(inode)); |
713 | } |
714 | |
715 | /* |
716 | * destroy an AFS inode struct |
717 | */ |
718 | static void afs_destroy_inode(struct inode *inode) |
719 | { |
720 | struct afs_vnode *vnode = AFS_FS_I(inode); |
721 | |
722 | _enter("%p{%llx:%llu}" , inode, vnode->fid.vid, vnode->fid.vnode); |
723 | |
724 | _debug("DESTROY INODE %p" , inode); |
725 | |
726 | atomic_dec(v: &afs_count_active_inodes); |
727 | } |
728 | |
729 | static void afs_get_volume_status_success(struct afs_operation *op) |
730 | { |
731 | struct afs_volume_status *vs = &op->volstatus.vs; |
732 | struct kstatfs *buf = op->volstatus.buf; |
733 | |
734 | if (vs->max_quota == 0) |
735 | buf->f_blocks = vs->part_max_blocks; |
736 | else |
737 | buf->f_blocks = vs->max_quota; |
738 | |
739 | if (buf->f_blocks > vs->blocks_in_use) |
740 | buf->f_bavail = buf->f_bfree = |
741 | buf->f_blocks - vs->blocks_in_use; |
742 | } |
743 | |
744 | static const struct afs_operation_ops afs_get_volume_status_operation = { |
745 | .issue_afs_rpc = afs_fs_get_volume_status, |
746 | .issue_yfs_rpc = yfs_fs_get_volume_status, |
747 | .success = afs_get_volume_status_success, |
748 | }; |
749 | |
750 | /* |
751 | * return information about an AFS volume |
752 | */ |
753 | static int afs_statfs(struct dentry *dentry, struct kstatfs *buf) |
754 | { |
755 | struct afs_super_info *as = AFS_FS_S(sb: dentry->d_sb); |
756 | struct afs_operation *op; |
757 | struct afs_vnode *vnode = AFS_FS_I(inode: d_inode(dentry)); |
758 | |
759 | buf->f_type = dentry->d_sb->s_magic; |
760 | buf->f_bsize = AFS_BLOCK_SIZE; |
761 | buf->f_namelen = AFSNAMEMAX - 1; |
762 | |
763 | if (as->dyn_root) { |
764 | buf->f_blocks = 1; |
765 | buf->f_bavail = 0; |
766 | buf->f_bfree = 0; |
767 | return 0; |
768 | } |
769 | |
770 | op = afs_alloc_operation(NULL, as->volume); |
771 | if (IS_ERR(ptr: op)) |
772 | return PTR_ERR(ptr: op); |
773 | |
774 | afs_op_set_vnode(op, n: 0, vnode); |
775 | op->nr_files = 1; |
776 | op->volstatus.buf = buf; |
777 | op->ops = &afs_get_volume_status_operation; |
778 | return afs_do_sync_operation(op); |
779 | } |
780 | |