Commit b1ece737 authored by Benjamin Coddington's avatar Benjamin Coddington Committed by Trond Myklebust

lockd: Introduce nlmclnt_operations

NFS would enjoy the ability to modify the behavior of the NLM client's
unlock RPC task in order to delay the transmission of the unlock until IO
that was submitted under that lock has completed.  This ability can ensure
that the NLM client will always complete the transmission of an unlock even
if the waiting caller has been interrupted with fatal signal.

For this purpose, a pointer to a struct nlmclnt_operations can be assigned
in a nfs_module's nfs_rpc_ops that will install those nlmclnt_operations on
the nlm_host.  The struct nlmclnt_operations defines three callback
operations that will be used in a following patch:

nlmclnt_alloc_call - used to call back after a successful allocation of
	a struct nlm_rqst in nlmclnt_proc().

nlmclnt_unlock_prepare - used to call back during NLM unlock's
	rpc_call_prepare.  The NLM client defers calling rpc_call_start()
	until this callback returns false.

nlmclnt_release_call - used to call back when the NLM client's struct
	nlm_rqst is freed.
Signed-off-by: default avatarBenjamin Coddington <bcodding@redhat.com>
Reviewed-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
parent 7d6ddf88
...@@ -69,6 +69,7 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init) ...@@ -69,6 +69,7 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init)
if (host->h_rpcclnt == NULL && nlm_bind_host(host) == NULL) if (host->h_rpcclnt == NULL && nlm_bind_host(host) == NULL)
goto out_nobind; goto out_nobind;
host->h_nlmclnt_ops = nlm_init->nlmclnt_ops;
return host; return host;
out_nobind: out_nobind:
nlmclnt_release_host(host); nlmclnt_release_host(host);
......
...@@ -150,17 +150,22 @@ static void nlmclnt_release_lockargs(struct nlm_rqst *req) ...@@ -150,17 +150,22 @@ static void nlmclnt_release_lockargs(struct nlm_rqst *req)
* @host: address of a valid nlm_host context representing the NLM server * @host: address of a valid nlm_host context representing the NLM server
* @cmd: fcntl-style file lock operation to perform * @cmd: fcntl-style file lock operation to perform
* @fl: address of arguments for the lock operation * @fl: address of arguments for the lock operation
* @data: address of data to be sent to callback operations
* *
*/ */
int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl, void *data)
{ {
struct nlm_rqst *call; struct nlm_rqst *call;
int status; int status;
const struct nlmclnt_operations *nlmclnt_ops = host->h_nlmclnt_ops;
call = nlm_alloc_call(host); call = nlm_alloc_call(host);
if (call == NULL) if (call == NULL)
return -ENOMEM; return -ENOMEM;
if (nlmclnt_ops && nlmclnt_ops->nlmclnt_alloc_call)
nlmclnt_ops->nlmclnt_alloc_call(data);
nlmclnt_locks_init_private(fl, host); nlmclnt_locks_init_private(fl, host);
if (!fl->fl_u.nfs_fl.owner) { if (!fl->fl_u.nfs_fl.owner) {
/* lockowner allocation has failed */ /* lockowner allocation has failed */
...@@ -169,6 +174,7 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) ...@@ -169,6 +174,7 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl)
} }
/* Set up the argument struct */ /* Set up the argument struct */
nlmclnt_setlockargs(call, fl); nlmclnt_setlockargs(call, fl);
call->a_callback_data = data;
if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { if (IS_SETLK(cmd) || IS_SETLKW(cmd)) {
if (fl->fl_type != F_UNLCK) { if (fl->fl_type != F_UNLCK) {
...@@ -214,8 +220,12 @@ struct nlm_rqst *nlm_alloc_call(struct nlm_host *host) ...@@ -214,8 +220,12 @@ struct nlm_rqst *nlm_alloc_call(struct nlm_host *host)
void nlmclnt_release_call(struct nlm_rqst *call) void nlmclnt_release_call(struct nlm_rqst *call)
{ {
const struct nlmclnt_operations *nlmclnt_ops = call->a_host->h_nlmclnt_ops;
if (!atomic_dec_and_test(&call->a_count)) if (!atomic_dec_and_test(&call->a_count))
return; return;
if (nlmclnt_ops && nlmclnt_ops->nlmclnt_release_call)
nlmclnt_ops->nlmclnt_release_call(call->a_callback_data);
nlmclnt_release_host(call->a_host); nlmclnt_release_host(call->a_host);
nlmclnt_release_lockargs(call); nlmclnt_release_lockargs(call);
kfree(call); kfree(call);
...@@ -687,6 +697,19 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) ...@@ -687,6 +697,19 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
return status; return status;
} }
static void nlmclnt_unlock_prepare(struct rpc_task *task, void *data)
{
struct nlm_rqst *req = data;
const struct nlmclnt_operations *nlmclnt_ops = req->a_host->h_nlmclnt_ops;
bool defer_call = false;
if (nlmclnt_ops && nlmclnt_ops->nlmclnt_unlock_prepare)
defer_call = nlmclnt_ops->nlmclnt_unlock_prepare(task, req->a_callback_data);
if (!defer_call)
rpc_call_start(task);
}
static void nlmclnt_unlock_callback(struct rpc_task *task, void *data) static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
{ {
struct nlm_rqst *req = data; struct nlm_rqst *req = data;
...@@ -720,6 +743,7 @@ static void nlmclnt_unlock_callback(struct rpc_task *task, void *data) ...@@ -720,6 +743,7 @@ static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
} }
static const struct rpc_call_ops nlmclnt_unlock_ops = { static const struct rpc_call_ops nlmclnt_unlock_ops = {
.rpc_call_prepare = nlmclnt_unlock_prepare,
.rpc_call_done = nlmclnt_unlock_callback, .rpc_call_done = nlmclnt_unlock_callback,
.rpc_release = nlmclnt_rpc_release, .rpc_release = nlmclnt_rpc_release,
}; };
......
...@@ -546,6 +546,7 @@ static int nfs_start_lockd(struct nfs_server *server) ...@@ -546,6 +546,7 @@ static int nfs_start_lockd(struct nfs_server *server)
.noresvport = server->flags & NFS_MOUNT_NORESVPORT ? .noresvport = server->flags & NFS_MOUNT_NORESVPORT ?
1 : 0, 1 : 0,
.net = clp->cl_net, .net = clp->cl_net,
.nlmclnt_ops = clp->cl_nfs_mod->rpc_ops->nlmclnt_ops,
}; };
if (nlm_init.nfs_version > 3) if (nlm_init.nfs_version > 3)
......
...@@ -870,7 +870,7 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl) ...@@ -870,7 +870,7 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
{ {
struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp);
return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl); return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl, NULL);
} }
static int nfs3_have_delegation(struct inode *inode, fmode_t flags) static int nfs3_have_delegation(struct inode *inode, fmode_t flags)
......
...@@ -638,7 +638,7 @@ nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl) ...@@ -638,7 +638,7 @@ nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
{ {
struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp);
return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl); return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl, NULL);
} }
/* Helper functions for NFS lock bounds checking */ /* Helper functions for NFS lock bounds checking */
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
/* Dummy declarations */ /* Dummy declarations */
struct svc_rqst; struct svc_rqst;
struct rpc_task;
/* /*
* This is the set of functions for lockd->nfsd communication * This is the set of functions for lockd->nfsd communication
...@@ -43,6 +44,7 @@ struct nlmclnt_initdata { ...@@ -43,6 +44,7 @@ struct nlmclnt_initdata {
u32 nfs_version; u32 nfs_version;
int noresvport; int noresvport;
struct net *net; struct net *net;
const struct nlmclnt_operations *nlmclnt_ops;
}; };
/* /*
...@@ -52,8 +54,26 @@ struct nlmclnt_initdata { ...@@ -52,8 +54,26 @@ struct nlmclnt_initdata {
extern struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init); extern struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init);
extern void nlmclnt_done(struct nlm_host *host); extern void nlmclnt_done(struct nlm_host *host);
extern int nlmclnt_proc(struct nlm_host *host, int cmd, /*
struct file_lock *fl); * NLM client operations provide a means to modify RPC processing of NLM
* requests. Callbacks receive a pointer to data passed into the call to
* nlmclnt_proc().
*/
struct nlmclnt_operations {
/* Called on successful allocation of nlm_rqst, use for allocation or
* reference counting. */
void (*nlmclnt_alloc_call)(void *);
/* Called in rpc_task_prepare for unlock. A return value of true
* indicates the callback has put the task to sleep on a waitqueue
* and NLM should not call rpc_call_start(). */
bool (*nlmclnt_unlock_prepare)(struct rpc_task*, void *);
/* Called when the nlm_rqst is freed, callbacks should clean up here */
void (*nlmclnt_release_call)(void *);
};
extern int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl, void *data);
extern int lockd_up(struct net *net); extern int lockd_up(struct net *net);
extern void lockd_down(struct net *net); extern void lockd_down(struct net *net);
......
...@@ -69,6 +69,7 @@ struct nlm_host { ...@@ -69,6 +69,7 @@ struct nlm_host {
char *h_addrbuf; /* address eyecatcher */ char *h_addrbuf; /* address eyecatcher */
struct net *net; /* host net */ struct net *net; /* host net */
char nodename[UNX_MAXNODENAME + 1]; char nodename[UNX_MAXNODENAME + 1];
const struct nlmclnt_operations *h_nlmclnt_ops; /* Callback ops for NLM users */
}; };
/* /*
...@@ -142,6 +143,7 @@ struct nlm_rqst { ...@@ -142,6 +143,7 @@ struct nlm_rqst {
struct nlm_block * a_block; struct nlm_block * a_block;
unsigned int a_retries; /* Retry count */ unsigned int a_retries; /* Retry count */
u8 a_owner[NLMCLNT_OHSIZE]; u8 a_owner[NLMCLNT_OHSIZE];
void * a_callback_data; /* sent to nlmclnt_operations callbacks */
}; };
/* /*
......
...@@ -1551,6 +1551,7 @@ struct nfs_rpc_ops { ...@@ -1551,6 +1551,7 @@ struct nfs_rpc_ops {
const struct inode_operations *dir_inode_ops; const struct inode_operations *dir_inode_ops;
const struct inode_operations *file_inode_ops; const struct inode_operations *file_inode_ops;
const struct file_operations *file_ops; const struct file_operations *file_ops;
const struct nlmclnt_operations *nlmclnt_ops;
int (*getroot) (struct nfs_server *, struct nfs_fh *, int (*getroot) (struct nfs_server *, struct nfs_fh *,
struct nfs_fsinfo *); struct nfs_fsinfo *);
......
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