aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4recover.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfs4recover.c')
-rw-r--r--fs/nfsd/nfs4recover.c136
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 */
47struct 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 */
47static struct file *rec_file; 57static struct file *rec_file;
48static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; 58static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
59static struct nfsd4_client_tracking_ops *client_tracking_ops;
49 60
50static int 61static int
51nfs4_save_creds(const struct cred **original_creds) 62nfs4_save_creds(const struct cred **original_creds)
@@ -117,7 +128,8 @@ out_no_tfm:
117 return status; 128 return status;
118} 129}
119 130
120void nfsd4_create_clid_dir(struct nfs4_client *clp) 131static void
132nfsd4_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
267void 279static void
268nfsd4_remove_clid_dir(struct nfs4_client *clp) 280nfsd4_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
297static int 308static int
@@ -310,8 +321,9 @@ purge_old(struct dentry *parent, struct dentry *child)
310 return 0; 321 return 0;
311} 322}
312 323
313void 324static void
314nfsd4_recdir_purge_old(void) { 325nfsd4_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
345int 357static int
346nfsd4_recdir_load(void) { 358nfsd4_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
363void 375static int
364nfsd4_init_recdir() 376nfsd4_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
392void 406static int
407nfsd4_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
421static void
393nfsd4_shutdown_recdir(void) 422nfsd4_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
430static void
431nfsd4_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
464static int
465nfsd4_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
480static 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
489int
490nfsd4_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
505void
506nfsd4_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
514void
515nfsd4_client_record_create(struct nfs4_client *clp)
516{
517 if (client_tracking_ops)
518 client_tracking_ops->create(clp);
519}
520
521void
522nfsd4_client_record_remove(struct nfs4_client *clp)
523{
524 if (client_tracking_ops)
525 client_tracking_ops->remove(clp);
526}
527
528int
529nfsd4_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
537void
538nfsd4_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}