aboutsummaryrefslogtreecommitdiffstats
path: root/fs/afs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-03-12 17:08:19 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-03-12 17:08:19 -0400
commit7b47a9e7c8f672b6fb0b77fca11a63a8a77f5a91 (patch)
treecf05645120ba2323c36acefdea6e62addf320f8c /fs/afs
parentdbc2fba3fc46084f502aec53183995a632998dcd (diff)
parentc99c2171fc61476afac0dfb59fb2c447a01fb1e0 (diff)
Merge branch 'work.mount' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs mount infrastructure updates from Al Viro: "The rest of core infrastructure; no new syscalls in that pile, but the old parts are switched to new infrastructure. At that point conversions of individual filesystems can happen independently; some are done here (afs, cgroup, procfs, etc.), there's also a large series outside of that pile dealing with NFS (quite a bit of option-parsing stuff is getting used there - it's one of the most convoluted filesystems in terms of mount-related logics), but NFS bits are the next cycle fodder. It got seriously simplified since the last cycle; documentation is probably the weakest bit at the moment - I considered dropping the commit introducing Documentation/filesystems/mount_api.txt (cutting the size increase by quarter ;-), but decided that it would be better to fix it up after -rc1 instead. That pile allows to do followup work in independent branches, which should make life much easier for the next cycle. fs/super.c size increase is unpleasant; there's a followup series that allows to shrink it considerably, but I decided to leave that until the next cycle" * 'work.mount' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (41 commits) afs: Use fs_context to pass parameters over automount afs: Add fs_context support vfs: Add some logging to the core users of the fs_context log vfs: Implement logging through fs_context vfs: Provide documentation for new mount API vfs: Remove kern_mount_data() hugetlbfs: Convert to fs_context cpuset: Use fs_context kernfs, sysfs, cgroup, intel_rdt: Support fs_context cgroup: store a reference to cgroup_ns into cgroup_fs_context cgroup1_get_tree(): separate "get cgroup_root to use" into a separate helper cgroup_do_mount(): massage calling conventions cgroup: stash cgroup_root reference into cgroup_fs_context cgroup2: switch to option-by-option parsing cgroup1: switch to option-by-option parsing cgroup: take options parsing into ->parse_monolithic() cgroup: fold cgroup1_mount() into cgroup1_get_tree() cgroup: start switching to fs_context ipc: Convert mqueue fs to fs_context proc: Add fs_context support to procfs ...
Diffstat (limited to 'fs/afs')
-rw-r--r--fs/afs/internal.h9
-rw-r--r--fs/afs/mntpt.c149
-rw-r--r--fs/afs/super.c430
-rw-r--r--fs/afs/volume.c4
4 files changed, 304 insertions, 288 deletions
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 8871b9e8645f..bb1f244b2b3a 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -36,15 +36,14 @@
36struct pagevec; 36struct pagevec;
37struct afs_call; 37struct afs_call;
38 38
39struct afs_mount_params { 39struct afs_fs_context {
40 bool rwpath; /* T if the parent should be considered R/W */
41 bool force; /* T to force cell type */ 40 bool force; /* T to force cell type */
42 bool autocell; /* T if set auto mount operation */ 41 bool autocell; /* T if set auto mount operation */
43 bool dyn_root; /* T if dynamic root */ 42 bool dyn_root; /* T if dynamic root */
43 bool no_cell; /* T if the source is "none" (for dynroot) */
44 afs_voltype_t type; /* type of volume requested */ 44 afs_voltype_t type; /* type of volume requested */
45 int volnamesz; /* size of volume name */ 45 unsigned int volnamesz; /* size of volume name */
46 const char *volname; /* name of volume to mount */ 46 const char *volname; /* name of volume to mount */
47 struct net *net_ns; /* Network namespace in effect */
48 struct afs_net *net; /* the AFS net namespace stuff */ 47 struct afs_net *net; /* the AFS net namespace stuff */
49 struct afs_cell *cell; /* cell in which to find volume */ 48 struct afs_cell *cell; /* cell in which to find volume */
50 struct afs_volume *volume; /* volume record */ 49 struct afs_volume *volume; /* volume record */
@@ -1274,7 +1273,7 @@ static inline struct afs_volume *__afs_get_volume(struct afs_volume *volume)
1274 return volume; 1273 return volume;
1275} 1274}
1276 1275
1277extern struct afs_volume *afs_create_volume(struct afs_mount_params *); 1276extern struct afs_volume *afs_create_volume(struct afs_fs_context *);
1278extern void afs_activate_volume(struct afs_volume *); 1277extern void afs_activate_volume(struct afs_volume *);
1279extern void afs_deactivate_volume(struct afs_volume *); 1278extern void afs_deactivate_volume(struct afs_volume *);
1280extern void afs_put_volume(struct afs_cell *, struct afs_volume *); 1279extern void afs_put_volume(struct afs_cell *, struct afs_volume *);
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index 2e51c6994148..eecd8b699186 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -17,6 +17,7 @@
17#include <linux/mount.h> 17#include <linux/mount.h>
18#include <linux/namei.h> 18#include <linux/namei.h>
19#include <linux/gfp.h> 19#include <linux/gfp.h>
20#include <linux/fs_context.h>
20#include "internal.h" 21#include "internal.h"
21 22
22 23
@@ -47,6 +48,8 @@ static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out);
47 48
48static unsigned long afs_mntpt_expiry_timeout = 10 * 60; 49static unsigned long afs_mntpt_expiry_timeout = 10 * 60;
49 50
51static const char afs_root_volume[] = "root.cell";
52
50/* 53/*
51 * no valid lookup procedure on this sort of dir 54 * no valid lookup procedure on this sort of dir
52 */ 55 */
@@ -68,108 +71,112 @@ static int afs_mntpt_open(struct inode *inode, struct file *file)
68} 71}
69 72
70/* 73/*
71 * create a vfsmount to be automounted 74 * Set the parameters for the proposed superblock.
72 */ 75 */
73static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) 76static int afs_mntpt_set_params(struct fs_context *fc, struct dentry *mntpt)
74{ 77{
75 struct afs_super_info *as; 78 struct afs_fs_context *ctx = fc->fs_private;
76 struct vfsmount *mnt; 79 struct afs_super_info *src_as = AFS_FS_S(mntpt->d_sb);
77 struct afs_vnode *vnode; 80 struct afs_vnode *vnode = AFS_FS_I(d_inode(mntpt));
78 struct page *page; 81 struct afs_cell *cell;
79 char *devname, *options; 82 const char *p;
80 bool rwpath = false;
81 int ret; 83 int ret;
82 84
83 _enter("{%pd}", mntpt); 85 if (fc->net_ns != src_as->net_ns) {
84 86 put_net(fc->net_ns);
85 BUG_ON(!d_inode(mntpt)); 87 fc->net_ns = get_net(src_as->net_ns);
86 88 }
87 ret = -ENOMEM;
88 devname = (char *) get_zeroed_page(GFP_KERNEL);
89 if (!devname)
90 goto error_no_devname;
91
92 options = (char *) get_zeroed_page(GFP_KERNEL);
93 if (!options)
94 goto error_no_options;
95 89
96 vnode = AFS_FS_I(d_inode(mntpt)); 90 if (src_as->volume && src_as->volume->type == AFSVL_RWVOL) {
91 ctx->type = AFSVL_RWVOL;
92 ctx->force = true;
93 }
94 if (ctx->cell) {
95 afs_put_cell(ctx->net, ctx->cell);
96 ctx->cell = NULL;
97 }
97 if (test_bit(AFS_VNODE_PSEUDODIR, &vnode->flags)) { 98 if (test_bit(AFS_VNODE_PSEUDODIR, &vnode->flags)) {
98 /* if the directory is a pseudo directory, use the d_name */ 99 /* if the directory is a pseudo directory, use the d_name */
99 static const char afs_root_cell[] = ":root.cell.";
100 unsigned size = mntpt->d_name.len; 100 unsigned size = mntpt->d_name.len;
101 101
102 ret = -ENOENT; 102 if (size < 2)
103 if (size < 2 || size > AFS_MAXCELLNAME) 103 return -ENOENT;
104 goto error_no_page;
105 104
105 p = mntpt->d_name.name;
106 if (mntpt->d_name.name[0] == '.') { 106 if (mntpt->d_name.name[0] == '.') {
107 devname[0] = '%'; 107 size--;
108 memcpy(devname + 1, mntpt->d_name.name + 1, size - 1); 108 p++;
109 memcpy(devname + size, afs_root_cell, 109 ctx->type = AFSVL_RWVOL;
110 sizeof(afs_root_cell)); 110 ctx->force = true;
111 rwpath = true;
112 } else {
113 devname[0] = '#';
114 memcpy(devname + 1, mntpt->d_name.name, size);
115 memcpy(devname + size + 1, afs_root_cell,
116 sizeof(afs_root_cell));
117 } 111 }
112 if (size > AFS_MAXCELLNAME)
113 return -ENAMETOOLONG;
114
115 cell = afs_lookup_cell(ctx->net, p, size, NULL, false);
116 if (IS_ERR(cell)) {
117 pr_err("kAFS: unable to lookup cell '%pd'\n", mntpt);
118 return PTR_ERR(cell);
119 }
120 ctx->cell = cell;
121
122 ctx->volname = afs_root_volume;
123 ctx->volnamesz = sizeof(afs_root_volume) - 1;
118 } else { 124 } else {
119 /* read the contents of the AFS special symlink */ 125 /* read the contents of the AFS special symlink */
126 struct page *page;
120 loff_t size = i_size_read(d_inode(mntpt)); 127 loff_t size = i_size_read(d_inode(mntpt));
121 char *buf; 128 char *buf;
122 129
123 ret = -EINVAL; 130 if (src_as->cell)
131 ctx->cell = afs_get_cell(src_as->cell);
132
124 if (size > PAGE_SIZE - 1) 133 if (size > PAGE_SIZE - 1)
125 goto error_no_page; 134 return -EINVAL;
126 135
127 page = read_mapping_page(d_inode(mntpt)->i_mapping, 0, NULL); 136 page = read_mapping_page(d_inode(mntpt)->i_mapping, 0, NULL);
128 if (IS_ERR(page)) { 137 if (IS_ERR(page))
129 ret = PTR_ERR(page); 138 return PTR_ERR(page);
130 goto error_no_page;
131 }
132 139
133 if (PageError(page)) { 140 if (PageError(page)) {
134 ret = afs_bad(AFS_FS_I(d_inode(mntpt)), afs_file_error_mntpt); 141 ret = afs_bad(AFS_FS_I(d_inode(mntpt)), afs_file_error_mntpt);
135 goto error; 142 put_page(page);
143 return ret;
136 } 144 }
137 145
138 buf = kmap_atomic(page); 146 buf = kmap(page);
139 memcpy(devname, buf, size); 147 ret = vfs_parse_fs_string(fc, "source", buf, size);
140 kunmap_atomic(buf); 148 kunmap(page);
141 put_page(page); 149 put_page(page);
142 page = NULL; 150 if (ret < 0)
151 return ret;
143 } 152 }
144 153
145 /* work out what options we want */ 154 return 0;
146 as = AFS_FS_S(mntpt->d_sb); 155}
147 if (as->cell) {
148 memcpy(options, "cell=", 5);
149 strcpy(options + 5, as->cell->name);
150 if ((as->volume && as->volume->type == AFSVL_RWVOL) || rwpath)
151 strcat(options, ",rwpath");
152 }
153 156
154 /* try and do the mount */ 157/*
155 _debug("--- attempting mount %s -o %s ---", devname, options); 158 * create a vfsmount to be automounted
156 mnt = vfs_submount(mntpt, &afs_fs_type, devname, options); 159 */
157 _debug("--- mount result %p ---", mnt); 160static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
161{
162 struct fs_context *fc;
163 struct vfsmount *mnt;
164 int ret;
158 165
159 free_page((unsigned long) devname); 166 BUG_ON(!d_inode(mntpt));
160 free_page((unsigned long) options);
161 _leave(" = %p", mnt);
162 return mnt;
163 167
164error: 168 fc = fs_context_for_submount(&afs_fs_type, mntpt);
165 put_page(page); 169 if (IS_ERR(fc))
166error_no_page: 170 return ERR_CAST(fc);
167 free_page((unsigned long) options); 171
168error_no_options: 172 ret = afs_mntpt_set_params(fc, mntpt);
169 free_page((unsigned long) devname); 173 if (!ret)
170error_no_devname: 174 mnt = fc_mount(fc);
171 _leave(" = %d", ret); 175 else
172 return ERR_PTR(ret); 176 mnt = ERR_PTR(ret);
177
178 put_fs_context(fc);
179 return mnt;
173} 180}
174 181
175/* 182/*
diff --git a/fs/afs/super.c b/fs/afs/super.c
index e684f6769b15..5adf012b8e27 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -1,6 +1,6 @@
1/* AFS superblock handling 1/* AFS superblock handling
2 * 2 *
3 * Copyright (c) 2002, 2007 Red Hat, Inc. All rights reserved. 3 * Copyright (c) 2002, 2007, 2018 Red Hat, Inc. All rights reserved.
4 * 4 *
5 * This software may be freely redistributed under the terms of the 5 * This software may be freely redistributed under the terms of the
6 * GNU General Public License. 6 * GNU General Public License.
@@ -21,7 +21,7 @@
21#include <linux/slab.h> 21#include <linux/slab.h>
22#include <linux/fs.h> 22#include <linux/fs.h>
23#include <linux/pagemap.h> 23#include <linux/pagemap.h>
24#include <linux/parser.h> 24#include <linux/fs_parser.h>
25#include <linux/statfs.h> 25#include <linux/statfs.h>
26#include <linux/sched.h> 26#include <linux/sched.h>
27#include <linux/nsproxy.h> 27#include <linux/nsproxy.h>
@@ -30,21 +30,22 @@
30#include "internal.h" 30#include "internal.h"
31 31
32static void afs_i_init_once(void *foo); 32static void afs_i_init_once(void *foo);
33static struct dentry *afs_mount(struct file_system_type *fs_type,
34 int flags, const char *dev_name, void *data);
35static void afs_kill_super(struct super_block *sb); 33static void afs_kill_super(struct super_block *sb);
36static struct inode *afs_alloc_inode(struct super_block *sb); 34static struct inode *afs_alloc_inode(struct super_block *sb);
37static void afs_destroy_inode(struct inode *inode); 35static void afs_destroy_inode(struct inode *inode);
38static int afs_statfs(struct dentry *dentry, struct kstatfs *buf); 36static int afs_statfs(struct dentry *dentry, struct kstatfs *buf);
39static int afs_show_devname(struct seq_file *m, struct dentry *root); 37static int afs_show_devname(struct seq_file *m, struct dentry *root);
40static int afs_show_options(struct seq_file *m, struct dentry *root); 38static int afs_show_options(struct seq_file *m, struct dentry *root);
39static int afs_init_fs_context(struct fs_context *fc);
40static const struct fs_parameter_description afs_fs_parameters;
41 41
42struct file_system_type afs_fs_type = { 42struct file_system_type afs_fs_type = {
43 .owner = THIS_MODULE, 43 .owner = THIS_MODULE,
44 .name = "afs", 44 .name = "afs",
45 .mount = afs_mount, 45 .init_fs_context = afs_init_fs_context,
46 .kill_sb = afs_kill_super, 46 .parameters = &afs_fs_parameters,
47 .fs_flags = 0, 47 .kill_sb = afs_kill_super,
48 .fs_flags = 0,
48}; 49};
49MODULE_ALIAS_FS("afs"); 50MODULE_ALIAS_FS("afs");
50 51
@@ -63,22 +64,22 @@ static const struct super_operations afs_super_ops = {
63static struct kmem_cache *afs_inode_cachep; 64static struct kmem_cache *afs_inode_cachep;
64static atomic_t afs_count_active_inodes; 65static atomic_t afs_count_active_inodes;
65 66
66enum { 67enum afs_param {
67 afs_no_opt, 68 Opt_autocell,
68 afs_opt_cell, 69 Opt_dyn,
69 afs_opt_dyn, 70 Opt_source,
70 afs_opt_rwpath,
71 afs_opt_vol,
72 afs_opt_autocell,
73}; 71};
74 72
75static const match_table_t afs_options_list = { 73static const struct fs_parameter_spec afs_param_specs[] = {
76 { afs_opt_cell, "cell=%s" }, 74 fsparam_flag ("autocell", Opt_autocell),
77 { afs_opt_dyn, "dyn" }, 75 fsparam_flag ("dyn", Opt_dyn),
78 { afs_opt_rwpath, "rwpath" }, 76 fsparam_string("source", Opt_source),
79 { afs_opt_vol, "vol=%s" }, 77 {}
80 { afs_opt_autocell, "autocell" }, 78};
81 { afs_no_opt, NULL }, 79
80static const struct fs_parameter_description afs_fs_parameters = {
81 .name = "kAFS",
82 .specs = afs_param_specs,
82}; 83};
83 84
84/* 85/*
@@ -190,84 +191,23 @@ static int afs_show_options(struct seq_file *m, struct dentry *root)
190} 191}
191 192
192/* 193/*
193 * parse the mount options 194 * Parse the source name to get cell name, volume name, volume type and R/W
194 * - this function has been shamelessly adapted from the ext3 fs which 195 * selector.
195 * shamelessly adapted it from the msdos fs 196 *
196 */ 197 * This can be one of the following:
197static int afs_parse_options(struct afs_mount_params *params,
198 char *options, const char **devname)
199{
200 struct afs_cell *cell;
201 substring_t args[MAX_OPT_ARGS];
202 char *p;
203 int token;
204
205 _enter("%s", options);
206
207 options[PAGE_SIZE - 1] = 0;
208
209 while ((p = strsep(&options, ","))) {
210 if (!*p)
211 continue;
212
213 token = match_token(p, afs_options_list, args);
214 switch (token) {
215 case afs_opt_cell:
216 rcu_read_lock();
217 cell = afs_lookup_cell_rcu(params->net,
218 args[0].from,
219 args[0].to - args[0].from);
220 rcu_read_unlock();
221 if (IS_ERR(cell))
222 return PTR_ERR(cell);
223 afs_put_cell(params->net, params->cell);
224 params->cell = cell;
225 break;
226
227 case afs_opt_rwpath:
228 params->rwpath = true;
229 break;
230
231 case afs_opt_vol:
232 *devname = args[0].from;
233 break;
234
235 case afs_opt_autocell:
236 params->autocell = true;
237 break;
238
239 case afs_opt_dyn:
240 params->dyn_root = true;
241 break;
242
243 default:
244 printk(KERN_ERR "kAFS:"
245 " Unknown or invalid mount option: '%s'\n", p);
246 return -EINVAL;
247 }
248 }
249
250 _leave(" = 0");
251 return 0;
252}
253
254/*
255 * parse a device name to get cell name, volume name, volume type and R/W
256 * selector
257 * - this can be one of the following:
258 * "%[cell:]volume[.]" R/W volume 198 * "%[cell:]volume[.]" R/W volume
259 * "#[cell:]volume[.]" R/O or R/W volume (rwpath=0), 199 * "#[cell:]volume[.]" R/O or R/W volume (R/O parent),
260 * or R/W (rwpath=1) volume 200 * or R/W (R/W parent) volume
261 * "%[cell:]volume.readonly" R/O volume 201 * "%[cell:]volume.readonly" R/O volume
262 * "#[cell:]volume.readonly" R/O volume 202 * "#[cell:]volume.readonly" R/O volume
263 * "%[cell:]volume.backup" Backup volume 203 * "%[cell:]volume.backup" Backup volume
264 * "#[cell:]volume.backup" Backup volume 204 * "#[cell:]volume.backup" Backup volume
265 */ 205 */
266static int afs_parse_device_name(struct afs_mount_params *params, 206static int afs_parse_source(struct fs_context *fc, struct fs_parameter *param)
267 const char *name)
268{ 207{
208 struct afs_fs_context *ctx = fc->fs_private;
269 struct afs_cell *cell; 209 struct afs_cell *cell;
270 const char *cellname, *suffix; 210 const char *cellname, *suffix, *name = param->string;
271 int cellnamesz; 211 int cellnamesz;
272 212
273 _enter(",%s", name); 213 _enter(",%s", name);
@@ -278,69 +218,149 @@ static int afs_parse_device_name(struct afs_mount_params *params,
278 } 218 }
279 219
280 if ((name[0] != '%' && name[0] != '#') || !name[1]) { 220 if ((name[0] != '%' && name[0] != '#') || !name[1]) {
221 /* To use dynroot, we don't want to have to provide a source */
222 if (strcmp(name, "none") == 0) {
223 ctx->no_cell = true;
224 return 0;
225 }
281 printk(KERN_ERR "kAFS: unparsable volume name\n"); 226 printk(KERN_ERR "kAFS: unparsable volume name\n");
282 return -EINVAL; 227 return -EINVAL;
283 } 228 }
284 229
285 /* determine the type of volume we're looking for */ 230 /* determine the type of volume we're looking for */
286 params->type = AFSVL_ROVOL; 231 if (name[0] == '%') {
287 params->force = false; 232 ctx->type = AFSVL_RWVOL;
288 if (params->rwpath || name[0] == '%') { 233 ctx->force = true;
289 params->type = AFSVL_RWVOL;
290 params->force = true;
291 } 234 }
292 name++; 235 name++;
293 236
294 /* split the cell name out if there is one */ 237 /* split the cell name out if there is one */
295 params->volname = strchr(name, ':'); 238 ctx->volname = strchr(name, ':');
296 if (params->volname) { 239 if (ctx->volname) {
297 cellname = name; 240 cellname = name;
298 cellnamesz = params->volname - name; 241 cellnamesz = ctx->volname - name;
299 params->volname++; 242 ctx->volname++;
300 } else { 243 } else {
301 params->volname = name; 244 ctx->volname = name;
302 cellname = NULL; 245 cellname = NULL;
303 cellnamesz = 0; 246 cellnamesz = 0;
304 } 247 }
305 248
306 /* the volume type is further affected by a possible suffix */ 249 /* the volume type is further affected by a possible suffix */
307 suffix = strrchr(params->volname, '.'); 250 suffix = strrchr(ctx->volname, '.');
308 if (suffix) { 251 if (suffix) {
309 if (strcmp(suffix, ".readonly") == 0) { 252 if (strcmp(suffix, ".readonly") == 0) {
310 params->type = AFSVL_ROVOL; 253 ctx->type = AFSVL_ROVOL;
311 params->force = true; 254 ctx->force = true;
312 } else if (strcmp(suffix, ".backup") == 0) { 255 } else if (strcmp(suffix, ".backup") == 0) {
313 params->type = AFSVL_BACKVOL; 256 ctx->type = AFSVL_BACKVOL;
314 params->force = true; 257 ctx->force = true;
315 } else if (suffix[1] == 0) { 258 } else if (suffix[1] == 0) {
316 } else { 259 } else {
317 suffix = NULL; 260 suffix = NULL;
318 } 261 }
319 } 262 }
320 263
321 params->volnamesz = suffix ? 264 ctx->volnamesz = suffix ?
322 suffix - params->volname : strlen(params->volname); 265 suffix - ctx->volname : strlen(ctx->volname);
323 266
324 _debug("cell %*.*s [%p]", 267 _debug("cell %*.*s [%p]",
325 cellnamesz, cellnamesz, cellname ?: "", params->cell); 268 cellnamesz, cellnamesz, cellname ?: "", ctx->cell);
326 269
327 /* lookup the cell record */ 270 /* lookup the cell record */
328 if (cellname || !params->cell) { 271 if (cellname) {
329 cell = afs_lookup_cell(params->net, cellname, cellnamesz, 272 cell = afs_lookup_cell(ctx->net, cellname, cellnamesz,
330 NULL, false); 273 NULL, false);
331 if (IS_ERR(cell)) { 274 if (IS_ERR(cell)) {
332 printk(KERN_ERR "kAFS: unable to lookup cell '%*.*s'\n", 275 pr_err("kAFS: unable to lookup cell '%*.*s'\n",
333 cellnamesz, cellnamesz, cellname ?: ""); 276 cellnamesz, cellnamesz, cellname ?: "");
334 return PTR_ERR(cell); 277 return PTR_ERR(cell);
335 } 278 }
336 afs_put_cell(params->net, params->cell); 279 afs_put_cell(ctx->net, ctx->cell);
337 params->cell = cell; 280 ctx->cell = cell;
338 } 281 }
339 282
340 _debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s", 283 _debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s",
341 params->cell->name, params->cell, 284 ctx->cell->name, ctx->cell,
342 params->volnamesz, params->volnamesz, params->volname, 285 ctx->volnamesz, ctx->volnamesz, ctx->volname,
343 suffix ?: "-", params->type, params->force ? " FORCE" : ""); 286 suffix ?: "-", ctx->type, ctx->force ? " FORCE" : "");
287
288 fc->source = param->string;
289 param->string = NULL;
290 return 0;
291}
292
293/*
294 * Parse a single mount parameter.
295 */
296static int afs_parse_param(struct fs_context *fc, struct fs_parameter *param)
297{
298 struct fs_parse_result result;
299 struct afs_fs_context *ctx = fc->fs_private;
300 int opt;
301
302 opt = fs_parse(fc, &afs_fs_parameters, param, &result);
303 if (opt < 0)
304 return opt;
305
306 switch (opt) {
307 case Opt_source:
308 return afs_parse_source(fc, param);
309
310 case Opt_autocell:
311 ctx->autocell = true;
312 break;
313
314 case Opt_dyn:
315 ctx->dyn_root = true;
316 break;
317
318 default:
319 return -EINVAL;
320 }
321
322 _leave(" = 0");
323 return 0;
324}
325
326/*
327 * Validate the options, get the cell key and look up the volume.
328 */
329static int afs_validate_fc(struct fs_context *fc)
330{
331 struct afs_fs_context *ctx = fc->fs_private;
332 struct afs_volume *volume;
333 struct key *key;
334
335 if (!ctx->dyn_root) {
336 if (ctx->no_cell) {
337 pr_warn("kAFS: Can only specify source 'none' with -o dyn\n");
338 return -EINVAL;
339 }
340
341 if (!ctx->cell) {
342 pr_warn("kAFS: No cell specified\n");
343 return -EDESTADDRREQ;
344 }
345
346 /* We try to do the mount securely. */
347 key = afs_request_key(ctx->cell);
348 if (IS_ERR(key))
349 return PTR_ERR(key);
350
351 ctx->key = key;
352
353 if (ctx->volume) {
354 afs_put_volume(ctx->cell, ctx->volume);
355 ctx->volume = NULL;
356 }
357
358 volume = afs_create_volume(ctx);
359 if (IS_ERR(volume))
360 return PTR_ERR(volume);
361
362 ctx->volume = volume;
363 }
344 364
345 return 0; 365 return 0;
346} 366}
@@ -348,39 +368,34 @@ static int afs_parse_device_name(struct afs_mount_params *params,
348/* 368/*
349 * check a superblock to see if it's the one we're looking for 369 * check a superblock to see if it's the one we're looking for
350 */ 370 */
351static int afs_test_super(struct super_block *sb, void *data) 371static int afs_test_super(struct super_block *sb, struct fs_context *fc)
352{ 372{
353 struct afs_super_info *as1 = data; 373 struct afs_fs_context *ctx = fc->fs_private;
354 struct afs_super_info *as = AFS_FS_S(sb); 374 struct afs_super_info *as = AFS_FS_S(sb);
355 375
356 return (as->net_ns == as1->net_ns && 376 return (as->net_ns == fc->net_ns &&
357 as->volume && 377 as->volume &&
358 as->volume->vid == as1->volume->vid && 378 as->volume->vid == ctx->volume->vid &&
359 !as->dyn_root); 379 !as->dyn_root);
360} 380}
361 381
362static int afs_dynroot_test_super(struct super_block *sb, void *data) 382static int afs_dynroot_test_super(struct super_block *sb, struct fs_context *fc)
363{ 383{
364 struct afs_super_info *as1 = data;
365 struct afs_super_info *as = AFS_FS_S(sb); 384 struct afs_super_info *as = AFS_FS_S(sb);
366 385
367 return (as->net_ns == as1->net_ns && 386 return (as->net_ns == fc->net_ns &&
368 as->dyn_root); 387 as->dyn_root);
369} 388}
370 389
371static int afs_set_super(struct super_block *sb, void *data) 390static int afs_set_super(struct super_block *sb, struct fs_context *fc)
372{ 391{
373 struct afs_super_info *as = data;
374
375 sb->s_fs_info = as;
376 return set_anon_super(sb, NULL); 392 return set_anon_super(sb, NULL);
377} 393}
378 394
379/* 395/*
380 * fill in the superblock 396 * fill in the superblock
381 */ 397 */
382static int afs_fill_super(struct super_block *sb, 398static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx)
383 struct afs_mount_params *params)
384{ 399{
385 struct afs_super_info *as = AFS_FS_S(sb); 400 struct afs_super_info *as = AFS_FS_S(sb);
386 struct afs_fid fid; 401 struct afs_fid fid;
@@ -412,13 +427,13 @@ static int afs_fill_super(struct super_block *sb,
412 fid.vnode = 1; 427 fid.vnode = 1;
413 fid.vnode_hi = 0; 428 fid.vnode_hi = 0;
414 fid.unique = 1; 429 fid.unique = 1;
415 inode = afs_iget(sb, params->key, &fid, NULL, NULL, NULL); 430 inode = afs_iget(sb, ctx->key, &fid, NULL, NULL, NULL);
416 } 431 }
417 432
418 if (IS_ERR(inode)) 433 if (IS_ERR(inode))
419 return PTR_ERR(inode); 434 return PTR_ERR(inode);
420 435
421 if (params->autocell || params->dyn_root) 436 if (ctx->autocell || as->dyn_root)
422 set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); 437 set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags);
423 438
424 ret = -ENOMEM; 439 ret = -ENOMEM;
@@ -443,17 +458,20 @@ error:
443 return ret; 458 return ret;
444} 459}
445 460
446static struct afs_super_info *afs_alloc_sbi(struct afs_mount_params *params) 461static struct afs_super_info *afs_alloc_sbi(struct fs_context *fc)
447{ 462{
463 struct afs_fs_context *ctx = fc->fs_private;
448 struct afs_super_info *as; 464 struct afs_super_info *as;
449 465
450 as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); 466 as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL);
451 if (as) { 467 if (as) {
452 as->net_ns = get_net(params->net_ns); 468 as->net_ns = get_net(fc->net_ns);
453 if (params->dyn_root) 469 if (ctx->dyn_root) {
454 as->dyn_root = true; 470 as->dyn_root = true;
455 else 471 } else {
456 as->cell = afs_get_cell(params->cell); 472 as->cell = afs_get_cell(ctx->cell);
473 as->volume = __afs_get_volume(ctx->volume);
474 }
457 } 475 }
458 return as; 476 return as;
459} 477}
@@ -475,7 +493,7 @@ static void afs_kill_super(struct super_block *sb)
475 493
476 if (as->dyn_root) 494 if (as->dyn_root)
477 afs_dynroot_depopulate(sb); 495 afs_dynroot_depopulate(sb);
478 496
479 /* Clear the callback interests (which will do ilookup5) before 497 /* Clear the callback interests (which will do ilookup5) before
480 * deactivating the superblock. 498 * deactivating the superblock.
481 */ 499 */
@@ -488,111 +506,103 @@ static void afs_kill_super(struct super_block *sb)
488} 506}
489 507
490/* 508/*
491 * get an AFS superblock 509 * Get an AFS superblock and root directory.
492 */ 510 */
493static struct dentry *afs_mount(struct file_system_type *fs_type, 511static int afs_get_tree(struct fs_context *fc)
494 int flags, const char *dev_name, void *options)
495{ 512{
496 struct afs_mount_params params; 513 struct afs_fs_context *ctx = fc->fs_private;
497 struct super_block *sb; 514 struct super_block *sb;
498 struct afs_volume *candidate;
499 struct key *key;
500 struct afs_super_info *as; 515 struct afs_super_info *as;
501 int ret; 516 int ret;
502 517
503 _enter(",,%s,%p", dev_name, options); 518 ret = afs_validate_fc(fc);
504 519 if (ret)
505 memset(&params, 0, sizeof(params));
506
507 ret = -EINVAL;
508 if (current->nsproxy->net_ns != &init_net)
509 goto error; 520 goto error;
510 params.net_ns = current->nsproxy->net_ns;
511 params.net = afs_net(params.net_ns);
512
513 /* parse the options and device name */
514 if (options) {
515 ret = afs_parse_options(&params, options, &dev_name);
516 if (ret < 0)
517 goto error;
518 }
519
520 if (!params.dyn_root) {
521 ret = afs_parse_device_name(&params, dev_name);
522 if (ret < 0)
523 goto error;
524 521
525 /* try and do the mount securely */ 522 _enter("");
526 key = afs_request_key(params.cell);
527 if (IS_ERR(key)) {
528 _leave(" = %ld [key]", PTR_ERR(key));
529 ret = PTR_ERR(key);
530 goto error;
531 }
532 params.key = key;
533 }
534 523
535 /* allocate a superblock info record */ 524 /* allocate a superblock info record */
536 ret = -ENOMEM; 525 ret = -ENOMEM;
537 as = afs_alloc_sbi(&params); 526 as = afs_alloc_sbi(fc);
538 if (!as) 527 if (!as)
539 goto error_key; 528 goto error;
540 529 fc->s_fs_info = as;
541 if (!params.dyn_root) {
542 /* Assume we're going to need a volume record; at the very
543 * least we can use it to update the volume record if we have
544 * one already. This checks that the volume exists within the
545 * cell.
546 */
547 candidate = afs_create_volume(&params);
548 if (IS_ERR(candidate)) {
549 ret = PTR_ERR(candidate);
550 goto error_as;
551 }
552
553 as->volume = candidate;
554 }
555 530
556 /* allocate a deviceless superblock */ 531 /* allocate a deviceless superblock */
557 sb = sget(fs_type, 532 sb = sget_fc(fc,
558 as->dyn_root ? afs_dynroot_test_super : afs_test_super, 533 as->dyn_root ? afs_dynroot_test_super : afs_test_super,
559 afs_set_super, flags, as); 534 afs_set_super);
560 if (IS_ERR(sb)) { 535 if (IS_ERR(sb)) {
561 ret = PTR_ERR(sb); 536 ret = PTR_ERR(sb);
562 goto error_as; 537 goto error;
563 } 538 }
564 539
565 if (!sb->s_root) { 540 if (!sb->s_root) {
566 /* initial superblock/root creation */ 541 /* initial superblock/root creation */
567 _debug("create"); 542 _debug("create");
568 ret = afs_fill_super(sb, &params); 543 ret = afs_fill_super(sb, ctx);
569 if (ret < 0) 544 if (ret < 0)
570 goto error_sb; 545 goto error_sb;
571 as = NULL;
572 sb->s_flags |= SB_ACTIVE; 546 sb->s_flags |= SB_ACTIVE;
573 } else { 547 } else {
574 _debug("reuse"); 548 _debug("reuse");
575 ASSERTCMP(sb->s_flags, &, SB_ACTIVE); 549 ASSERTCMP(sb->s_flags, &, SB_ACTIVE);
576 afs_destroy_sbi(as);
577 as = NULL;
578 } 550 }
579 551
580 afs_put_cell(params.net, params.cell); 552 fc->root = dget(sb->s_root);
581 key_put(params.key);
582 _leave(" = 0 [%p]", sb); 553 _leave(" = 0 [%p]", sb);
583 return dget(sb->s_root); 554 return 0;
584 555
585error_sb: 556error_sb:
586 deactivate_locked_super(sb); 557 deactivate_locked_super(sb);
587 goto error_key;
588error_as:
589 afs_destroy_sbi(as);
590error_key:
591 key_put(params.key);
592error: 558error:
593 afs_put_cell(params.net, params.cell);
594 _leave(" = %d", ret); 559 _leave(" = %d", ret);
595 return ERR_PTR(ret); 560 return ret;
561}
562
563static void afs_free_fc(struct fs_context *fc)
564{
565 struct afs_fs_context *ctx = fc->fs_private;
566
567 afs_destroy_sbi(fc->s_fs_info);
568 afs_put_volume(ctx->cell, ctx->volume);
569 afs_put_cell(ctx->net, ctx->cell);
570 key_put(ctx->key);
571 kfree(ctx);
572}
573
574static const struct fs_context_operations afs_context_ops = {
575 .free = afs_free_fc,
576 .parse_param = afs_parse_param,
577 .get_tree = afs_get_tree,
578};
579
580/*
581 * Set up the filesystem mount context.
582 */
583static int afs_init_fs_context(struct fs_context *fc)
584{
585 struct afs_fs_context *ctx;
586 struct afs_cell *cell;
587
588 ctx = kzalloc(sizeof(struct afs_fs_context), GFP_KERNEL);
589 if (!ctx)
590 return -ENOMEM;
591
592 ctx->type = AFSVL_ROVOL;
593 ctx->net = afs_net(fc->net_ns);
594
595 /* Default to the workstation cell. */
596 rcu_read_lock();
597 cell = afs_lookup_cell_rcu(ctx->net, NULL, 0);
598 rcu_read_unlock();
599 if (IS_ERR(cell))
600 cell = NULL;
601 ctx->cell = cell;
602
603 fc->fs_private = ctx;
604 fc->ops = &afs_context_ops;
605 return 0;
596} 606}
597 607
598/* 608/*
diff --git a/fs/afs/volume.c b/fs/afs/volume.c
index 00975ed3640f..f6eba2def0a1 100644
--- a/fs/afs/volume.c
+++ b/fs/afs/volume.c
@@ -21,7 +21,7 @@ static const char *const afs_voltypes[] = { "R/W", "R/O", "BAK" };
21/* 21/*
22 * Allocate a volume record and load it up from a vldb record. 22 * Allocate a volume record and load it up from a vldb record.
23 */ 23 */
24static struct afs_volume *afs_alloc_volume(struct afs_mount_params *params, 24static struct afs_volume *afs_alloc_volume(struct afs_fs_context *params,
25 struct afs_vldb_entry *vldb, 25 struct afs_vldb_entry *vldb,
26 unsigned long type_mask) 26 unsigned long type_mask)
27{ 27{
@@ -113,7 +113,7 @@ static struct afs_vldb_entry *afs_vl_lookup_vldb(struct afs_cell *cell,
113 * - Rule 3: If parent volume is R/W, then only mount R/W volume unless 113 * - Rule 3: If parent volume is R/W, then only mount R/W volume unless
114 * explicitly told otherwise 114 * explicitly told otherwise
115 */ 115 */
116struct afs_volume *afs_create_volume(struct afs_mount_params *params) 116struct afs_volume *afs_create_volume(struct afs_fs_context *params)
117{ 117{
118 struct afs_vldb_entry *vldb; 118 struct afs_vldb_entry *vldb;
119 struct afs_volume *volume; 119 struct afs_volume *volume;