diff options
author | Stanislav Kinsbursky <skinsbursky@parallels.com> | 2011-10-25 07:16:36 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-10-25 07:15:48 -0400 |
commit | 914edb1bb2abe2ae4775368f2ffb7f41010fb81e (patch) | |
tree | c3a46e520de7e003c1a867dae4aa3740c4f074d2 /net/sunrpc | |
parent | dc6f55e9f8dac4b6479be67c5c9128ad37bb491f (diff) |
SUNRPC: introduce helpers for reference counted rpcbind clients
v6:
1) added write memory barrier to rpcb_set_local to make sure, that rpcbind
clients become valid before rpcb_users assignment
2) explicitly set rpcb_users to 1 instead of incrementing it (looks clearer from
my pow).
v5: fixed races with rpcb_users in rpcb_get_local()
This helpers will be used for dynamical creation and destruction of rpcbind
clients.
Variable rpcb_users is actually a counter of lauched RPC services. If rpcbind
clients has been created already, then we just increase rpcb_users.
Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/rpcb_clnt.c | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index f588b852d41c..78af56579fa1 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c | |||
@@ -114,6 +114,9 @@ static struct rpc_program rpcb_program; | |||
114 | static struct rpc_clnt * rpcb_local_clnt; | 114 | static struct rpc_clnt * rpcb_local_clnt; |
115 | static struct rpc_clnt * rpcb_local_clnt4; | 115 | static struct rpc_clnt * rpcb_local_clnt4; |
116 | 116 | ||
117 | DEFINE_SPINLOCK(rpcb_clnt_lock); | ||
118 | unsigned int rpcb_users; | ||
119 | |||
117 | struct rpcbind_args { | 120 | struct rpcbind_args { |
118 | struct rpc_xprt * r_xprt; | 121 | struct rpc_xprt * r_xprt; |
119 | 122 | ||
@@ -161,6 +164,56 @@ static void rpcb_map_release(void *data) | |||
161 | kfree(map); | 164 | kfree(map); |
162 | } | 165 | } |
163 | 166 | ||
167 | static int rpcb_get_local(void) | ||
168 | { | ||
169 | int cnt; | ||
170 | |||
171 | spin_lock(&rpcb_clnt_lock); | ||
172 | if (rpcb_users) | ||
173 | rpcb_users++; | ||
174 | cnt = rpcb_users; | ||
175 | spin_unlock(&rpcb_clnt_lock); | ||
176 | |||
177 | return cnt; | ||
178 | } | ||
179 | |||
180 | void rpcb_put_local(void) | ||
181 | { | ||
182 | struct rpc_clnt *clnt = rpcb_local_clnt; | ||
183 | struct rpc_clnt *clnt4 = rpcb_local_clnt4; | ||
184 | int shutdown; | ||
185 | |||
186 | spin_lock(&rpcb_clnt_lock); | ||
187 | if (--rpcb_users == 0) { | ||
188 | rpcb_local_clnt = NULL; | ||
189 | rpcb_local_clnt4 = NULL; | ||
190 | } | ||
191 | shutdown = !rpcb_users; | ||
192 | spin_unlock(&rpcb_clnt_lock); | ||
193 | |||
194 | if (shutdown) { | ||
195 | /* | ||
196 | * cleanup_rpcb_clnt - remove xprtsock's sysctls, unregister | ||
197 | */ | ||
198 | if (clnt4) | ||
199 | rpc_shutdown_client(clnt4); | ||
200 | if (clnt) | ||
201 | rpc_shutdown_client(clnt); | ||
202 | } | ||
203 | } | ||
204 | |||
205 | static void rpcb_set_local(struct rpc_clnt *clnt, struct rpc_clnt *clnt4) | ||
206 | { | ||
207 | /* Protected by rpcb_create_local_mutex */ | ||
208 | rpcb_local_clnt = clnt; | ||
209 | rpcb_local_clnt4 = clnt4; | ||
210 | smp_wmb(); | ||
211 | rpcb_users = 1; | ||
212 | dprintk("RPC: created new rpcb local clients (rpcb_local_clnt: " | ||
213 | "%p, rpcb_local_clnt4: %p)\n", rpcb_local_clnt, | ||
214 | rpcb_local_clnt4); | ||
215 | } | ||
216 | |||
164 | /* | 217 | /* |
165 | * Returns zero on success, otherwise a negative errno value | 218 | * Returns zero on success, otherwise a negative errno value |
166 | * is returned. | 219 | * is returned. |