.. | .. |
---|
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 | } |
---|