aboutsummaryrefslogtreecommitdiffstats
path: root/fs/lockd/clntproc.c
diff options
context:
space:
mode:
authorBenjamin Coddington <bcodding@redhat.com>2017-04-11 12:50:11 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2017-04-21 10:45:01 -0400
commitb1ece737f44f91dca8f4829cf0b442e752e406db (patch)
treed0368ec8da45be194c4cde25d46e178ea9060715 /fs/lockd/clntproc.c
parent7d6ddf88c4db372689c8aa65ea652d0514d66c06 (diff)
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: Benjamin Coddington <bcodding@redhat.com> Reviewed-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/lockd/clntproc.c')
-rw-r--r--fs/lockd/clntproc.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 112952037933..066ac313ae5c 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -150,17 +150,22 @@ static void nlmclnt_release_lockargs(struct nlm_rqst *req)
150 * @host: address of a valid nlm_host context representing the NLM server 150 * @host: address of a valid nlm_host context representing the NLM server
151 * @cmd: fcntl-style file lock operation to perform 151 * @cmd: fcntl-style file lock operation to perform
152 * @fl: address of arguments for the lock operation 152 * @fl: address of arguments for the lock operation
153 * @data: address of data to be sent to callback operations
153 * 154 *
154 */ 155 */
155int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) 156int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl, void *data)
156{ 157{
157 struct nlm_rqst *call; 158 struct nlm_rqst *call;
158 int status; 159 int status;
160 const struct nlmclnt_operations *nlmclnt_ops = host->h_nlmclnt_ops;
159 161
160 call = nlm_alloc_call(host); 162 call = nlm_alloc_call(host);
161 if (call == NULL) 163 if (call == NULL)
162 return -ENOMEM; 164 return -ENOMEM;
163 165
166 if (nlmclnt_ops && nlmclnt_ops->nlmclnt_alloc_call)
167 nlmclnt_ops->nlmclnt_alloc_call(data);
168
164 nlmclnt_locks_init_private(fl, host); 169 nlmclnt_locks_init_private(fl, host);
165 if (!fl->fl_u.nfs_fl.owner) { 170 if (!fl->fl_u.nfs_fl.owner) {
166 /* lockowner allocation has failed */ 171 /* lockowner allocation has failed */
@@ -169,6 +174,7 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl)
169 } 174 }
170 /* Set up the argument struct */ 175 /* Set up the argument struct */
171 nlmclnt_setlockargs(call, fl); 176 nlmclnt_setlockargs(call, fl);
177 call->a_callback_data = data;
172 178
173 if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { 179 if (IS_SETLK(cmd) || IS_SETLKW(cmd)) {
174 if (fl->fl_type != F_UNLCK) { 180 if (fl->fl_type != F_UNLCK) {
@@ -214,8 +220,12 @@ struct nlm_rqst *nlm_alloc_call(struct nlm_host *host)
214 220
215void nlmclnt_release_call(struct nlm_rqst *call) 221void nlmclnt_release_call(struct nlm_rqst *call)
216{ 222{
223 const struct nlmclnt_operations *nlmclnt_ops = call->a_host->h_nlmclnt_ops;
224
217 if (!atomic_dec_and_test(&call->a_count)) 225 if (!atomic_dec_and_test(&call->a_count))
218 return; 226 return;
227 if (nlmclnt_ops && nlmclnt_ops->nlmclnt_release_call)
228 nlmclnt_ops->nlmclnt_release_call(call->a_callback_data);
219 nlmclnt_release_host(call->a_host); 229 nlmclnt_release_host(call->a_host);
220 nlmclnt_release_lockargs(call); 230 nlmclnt_release_lockargs(call);
221 kfree(call); 231 kfree(call);
@@ -687,6 +697,19 @@ out:
687 return status; 697 return status;
688} 698}
689 699
700static void nlmclnt_unlock_prepare(struct rpc_task *task, void *data)
701{
702 struct nlm_rqst *req = data;
703 const struct nlmclnt_operations *nlmclnt_ops = req->a_host->h_nlmclnt_ops;
704 bool defer_call = false;
705
706 if (nlmclnt_ops && nlmclnt_ops->nlmclnt_unlock_prepare)
707 defer_call = nlmclnt_ops->nlmclnt_unlock_prepare(task, req->a_callback_data);
708
709 if (!defer_call)
710 rpc_call_start(task);
711}
712
690static void nlmclnt_unlock_callback(struct rpc_task *task, void *data) 713static void nlmclnt_unlock_callback(struct rpc_task *task, void *data)
691{ 714{
692 struct nlm_rqst *req = data; 715 struct nlm_rqst *req = data;
@@ -720,6 +743,7 @@ die:
720} 743}
721 744
722static const struct rpc_call_ops nlmclnt_unlock_ops = { 745static const struct rpc_call_ops nlmclnt_unlock_ops = {
746 .rpc_call_prepare = nlmclnt_unlock_prepare,
723 .rpc_call_done = nlmclnt_unlock_callback, 747 .rpc_call_done = nlmclnt_unlock_callback,
724 .rpc_release = nlmclnt_rpc_release, 748 .rpc_release = nlmclnt_rpc_release,
725}; 749};