diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-12 17:08:19 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-12 17:08:19 -0400 |
commit | 7b47a9e7c8f672b6fb0b77fca11a63a8a77f5a91 (patch) | |
tree | cf05645120ba2323c36acefdea6e62addf320f8c /fs/afs | |
parent | dbc2fba3fc46084f502aec53183995a632998dcd (diff) | |
parent | c99c2171fc61476afac0dfb59fb2c447a01fb1e0 (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.h | 9 | ||||
-rw-r--r-- | fs/afs/mntpt.c | 149 | ||||
-rw-r--r-- | fs/afs/super.c | 430 | ||||
-rw-r--r-- | fs/afs/volume.c | 4 |
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 @@ | |||
36 | struct pagevec; | 36 | struct pagevec; |
37 | struct afs_call; | 37 | struct afs_call; |
38 | 38 | ||
39 | struct afs_mount_params { | 39 | struct 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 | ||
1277 | extern struct afs_volume *afs_create_volume(struct afs_mount_params *); | 1276 | extern struct afs_volume *afs_create_volume(struct afs_fs_context *); |
1278 | extern void afs_activate_volume(struct afs_volume *); | 1277 | extern void afs_activate_volume(struct afs_volume *); |
1279 | extern void afs_deactivate_volume(struct afs_volume *); | 1278 | extern void afs_deactivate_volume(struct afs_volume *); |
1280 | extern void afs_put_volume(struct afs_cell *, struct afs_volume *); | 1279 | extern 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 | ||
48 | static unsigned long afs_mntpt_expiry_timeout = 10 * 60; | 49 | static unsigned long afs_mntpt_expiry_timeout = 10 * 60; |
49 | 50 | ||
51 | static 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 | */ |
73 | static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) | 76 | static 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); | 160 | static 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 | ||
164 | error: | 168 | fc = fs_context_for_submount(&afs_fs_type, mntpt); |
165 | put_page(page); | 169 | if (IS_ERR(fc)) |
166 | error_no_page: | 170 | return ERR_CAST(fc); |
167 | free_page((unsigned long) options); | 171 | |
168 | error_no_options: | 172 | ret = afs_mntpt_set_params(fc, mntpt); |
169 | free_page((unsigned long) devname); | 173 | if (!ret) |
170 | error_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 | ||
32 | static void afs_i_init_once(void *foo); | 32 | static void afs_i_init_once(void *foo); |
33 | static struct dentry *afs_mount(struct file_system_type *fs_type, | ||
34 | int flags, const char *dev_name, void *data); | ||
35 | static void afs_kill_super(struct super_block *sb); | 33 | static void afs_kill_super(struct super_block *sb); |
36 | static struct inode *afs_alloc_inode(struct super_block *sb); | 34 | static struct inode *afs_alloc_inode(struct super_block *sb); |
37 | static void afs_destroy_inode(struct inode *inode); | 35 | static void afs_destroy_inode(struct inode *inode); |
38 | static int afs_statfs(struct dentry *dentry, struct kstatfs *buf); | 36 | static int afs_statfs(struct dentry *dentry, struct kstatfs *buf); |
39 | static int afs_show_devname(struct seq_file *m, struct dentry *root); | 37 | static int afs_show_devname(struct seq_file *m, struct dentry *root); |
40 | static int afs_show_options(struct seq_file *m, struct dentry *root); | 38 | static int afs_show_options(struct seq_file *m, struct dentry *root); |
39 | static int afs_init_fs_context(struct fs_context *fc); | ||
40 | static const struct fs_parameter_description afs_fs_parameters; | ||
41 | 41 | ||
42 | struct file_system_type afs_fs_type = { | 42 | struct 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 | }; |
49 | MODULE_ALIAS_FS("afs"); | 50 | MODULE_ALIAS_FS("afs"); |
50 | 51 | ||
@@ -63,22 +64,22 @@ static const struct super_operations afs_super_ops = { | |||
63 | static struct kmem_cache *afs_inode_cachep; | 64 | static struct kmem_cache *afs_inode_cachep; |
64 | static atomic_t afs_count_active_inodes; | 65 | static atomic_t afs_count_active_inodes; |
65 | 66 | ||
66 | enum { | 67 | enum 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 | ||
75 | static const match_table_t afs_options_list = { | 73 | static 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 | |
80 | static 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: |
197 | static 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 | */ |
266 | static int afs_parse_device_name(struct afs_mount_params *params, | 206 | static 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 | */ | ||
296 | static 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 | */ | ||
329 | static 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 | */ |
351 | static int afs_test_super(struct super_block *sb, void *data) | 371 | static 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 | ||
362 | static int afs_dynroot_test_super(struct super_block *sb, void *data) | 382 | static 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 | ||
371 | static int afs_set_super(struct super_block *sb, void *data) | 390 | static 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 | */ |
382 | static int afs_fill_super(struct super_block *sb, | 398 | static 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 | ||
446 | static struct afs_super_info *afs_alloc_sbi(struct afs_mount_params *params) | 461 | static 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 | */ |
493 | static struct dentry *afs_mount(struct file_system_type *fs_type, | 511 | static 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(¶ms, 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(¶ms, options, &dev_name); | ||
516 | if (ret < 0) | ||
517 | goto error; | ||
518 | } | ||
519 | |||
520 | if (!params.dyn_root) { | ||
521 | ret = afs_parse_device_name(¶ms, 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(¶ms); | 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(¶ms); | ||
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, ¶ms); | 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 | ||
585 | error_sb: | 556 | error_sb: |
586 | deactivate_locked_super(sb); | 557 | deactivate_locked_super(sb); |
587 | goto error_key; | ||
588 | error_as: | ||
589 | afs_destroy_sbi(as); | ||
590 | error_key: | ||
591 | key_put(params.key); | ||
592 | error: | 558 | error: |
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 | |||
563 | static 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 | |||
574 | static 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 | */ | ||
583 | static 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 | */ |
24 | static struct afs_volume *afs_alloc_volume(struct afs_mount_params *params, | 24 | static 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 | */ |
116 | struct afs_volume *afs_create_volume(struct afs_mount_params *params) | 116 | struct 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; |