diff options
| -rw-r--r-- | fs/afs/internal.h | 8 | ||||
| -rw-r--r-- | fs/afs/mntpt.c | 1 | ||||
| -rw-r--r-- | fs/afs/super.c | 460 | ||||
| -rw-r--r-- | fs/afs/volume.c | 4 |
4 files changed, 259 insertions, 214 deletions
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 8871b9e8645f..3ed0550a2e29 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
| @@ -36,15 +36,15 @@ | |||
| 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 */ | 40 | bool rwpath; /* T if the parent should be considered R/W */ |
| 41 | bool force; /* T to force cell type */ | 41 | bool force; /* T to force cell type */ |
| 42 | bool autocell; /* T if set auto mount operation */ | 42 | bool autocell; /* T if set auto mount operation */ |
| 43 | bool dyn_root; /* T if dynamic root */ | 43 | bool dyn_root; /* T if dynamic root */ |
| 44 | bool no_cell; /* T if the source is "none" (for dynroot) */ | ||
| 44 | afs_voltype_t type; /* type of volume requested */ | 45 | afs_voltype_t type; /* type of volume requested */ |
| 45 | int volnamesz; /* size of volume name */ | 46 | unsigned int volnamesz; /* size of volume name */ |
| 46 | const char *volname; /* name of volume to mount */ | 47 | 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 */ | 48 | struct afs_net *net; /* the AFS net namespace stuff */ |
| 49 | struct afs_cell *cell; /* cell in which to find volume */ | 49 | struct afs_cell *cell; /* cell in which to find volume */ |
| 50 | struct afs_volume *volume; /* volume record */ | 50 | struct afs_volume *volume; /* volume record */ |
| @@ -1274,7 +1274,7 @@ static inline struct afs_volume *__afs_get_volume(struct afs_volume *volume) | |||
| 1274 | return volume; | 1274 | return volume; |
| 1275 | } | 1275 | } |
| 1276 | 1276 | ||
| 1277 | extern struct afs_volume *afs_create_volume(struct afs_mount_params *); | 1277 | extern struct afs_volume *afs_create_volume(struct afs_fs_context *); |
| 1278 | extern void afs_activate_volume(struct afs_volume *); | 1278 | extern void afs_activate_volume(struct afs_volume *); |
| 1279 | extern void afs_deactivate_volume(struct afs_volume *); | 1279 | extern void afs_deactivate_volume(struct afs_volume *); |
| 1280 | extern void afs_put_volume(struct afs_cell *, struct afs_volume *); | 1280 | 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..b3f41d27590b 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 | ||
diff --git a/fs/afs/super.c b/fs/afs/super.c index dcd07fe99871..e1a7a8085262 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,28 @@ 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_cell, |
| 69 | afs_opt_dyn, | 70 | Opt_dyn, |
| 70 | afs_opt_rwpath, | 71 | Opt_rwpath, |
| 71 | afs_opt_vol, | 72 | Opt_source, |
| 72 | afs_opt_autocell, | 73 | Opt_vol, |
| 73 | }; | 74 | }; |
| 74 | 75 | ||
| 75 | static const match_table_t afs_options_list = { | 76 | static const struct fs_parameter_spec afs_param_specs[] = { |
| 76 | { afs_opt_cell, "cell=%s" }, | 77 | fsparam_flag ("autocell", Opt_autocell), |
| 77 | { afs_opt_dyn, "dyn" }, | 78 | fsparam_string("cell", Opt_cell), |
| 78 | { afs_opt_rwpath, "rwpath" }, | 79 | fsparam_flag ("dyn", Opt_dyn), |
| 79 | { afs_opt_vol, "vol=%s" }, | 80 | fsparam_flag ("rwpath", Opt_rwpath), |
| 80 | { afs_opt_autocell, "autocell" }, | 81 | fsparam_string("source", Opt_source), |
| 81 | { afs_no_opt, NULL }, | 82 | fsparam_string("vol", Opt_vol), |
| 83 | {} | ||
| 84 | }; | ||
| 85 | |||
| 86 | static const struct fs_parameter_description afs_fs_parameters = { | ||
| 87 | .name = "kAFS", | ||
| 88 | .specs = afs_param_specs, | ||
| 82 | }; | 89 | }; |
| 83 | 90 | ||
| 84 | /* | 91 | /* |
| @@ -190,71 +197,10 @@ static int afs_show_options(struct seq_file *m, struct dentry *root) | |||
| 190 | } | 197 | } |
| 191 | 198 | ||
| 192 | /* | 199 | /* |
| 193 | * parse the mount options | 200 | * 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 | 201 | * selector. |
| 195 | * shamelessly adapted it from the msdos fs | 202 | * |
| 196 | */ | 203 | * 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 | 204 | * "%[cell:]volume[.]" R/W volume |
| 259 | * "#[cell:]volume[.]" R/O or R/W volume (rwpath=0), | 205 | * "#[cell:]volume[.]" R/O or R/W volume (rwpath=0), |
| 260 | * or R/W (rwpath=1) volume | 206 | * or R/W (rwpath=1) volume |
| @@ -263,11 +209,11 @@ static int afs_parse_options(struct afs_mount_params *params, | |||
| 263 | * "%[cell:]volume.backup" Backup volume | 209 | * "%[cell:]volume.backup" Backup volume |
| 264 | * "#[cell:]volume.backup" Backup volume | 210 | * "#[cell:]volume.backup" Backup volume |
| 265 | */ | 211 | */ |
| 266 | static int afs_parse_device_name(struct afs_mount_params *params, | 212 | static int afs_parse_source(struct fs_context *fc, struct fs_parameter *param) |
| 267 | const char *name) | ||
| 268 | { | 213 | { |
| 214 | struct afs_fs_context *ctx = fc->fs_private; | ||
| 269 | struct afs_cell *cell; | 215 | struct afs_cell *cell; |
| 270 | const char *cellname, *suffix; | 216 | const char *cellname, *suffix, *name = param->string; |
| 271 | int cellnamesz; | 217 | int cellnamesz; |
| 272 | 218 | ||
| 273 | _enter(",%s", name); | 219 | _enter(",%s", name); |
| @@ -278,69 +224,174 @@ static int afs_parse_device_name(struct afs_mount_params *params, | |||
| 278 | } | 224 | } |
| 279 | 225 | ||
| 280 | if ((name[0] != '%' && name[0] != '#') || !name[1]) { | 226 | if ((name[0] != '%' && name[0] != '#') || !name[1]) { |
| 227 | /* To use dynroot, we don't want to have to provide a source */ | ||
| 228 | if (strcmp(name, "none") == 0) { | ||
| 229 | ctx->no_cell = true; | ||
| 230 | return 0; | ||
| 231 | } | ||
| 281 | printk(KERN_ERR "kAFS: unparsable volume name\n"); | 232 | printk(KERN_ERR "kAFS: unparsable volume name\n"); |
| 282 | return -EINVAL; | 233 | return -EINVAL; |
| 283 | } | 234 | } |
| 284 | 235 | ||
| 285 | /* determine the type of volume we're looking for */ | 236 | /* determine the type of volume we're looking for */ |
| 286 | params->type = AFSVL_ROVOL; | 237 | ctx->type = AFSVL_ROVOL; |
| 287 | params->force = false; | 238 | ctx->force = false; |
| 288 | if (params->rwpath || name[0] == '%') { | 239 | if (ctx->rwpath || name[0] == '%') { |
| 289 | params->type = AFSVL_RWVOL; | 240 | ctx->type = AFSVL_RWVOL; |
| 290 | params->force = true; | 241 | ctx->force = true; |
| 291 | } | 242 | } |
| 292 | name++; | 243 | name++; |
| 293 | 244 | ||
| 294 | /* split the cell name out if there is one */ | 245 | /* split the cell name out if there is one */ |
| 295 | params->volname = strchr(name, ':'); | 246 | ctx->volname = strchr(name, ':'); |
| 296 | if (params->volname) { | 247 | if (ctx->volname) { |
| 297 | cellname = name; | 248 | cellname = name; |
| 298 | cellnamesz = params->volname - name; | 249 | cellnamesz = ctx->volname - name; |
| 299 | params->volname++; | 250 | ctx->volname++; |
| 300 | } else { | 251 | } else { |
| 301 | params->volname = name; | 252 | ctx->volname = name; |
| 302 | cellname = NULL; | 253 | cellname = NULL; |
| 303 | cellnamesz = 0; | 254 | cellnamesz = 0; |
| 304 | } | 255 | } |
| 305 | 256 | ||
| 306 | /* the volume type is further affected by a possible suffix */ | 257 | /* the volume type is further affected by a possible suffix */ |
| 307 | suffix = strrchr(params->volname, '.'); | 258 | suffix = strrchr(ctx->volname, '.'); |
| 308 | if (suffix) { | 259 | if (suffix) { |
| 309 | if (strcmp(suffix, ".readonly") == 0) { | 260 | if (strcmp(suffix, ".readonly") == 0) { |
| 310 | params->type = AFSVL_ROVOL; | 261 | ctx->type = AFSVL_ROVOL; |
| 311 | params->force = true; | 262 | ctx->force = true; |
| 312 | } else if (strcmp(suffix, ".backup") == 0) { | 263 | } else if (strcmp(suffix, ".backup") == 0) { |
| 313 | params->type = AFSVL_BACKVOL; | 264 | ctx->type = AFSVL_BACKVOL; |
| 314 | params->force = true; | 265 | ctx->force = true; |
| 315 | } else if (suffix[1] == 0) { | 266 | } else if (suffix[1] == 0) { |
| 316 | } else { | 267 | } else { |
| 317 | suffix = NULL; | 268 | suffix = NULL; |
| 318 | } | 269 | } |
| 319 | } | 270 | } |
| 320 | 271 | ||
| 321 | params->volnamesz = suffix ? | 272 | ctx->volnamesz = suffix ? |
| 322 | suffix - params->volname : strlen(params->volname); | 273 | suffix - ctx->volname : strlen(ctx->volname); |
| 323 | 274 | ||
| 324 | _debug("cell %*.*s [%p]", | 275 | _debug("cell %*.*s [%p]", |
| 325 | cellnamesz, cellnamesz, cellname ?: "", params->cell); | 276 | cellnamesz, cellnamesz, cellname ?: "", ctx->cell); |
| 326 | 277 | ||
| 327 | /* lookup the cell record */ | 278 | /* lookup the cell record */ |
| 328 | if (cellname || !params->cell) { | 279 | if (cellname) { |
| 329 | cell = afs_lookup_cell(params->net, cellname, cellnamesz, | 280 | cell = afs_lookup_cell(ctx->net, cellname, cellnamesz, |
| 330 | NULL, false); | 281 | NULL, false); |
| 331 | if (IS_ERR(cell)) { | 282 | if (IS_ERR(cell)) { |
| 332 | printk(KERN_ERR "kAFS: unable to lookup cell '%*.*s'\n", | 283 | pr_err("kAFS: unable to lookup cell '%*.*s'\n", |
| 333 | cellnamesz, cellnamesz, cellname ?: ""); | 284 | cellnamesz, cellnamesz, cellname ?: ""); |
| 334 | return PTR_ERR(cell); | 285 | return PTR_ERR(cell); |
| 335 | } | 286 | } |
| 336 | afs_put_cell(params->net, params->cell); | 287 | afs_put_cell(ctx->net, ctx->cell); |
| 337 | params->cell = cell; | 288 | ctx->cell = cell; |
| 338 | } | 289 | } |
| 339 | 290 | ||
| 340 | _debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s", | 291 | _debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s", |
| 341 | params->cell->name, params->cell, | 292 | ctx->cell->name, ctx->cell, |
| 342 | params->volnamesz, params->volnamesz, params->volname, | 293 | ctx->volnamesz, ctx->volnamesz, ctx->volname, |
| 343 | suffix ?: "-", params->type, params->force ? " FORCE" : ""); | 294 | suffix ?: "-", ctx->type, ctx->force ? " FORCE" : ""); |
| 295 | |||
| 296 | fc->source = param->string; | ||
| 297 | param->string = NULL; | ||
| 298 | return 0; | ||
| 299 | } | ||
| 300 | |||
| 301 | /* | ||
| 302 | * Parse a single mount parameter. | ||
| 303 | */ | ||
| 304 | static int afs_parse_param(struct fs_context *fc, struct fs_parameter *param) | ||
| 305 | { | ||
| 306 | struct fs_parse_result result; | ||
| 307 | struct afs_fs_context *ctx = fc->fs_private; | ||
| 308 | struct afs_cell *cell; | ||
| 309 | int opt; | ||
| 310 | |||
| 311 | opt = fs_parse(fc, &afs_fs_parameters, param, &result); | ||
| 312 | if (opt < 0) | ||
| 313 | return opt; | ||
| 314 | |||
| 315 | switch (opt) { | ||
| 316 | case Opt_cell: | ||
| 317 | if (param->size <= 0) | ||
| 318 | return -EINVAL; | ||
| 319 | if (param->size > AFS_MAXCELLNAME) | ||
| 320 | return -ENAMETOOLONG; | ||
| 321 | |||
| 322 | rcu_read_lock(); | ||
| 323 | cell = afs_lookup_cell_rcu(ctx->net, param->string, param->size); | ||
| 324 | rcu_read_unlock(); | ||
| 325 | if (IS_ERR(cell)) | ||
| 326 | return PTR_ERR(cell); | ||
| 327 | afs_put_cell(ctx->net, ctx->cell); | ||
| 328 | ctx->cell = cell; | ||
| 329 | break; | ||
| 330 | |||
| 331 | case Opt_source: | ||
| 332 | return afs_parse_source(fc, param); | ||
| 333 | |||
| 334 | case Opt_autocell: | ||
| 335 | ctx->autocell = true; | ||
| 336 | break; | ||
| 337 | |||
| 338 | case Opt_dyn: | ||
| 339 | ctx->dyn_root = true; | ||
| 340 | break; | ||
| 341 | |||
| 342 | case Opt_rwpath: | ||
| 343 | ctx->rwpath = true; | ||
| 344 | break; | ||
| 345 | |||
| 346 | case Opt_vol: | ||
| 347 | return invalf(fc, "'vol' param is obsolete"); | ||
| 348 | |||
| 349 | default: | ||
| 350 | return -EINVAL; | ||
| 351 | } | ||
| 352 | |||
| 353 | _leave(" = 0"); | ||
| 354 | return 0; | ||
| 355 | } | ||
| 356 | |||
| 357 | /* | ||
| 358 | * Validate the options, get the cell key and look up the volume. | ||
| 359 | */ | ||
| 360 | static int afs_validate_fc(struct fs_context *fc) | ||
| 361 | { | ||
| 362 | struct afs_fs_context *ctx = fc->fs_private; | ||
| 363 | struct afs_volume *volume; | ||
| 364 | struct key *key; | ||
| 365 | |||
| 366 | if (!ctx->dyn_root) { | ||
| 367 | if (ctx->no_cell) { | ||
| 368 | pr_warn("kAFS: Can only specify source 'none' with -o dyn\n"); | ||
| 369 | return -EINVAL; | ||
| 370 | } | ||
| 371 | |||
| 372 | if (!ctx->cell) { | ||
| 373 | pr_warn("kAFS: No cell specified\n"); | ||
| 374 | return -EDESTADDRREQ; | ||
| 375 | } | ||
| 376 | |||
| 377 | /* We try to do the mount securely. */ | ||
| 378 | key = afs_request_key(ctx->cell); | ||
| 379 | if (IS_ERR(key)) | ||
| 380 | return PTR_ERR(key); | ||
| 381 | |||
| 382 | ctx->key = key; | ||
| 383 | |||
| 384 | if (ctx->volume) { | ||
| 385 | afs_put_volume(ctx->cell, ctx->volume); | ||
| 386 | ctx->volume = NULL; | ||
| 387 | } | ||
| 388 | |||
| 389 | volume = afs_create_volume(ctx); | ||
| 390 | if (IS_ERR(volume)) | ||
| 391 | return PTR_ERR(volume); | ||
| 392 | |||
| 393 | ctx->volume = volume; | ||
| 394 | } | ||
| 344 | 395 | ||
| 345 | return 0; | 396 | return 0; |
| 346 | } | 397 | } |
| @@ -348,39 +399,34 @@ static int afs_parse_device_name(struct afs_mount_params *params, | |||
| 348 | /* | 399 | /* |
| 349 | * check a superblock to see if it's the one we're looking for | 400 | * check a superblock to see if it's the one we're looking for |
| 350 | */ | 401 | */ |
| 351 | static int afs_test_super(struct super_block *sb, void *data) | 402 | static int afs_test_super(struct super_block *sb, struct fs_context *fc) |
| 352 | { | 403 | { |
| 353 | struct afs_super_info *as1 = data; | 404 | struct afs_fs_context *ctx = fc->fs_private; |
| 354 | struct afs_super_info *as = AFS_FS_S(sb); | 405 | struct afs_super_info *as = AFS_FS_S(sb); |
| 355 | 406 | ||
| 356 | return (as->net_ns == as1->net_ns && | 407 | return (as->net_ns == fc->net_ns && |
| 357 | as->volume && | 408 | as->volume && |
| 358 | as->volume->vid == as1->volume->vid && | 409 | as->volume->vid == ctx->volume->vid && |
| 359 | !as->dyn_root); | 410 | !as->dyn_root); |
| 360 | } | 411 | } |
| 361 | 412 | ||
| 362 | static int afs_dynroot_test_super(struct super_block *sb, void *data) | 413 | static int afs_dynroot_test_super(struct super_block *sb, struct fs_context *fc) |
| 363 | { | 414 | { |
| 364 | struct afs_super_info *as1 = data; | ||
| 365 | struct afs_super_info *as = AFS_FS_S(sb); | 415 | struct afs_super_info *as = AFS_FS_S(sb); |
| 366 | 416 | ||
| 367 | return (as->net_ns == as1->net_ns && | 417 | return (as->net_ns == fc->net_ns && |
| 368 | as->dyn_root); | 418 | as->dyn_root); |
| 369 | } | 419 | } |
| 370 | 420 | ||
| 371 | static int afs_set_super(struct super_block *sb, void *data) | 421 | static int afs_set_super(struct super_block *sb, struct fs_context *fc) |
| 372 | { | 422 | { |
| 373 | struct afs_super_info *as = data; | ||
| 374 | |||
| 375 | sb->s_fs_info = as; | ||
| 376 | return set_anon_super(sb, NULL); | 423 | return set_anon_super(sb, NULL); |
| 377 | } | 424 | } |
| 378 | 425 | ||
| 379 | /* | 426 | /* |
| 380 | * fill in the superblock | 427 | * fill in the superblock |
| 381 | */ | 428 | */ |
| 382 | static int afs_fill_super(struct super_block *sb, | 429 | static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx) |
| 383 | struct afs_mount_params *params) | ||
| 384 | { | 430 | { |
| 385 | struct afs_super_info *as = AFS_FS_S(sb); | 431 | struct afs_super_info *as = AFS_FS_S(sb); |
| 386 | struct afs_fid fid; | 432 | struct afs_fid fid; |
| @@ -412,13 +458,13 @@ static int afs_fill_super(struct super_block *sb, | |||
| 412 | fid.vnode = 1; | 458 | fid.vnode = 1; |
| 413 | fid.vnode_hi = 0; | 459 | fid.vnode_hi = 0; |
| 414 | fid.unique = 1; | 460 | fid.unique = 1; |
| 415 | inode = afs_iget(sb, params->key, &fid, NULL, NULL, NULL); | 461 | inode = afs_iget(sb, ctx->key, &fid, NULL, NULL, NULL); |
| 416 | } | 462 | } |
| 417 | 463 | ||
| 418 | if (IS_ERR(inode)) | 464 | if (IS_ERR(inode)) |
| 419 | return PTR_ERR(inode); | 465 | return PTR_ERR(inode); |
| 420 | 466 | ||
| 421 | if (params->autocell || params->dyn_root) | 467 | if (ctx->autocell || as->dyn_root) |
| 422 | set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); | 468 | set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); |
| 423 | 469 | ||
| 424 | ret = -ENOMEM; | 470 | ret = -ENOMEM; |
| @@ -443,17 +489,20 @@ error: | |||
| 443 | return ret; | 489 | return ret; |
| 444 | } | 490 | } |
| 445 | 491 | ||
| 446 | static struct afs_super_info *afs_alloc_sbi(struct afs_mount_params *params) | 492 | static struct afs_super_info *afs_alloc_sbi(struct fs_context *fc) |
| 447 | { | 493 | { |
| 494 | struct afs_fs_context *ctx = fc->fs_private; | ||
| 448 | struct afs_super_info *as; | 495 | struct afs_super_info *as; |
| 449 | 496 | ||
| 450 | as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); | 497 | as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); |
| 451 | if (as) { | 498 | if (as) { |
| 452 | as->net_ns = get_net(params->net_ns); | 499 | as->net_ns = get_net(fc->net_ns); |
| 453 | if (params->dyn_root) | 500 | if (ctx->dyn_root) { |
| 454 | as->dyn_root = true; | 501 | as->dyn_root = true; |
| 455 | else | 502 | } else { |
| 456 | as->cell = afs_get_cell(params->cell); | 503 | as->cell = afs_get_cell(ctx->cell); |
| 504 | as->volume = __afs_get_volume(ctx->volume); | ||
| 505 | } | ||
| 457 | } | 506 | } |
| 458 | return as; | 507 | return as; |
| 459 | } | 508 | } |
| @@ -475,7 +524,7 @@ static void afs_kill_super(struct super_block *sb) | |||
| 475 | 524 | ||
| 476 | if (as->dyn_root) | 525 | if (as->dyn_root) |
| 477 | afs_dynroot_depopulate(sb); | 526 | afs_dynroot_depopulate(sb); |
| 478 | 527 | ||
| 479 | /* Clear the callback interests (which will do ilookup5) before | 528 | /* Clear the callback interests (which will do ilookup5) before |
| 480 | * deactivating the superblock. | 529 | * deactivating the superblock. |
| 481 | */ | 530 | */ |
| @@ -488,111 +537,106 @@ static void afs_kill_super(struct super_block *sb) | |||
| 488 | } | 537 | } |
| 489 | 538 | ||
| 490 | /* | 539 | /* |
| 491 | * get an AFS superblock | 540 | * Get an AFS superblock and root directory. |
| 492 | */ | 541 | */ |
| 493 | static struct dentry *afs_mount(struct file_system_type *fs_type, | 542 | static int afs_get_tree(struct fs_context *fc) |
| 494 | int flags, const char *dev_name, void *options) | ||
| 495 | { | 543 | { |
| 496 | struct afs_mount_params params; | 544 | struct afs_fs_context *ctx = fc->fs_private; |
| 497 | struct super_block *sb; | 545 | struct super_block *sb; |
| 498 | struct afs_volume *candidate; | ||
| 499 | struct key *key; | ||
| 500 | struct afs_super_info *as; | 546 | struct afs_super_info *as; |
| 501 | int ret; | 547 | int ret; |
| 502 | 548 | ||
| 503 | _enter(",,%s,%p", dev_name, options); | 549 | ret = afs_validate_fc(fc); |
| 504 | 550 | if (ret) | |
| 505 | memset(¶ms, 0, sizeof(params)); | ||
| 506 | |||
| 507 | ret = -EINVAL; | ||
| 508 | if (current->nsproxy->net_ns != &init_net) | ||
| 509 | goto error; | 551 | 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 | 552 | ||
| 525 | /* try and do the mount securely */ | 553 | _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 | 554 | ||
| 535 | /* allocate a superblock info record */ | 555 | /* allocate a superblock info record */ |
| 536 | ret = -ENOMEM; | 556 | ret = -ENOMEM; |
| 537 | as = afs_alloc_sbi(¶ms); | 557 | as = afs_alloc_sbi(fc); |
| 538 | if (!as) | 558 | if (!as) |
| 539 | goto error_key; | 559 | goto error; |
| 540 | 560 | 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 | 561 | ||
| 556 | /* allocate a deviceless superblock */ | 562 | /* allocate a deviceless superblock */ |
| 557 | sb = sget(fs_type, | 563 | sb = sget_fc(fc, |
| 558 | as->dyn_root ? afs_dynroot_test_super : afs_test_super, | 564 | as->dyn_root ? afs_dynroot_test_super : afs_test_super, |
| 559 | afs_set_super, flags, as); | 565 | afs_set_super); |
| 560 | if (IS_ERR(sb)) { | 566 | if (IS_ERR(sb)) { |
| 561 | ret = PTR_ERR(sb); | 567 | ret = PTR_ERR(sb); |
| 562 | goto error_as; | 568 | goto error; |
| 563 | } | 569 | } |
| 564 | 570 | ||
| 565 | if (!sb->s_root) { | 571 | if (!sb->s_root) { |
| 566 | /* initial superblock/root creation */ | 572 | /* initial superblock/root creation */ |
| 567 | _debug("create"); | 573 | _debug("create"); |
| 568 | ret = afs_fill_super(sb, ¶ms); | 574 | ret = afs_fill_super(sb, ctx); |
| 569 | if (ret < 0) | 575 | if (ret < 0) |
| 570 | goto error_sb; | 576 | goto error_sb; |
| 571 | as = NULL; | ||
| 572 | sb->s_flags |= SB_ACTIVE; | 577 | sb->s_flags |= SB_ACTIVE; |
| 573 | } else { | 578 | } else { |
| 574 | _debug("reuse"); | 579 | _debug("reuse"); |
| 575 | ASSERTCMP(sb->s_flags, &, SB_ACTIVE); | 580 | ASSERTCMP(sb->s_flags, &, SB_ACTIVE); |
| 576 | afs_destroy_sbi(as); | ||
| 577 | as = NULL; | ||
| 578 | } | 581 | } |
| 579 | 582 | ||
| 580 | afs_put_cell(params.net, params.cell); | 583 | fc->root = dget(sb->s_root); |
| 581 | key_put(params.key); | ||
| 582 | _leave(" = 0 [%p]", sb); | 584 | _leave(" = 0 [%p]", sb); |
| 583 | return dget(sb->s_root); | 585 | return 0; |
| 584 | 586 | ||
| 585 | error_sb: | 587 | error_sb: |
| 586 | deactivate_locked_super(sb); | 588 | 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: | 589 | error: |
| 593 | afs_put_cell(params.net, params.cell); | ||
| 594 | _leave(" = %d", ret); | 590 | _leave(" = %d", ret); |
| 595 | return ERR_PTR(ret); | 591 | return ret; |
| 592 | } | ||
| 593 | |||
| 594 | static void afs_free_fc(struct fs_context *fc) | ||
| 595 | { | ||
| 596 | struct afs_fs_context *ctx = fc->fs_private; | ||
| 597 | |||
| 598 | afs_destroy_sbi(fc->s_fs_info); | ||
| 599 | afs_put_volume(ctx->cell, ctx->volume); | ||
| 600 | afs_put_cell(ctx->net, ctx->cell); | ||
| 601 | key_put(ctx->key); | ||
| 602 | kfree(ctx); | ||
| 603 | } | ||
| 604 | |||
| 605 | static const struct fs_context_operations afs_context_ops = { | ||
| 606 | .free = afs_free_fc, | ||
| 607 | .parse_param = afs_parse_param, | ||
| 608 | .get_tree = afs_get_tree, | ||
| 609 | }; | ||
| 610 | |||
| 611 | /* | ||
| 612 | * Set up the filesystem mount context. | ||
| 613 | */ | ||
| 614 | static int afs_init_fs_context(struct fs_context *fc) | ||
| 615 | { | ||
| 616 | struct afs_fs_context *ctx; | ||
| 617 | struct afs_cell *cell; | ||
| 618 | |||
| 619 | if (current->nsproxy->net_ns != &init_net) | ||
| 620 | return -EINVAL; | ||
| 621 | |||
| 622 | ctx = kzalloc(sizeof(struct afs_fs_context), GFP_KERNEL); | ||
| 623 | if (!ctx) | ||
| 624 | return -ENOMEM; | ||
| 625 | |||
| 626 | ctx->type = AFSVL_ROVOL; | ||
| 627 | ctx->net = afs_net(fc->net_ns); | ||
| 628 | |||
| 629 | /* Default to the workstation cell. */ | ||
| 630 | rcu_read_lock(); | ||
| 631 | cell = afs_lookup_cell_rcu(ctx->net, NULL, 0); | ||
| 632 | rcu_read_unlock(); | ||
| 633 | if (IS_ERR(cell)) | ||
| 634 | cell = NULL; | ||
| 635 | ctx->cell = cell; | ||
| 636 | |||
| 637 | fc->fs_private = ctx; | ||
| 638 | fc->ops = &afs_context_ops; | ||
| 639 | return 0; | ||
| 596 | } | 640 | } |
| 597 | 641 | ||
| 598 | /* | 642 | /* |
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; |
