aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/lockd/clntlock.c1
-rw-r--r--fs/lockd/clntproc.c26
-rw-r--r--fs/nfs/client.c1
-rw-r--r--fs/nfs/nfs3proc.c2
-rw-r--r--fs/nfs/proc.c2
-rw-r--r--include/linux/lockd/bind.h24
-rw-r--r--include/linux/lockd/lockd.h2
-rw-r--r--include/linux/nfs_xdr.h1
8 files changed, 54 insertions, 5 deletions
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index 41e491b8e5d7..27d577dbe51a 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -69,6 +69,7 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init)
69 if (host->h_rpcclnt == NULL && nlm_bind_host(host) == NULL) 69 if (host->h_rpcclnt == NULL && nlm_bind_host(host) == NULL)
70 goto out_nobind; 70 goto out_nobind;
71 71
72 host->h_nlmclnt_ops = nlm_init->nlmclnt_ops;
72 return host; 73 return host;
73out_nobind: 74out_nobind:
74 nlmclnt_release_host(host); 75 nlmclnt_release_host(host);
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};
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 3e7b2e6a7cfb..e0302101e18a 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -546,6 +546,7 @@ static int nfs_start_lockd(struct nfs_server *server)
546 .noresvport = server->flags & NFS_MOUNT_NORESVPORT ? 546 .noresvport = server->flags & NFS_MOUNT_NORESVPORT ?
547 1 : 0, 547 1 : 0,
548 .net = clp->cl_net, 548 .net = clp->cl_net,
549 .nlmclnt_ops = clp->cl_nfs_mod->rpc_ops->nlmclnt_ops,
549 }; 550 };
550 551
551 if (nlm_init.nfs_version > 3) 552 if (nlm_init.nfs_version > 3)
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index dc925b531f32..03b3c3de28f1 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -870,7 +870,7 @@ nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
870{ 870{
871 struct inode *inode = file_inode(filp); 871 struct inode *inode = file_inode(filp);
872 872
873 return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl); 873 return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl, NULL);
874} 874}
875 875
876static int nfs3_have_delegation(struct inode *inode, fmode_t flags) 876static int nfs3_have_delegation(struct inode *inode, fmode_t flags)
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index b7bca8303989..9872cf676a50 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -638,7 +638,7 @@ nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
638{ 638{
639 struct inode *inode = file_inode(filp); 639 struct inode *inode = file_inode(filp);
640 640
641 return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl); 641 return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl, NULL);
642} 642}
643 643
644/* Helper functions for NFS lock bounds checking */ 644/* Helper functions for NFS lock bounds checking */
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
index 140edab64446..05728396a1a1 100644
--- a/include/linux/lockd/bind.h
+++ b/include/linux/lockd/bind.h
@@ -18,6 +18,7 @@
18 18
19/* Dummy declarations */ 19/* Dummy declarations */
20struct svc_rqst; 20struct svc_rqst;
21struct rpc_task;
21 22
22/* 23/*
23 * This is the set of functions for lockd->nfsd communication 24 * This is the set of functions for lockd->nfsd communication
@@ -43,6 +44,7 @@ struct nlmclnt_initdata {
43 u32 nfs_version; 44 u32 nfs_version;
44 int noresvport; 45 int noresvport;
45 struct net *net; 46 struct net *net;
47 const struct nlmclnt_operations *nlmclnt_ops;
46}; 48};
47 49
48/* 50/*
@@ -52,8 +54,26 @@ struct nlmclnt_initdata {
52extern struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init); 54extern struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init);
53extern void nlmclnt_done(struct nlm_host *host); 55extern void nlmclnt_done(struct nlm_host *host);
54 56
55extern int nlmclnt_proc(struct nlm_host *host, int cmd, 57/*
56 struct file_lock *fl); 58 * NLM client operations provide a means to modify RPC processing of NLM
59 * requests. Callbacks receive a pointer to data passed into the call to
60 * nlmclnt_proc().
61 */
62struct nlmclnt_operations {
63 /* Called on successful allocation of nlm_rqst, use for allocation or
64 * reference counting. */
65 void (*nlmclnt_alloc_call)(void *);
66
67 /* Called in rpc_task_prepare for unlock. A return value of true
68 * indicates the callback has put the task to sleep on a waitqueue
69 * and NLM should not call rpc_call_start(). */
70 bool (*nlmclnt_unlock_prepare)(struct rpc_task*, void *);
71
72 /* Called when the nlm_rqst is freed, callbacks should clean up here */
73 void (*nlmclnt_release_call)(void *);
74};
75
76extern int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl, void *data);
57extern int lockd_up(struct net *net); 77extern int lockd_up(struct net *net);
58extern void lockd_down(struct net *net); 78extern void lockd_down(struct net *net);
59 79
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index b37dee3acaba..41f7b6a04d69 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -69,6 +69,7 @@ struct nlm_host {
69 char *h_addrbuf; /* address eyecatcher */ 69 char *h_addrbuf; /* address eyecatcher */
70 struct net *net; /* host net */ 70 struct net *net; /* host net */
71 char nodename[UNX_MAXNODENAME + 1]; 71 char nodename[UNX_MAXNODENAME + 1];
72 const struct nlmclnt_operations *h_nlmclnt_ops; /* Callback ops for NLM users */
72}; 73};
73 74
74/* 75/*
@@ -142,6 +143,7 @@ struct nlm_rqst {
142 struct nlm_block * a_block; 143 struct nlm_block * a_block;
143 unsigned int a_retries; /* Retry count */ 144 unsigned int a_retries; /* Retry count */
144 u8 a_owner[NLMCLNT_OHSIZE]; 145 u8 a_owner[NLMCLNT_OHSIZE];
146 void * a_callback_data; /* sent to nlmclnt_operations callbacks */
145}; 147};
146 148
147/* 149/*
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 51e27f9746ee..677c6b91dfcd 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1551,6 +1551,7 @@ struct nfs_rpc_ops {
1551 const struct inode_operations *dir_inode_ops; 1551 const struct inode_operations *dir_inode_ops;
1552 const struct inode_operations *file_inode_ops; 1552 const struct inode_operations *file_inode_ops;
1553 const struct file_operations *file_ops; 1553 const struct file_operations *file_ops;
1554 const struct nlmclnt_operations *nlmclnt_ops;
1554 1555
1555 int (*getroot) (struct nfs_server *, struct nfs_fh *, 1556 int (*getroot) (struct nfs_server *, struct nfs_fh *,
1556 struct nfs_fsinfo *); 1557 struct nfs_fsinfo *);