diff options
Diffstat (limited to 'fs/nfsd/nfs4recover.c')
-rw-r--r-- | fs/nfsd/nfs4recover.c | 136 |
1 files changed, 126 insertions, 10 deletions
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 6523809839c3..e616f88b7f19 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
@@ -43,9 +43,20 @@ | |||
43 | 43 | ||
44 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 44 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
45 | 45 | ||
46 | /* Declarations */ | ||
47 | struct nfsd4_client_tracking_ops { | ||
48 | int (*init)(struct net *); | ||
49 | void (*exit)(struct net *); | ||
50 | void (*create)(struct nfs4_client *); | ||
51 | void (*remove)(struct nfs4_client *); | ||
52 | int (*check)(struct nfs4_client *); | ||
53 | void (*grace_done)(struct net *, time_t); | ||
54 | }; | ||
55 | |||
46 | /* Globals */ | 56 | /* Globals */ |
47 | static struct file *rec_file; | 57 | static struct file *rec_file; |
48 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; | 58 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; |
59 | static struct nfsd4_client_tracking_ops *client_tracking_ops; | ||
49 | 60 | ||
50 | static int | 61 | static int |
51 | nfs4_save_creds(const struct cred **original_creds) | 62 | nfs4_save_creds(const struct cred **original_creds) |
@@ -117,7 +128,8 @@ out_no_tfm: | |||
117 | return status; | 128 | return status; |
118 | } | 129 | } |
119 | 130 | ||
120 | void nfsd4_create_clid_dir(struct nfs4_client *clp) | 131 | static void |
132 | nfsd4_create_clid_dir(struct nfs4_client *clp) | ||
121 | { | 133 | { |
122 | const struct cred *original_cred; | 134 | const struct cred *original_cred; |
123 | char *dname = clp->cl_recdir; | 135 | char *dname = clp->cl_recdir; |
@@ -264,7 +276,7 @@ out_unlock: | |||
264 | return status; | 276 | return status; |
265 | } | 277 | } |
266 | 278 | ||
267 | void | 279 | static void |
268 | nfsd4_remove_clid_dir(struct nfs4_client *clp) | 280 | nfsd4_remove_clid_dir(struct nfs4_client *clp) |
269 | { | 281 | { |
270 | const struct cred *original_cred; | 282 | const struct cred *original_cred; |
@@ -291,7 +303,6 @@ out: | |||
291 | if (status) | 303 | if (status) |
292 | printk("NFSD: Failed to remove expired client state directory" | 304 | printk("NFSD: Failed to remove expired client state directory" |
293 | " %.*s\n", HEXDIR_LEN, clp->cl_recdir); | 305 | " %.*s\n", HEXDIR_LEN, clp->cl_recdir); |
294 | return; | ||
295 | } | 306 | } |
296 | 307 | ||
297 | static int | 308 | static int |
@@ -310,8 +321,9 @@ purge_old(struct dentry *parent, struct dentry *child) | |||
310 | return 0; | 321 | return 0; |
311 | } | 322 | } |
312 | 323 | ||
313 | void | 324 | static void |
314 | nfsd4_recdir_purge_old(void) { | 325 | nfsd4_recdir_purge_old(struct net *net, time_t boot_time) |
326 | { | ||
315 | int status; | 327 | int status; |
316 | 328 | ||
317 | if (!rec_file) | 329 | if (!rec_file) |
@@ -342,7 +354,7 @@ load_recdir(struct dentry *parent, struct dentry *child) | |||
342 | return 0; | 354 | return 0; |
343 | } | 355 | } |
344 | 356 | ||
345 | int | 357 | static int |
346 | nfsd4_recdir_load(void) { | 358 | nfsd4_recdir_load(void) { |
347 | int status; | 359 | int status; |
348 | 360 | ||
@@ -360,8 +372,8 @@ nfsd4_recdir_load(void) { | |||
360 | * Hold reference to the recovery directory. | 372 | * Hold reference to the recovery directory. |
361 | */ | 373 | */ |
362 | 374 | ||
363 | void | 375 | static int |
364 | nfsd4_init_recdir() | 376 | nfsd4_init_recdir(void) |
365 | { | 377 | { |
366 | const struct cred *original_cred; | 378 | const struct cred *original_cred; |
367 | int status; | 379 | int status; |
@@ -376,20 +388,37 @@ nfsd4_init_recdir() | |||
376 | printk("NFSD: Unable to change credentials to find recovery" | 388 | printk("NFSD: Unable to change credentials to find recovery" |
377 | " directory: error %d\n", | 389 | " directory: error %d\n", |
378 | status); | 390 | status); |
379 | return; | 391 | return status; |
380 | } | 392 | } |
381 | 393 | ||
382 | rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0); | 394 | rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0); |
383 | if (IS_ERR(rec_file)) { | 395 | if (IS_ERR(rec_file)) { |
384 | printk("NFSD: unable to find recovery directory %s\n", | 396 | printk("NFSD: unable to find recovery directory %s\n", |
385 | user_recovery_dirname); | 397 | user_recovery_dirname); |
398 | status = PTR_ERR(rec_file); | ||
386 | rec_file = NULL; | 399 | rec_file = NULL; |
387 | } | 400 | } |
388 | 401 | ||
389 | nfs4_reset_creds(original_cred); | 402 | nfs4_reset_creds(original_cred); |
403 | return status; | ||
390 | } | 404 | } |
391 | 405 | ||
392 | void | 406 | static int |
407 | nfsd4_load_reboot_recovery_data(struct net *net) | ||
408 | { | ||
409 | int status; | ||
410 | |||
411 | nfs4_lock_state(); | ||
412 | status = nfsd4_init_recdir(); | ||
413 | if (!status) | ||
414 | status = nfsd4_recdir_load(); | ||
415 | nfs4_unlock_state(); | ||
416 | if (status) | ||
417 | printk(KERN_ERR "NFSD: Failure reading reboot recovery data\n"); | ||
418 | return status; | ||
419 | } | ||
420 | |||
421 | static void | ||
393 | nfsd4_shutdown_recdir(void) | 422 | nfsd4_shutdown_recdir(void) |
394 | { | 423 | { |
395 | if (!rec_file) | 424 | if (!rec_file) |
@@ -398,6 +427,13 @@ nfsd4_shutdown_recdir(void) | |||
398 | rec_file = NULL; | 427 | rec_file = NULL; |
399 | } | 428 | } |
400 | 429 | ||
430 | static void | ||
431 | nfsd4_legacy_tracking_exit(struct net *net) | ||
432 | { | ||
433 | nfs4_release_reclaim(); | ||
434 | nfsd4_shutdown_recdir(); | ||
435 | } | ||
436 | |||
401 | /* | 437 | /* |
402 | * Change the NFSv4 recovery directory to recdir. | 438 | * Change the NFSv4 recovery directory to recdir. |
403 | */ | 439 | */ |
@@ -424,3 +460,83 @@ nfs4_recoverydir(void) | |||
424 | { | 460 | { |
425 | return user_recovery_dirname; | 461 | return user_recovery_dirname; |
426 | } | 462 | } |
463 | |||
464 | static int | ||
465 | nfsd4_check_legacy_client(struct nfs4_client *clp) | ||
466 | { | ||
467 | /* did we already find that this client is stable? */ | ||
468 | if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) | ||
469 | return 0; | ||
470 | |||
471 | /* look for it in the reclaim hashtable otherwise */ | ||
472 | if (nfsd4_find_reclaim_client(clp)) { | ||
473 | set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); | ||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | return -ENOENT; | ||
478 | } | ||
479 | |||
480 | static struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = { | ||
481 | .init = nfsd4_load_reboot_recovery_data, | ||
482 | .exit = nfsd4_legacy_tracking_exit, | ||
483 | .create = nfsd4_create_clid_dir, | ||
484 | .remove = nfsd4_remove_clid_dir, | ||
485 | .check = nfsd4_check_legacy_client, | ||
486 | .grace_done = nfsd4_recdir_purge_old, | ||
487 | }; | ||
488 | |||
489 | int | ||
490 | nfsd4_client_tracking_init(struct net *net) | ||
491 | { | ||
492 | int status; | ||
493 | |||
494 | client_tracking_ops = &nfsd4_legacy_tracking_ops; | ||
495 | |||
496 | status = client_tracking_ops->init(net); | ||
497 | if (status) { | ||
498 | printk(KERN_WARNING "NFSD: Unable to initialize client " | ||
499 | "recovery tracking! (%d)\n", status); | ||
500 | client_tracking_ops = NULL; | ||
501 | } | ||
502 | return status; | ||
503 | } | ||
504 | |||
505 | void | ||
506 | nfsd4_client_tracking_exit(struct net *net) | ||
507 | { | ||
508 | if (client_tracking_ops) { | ||
509 | client_tracking_ops->exit(net); | ||
510 | client_tracking_ops = NULL; | ||
511 | } | ||
512 | } | ||
513 | |||
514 | void | ||
515 | nfsd4_client_record_create(struct nfs4_client *clp) | ||
516 | { | ||
517 | if (client_tracking_ops) | ||
518 | client_tracking_ops->create(clp); | ||
519 | } | ||
520 | |||
521 | void | ||
522 | nfsd4_client_record_remove(struct nfs4_client *clp) | ||
523 | { | ||
524 | if (client_tracking_ops) | ||
525 | client_tracking_ops->remove(clp); | ||
526 | } | ||
527 | |||
528 | int | ||
529 | nfsd4_client_record_check(struct nfs4_client *clp) | ||
530 | { | ||
531 | if (client_tracking_ops) | ||
532 | return client_tracking_ops->check(clp); | ||
533 | |||
534 | return -EOPNOTSUPP; | ||
535 | } | ||
536 | |||
537 | void | ||
538 | nfsd4_record_grace_done(struct net *net, time_t boot_time) | ||
539 | { | ||
540 | if (client_tracking_ops) | ||
541 | client_tracking_ops->grace_done(net, boot_time); | ||
542 | } | ||