aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4recover.c
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2012-03-21 16:42:43 -0400
committerJ. Bruce Fields <bfields@redhat.com>2012-03-26 11:49:47 -0400
commit2a4317c55438d8589a015d42912454ede12031f0 (patch)
treecfcc8d551c750bd46ea86fb5fd4ed5d305063615 /fs/nfsd/nfs4recover.c
parenta52d726bbd928164609e6abc4dc967e819dbf09c (diff)
nfsd: add nfsd4_client_tracking_ops struct and a way to set it
Abstract out the mechanism that we use to track clients into a set of client name tracking functions. This gives us a mechanism to plug in a new set of client tracking functions without disturbing the callers. It also gives us a way to decide on what tracking scheme to use at runtime. For now, this just looks like pointless abstraction, but later we'll add a new alternate scheme for tracking clients on stable storage. Note too that this patch anticipates the eventual containerization of this code by passing in struct net pointers in places. No attempt is made to containerize the legacy client tracker however. Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
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}