| .. | .. |
|---|
| 1 | 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 | 5 | * This software may be freely redistributed under the terms of the |
|---|
| 6 | 6 | * GNU General Public License. |
|---|
| .. | .. |
|---|
| 21 | 21 | #include <linux/slab.h> |
|---|
| 22 | 22 | #include <linux/fs.h> |
|---|
| 23 | 23 | #include <linux/pagemap.h> |
|---|
| 24 | | -#include <linux/parser.h> |
|---|
| 24 | +#include <linux/fs_parser.h> |
|---|
| 25 | 25 | #include <linux/statfs.h> |
|---|
| 26 | 26 | #include <linux/sched.h> |
|---|
| 27 | 27 | #include <linux/nsproxy.h> |
|---|
| .. | .. |
|---|
| 30 | 30 | #include "internal.h" |
|---|
| 31 | 31 | |
|---|
| 32 | 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 | 33 | static void afs_kill_super(struct super_block *sb); |
|---|
| 36 | 34 | static struct inode *afs_alloc_inode(struct super_block *sb); |
|---|
| 37 | 35 | static void afs_destroy_inode(struct inode *inode); |
|---|
| 36 | +static void afs_free_inode(struct inode *inode); |
|---|
| 38 | 37 | static int afs_statfs(struct dentry *dentry, struct kstatfs *buf); |
|---|
| 39 | 38 | static int afs_show_devname(struct seq_file *m, struct dentry *root); |
|---|
| 40 | 39 | static int afs_show_options(struct seq_file *m, struct dentry *root); |
|---|
| 40 | +static int afs_init_fs_context(struct fs_context *fc); |
|---|
| 41 | +static const struct fs_parameter_spec afs_fs_parameters[]; |
|---|
| 41 | 42 | |
|---|
| 42 | 43 | struct file_system_type afs_fs_type = { |
|---|
| 43 | | - .owner = THIS_MODULE, |
|---|
| 44 | | - .name = "afs", |
|---|
| 45 | | - .mount = afs_mount, |
|---|
| 46 | | - .kill_sb = afs_kill_super, |
|---|
| 47 | | - .fs_flags = 0, |
|---|
| 44 | + .owner = THIS_MODULE, |
|---|
| 45 | + .name = "afs", |
|---|
| 46 | + .init_fs_context = afs_init_fs_context, |
|---|
| 47 | + .parameters = afs_fs_parameters, |
|---|
| 48 | + .kill_sb = afs_kill_super, |
|---|
| 49 | + .fs_flags = FS_RENAME_DOES_D_MOVE, |
|---|
| 48 | 50 | }; |
|---|
| 49 | 51 | MODULE_ALIAS_FS("afs"); |
|---|
| 50 | 52 | |
|---|
| .. | .. |
|---|
| 55 | 57 | .alloc_inode = afs_alloc_inode, |
|---|
| 56 | 58 | .drop_inode = afs_drop_inode, |
|---|
| 57 | 59 | .destroy_inode = afs_destroy_inode, |
|---|
| 60 | + .free_inode = afs_free_inode, |
|---|
| 58 | 61 | .evict_inode = afs_evict_inode, |
|---|
| 59 | 62 | .show_devname = afs_show_devname, |
|---|
| 60 | 63 | .show_options = afs_show_options, |
|---|
| .. | .. |
|---|
| 63 | 66 | static struct kmem_cache *afs_inode_cachep; |
|---|
| 64 | 67 | static atomic_t afs_count_active_inodes; |
|---|
| 65 | 68 | |
|---|
| 66 | | -enum { |
|---|
| 67 | | - afs_no_opt, |
|---|
| 68 | | - afs_opt_cell, |
|---|
| 69 | | - afs_opt_dyn, |
|---|
| 70 | | - afs_opt_rwpath, |
|---|
| 71 | | - afs_opt_vol, |
|---|
| 72 | | - afs_opt_autocell, |
|---|
| 69 | +enum afs_param { |
|---|
| 70 | + Opt_autocell, |
|---|
| 71 | + Opt_dyn, |
|---|
| 72 | + Opt_flock, |
|---|
| 73 | + Opt_source, |
|---|
| 73 | 74 | }; |
|---|
| 74 | 75 | |
|---|
| 75 | | -static const match_table_t afs_options_list = { |
|---|
| 76 | | - { afs_opt_cell, "cell=%s" }, |
|---|
| 77 | | - { afs_opt_dyn, "dyn" }, |
|---|
| 78 | | - { afs_opt_rwpath, "rwpath" }, |
|---|
| 79 | | - { afs_opt_vol, "vol=%s" }, |
|---|
| 80 | | - { afs_opt_autocell, "autocell" }, |
|---|
| 81 | | - { afs_no_opt, NULL }, |
|---|
| 76 | +static const struct constant_table afs_param_flock[] = { |
|---|
| 77 | + {"local", afs_flock_mode_local }, |
|---|
| 78 | + {"openafs", afs_flock_mode_openafs }, |
|---|
| 79 | + {"strict", afs_flock_mode_strict }, |
|---|
| 80 | + {"write", afs_flock_mode_write }, |
|---|
| 81 | + {} |
|---|
| 82 | +}; |
|---|
| 83 | + |
|---|
| 84 | +static const struct fs_parameter_spec afs_fs_parameters[] = { |
|---|
| 85 | + fsparam_flag ("autocell", Opt_autocell), |
|---|
| 86 | + fsparam_flag ("dyn", Opt_dyn), |
|---|
| 87 | + fsparam_enum ("flock", Opt_flock, afs_param_flock), |
|---|
| 88 | + fsparam_string("source", Opt_source), |
|---|
| 89 | + {} |
|---|
| 82 | 90 | }; |
|---|
| 83 | 91 | |
|---|
| 84 | 92 | /* |
|---|
| .. | .. |
|---|
| 181 | 189 | static int afs_show_options(struct seq_file *m, struct dentry *root) |
|---|
| 182 | 190 | { |
|---|
| 183 | 191 | struct afs_super_info *as = AFS_FS_S(root->d_sb); |
|---|
| 192 | + const char *p = NULL; |
|---|
| 184 | 193 | |
|---|
| 185 | 194 | if (as->dyn_root) |
|---|
| 186 | 195 | seq_puts(m, ",dyn"); |
|---|
| 187 | 196 | if (test_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(d_inode(root))->flags)) |
|---|
| 188 | 197 | seq_puts(m, ",autocell"); |
|---|
| 189 | | - return 0; |
|---|
| 190 | | -} |
|---|
| 191 | | - |
|---|
| 192 | | -/* |
|---|
| 193 | | - * parse the mount options |
|---|
| 194 | | - * - this function has been shamelessly adapted from the ext3 fs which |
|---|
| 195 | | - * shamelessly adapted it from the msdos fs |
|---|
| 196 | | - */ |
|---|
| 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 | | - } |
|---|
| 198 | + switch (as->flock_mode) { |
|---|
| 199 | + case afs_flock_mode_unset: break; |
|---|
| 200 | + case afs_flock_mode_local: p = "local"; break; |
|---|
| 201 | + case afs_flock_mode_openafs: p = "openafs"; break; |
|---|
| 202 | + case afs_flock_mode_strict: p = "strict"; break; |
|---|
| 203 | + case afs_flock_mode_write: p = "write"; break; |
|---|
| 248 | 204 | } |
|---|
| 205 | + if (p) |
|---|
| 206 | + seq_printf(m, ",flock=%s", p); |
|---|
| 249 | 207 | |
|---|
| 250 | | - _leave(" = 0"); |
|---|
| 251 | 208 | return 0; |
|---|
| 252 | 209 | } |
|---|
| 253 | 210 | |
|---|
| 254 | 211 | /* |
|---|
| 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: |
|---|
| 212 | + * Parse the source name to get cell name, volume name, volume type and R/W |
|---|
| 213 | + * selector. |
|---|
| 214 | + * |
|---|
| 215 | + * This can be one of the following: |
|---|
| 258 | 216 | * "%[cell:]volume[.]" R/W volume |
|---|
| 259 | | - * "#[cell:]volume[.]" R/O or R/W volume (rwpath=0), |
|---|
| 260 | | - * or R/W (rwpath=1) volume |
|---|
| 217 | + * "#[cell:]volume[.]" R/O or R/W volume (R/O parent), |
|---|
| 218 | + * or R/W (R/W parent) volume |
|---|
| 261 | 219 | * "%[cell:]volume.readonly" R/O volume |
|---|
| 262 | 220 | * "#[cell:]volume.readonly" R/O volume |
|---|
| 263 | 221 | * "%[cell:]volume.backup" Backup volume |
|---|
| 264 | 222 | * "#[cell:]volume.backup" Backup volume |
|---|
| 265 | 223 | */ |
|---|
| 266 | | -static int afs_parse_device_name(struct afs_mount_params *params, |
|---|
| 267 | | - const char *name) |
|---|
| 224 | +static int afs_parse_source(struct fs_context *fc, struct fs_parameter *param) |
|---|
| 268 | 225 | { |
|---|
| 226 | + struct afs_fs_context *ctx = fc->fs_private; |
|---|
| 269 | 227 | struct afs_cell *cell; |
|---|
| 270 | | - const char *cellname, *suffix; |
|---|
| 228 | + const char *cellname, *suffix, *name = param->string; |
|---|
| 271 | 229 | int cellnamesz; |
|---|
| 272 | 230 | |
|---|
| 273 | 231 | _enter(",%s", name); |
|---|
| 232 | + |
|---|
| 233 | + if (fc->source) |
|---|
| 234 | + return invalf(fc, "kAFS: Multiple sources not supported"); |
|---|
| 274 | 235 | |
|---|
| 275 | 236 | if (!name) { |
|---|
| 276 | 237 | printk(KERN_ERR "kAFS: no volume name specified\n"); |
|---|
| .. | .. |
|---|
| 278 | 239 | } |
|---|
| 279 | 240 | |
|---|
| 280 | 241 | if ((name[0] != '%' && name[0] != '#') || !name[1]) { |
|---|
| 242 | + /* To use dynroot, we don't want to have to provide a source */ |
|---|
| 243 | + if (strcmp(name, "none") == 0) { |
|---|
| 244 | + ctx->no_cell = true; |
|---|
| 245 | + return 0; |
|---|
| 246 | + } |
|---|
| 281 | 247 | printk(KERN_ERR "kAFS: unparsable volume name\n"); |
|---|
| 282 | 248 | return -EINVAL; |
|---|
| 283 | 249 | } |
|---|
| 284 | 250 | |
|---|
| 285 | 251 | /* determine the type of volume we're looking for */ |
|---|
| 286 | | - params->type = AFSVL_ROVOL; |
|---|
| 287 | | - params->force = false; |
|---|
| 288 | | - if (params->rwpath || name[0] == '%') { |
|---|
| 289 | | - params->type = AFSVL_RWVOL; |
|---|
| 290 | | - params->force = true; |
|---|
| 252 | + if (name[0] == '%') { |
|---|
| 253 | + ctx->type = AFSVL_RWVOL; |
|---|
| 254 | + ctx->force = true; |
|---|
| 291 | 255 | } |
|---|
| 292 | 256 | name++; |
|---|
| 293 | 257 | |
|---|
| 294 | 258 | /* split the cell name out if there is one */ |
|---|
| 295 | | - params->volname = strchr(name, ':'); |
|---|
| 296 | | - if (params->volname) { |
|---|
| 259 | + ctx->volname = strchr(name, ':'); |
|---|
| 260 | + if (ctx->volname) { |
|---|
| 297 | 261 | cellname = name; |
|---|
| 298 | | - cellnamesz = params->volname - name; |
|---|
| 299 | | - params->volname++; |
|---|
| 262 | + cellnamesz = ctx->volname - name; |
|---|
| 263 | + ctx->volname++; |
|---|
| 300 | 264 | } else { |
|---|
| 301 | | - params->volname = name; |
|---|
| 265 | + ctx->volname = name; |
|---|
| 302 | 266 | cellname = NULL; |
|---|
| 303 | 267 | cellnamesz = 0; |
|---|
| 304 | 268 | } |
|---|
| 305 | 269 | |
|---|
| 306 | 270 | /* the volume type is further affected by a possible suffix */ |
|---|
| 307 | | - suffix = strrchr(params->volname, '.'); |
|---|
| 271 | + suffix = strrchr(ctx->volname, '.'); |
|---|
| 308 | 272 | if (suffix) { |
|---|
| 309 | 273 | if (strcmp(suffix, ".readonly") == 0) { |
|---|
| 310 | | - params->type = AFSVL_ROVOL; |
|---|
| 311 | | - params->force = true; |
|---|
| 274 | + ctx->type = AFSVL_ROVOL; |
|---|
| 275 | + ctx->force = true; |
|---|
| 312 | 276 | } else if (strcmp(suffix, ".backup") == 0) { |
|---|
| 313 | | - params->type = AFSVL_BACKVOL; |
|---|
| 314 | | - params->force = true; |
|---|
| 277 | + ctx->type = AFSVL_BACKVOL; |
|---|
| 278 | + ctx->force = true; |
|---|
| 315 | 279 | } else if (suffix[1] == 0) { |
|---|
| 316 | 280 | } else { |
|---|
| 317 | 281 | suffix = NULL; |
|---|
| 318 | 282 | } |
|---|
| 319 | 283 | } |
|---|
| 320 | 284 | |
|---|
| 321 | | - params->volnamesz = suffix ? |
|---|
| 322 | | - suffix - params->volname : strlen(params->volname); |
|---|
| 285 | + ctx->volnamesz = suffix ? |
|---|
| 286 | + suffix - ctx->volname : strlen(ctx->volname); |
|---|
| 323 | 287 | |
|---|
| 324 | 288 | _debug("cell %*.*s [%p]", |
|---|
| 325 | | - cellnamesz, cellnamesz, cellname ?: "", params->cell); |
|---|
| 289 | + cellnamesz, cellnamesz, cellname ?: "", ctx->cell); |
|---|
| 326 | 290 | |
|---|
| 327 | 291 | /* lookup the cell record */ |
|---|
| 328 | | - if (cellname || !params->cell) { |
|---|
| 329 | | - cell = afs_lookup_cell(params->net, cellname, cellnamesz, |
|---|
| 292 | + if (cellname) { |
|---|
| 293 | + cell = afs_lookup_cell(ctx->net, cellname, cellnamesz, |
|---|
| 330 | 294 | NULL, false); |
|---|
| 331 | 295 | if (IS_ERR(cell)) { |
|---|
| 332 | | - printk(KERN_ERR "kAFS: unable to lookup cell '%*.*s'\n", |
|---|
| 296 | + pr_err("kAFS: unable to lookup cell '%*.*s'\n", |
|---|
| 333 | 297 | cellnamesz, cellnamesz, cellname ?: ""); |
|---|
| 334 | 298 | return PTR_ERR(cell); |
|---|
| 335 | 299 | } |
|---|
| 336 | | - afs_put_cell(params->net, params->cell); |
|---|
| 337 | | - params->cell = cell; |
|---|
| 300 | + afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_parse); |
|---|
| 301 | + afs_see_cell(cell, afs_cell_trace_see_source); |
|---|
| 302 | + ctx->cell = cell; |
|---|
| 338 | 303 | } |
|---|
| 339 | 304 | |
|---|
| 340 | 305 | _debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s", |
|---|
| 341 | | - params->cell->name, params->cell, |
|---|
| 342 | | - params->volnamesz, params->volnamesz, params->volname, |
|---|
| 343 | | - suffix ?: "-", params->type, params->force ? " FORCE" : ""); |
|---|
| 306 | + ctx->cell->name, ctx->cell, |
|---|
| 307 | + ctx->volnamesz, ctx->volnamesz, ctx->volname, |
|---|
| 308 | + suffix ?: "-", ctx->type, ctx->force ? " FORCE" : ""); |
|---|
| 309 | + |
|---|
| 310 | + fc->source = param->string; |
|---|
| 311 | + param->string = NULL; |
|---|
| 312 | + return 0; |
|---|
| 313 | +} |
|---|
| 314 | + |
|---|
| 315 | +/* |
|---|
| 316 | + * Parse a single mount parameter. |
|---|
| 317 | + */ |
|---|
| 318 | +static int afs_parse_param(struct fs_context *fc, struct fs_parameter *param) |
|---|
| 319 | +{ |
|---|
| 320 | + struct fs_parse_result result; |
|---|
| 321 | + struct afs_fs_context *ctx = fc->fs_private; |
|---|
| 322 | + int opt; |
|---|
| 323 | + |
|---|
| 324 | + opt = fs_parse(fc, afs_fs_parameters, param, &result); |
|---|
| 325 | + if (opt < 0) |
|---|
| 326 | + return opt; |
|---|
| 327 | + |
|---|
| 328 | + switch (opt) { |
|---|
| 329 | + case Opt_source: |
|---|
| 330 | + return afs_parse_source(fc, param); |
|---|
| 331 | + |
|---|
| 332 | + case Opt_autocell: |
|---|
| 333 | + ctx->autocell = true; |
|---|
| 334 | + break; |
|---|
| 335 | + |
|---|
| 336 | + case Opt_dyn: |
|---|
| 337 | + ctx->dyn_root = true; |
|---|
| 338 | + break; |
|---|
| 339 | + |
|---|
| 340 | + case Opt_flock: |
|---|
| 341 | + ctx->flock_mode = result.uint_32; |
|---|
| 342 | + break; |
|---|
| 343 | + |
|---|
| 344 | + default: |
|---|
| 345 | + return -EINVAL; |
|---|
| 346 | + } |
|---|
| 347 | + |
|---|
| 348 | + _leave(" = 0"); |
|---|
| 349 | + return 0; |
|---|
| 350 | +} |
|---|
| 351 | + |
|---|
| 352 | +/* |
|---|
| 353 | + * Validate the options, get the cell key and look up the volume. |
|---|
| 354 | + */ |
|---|
| 355 | +static int afs_validate_fc(struct fs_context *fc) |
|---|
| 356 | +{ |
|---|
| 357 | + struct afs_fs_context *ctx = fc->fs_private; |
|---|
| 358 | + struct afs_volume *volume; |
|---|
| 359 | + struct afs_cell *cell; |
|---|
| 360 | + struct key *key; |
|---|
| 361 | + int ret; |
|---|
| 362 | + |
|---|
| 363 | + if (!ctx->dyn_root) { |
|---|
| 364 | + if (ctx->no_cell) { |
|---|
| 365 | + pr_warn("kAFS: Can only specify source 'none' with -o dyn\n"); |
|---|
| 366 | + return -EINVAL; |
|---|
| 367 | + } |
|---|
| 368 | + |
|---|
| 369 | + if (!ctx->cell) { |
|---|
| 370 | + pr_warn("kAFS: No cell specified\n"); |
|---|
| 371 | + return -EDESTADDRREQ; |
|---|
| 372 | + } |
|---|
| 373 | + |
|---|
| 374 | + reget_key: |
|---|
| 375 | + /* We try to do the mount securely. */ |
|---|
| 376 | + key = afs_request_key(ctx->cell); |
|---|
| 377 | + if (IS_ERR(key)) |
|---|
| 378 | + return PTR_ERR(key); |
|---|
| 379 | + |
|---|
| 380 | + ctx->key = key; |
|---|
| 381 | + |
|---|
| 382 | + if (ctx->volume) { |
|---|
| 383 | + afs_put_volume(ctx->net, ctx->volume, |
|---|
| 384 | + afs_volume_trace_put_validate_fc); |
|---|
| 385 | + ctx->volume = NULL; |
|---|
| 386 | + } |
|---|
| 387 | + |
|---|
| 388 | + if (test_bit(AFS_CELL_FL_CHECK_ALIAS, &ctx->cell->flags)) { |
|---|
| 389 | + ret = afs_cell_detect_alias(ctx->cell, key); |
|---|
| 390 | + if (ret < 0) |
|---|
| 391 | + return ret; |
|---|
| 392 | + if (ret == 1) { |
|---|
| 393 | + _debug("switch to alias"); |
|---|
| 394 | + key_put(ctx->key); |
|---|
| 395 | + ctx->key = NULL; |
|---|
| 396 | + cell = afs_use_cell(ctx->cell->alias_of, |
|---|
| 397 | + afs_cell_trace_use_fc_alias); |
|---|
| 398 | + afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_fc); |
|---|
| 399 | + ctx->cell = cell; |
|---|
| 400 | + goto reget_key; |
|---|
| 401 | + } |
|---|
| 402 | + } |
|---|
| 403 | + |
|---|
| 404 | + volume = afs_create_volume(ctx); |
|---|
| 405 | + if (IS_ERR(volume)) |
|---|
| 406 | + return PTR_ERR(volume); |
|---|
| 407 | + |
|---|
| 408 | + ctx->volume = volume; |
|---|
| 409 | + } |
|---|
| 344 | 410 | |
|---|
| 345 | 411 | return 0; |
|---|
| 346 | 412 | } |
|---|
| .. | .. |
|---|
| 348 | 414 | /* |
|---|
| 349 | 415 | * check a superblock to see if it's the one we're looking for |
|---|
| 350 | 416 | */ |
|---|
| 351 | | -static int afs_test_super(struct super_block *sb, void *data) |
|---|
| 417 | +static int afs_test_super(struct super_block *sb, struct fs_context *fc) |
|---|
| 352 | 418 | { |
|---|
| 353 | | - struct afs_super_info *as1 = data; |
|---|
| 419 | + struct afs_fs_context *ctx = fc->fs_private; |
|---|
| 354 | 420 | struct afs_super_info *as = AFS_FS_S(sb); |
|---|
| 355 | 421 | |
|---|
| 356 | | - return (as->net_ns == as1->net_ns && |
|---|
| 422 | + return (as->net_ns == fc->net_ns && |
|---|
| 357 | 423 | as->volume && |
|---|
| 358 | | - as->volume->vid == as1->volume->vid && |
|---|
| 359 | | - as->cell == as1->cell && |
|---|
| 424 | + as->volume->vid == ctx->volume->vid && |
|---|
| 425 | + as->cell == ctx->cell && |
|---|
| 360 | 426 | !as->dyn_root); |
|---|
| 361 | 427 | } |
|---|
| 362 | 428 | |
|---|
| 363 | | -static int afs_dynroot_test_super(struct super_block *sb, void *data) |
|---|
| 429 | +static int afs_dynroot_test_super(struct super_block *sb, struct fs_context *fc) |
|---|
| 364 | 430 | { |
|---|
| 365 | | - struct afs_super_info *as1 = data; |
|---|
| 366 | 431 | struct afs_super_info *as = AFS_FS_S(sb); |
|---|
| 367 | 432 | |
|---|
| 368 | | - return (as->net_ns == as1->net_ns && |
|---|
| 433 | + return (as->net_ns == fc->net_ns && |
|---|
| 369 | 434 | as->dyn_root); |
|---|
| 370 | 435 | } |
|---|
| 371 | 436 | |
|---|
| 372 | | -static int afs_set_super(struct super_block *sb, void *data) |
|---|
| 437 | +static int afs_set_super(struct super_block *sb, struct fs_context *fc) |
|---|
| 373 | 438 | { |
|---|
| 374 | | - struct afs_super_info *as = data; |
|---|
| 375 | | - |
|---|
| 376 | | - sb->s_fs_info = as; |
|---|
| 377 | 439 | return set_anon_super(sb, NULL); |
|---|
| 378 | 440 | } |
|---|
| 379 | 441 | |
|---|
| 380 | 442 | /* |
|---|
| 381 | 443 | * fill in the superblock |
|---|
| 382 | 444 | */ |
|---|
| 383 | | -static int afs_fill_super(struct super_block *sb, |
|---|
| 384 | | - struct afs_mount_params *params) |
|---|
| 445 | +static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx) |
|---|
| 385 | 446 | { |
|---|
| 386 | 447 | struct afs_super_info *as = AFS_FS_S(sb); |
|---|
| 387 | | - struct afs_fid fid; |
|---|
| 388 | 448 | struct inode *inode = NULL; |
|---|
| 389 | 449 | int ret; |
|---|
| 390 | 450 | |
|---|
| .. | .. |
|---|
| 401 | 461 | ret = super_setup_bdi(sb); |
|---|
| 402 | 462 | if (ret) |
|---|
| 403 | 463 | return ret; |
|---|
| 404 | | - sb->s_bdi->ra_pages = VM_MAX_READAHEAD * 1024 / PAGE_SIZE; |
|---|
| 405 | 464 | |
|---|
| 406 | 465 | /* allocate the root inode and dentry */ |
|---|
| 407 | 466 | if (as->dyn_root) { |
|---|
| 408 | 467 | inode = afs_iget_pseudo_dir(sb, true); |
|---|
| 409 | 468 | } else { |
|---|
| 410 | | - sprintf(sb->s_id, "%u", as->volume->vid); |
|---|
| 469 | + sprintf(sb->s_id, "%llu", as->volume->vid); |
|---|
| 411 | 470 | afs_activate_volume(as->volume); |
|---|
| 412 | | - fid.vid = as->volume->vid; |
|---|
| 413 | | - fid.vnode = 1; |
|---|
| 414 | | - fid.unique = 1; |
|---|
| 415 | | - inode = afs_iget(sb, params->key, &fid, NULL, NULL, NULL); |
|---|
| 471 | + inode = afs_root_iget(sb, ctx->key); |
|---|
| 416 | 472 | } |
|---|
| 417 | 473 | |
|---|
| 418 | 474 | if (IS_ERR(inode)) |
|---|
| 419 | 475 | return PTR_ERR(inode); |
|---|
| 420 | 476 | |
|---|
| 421 | | - if (params->autocell || params->dyn_root) |
|---|
| 477 | + if (ctx->autocell || as->dyn_root) |
|---|
| 422 | 478 | set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); |
|---|
| 423 | 479 | |
|---|
| 424 | 480 | ret = -ENOMEM; |
|---|
| .. | .. |
|---|
| 433 | 489 | goto error; |
|---|
| 434 | 490 | } else { |
|---|
| 435 | 491 | sb->s_d_op = &afs_fs_dentry_operations; |
|---|
| 492 | + rcu_assign_pointer(as->volume->sb, sb); |
|---|
| 436 | 493 | } |
|---|
| 437 | 494 | |
|---|
| 438 | 495 | _leave(" = 0"); |
|---|
| .. | .. |
|---|
| 443 | 500 | return ret; |
|---|
| 444 | 501 | } |
|---|
| 445 | 502 | |
|---|
| 446 | | -static struct afs_super_info *afs_alloc_sbi(struct afs_mount_params *params) |
|---|
| 503 | +static struct afs_super_info *afs_alloc_sbi(struct fs_context *fc) |
|---|
| 447 | 504 | { |
|---|
| 505 | + struct afs_fs_context *ctx = fc->fs_private; |
|---|
| 448 | 506 | struct afs_super_info *as; |
|---|
| 449 | 507 | |
|---|
| 450 | 508 | as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); |
|---|
| 451 | 509 | if (as) { |
|---|
| 452 | | - as->net_ns = get_net(params->net_ns); |
|---|
| 453 | | - if (params->dyn_root) |
|---|
| 510 | + as->net_ns = get_net(fc->net_ns); |
|---|
| 511 | + as->flock_mode = ctx->flock_mode; |
|---|
| 512 | + if (ctx->dyn_root) { |
|---|
| 454 | 513 | as->dyn_root = true; |
|---|
| 455 | | - else |
|---|
| 456 | | - as->cell = afs_get_cell(params->cell); |
|---|
| 514 | + } else { |
|---|
| 515 | + as->cell = afs_use_cell(ctx->cell, afs_cell_trace_use_sbi); |
|---|
| 516 | + as->volume = afs_get_volume(ctx->volume, |
|---|
| 517 | + afs_volume_trace_get_alloc_sbi); |
|---|
| 518 | + } |
|---|
| 457 | 519 | } |
|---|
| 458 | 520 | return as; |
|---|
| 459 | 521 | } |
|---|
| .. | .. |
|---|
| 461 | 523 | static void afs_destroy_sbi(struct afs_super_info *as) |
|---|
| 462 | 524 | { |
|---|
| 463 | 525 | if (as) { |
|---|
| 464 | | - afs_put_volume(as->cell, as->volume); |
|---|
| 465 | | - afs_put_cell(afs_net(as->net_ns), as->cell); |
|---|
| 526 | + struct afs_net *net = afs_net(as->net_ns); |
|---|
| 527 | + afs_put_volume(net, as->volume, afs_volume_trace_put_destroy_sbi); |
|---|
| 528 | + afs_unuse_cell(net, as->cell, afs_cell_trace_unuse_sbi); |
|---|
| 466 | 529 | put_net(as->net_ns); |
|---|
| 467 | 530 | kfree(as); |
|---|
| 468 | 531 | } |
|---|
| .. | .. |
|---|
| 471 | 534 | static void afs_kill_super(struct super_block *sb) |
|---|
| 472 | 535 | { |
|---|
| 473 | 536 | struct afs_super_info *as = AFS_FS_S(sb); |
|---|
| 474 | | - struct afs_net *net = afs_net(as->net_ns); |
|---|
| 475 | 537 | |
|---|
| 476 | 538 | if (as->dyn_root) |
|---|
| 477 | 539 | afs_dynroot_depopulate(sb); |
|---|
| 478 | | - |
|---|
| 540 | + |
|---|
| 479 | 541 | /* Clear the callback interests (which will do ilookup5) before |
|---|
| 480 | 542 | * deactivating the superblock. |
|---|
| 481 | 543 | */ |
|---|
| 482 | 544 | if (as->volume) |
|---|
| 483 | | - afs_clear_callback_interests(net, as->volume->servers); |
|---|
| 545 | + rcu_assign_pointer(as->volume->sb, NULL); |
|---|
| 484 | 546 | kill_anon_super(sb); |
|---|
| 485 | 547 | if (as->volume) |
|---|
| 486 | 548 | afs_deactivate_volume(as->volume); |
|---|
| .. | .. |
|---|
| 488 | 550 | } |
|---|
| 489 | 551 | |
|---|
| 490 | 552 | /* |
|---|
| 491 | | - * get an AFS superblock |
|---|
| 553 | + * Get an AFS superblock and root directory. |
|---|
| 492 | 554 | */ |
|---|
| 493 | | -static struct dentry *afs_mount(struct file_system_type *fs_type, |
|---|
| 494 | | - int flags, const char *dev_name, void *options) |
|---|
| 555 | +static int afs_get_tree(struct fs_context *fc) |
|---|
| 495 | 556 | { |
|---|
| 496 | | - struct afs_mount_params params; |
|---|
| 557 | + struct afs_fs_context *ctx = fc->fs_private; |
|---|
| 497 | 558 | struct super_block *sb; |
|---|
| 498 | | - struct afs_volume *candidate; |
|---|
| 499 | | - struct key *key; |
|---|
| 500 | 559 | struct afs_super_info *as; |
|---|
| 501 | 560 | int ret; |
|---|
| 502 | 561 | |
|---|
| 503 | | - _enter(",,%s,%p", dev_name, options); |
|---|
| 504 | | - |
|---|
| 505 | | - memset(¶ms, 0, sizeof(params)); |
|---|
| 506 | | - |
|---|
| 507 | | - ret = -EINVAL; |
|---|
| 508 | | - if (current->nsproxy->net_ns != &init_net) |
|---|
| 562 | + ret = afs_validate_fc(fc); |
|---|
| 563 | + if (ret) |
|---|
| 509 | 564 | 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 | 565 | |
|---|
| 520 | | - if (!params.dyn_root) { |
|---|
| 521 | | - ret = afs_parse_device_name(¶ms, dev_name); |
|---|
| 522 | | - if (ret < 0) |
|---|
| 523 | | - goto error; |
|---|
| 524 | | - |
|---|
| 525 | | - /* try and do the mount securely */ |
|---|
| 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 | | - } |
|---|
| 566 | + _enter(""); |
|---|
| 534 | 567 | |
|---|
| 535 | 568 | /* allocate a superblock info record */ |
|---|
| 536 | 569 | ret = -ENOMEM; |
|---|
| 537 | | - as = afs_alloc_sbi(¶ms); |
|---|
| 570 | + as = afs_alloc_sbi(fc); |
|---|
| 538 | 571 | if (!as) |
|---|
| 539 | | - goto error_key; |
|---|
| 540 | | - |
|---|
| 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 | | - } |
|---|
| 572 | + goto error; |
|---|
| 573 | + fc->s_fs_info = as; |
|---|
| 555 | 574 | |
|---|
| 556 | 575 | /* allocate a deviceless superblock */ |
|---|
| 557 | | - sb = sget(fs_type, |
|---|
| 558 | | - as->dyn_root ? afs_dynroot_test_super : afs_test_super, |
|---|
| 559 | | - afs_set_super, flags, as); |
|---|
| 576 | + sb = sget_fc(fc, |
|---|
| 577 | + as->dyn_root ? afs_dynroot_test_super : afs_test_super, |
|---|
| 578 | + afs_set_super); |
|---|
| 560 | 579 | if (IS_ERR(sb)) { |
|---|
| 561 | 580 | ret = PTR_ERR(sb); |
|---|
| 562 | | - goto error_as; |
|---|
| 581 | + goto error; |
|---|
| 563 | 582 | } |
|---|
| 564 | 583 | |
|---|
| 565 | 584 | if (!sb->s_root) { |
|---|
| 566 | 585 | /* initial superblock/root creation */ |
|---|
| 567 | 586 | _debug("create"); |
|---|
| 568 | | - ret = afs_fill_super(sb, ¶ms); |
|---|
| 587 | + ret = afs_fill_super(sb, ctx); |
|---|
| 569 | 588 | if (ret < 0) |
|---|
| 570 | 589 | goto error_sb; |
|---|
| 571 | | - as = NULL; |
|---|
| 572 | 590 | sb->s_flags |= SB_ACTIVE; |
|---|
| 573 | 591 | } else { |
|---|
| 574 | 592 | _debug("reuse"); |
|---|
| 575 | 593 | ASSERTCMP(sb->s_flags, &, SB_ACTIVE); |
|---|
| 576 | | - afs_destroy_sbi(as); |
|---|
| 577 | | - as = NULL; |
|---|
| 578 | 594 | } |
|---|
| 579 | 595 | |
|---|
| 580 | | - afs_put_cell(params.net, params.cell); |
|---|
| 581 | | - key_put(params.key); |
|---|
| 596 | + fc->root = dget(sb->s_root); |
|---|
| 597 | + trace_afs_get_tree(as->cell, as->volume); |
|---|
| 582 | 598 | _leave(" = 0 [%p]", sb); |
|---|
| 583 | | - return dget(sb->s_root); |
|---|
| 599 | + return 0; |
|---|
| 584 | 600 | |
|---|
| 585 | 601 | error_sb: |
|---|
| 586 | 602 | 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 | 603 | error: |
|---|
| 593 | | - afs_put_cell(params.net, params.cell); |
|---|
| 594 | 604 | _leave(" = %d", ret); |
|---|
| 595 | | - return ERR_PTR(ret); |
|---|
| 605 | + return ret; |
|---|
| 606 | +} |
|---|
| 607 | + |
|---|
| 608 | +static void afs_free_fc(struct fs_context *fc) |
|---|
| 609 | +{ |
|---|
| 610 | + struct afs_fs_context *ctx = fc->fs_private; |
|---|
| 611 | + |
|---|
| 612 | + afs_destroy_sbi(fc->s_fs_info); |
|---|
| 613 | + afs_put_volume(ctx->net, ctx->volume, afs_volume_trace_put_free_fc); |
|---|
| 614 | + afs_unuse_cell(ctx->net, ctx->cell, afs_cell_trace_unuse_fc); |
|---|
| 615 | + key_put(ctx->key); |
|---|
| 616 | + kfree(ctx); |
|---|
| 617 | +} |
|---|
| 618 | + |
|---|
| 619 | +static const struct fs_context_operations afs_context_ops = { |
|---|
| 620 | + .free = afs_free_fc, |
|---|
| 621 | + .parse_param = afs_parse_param, |
|---|
| 622 | + .get_tree = afs_get_tree, |
|---|
| 623 | +}; |
|---|
| 624 | + |
|---|
| 625 | +/* |
|---|
| 626 | + * Set up the filesystem mount context. |
|---|
| 627 | + */ |
|---|
| 628 | +static int afs_init_fs_context(struct fs_context *fc) |
|---|
| 629 | +{ |
|---|
| 630 | + struct afs_fs_context *ctx; |
|---|
| 631 | + struct afs_cell *cell; |
|---|
| 632 | + |
|---|
| 633 | + ctx = kzalloc(sizeof(struct afs_fs_context), GFP_KERNEL); |
|---|
| 634 | + if (!ctx) |
|---|
| 635 | + return -ENOMEM; |
|---|
| 636 | + |
|---|
| 637 | + ctx->type = AFSVL_ROVOL; |
|---|
| 638 | + ctx->net = afs_net(fc->net_ns); |
|---|
| 639 | + |
|---|
| 640 | + /* Default to the workstation cell. */ |
|---|
| 641 | + cell = afs_find_cell(ctx->net, NULL, 0, afs_cell_trace_use_fc); |
|---|
| 642 | + if (IS_ERR(cell)) |
|---|
| 643 | + cell = NULL; |
|---|
| 644 | + ctx->cell = cell; |
|---|
| 645 | + |
|---|
| 646 | + fc->fs_private = ctx; |
|---|
| 647 | + fc->ops = &afs_context_ops; |
|---|
| 648 | + return 0; |
|---|
| 596 | 649 | } |
|---|
| 597 | 650 | |
|---|
| 598 | 651 | /* |
|---|
| .. | .. |
|---|
| 637 | 690 | vnode->volume = NULL; |
|---|
| 638 | 691 | vnode->lock_key = NULL; |
|---|
| 639 | 692 | vnode->permit_cache = NULL; |
|---|
| 640 | | - vnode->cb_interest = NULL; |
|---|
| 641 | 693 | #ifdef CONFIG_AFS_FSCACHE |
|---|
| 642 | 694 | vnode->cache = NULL; |
|---|
| 643 | 695 | #endif |
|---|
| 644 | 696 | |
|---|
| 645 | 697 | vnode->flags = 1 << AFS_VNODE_UNSET; |
|---|
| 646 | | - vnode->cb_type = 0; |
|---|
| 647 | 698 | vnode->lock_state = AFS_VNODE_LOCK_NONE; |
|---|
| 699 | + |
|---|
| 700 | + init_rwsem(&vnode->rmdir_lock); |
|---|
| 648 | 701 | |
|---|
| 649 | 702 | _leave(" = %p", &vnode->vfs_inode); |
|---|
| 650 | 703 | return &vnode->vfs_inode; |
|---|
| 651 | 704 | } |
|---|
| 652 | 705 | |
|---|
| 653 | | -static void afs_i_callback(struct rcu_head *head) |
|---|
| 706 | +static void afs_free_inode(struct inode *inode) |
|---|
| 654 | 707 | { |
|---|
| 655 | | - struct inode *inode = container_of(head, struct inode, i_rcu); |
|---|
| 656 | | - struct afs_vnode *vnode = AFS_FS_I(inode); |
|---|
| 657 | | - kmem_cache_free(afs_inode_cachep, vnode); |
|---|
| 708 | + kmem_cache_free(afs_inode_cachep, AFS_FS_I(inode)); |
|---|
| 658 | 709 | } |
|---|
| 659 | 710 | |
|---|
| 660 | 711 | /* |
|---|
| .. | .. |
|---|
| 664 | 715 | { |
|---|
| 665 | 716 | struct afs_vnode *vnode = AFS_FS_I(inode); |
|---|
| 666 | 717 | |
|---|
| 667 | | - _enter("%p{%x:%u}", inode, vnode->fid.vid, vnode->fid.vnode); |
|---|
| 718 | + _enter("%p{%llx:%llu}", inode, vnode->fid.vid, vnode->fid.vnode); |
|---|
| 668 | 719 | |
|---|
| 669 | 720 | _debug("DESTROY INODE %p", inode); |
|---|
| 670 | 721 | |
|---|
| 671 | | - ASSERTCMP(vnode->cb_interest, ==, NULL); |
|---|
| 672 | | - |
|---|
| 673 | | - call_rcu(&inode->i_rcu, afs_i_callback); |
|---|
| 674 | 722 | atomic_dec(&afs_count_active_inodes); |
|---|
| 675 | 723 | } |
|---|
| 724 | + |
|---|
| 725 | +static void afs_get_volume_status_success(struct afs_operation *op) |
|---|
| 726 | +{ |
|---|
| 727 | + struct afs_volume_status *vs = &op->volstatus.vs; |
|---|
| 728 | + struct kstatfs *buf = op->volstatus.buf; |
|---|
| 729 | + |
|---|
| 730 | + if (vs->max_quota == 0) |
|---|
| 731 | + buf->f_blocks = vs->part_max_blocks; |
|---|
| 732 | + else |
|---|
| 733 | + buf->f_blocks = vs->max_quota; |
|---|
| 734 | + |
|---|
| 735 | + if (buf->f_blocks > vs->blocks_in_use) |
|---|
| 736 | + buf->f_bavail = buf->f_bfree = |
|---|
| 737 | + buf->f_blocks - vs->blocks_in_use; |
|---|
| 738 | +} |
|---|
| 739 | + |
|---|
| 740 | +static const struct afs_operation_ops afs_get_volume_status_operation = { |
|---|
| 741 | + .issue_afs_rpc = afs_fs_get_volume_status, |
|---|
| 742 | + .issue_yfs_rpc = yfs_fs_get_volume_status, |
|---|
| 743 | + .success = afs_get_volume_status_success, |
|---|
| 744 | +}; |
|---|
| 676 | 745 | |
|---|
| 677 | 746 | /* |
|---|
| 678 | 747 | * return information about an AFS volume |
|---|
| .. | .. |
|---|
| 680 | 749 | static int afs_statfs(struct dentry *dentry, struct kstatfs *buf) |
|---|
| 681 | 750 | { |
|---|
| 682 | 751 | struct afs_super_info *as = AFS_FS_S(dentry->d_sb); |
|---|
| 683 | | - struct afs_fs_cursor fc; |
|---|
| 684 | | - struct afs_volume_status vs; |
|---|
| 752 | + struct afs_operation *op; |
|---|
| 685 | 753 | struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); |
|---|
| 686 | | - struct key *key; |
|---|
| 687 | | - int ret; |
|---|
| 688 | 754 | |
|---|
| 689 | 755 | buf->f_type = dentry->d_sb->s_magic; |
|---|
| 690 | 756 | buf->f_bsize = AFS_BLOCK_SIZE; |
|---|
| .. | .. |
|---|
| 697 | 763 | return 0; |
|---|
| 698 | 764 | } |
|---|
| 699 | 765 | |
|---|
| 700 | | - key = afs_request_key(vnode->volume->cell); |
|---|
| 701 | | - if (IS_ERR(key)) |
|---|
| 702 | | - return PTR_ERR(key); |
|---|
| 766 | + op = afs_alloc_operation(NULL, as->volume); |
|---|
| 767 | + if (IS_ERR(op)) |
|---|
| 768 | + return PTR_ERR(op); |
|---|
| 703 | 769 | |
|---|
| 704 | | - ret = -ERESTARTSYS; |
|---|
| 705 | | - if (afs_begin_vnode_operation(&fc, vnode, key)) { |
|---|
| 706 | | - fc.flags |= AFS_FS_CURSOR_NO_VSLEEP; |
|---|
| 707 | | - while (afs_select_fileserver(&fc)) { |
|---|
| 708 | | - fc.cb_break = afs_calc_vnode_cb_break(vnode); |
|---|
| 709 | | - afs_fs_get_volume_status(&fc, &vs); |
|---|
| 710 | | - } |
|---|
| 711 | | - |
|---|
| 712 | | - afs_check_for_remote_deletion(&fc, fc.vnode); |
|---|
| 713 | | - afs_vnode_commit_status(&fc, vnode, fc.cb_break); |
|---|
| 714 | | - ret = afs_end_vnode_operation(&fc); |
|---|
| 715 | | - } |
|---|
| 716 | | - |
|---|
| 717 | | - key_put(key); |
|---|
| 718 | | - |
|---|
| 719 | | - if (ret == 0) { |
|---|
| 720 | | - if (vs.max_quota == 0) |
|---|
| 721 | | - buf->f_blocks = vs.part_max_blocks; |
|---|
| 722 | | - else |
|---|
| 723 | | - buf->f_blocks = vs.max_quota; |
|---|
| 724 | | - buf->f_bavail = buf->f_bfree = buf->f_blocks - vs.blocks_in_use; |
|---|
| 725 | | - } |
|---|
| 726 | | - |
|---|
| 727 | | - return ret; |
|---|
| 770 | + afs_op_set_vnode(op, 0, vnode); |
|---|
| 771 | + op->nr_files = 1; |
|---|
| 772 | + op->volstatus.buf = buf; |
|---|
| 773 | + op->ops = &afs_get_volume_status_operation; |
|---|
| 774 | + return afs_do_sync_operation(op); |
|---|
| 728 | 775 | } |
|---|