Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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)
		goto out_nobind;

	host->h_nlmclnt_ops = nlm_init->nlmclnt_ops;
	return host;
out_nobind:
	nlmclnt_release_host(host);
+25 −1
Original line number Diff line number Diff line
@@ -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
 * @cmd: fcntl-style file lock operation to perform
 * @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;
	int			status;
	const struct nlmclnt_operations *nlmclnt_ops = host->h_nlmclnt_ops;

	call = nlm_alloc_call(host);
	if (call == NULL)
		return -ENOMEM;

	if (nlmclnt_ops && nlmclnt_ops->nlmclnt_alloc_call)
		nlmclnt_ops->nlmclnt_alloc_call(data);

	nlmclnt_locks_init_private(fl, host);
	if (!fl->fl_u.nfs_fl.owner) {
		/* lockowner allocation has failed */
@@ -169,6 +174,7 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl)
	}
	/* Set up the argument struct */
	nlmclnt_setlockargs(call, fl);
	call->a_callback_data = data;

	if (IS_SETLK(cmd) || IS_SETLKW(cmd)) {
		if (fl->fl_type != F_UNLCK) {
@@ -214,8 +220,12 @@ struct nlm_rqst *nlm_alloc_call(struct nlm_host *host)

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))
		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_lockargs(call);
	kfree(call);
@@ -687,6 +697,19 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
	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)
{
	struct nlm_rqst	*req = 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 = {
	.rpc_call_prepare = nlmclnt_unlock_prepare,
	.rpc_call_done = nlmclnt_unlock_callback,
	.rpc_release = nlmclnt_rpc_release,
};
+1 −0
Original line number Diff line number Diff line
@@ -546,6 +546,7 @@ static int nfs_start_lockd(struct nfs_server *server)
		.noresvport	= server->flags & NFS_MOUNT_NORESVPORT ?
					1 : 0,
		.net		= clp->cl_net,
		.nlmclnt_ops 	= clp->cl_nfs_mod->rpc_ops->nlmclnt_ops,
	};

	if (nlm_init.nfs_version > 3)
+1 −1
Original line number Diff line number Diff line
@@ -870,7 +870,7 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
{
	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)
+1 −1
Original line number Diff line number Diff line
@@ -638,7 +638,7 @@ nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
{
	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 */
Loading