aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
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
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')
-rw-r--r--fs/nfsd/nfs4recover.c136
-rw-r--r--fs/nfsd/nfs4state.c63
-rw-r--r--fs/nfsd/state.h15
3 files changed, 156 insertions, 58 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}
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 8be612abd0d7..1841f8bf845e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2085,7 +2085,7 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
2085 goto out; 2085 goto out;
2086 2086
2087 status = nfs_ok; 2087 status = nfs_ok;
2088 nfsd4_create_clid_dir(cstate->session->se_client); 2088 nfsd4_client_record_create(cstate->session->se_client);
2089out: 2089out:
2090 nfs4_unlock_state(); 2090 nfs4_unlock_state();
2091 return status; 2091 return status;
@@ -2280,7 +2280,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
2280 conf = find_confirmed_client_by_str(unconf->cl_recdir, 2280 conf = find_confirmed_client_by_str(unconf->cl_recdir,
2281 hash); 2281 hash);
2282 if (conf) { 2282 if (conf) {
2283 nfsd4_remove_clid_dir(conf); 2283 nfsd4_client_record_remove(conf);
2284 expire_client(conf); 2284 expire_client(conf);
2285 } 2285 }
2286 move_to_confirmed(unconf); 2286 move_to_confirmed(unconf);
@@ -3159,7 +3159,7 @@ static void
3159nfsd4_end_grace(void) 3159nfsd4_end_grace(void)
3160{ 3160{
3161 dprintk("NFSD: end of grace period\n"); 3161 dprintk("NFSD: end of grace period\n");
3162 nfsd4_recdir_purge_old(); 3162 nfsd4_record_grace_done(&init_net, boot_time);
3163 locks_end_grace(&nfsd4_manager); 3163 locks_end_grace(&nfsd4_manager);
3164 /* 3164 /*
3165 * Now that every NFSv4 client has had the chance to recover and 3165 * Now that every NFSv4 client has had the chance to recover and
@@ -3208,7 +3208,7 @@ nfs4_laundromat(void)
3208 clp = list_entry(pos, struct nfs4_client, cl_lru); 3208 clp = list_entry(pos, struct nfs4_client, cl_lru);
3209 dprintk("NFSD: purging unused client (clientid %08x)\n", 3209 dprintk("NFSD: purging unused client (clientid %08x)\n",
3210 clp->cl_clientid.cl_id); 3210 clp->cl_clientid.cl_id);
3211 nfsd4_remove_clid_dir(clp); 3211 nfsd4_client_record_remove(clp);
3212 expire_client(clp); 3212 expire_client(clp);
3213 } 3213 }
3214 spin_lock(&recall_lock); 3214 spin_lock(&recall_lock);
@@ -3639,7 +3639,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3639 dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", 3639 dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
3640 __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid)); 3640 __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid));
3641 3641
3642 nfsd4_create_clid_dir(oo->oo_owner.so_client); 3642 nfsd4_client_record_create(oo->oo_owner.so_client);
3643 status = nfs_ok; 3643 status = nfs_ok;
3644out: 3644out:
3645 if (!cstate->replay_owner) 3645 if (!cstate->replay_owner)
@@ -4481,7 +4481,7 @@ nfs4_client_to_reclaim(const char *name)
4481 return 1; 4481 return 1;
4482} 4482}
4483 4483
4484static void 4484void
4485nfs4_release_reclaim(void) 4485nfs4_release_reclaim(void)
4486{ 4486{
4487 struct nfs4_client_reclaim *crp = NULL; 4487 struct nfs4_client_reclaim *crp = NULL;
@@ -4501,7 +4501,7 @@ nfs4_release_reclaim(void)
4501 4501
4502/* 4502/*
4503 * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ 4503 * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
4504static struct nfs4_client_reclaim * 4504struct nfs4_client_reclaim *
4505nfsd4_find_reclaim_client(struct nfs4_client *clp) 4505nfsd4_find_reclaim_client(struct nfs4_client *clp)
4506{ 4506{
4507 unsigned int strhashval; 4507 unsigned int strhashval;
@@ -4521,22 +4521,6 @@ nfsd4_find_reclaim_client(struct nfs4_client *clp)
4521 return NULL; 4521 return NULL;
4522} 4522}
4523 4523
4524static int
4525nfsd4_client_record_check(struct nfs4_client *clp)
4526{
4527 /* did we already find that this client is stable? */
4528 if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
4529 return 0;
4530
4531 /* look for it in the reclaim hashtable otherwise */
4532 if (nfsd4_find_reclaim_client(clp)) {
4533 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
4534 return 0;
4535 }
4536
4537 return -ENOENT;
4538}
4539
4540/* 4524/*
4541* Called from OPEN. Look for clientid in reclaim list. 4525* Called from OPEN. Look for clientid in reclaim list.
4542*/ 4526*/
@@ -4562,7 +4546,7 @@ void nfsd_forget_clients(u64 num)
4562 4546
4563 nfs4_lock_state(); 4547 nfs4_lock_state();
4564 list_for_each_entry_safe(clp, next, &client_lru, cl_lru) { 4548 list_for_each_entry_safe(clp, next, &client_lru, cl_lru) {
4565 nfsd4_remove_clid_dir(clp); 4549 nfsd4_client_record_remove(clp);
4566 expire_client(clp); 4550 expire_client(clp);
4567 if (++count == num) 4551 if (++count == num)
4568 break; 4552 break;
@@ -4697,19 +4681,6 @@ nfs4_state_init(void)
4697 reclaim_str_hashtbl_size = 0; 4681 reclaim_str_hashtbl_size = 0;
4698} 4682}
4699 4683
4700static void
4701nfsd4_load_reboot_recovery_data(void)
4702{
4703 int status;
4704
4705 nfs4_lock_state();
4706 nfsd4_init_recdir();
4707 status = nfsd4_recdir_load();
4708 nfs4_unlock_state();
4709 if (status)
4710 printk("NFSD: Failure reading reboot recovery data\n");
4711}
4712
4713/* 4684/*
4714 * Since the lifetime of a delegation isn't limited to that of an open, a 4685 * Since the lifetime of a delegation isn't limited to that of an open, a
4715 * client may quite reasonably hang on to a delegation as long as it has 4686 * client may quite reasonably hang on to a delegation as long as it has
@@ -4738,7 +4709,15 @@ nfs4_state_start(void)
4738{ 4709{
4739 int ret; 4710 int ret;
4740 4711
4741 nfsd4_load_reboot_recovery_data(); 4712 /*
4713 * FIXME: For now, we hang most of the pernet global stuff off of
4714 * init_net until nfsd is fully containerized. Eventually, we'll
4715 * need to pass a net pointer into this function, take a reference
4716 * to that instead and then do most of the rest of this on a per-net
4717 * basis.
4718 */
4719 get_net(&init_net);
4720 nfsd4_client_tracking_init(&init_net);
4742 boot_time = get_seconds(); 4721 boot_time = get_seconds();
4743 locks_start_grace(&nfsd4_manager); 4722 locks_start_grace(&nfsd4_manager);
4744 printk(KERN_INFO "NFSD: starting %ld-second grace period\n", 4723 printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
@@ -4762,8 +4741,8 @@ nfs4_state_start(void)
4762out_free_laundry: 4741out_free_laundry:
4763 destroy_workqueue(laundry_wq); 4742 destroy_workqueue(laundry_wq);
4764out_recovery: 4743out_recovery:
4765 nfs4_release_reclaim(); 4744 nfsd4_client_tracking_exit(&init_net);
4766 nfsd4_shutdown_recdir(); 4745 put_net(&init_net);
4767 return ret; 4746 return ret;
4768} 4747}
4769 4748
@@ -4797,7 +4776,8 @@ __nfs4_state_shutdown(void)
4797 unhash_delegation(dp); 4776 unhash_delegation(dp);
4798 } 4777 }
4799 4778
4800 nfsd4_shutdown_recdir(); 4779 nfsd4_client_tracking_exit(&init_net);
4780 put_net(&init_net);
4801} 4781}
4802 4782
4803void 4783void
@@ -4807,7 +4787,6 @@ nfs4_state_shutdown(void)
4807 destroy_workqueue(laundry_wq); 4787 destroy_workqueue(laundry_wq);
4808 locks_end_grace(&nfsd4_manager); 4788 locks_end_grace(&nfsd4_manager);
4809 nfs4_lock_state(); 4789 nfs4_lock_state();
4810 nfs4_release_reclaim();
4811 __nfs4_state_shutdown(); 4790 __nfs4_state_shutdown();
4812 nfs4_unlock_state(); 4791 nfs4_unlock_state();
4813 nfsd4_destroy_callback_queue(); 4792 nfsd4_destroy_callback_queue();
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 115215723f76..89ab137d379a 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -457,6 +457,8 @@ extern __be32 nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
457extern void nfs4_lock_state(void); 457extern void nfs4_lock_state(void);
458extern void nfs4_unlock_state(void); 458extern void nfs4_unlock_state(void);
459extern int nfs4_in_grace(void); 459extern int nfs4_in_grace(void);
460extern void nfs4_release_reclaim(void);
461extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(struct nfs4_client *crp);
460extern __be32 nfs4_check_open_reclaim(clientid_t *clid); 462extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
461extern void nfs4_free_openowner(struct nfs4_openowner *); 463extern void nfs4_free_openowner(struct nfs4_openowner *);
462extern void nfs4_free_lockowner(struct nfs4_lockowner *); 464extern void nfs4_free_lockowner(struct nfs4_lockowner *);
@@ -471,16 +473,17 @@ extern void nfsd4_destroy_callback_queue(void);
471extern void nfsd4_shutdown_callback(struct nfs4_client *); 473extern void nfsd4_shutdown_callback(struct nfs4_client *);
472extern void nfs4_put_delegation(struct nfs4_delegation *dp); 474extern void nfs4_put_delegation(struct nfs4_delegation *dp);
473extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); 475extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
474extern void nfsd4_init_recdir(void);
475extern int nfsd4_recdir_load(void);
476extern void nfsd4_shutdown_recdir(void);
477extern int nfs4_client_to_reclaim(const char *name); 476extern int nfs4_client_to_reclaim(const char *name);
478extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id); 477extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id);
479extern void nfsd4_recdir_purge_old(void);
480extern void nfsd4_create_clid_dir(struct nfs4_client *clp);
481extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
482extern void release_session_client(struct nfsd4_session *); 478extern void release_session_client(struct nfsd4_session *);
483extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *); 479extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *);
484extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *); 480extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);
485 481
482/* nfs4recover operations */
483extern int nfsd4_client_tracking_init(struct net *net);
484extern void nfsd4_client_tracking_exit(struct net *net);
485extern void nfsd4_client_record_create(struct nfs4_client *clp);
486extern void nfsd4_client_record_remove(struct nfs4_client *clp);
487extern int nfsd4_client_record_check(struct nfs4_client *clp);
488extern void nfsd4_record_grace_done(struct net *net, time_t boot_time);
486#endif /* NFSD4_STATE_H */ 489#endif /* NFSD4_STATE_H */