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