Commit 2a4317c5 authored by Jeff Layton's avatar Jeff Layton Committed by J. Bruce Fields

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: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent a52d726b
...@@ -43,9 +43,20 @@ ...@@ -43,9 +43,20 @@
#define NFSDDBG_FACILITY NFSDDBG_PROC #define NFSDDBG_FACILITY NFSDDBG_PROC
/* Declarations */
struct nfsd4_client_tracking_ops {
int (*init)(struct net *);
void (*exit)(struct net *);
void (*create)(struct nfs4_client *);
void (*remove)(struct nfs4_client *);
int (*check)(struct nfs4_client *);
void (*grace_done)(struct net *, time_t);
};
/* Globals */ /* Globals */
static struct file *rec_file; static struct file *rec_file;
static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
static struct nfsd4_client_tracking_ops *client_tracking_ops;
static int static int
nfs4_save_creds(const struct cred **original_creds) nfs4_save_creds(const struct cred **original_creds)
...@@ -117,7 +128,8 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) ...@@ -117,7 +128,8 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
return status; return status;
} }
void nfsd4_create_clid_dir(struct nfs4_client *clp) static void
nfsd4_create_clid_dir(struct nfs4_client *clp)
{ {
const struct cred *original_cred; const struct cred *original_cred;
char *dname = clp->cl_recdir; char *dname = clp->cl_recdir;
...@@ -264,7 +276,7 @@ nfsd4_unlink_clid_dir(char *name, int namlen) ...@@ -264,7 +276,7 @@ nfsd4_unlink_clid_dir(char *name, int namlen)
return status; return status;
} }
void static void
nfsd4_remove_clid_dir(struct nfs4_client *clp) nfsd4_remove_clid_dir(struct nfs4_client *clp)
{ {
const struct cred *original_cred; const struct cred *original_cred;
...@@ -291,7 +303,6 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp) ...@@ -291,7 +303,6 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
if (status) if (status)
printk("NFSD: Failed to remove expired client state directory" printk("NFSD: Failed to remove expired client state directory"
" %.*s\n", HEXDIR_LEN, clp->cl_recdir); " %.*s\n", HEXDIR_LEN, clp->cl_recdir);
return;
} }
static int static int
...@@ -310,8 +321,9 @@ purge_old(struct dentry *parent, struct dentry *child) ...@@ -310,8 +321,9 @@ purge_old(struct dentry *parent, struct dentry *child)
return 0; return 0;
} }
void static void
nfsd4_recdir_purge_old(void) { nfsd4_recdir_purge_old(struct net *net, time_t boot_time)
{
int status; int status;
if (!rec_file) if (!rec_file)
...@@ -342,7 +354,7 @@ load_recdir(struct dentry *parent, struct dentry *child) ...@@ -342,7 +354,7 @@ load_recdir(struct dentry *parent, struct dentry *child)
return 0; return 0;
} }
int static int
nfsd4_recdir_load(void) { nfsd4_recdir_load(void) {
int status; int status;
...@@ -360,8 +372,8 @@ nfsd4_recdir_load(void) { ...@@ -360,8 +372,8 @@ nfsd4_recdir_load(void) {
* Hold reference to the recovery directory. * Hold reference to the recovery directory.
*/ */
void static int
nfsd4_init_recdir() nfsd4_init_recdir(void)
{ {
const struct cred *original_cred; const struct cred *original_cred;
int status; int status;
...@@ -376,20 +388,37 @@ nfsd4_init_recdir() ...@@ -376,20 +388,37 @@ nfsd4_init_recdir()
printk("NFSD: Unable to change credentials to find recovery" printk("NFSD: Unable to change credentials to find recovery"
" directory: error %d\n", " directory: error %d\n",
status); status);
return; return status;
} }
rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0); rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0);
if (IS_ERR(rec_file)) { if (IS_ERR(rec_file)) {
printk("NFSD: unable to find recovery directory %s\n", printk("NFSD: unable to find recovery directory %s\n",
user_recovery_dirname); user_recovery_dirname);
status = PTR_ERR(rec_file);
rec_file = NULL; rec_file = NULL;
} }
nfs4_reset_creds(original_cred); nfs4_reset_creds(original_cred);
return status;
} }
void static int
nfsd4_load_reboot_recovery_data(struct net *net)
{
int status;
nfs4_lock_state();
status = nfsd4_init_recdir();
if (!status)
status = nfsd4_recdir_load();
nfs4_unlock_state();
if (status)
printk(KERN_ERR "NFSD: Failure reading reboot recovery data\n");
return status;
}
static void
nfsd4_shutdown_recdir(void) nfsd4_shutdown_recdir(void)
{ {
if (!rec_file) if (!rec_file)
...@@ -398,6 +427,13 @@ nfsd4_shutdown_recdir(void) ...@@ -398,6 +427,13 @@ nfsd4_shutdown_recdir(void)
rec_file = NULL; rec_file = NULL;
} }
static void
nfsd4_legacy_tracking_exit(struct net *net)
{
nfs4_release_reclaim();
nfsd4_shutdown_recdir();
}
/* /*
* Change the NFSv4 recovery directory to recdir. * Change the NFSv4 recovery directory to recdir.
*/ */
...@@ -424,3 +460,83 @@ nfs4_recoverydir(void) ...@@ -424,3 +460,83 @@ nfs4_recoverydir(void)
{ {
return user_recovery_dirname; return user_recovery_dirname;
} }
static int
nfsd4_check_legacy_client(struct nfs4_client *clp)
{
/* did we already find that this client is stable? */
if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
return 0;
/* look for it in the reclaim hashtable otherwise */
if (nfsd4_find_reclaim_client(clp)) {
set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
return 0;
}
return -ENOENT;
}
static struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = {
.init = nfsd4_load_reboot_recovery_data,
.exit = nfsd4_legacy_tracking_exit,
.create = nfsd4_create_clid_dir,
.remove = nfsd4_remove_clid_dir,
.check = nfsd4_check_legacy_client,
.grace_done = nfsd4_recdir_purge_old,
};
int
nfsd4_client_tracking_init(struct net *net)
{
int status;
client_tracking_ops = &nfsd4_legacy_tracking_ops;
status = client_tracking_ops->init(net);
if (status) {
printk(KERN_WARNING "NFSD: Unable to initialize client "
"recovery tracking! (%d)\n", status);
client_tracking_ops = NULL;
}
return status;
}
void
nfsd4_client_tracking_exit(struct net *net)
{
if (client_tracking_ops) {
client_tracking_ops->exit(net);
client_tracking_ops = NULL;
}
}
void
nfsd4_client_record_create(struct nfs4_client *clp)
{
if (client_tracking_ops)
client_tracking_ops->create(clp);
}
void
nfsd4_client_record_remove(struct nfs4_client *clp)
{
if (client_tracking_ops)
client_tracking_ops->remove(clp);
}
int
nfsd4_client_record_check(struct nfs4_client *clp)
{
if (client_tracking_ops)
return client_tracking_ops->check(clp);
return -EOPNOTSUPP;
}
void
nfsd4_record_grace_done(struct net *net, time_t boot_time)
{
if (client_tracking_ops)
client_tracking_ops->grace_done(net, boot_time);
}
...@@ -2085,7 +2085,7 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta ...@@ -2085,7 +2085,7 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
goto out; goto out;
status = nfs_ok; status = nfs_ok;
nfsd4_create_clid_dir(cstate->session->se_client); nfsd4_client_record_create(cstate->session->se_client);
out: out:
nfs4_unlock_state(); nfs4_unlock_state();
return status; return status;
...@@ -2280,7 +2280,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, ...@@ -2280,7 +2280,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
conf = find_confirmed_client_by_str(unconf->cl_recdir, conf = find_confirmed_client_by_str(unconf->cl_recdir,
hash); hash);
if (conf) { if (conf) {
nfsd4_remove_clid_dir(conf); nfsd4_client_record_remove(conf);
expire_client(conf); expire_client(conf);
} }
move_to_confirmed(unconf); move_to_confirmed(unconf);
...@@ -3159,7 +3159,7 @@ static void ...@@ -3159,7 +3159,7 @@ static void
nfsd4_end_grace(void) nfsd4_end_grace(void)
{ {
dprintk("NFSD: end of grace period\n"); dprintk("NFSD: end of grace period\n");
nfsd4_recdir_purge_old(); nfsd4_record_grace_done(&init_net, boot_time);
locks_end_grace(&nfsd4_manager); locks_end_grace(&nfsd4_manager);
/* /*
* Now that every NFSv4 client has had the chance to recover and * Now that every NFSv4 client has had the chance to recover and
...@@ -3208,7 +3208,7 @@ nfs4_laundromat(void) ...@@ -3208,7 +3208,7 @@ nfs4_laundromat(void)
clp = list_entry(pos, struct nfs4_client, cl_lru); clp = list_entry(pos, struct nfs4_client, cl_lru);
dprintk("NFSD: purging unused client (clientid %08x)\n", dprintk("NFSD: purging unused client (clientid %08x)\n",
clp->cl_clientid.cl_id); clp->cl_clientid.cl_id);
nfsd4_remove_clid_dir(clp); nfsd4_client_record_remove(clp);
expire_client(clp); expire_client(clp);
} }
spin_lock(&recall_lock); spin_lock(&recall_lock);
...@@ -3639,7 +3639,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -3639,7 +3639,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
__func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid)); __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid));
nfsd4_create_clid_dir(oo->oo_owner.so_client); nfsd4_client_record_create(oo->oo_owner.so_client);
status = nfs_ok; status = nfs_ok;
out: out:
if (!cstate->replay_owner) if (!cstate->replay_owner)
...@@ -4481,7 +4481,7 @@ nfs4_client_to_reclaim(const char *name) ...@@ -4481,7 +4481,7 @@ nfs4_client_to_reclaim(const char *name)
return 1; return 1;
} }
static void void
nfs4_release_reclaim(void) nfs4_release_reclaim(void)
{ {
struct nfs4_client_reclaim *crp = NULL; struct nfs4_client_reclaim *crp = NULL;
...@@ -4501,7 +4501,7 @@ nfs4_release_reclaim(void) ...@@ -4501,7 +4501,7 @@ nfs4_release_reclaim(void)
/* /*
* called from OPEN, CLAIM_PREVIOUS with a new clientid. */ * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
static struct nfs4_client_reclaim * struct nfs4_client_reclaim *
nfsd4_find_reclaim_client(struct nfs4_client *clp) nfsd4_find_reclaim_client(struct nfs4_client *clp)
{ {
unsigned int strhashval; unsigned int strhashval;
...@@ -4521,22 +4521,6 @@ nfsd4_find_reclaim_client(struct nfs4_client *clp) ...@@ -4521,22 +4521,6 @@ nfsd4_find_reclaim_client(struct nfs4_client *clp)
return NULL; return NULL;
} }
static int
nfsd4_client_record_check(struct nfs4_client *clp)
{
/* did we already find that this client is stable? */
if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
return 0;
/* look for it in the reclaim hashtable otherwise */
if (nfsd4_find_reclaim_client(clp)) {
set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
return 0;
}
return -ENOENT;
}
/* /*
* Called from OPEN. Look for clientid in reclaim list. * Called from OPEN. Look for clientid in reclaim list.
*/ */
...@@ -4562,7 +4546,7 @@ void nfsd_forget_clients(u64 num) ...@@ -4562,7 +4546,7 @@ void nfsd_forget_clients(u64 num)
nfs4_lock_state(); nfs4_lock_state();
list_for_each_entry_safe(clp, next, &client_lru, cl_lru) { list_for_each_entry_safe(clp, next, &client_lru, cl_lru) {
nfsd4_remove_clid_dir(clp); nfsd4_client_record_remove(clp);
expire_client(clp); expire_client(clp);
if (++count == num) if (++count == num)
break; break;
...@@ -4697,19 +4681,6 @@ nfs4_state_init(void) ...@@ -4697,19 +4681,6 @@ nfs4_state_init(void)
reclaim_str_hashtbl_size = 0; reclaim_str_hashtbl_size = 0;
} }
static void
nfsd4_load_reboot_recovery_data(void)
{
int status;
nfs4_lock_state();
nfsd4_init_recdir();
status = nfsd4_recdir_load();
nfs4_unlock_state();
if (status)
printk("NFSD: Failure reading reboot recovery data\n");
}
/* /*
* Since the lifetime of a delegation isn't limited to that of an open, a * Since the lifetime of a delegation isn't limited to that of an open, a
* client may quite reasonably hang on to a delegation as long as it has * client may quite reasonably hang on to a delegation as long as it has
...@@ -4738,7 +4709,15 @@ nfs4_state_start(void) ...@@ -4738,7 +4709,15 @@ nfs4_state_start(void)
{ {
int ret; int ret;
nfsd4_load_reboot_recovery_data(); /*
* FIXME: For now, we hang most of the pernet global stuff off of
* init_net until nfsd is fully containerized. Eventually, we'll
* need to pass a net pointer into this function, take a reference
* to that instead and then do most of the rest of this on a per-net
* basis.
*/
get_net(&init_net);
nfsd4_client_tracking_init(&init_net);
boot_time = get_seconds(); boot_time = get_seconds();
locks_start_grace(&nfsd4_manager); locks_start_grace(&nfsd4_manager);
printk(KERN_INFO "NFSD: starting %ld-second grace period\n", printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
...@@ -4762,8 +4741,8 @@ nfs4_state_start(void) ...@@ -4762,8 +4741,8 @@ nfs4_state_start(void)
out_free_laundry: out_free_laundry:
destroy_workqueue(laundry_wq); destroy_workqueue(laundry_wq);
out_recovery: out_recovery:
nfs4_release_reclaim(); nfsd4_client_tracking_exit(&init_net);
nfsd4_shutdown_recdir(); put_net(&init_net);
return ret; return ret;
} }
...@@ -4797,7 +4776,8 @@ __nfs4_state_shutdown(void) ...@@ -4797,7 +4776,8 @@ __nfs4_state_shutdown(void)
unhash_delegation(dp); unhash_delegation(dp);
} }
nfsd4_shutdown_recdir(); nfsd4_client_tracking_exit(&init_net);
put_net(&init_net);
} }
void void
...@@ -4807,7 +4787,6 @@ nfs4_state_shutdown(void) ...@@ -4807,7 +4787,6 @@ nfs4_state_shutdown(void)
destroy_workqueue(laundry_wq); destroy_workqueue(laundry_wq);
locks_end_grace(&nfsd4_manager); locks_end_grace(&nfsd4_manager);
nfs4_lock_state(); nfs4_lock_state();
nfs4_release_reclaim();
__nfs4_state_shutdown(); __nfs4_state_shutdown();
nfs4_unlock_state(); nfs4_unlock_state();
nfsd4_destroy_callback_queue(); nfsd4_destroy_callback_queue();
......
...@@ -457,6 +457,8 @@ extern __be32 nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, ...@@ -457,6 +457,8 @@ extern __be32 nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
extern void nfs4_lock_state(void); extern void nfs4_lock_state(void);
extern void nfs4_unlock_state(void); extern void nfs4_unlock_state(void);
extern int nfs4_in_grace(void); extern int nfs4_in_grace(void);
extern void nfs4_release_reclaim(void);
extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(struct nfs4_client *crp);
extern __be32 nfs4_check_open_reclaim(clientid_t *clid); extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
extern void nfs4_free_openowner(struct nfs4_openowner *); extern void nfs4_free_openowner(struct nfs4_openowner *);
extern void nfs4_free_lockowner(struct nfs4_lockowner *); extern void nfs4_free_lockowner(struct nfs4_lockowner *);
...@@ -471,16 +473,17 @@ extern void nfsd4_destroy_callback_queue(void); ...@@ -471,16 +473,17 @@ extern void nfsd4_destroy_callback_queue(void);
extern void nfsd4_shutdown_callback(struct nfs4_client *); extern void nfsd4_shutdown_callback(struct nfs4_client *);
extern void nfs4_put_delegation(struct nfs4_delegation *dp); extern void nfs4_put_delegation(struct nfs4_delegation *dp);
extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
extern void nfsd4_init_recdir(void);
extern int nfsd4_recdir_load(void);
extern void nfsd4_shutdown_recdir(void);
extern int nfs4_client_to_reclaim(const char *name); extern int nfs4_client_to_reclaim(const char *name);
extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id); extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id);
extern void nfsd4_recdir_purge_old(void);
extern void nfsd4_create_clid_dir(struct nfs4_client *clp);
extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
extern void release_session_client(struct nfsd4_session *); extern void release_session_client(struct nfsd4_session *);
extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *); extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *);
extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *); extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);
/* nfs4recover operations */
extern int nfsd4_client_tracking_init(struct net *net);
extern void nfsd4_client_tracking_exit(struct net *net);
extern void nfsd4_client_record_create(struct nfs4_client *clp);
extern void nfsd4_client_record_remove(struct nfs4_client *clp);
extern int nfsd4_client_record_check(struct nfs4_client *clp);
extern void nfsd4_record_grace_done(struct net *net, time_t boot_time);
#endif /* NFSD4_STATE_H */ #endif /* NFSD4_STATE_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment