aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 */