]>
Commit | Line | Data |
---|---|---|
8b272c0e JR |
1 | All of the above |
2 | --- | |
3 | fs/lockd/host.c | 39 + | |
4 | fs/lockd/mon.c | 2 | |
5 | fs/lockd/svc.c | 6 | |
6 | fs/nfs/Makefile | 4 | |
7 | fs/nfs/client.c | 28 - | |
8 | fs/nfs/delegation.c | 186 +++-- | |
9 | fs/nfs/delegation.h | 26 - | |
10 | fs/nfs/dir.c | 16 | |
11 | fs/nfs/direct.c | 34 + | |
12 | fs/nfs/inode.c | 73 +- | |
13 | fs/nfs/internal.h | 4 | |
14 | fs/nfs/mount_clnt.c | 169 +++-- | |
15 | fs/nfs/nfs2xdr.c | 6 | |
16 | fs/nfs/nfs3proc.c | 4 | |
17 | fs/nfs/nfs3xdr.c | 8 | |
18 | fs/nfs/nfs4_fs.h | 40 + | |
19 | fs/nfs/nfs4proc.c | 760 +++++++++++++--------- | |
20 | fs/nfs/nfs4state.c | 310 ++++++--- | |
21 | fs/nfs/nfs4xdr.c | 126 ++-- | |
22 | fs/nfs/nfsroot.c | 5 | |
23 | fs/nfs/pagelist.c | 60 +- | |
24 | fs/nfs/read.c | 40 + | |
25 | fs/nfs/super.c | 1189 +++++++++++++++++++++++++++++----- | |
26 | fs/nfs/write.c | 149 ++-- | |
27 | fs/nfsd/nfs4callback.c | 18 - | |
28 | fs/nfsd/nfs4state.c | 1 | |
29 | include/linux/lockd/lockd.h | 1 | |
30 | include/linux/nfs4.h | 1 | |
31 | include/linux/nfs4_mount.h | 3 | |
32 | include/linux/nfs_fs.h | 28 - | |
33 | include/linux/nfs_fs_sb.h | 8 | |
34 | include/linux/nfs_mount.h | 3 | |
35 | include/linux/nfs_page.h | 25 - | |
36 | include/linux/nfs_xdr.h | 5 | |
37 | include/linux/sunrpc/auth.h | 48 + | |
38 | include/linux/sunrpc/auth_gss.h | 6 | |
39 | include/linux/sunrpc/clnt.h | 33 - | |
40 | include/linux/sunrpc/gss_api.h | 2 | |
41 | include/linux/sunrpc/rpc_pipe_fs.h | 2 | |
42 | include/linux/sunrpc/sched.h | 6 | |
43 | include/linux/sunrpc/svcsock.h | 1 | |
44 | include/linux/sunrpc/xprt.h | 16 | |
45 | kernel/auditsc.c | 1 | |
46 | net/sunrpc/auth.c | 357 +++++++--- | |
47 | net/sunrpc/auth_gss/auth_gss.c | 339 ++++++---- | |
48 | net/sunrpc/auth_gss/gss_krb5_mech.c | 2 | |
49 | net/sunrpc/auth_gss/gss_spkm3_mech.c | 2 | |
50 | net/sunrpc/auth_null.c | 10 | |
51 | net/sunrpc/auth_unix.c | 54 +- | |
52 | net/sunrpc/clnt.c | 367 +++++++--- | |
53 | net/sunrpc/rpc_pipe.c | 87 ++ | |
54 | net/sunrpc/rpcb_clnt.c | 65 +- | |
55 | net/sunrpc/sched.c | 209 ++---- | |
56 | net/sunrpc/sunrpc_syms.c | 8 | |
57 | net/sunrpc/svcsock.c | 20 + | |
58 | net/sunrpc/xprt.c | 19 - | |
59 | net/sunrpc/xprtsock.c | 81 +- | |
60 | 57 files changed, 3305 insertions(+), 1807 deletions(-) | |
61 | ||
62 | diff --git a/fs/lockd/host.c b/fs/lockd/host.c | |
63 | index 96070bf..572601e 100644 | |
64 | --- a/fs/lockd/host.c | |
65 | +++ b/fs/lockd/host.c | |
66 | @@ -44,9 +44,8 @@ static struct nsm_handle * nsm_find(const struct sockaddr_in *sin, | |
67 | */ | |
68 | static struct nlm_host * | |
69 | nlm_lookup_host(int server, const struct sockaddr_in *sin, | |
70 | - int proto, int version, | |
71 | - const char *hostname, | |
72 | - int hostname_len) | |
73 | + int proto, int version, const char *hostname, | |
74 | + int hostname_len, const struct sockaddr_in *ssin) | |
75 | { | |
76 | struct hlist_head *chain; | |
77 | struct hlist_node *pos; | |
78 | @@ -54,7 +53,9 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, | |
79 | struct nsm_handle *nsm = NULL; | |
80 | int hash; | |
81 | ||
82 | - dprintk("lockd: nlm_lookup_host(%u.%u.%u.%u, p=%d, v=%d, my role=%s, name=%.*s)\n", | |
83 | + dprintk("lockd: nlm_lookup_host("NIPQUAD_FMT"->"NIPQUAD_FMT | |
84 | + ", p=%d, v=%d, my role=%s, name=%.*s)\n", | |
85 | + NIPQUAD(ssin->sin_addr.s_addr), | |
86 | NIPQUAD(sin->sin_addr.s_addr), proto, version, | |
87 | server? "server" : "client", | |
88 | hostname_len, | |
89 | @@ -91,6 +92,8 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, | |
90 | continue; | |
91 | if (host->h_server != server) | |
92 | continue; | |
93 | + if (!nlm_cmp_addr(&host->h_saddr, ssin)) | |
94 | + continue; | |
95 | ||
96 | /* Move to head of hash chain. */ | |
97 | hlist_del(&host->h_hash); | |
98 | @@ -118,6 +121,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, | |
99 | host->h_name = nsm->sm_name; | |
100 | host->h_addr = *sin; | |
101 | host->h_addr.sin_port = 0; /* ouch! */ | |
102 | + host->h_saddr = *ssin; | |
103 | host->h_version = version; | |
104 | host->h_proto = proto; | |
105 | host->h_rpcclnt = NULL; | |
106 | @@ -161,15 +165,9 @@ nlm_destroy_host(struct nlm_host *host) | |
107 | */ | |
108 | nsm_unmonitor(host); | |
109 | ||
110 | - if ((clnt = host->h_rpcclnt) != NULL) { | |
111 | - if (atomic_read(&clnt->cl_users)) { | |
112 | - printk(KERN_WARNING | |
113 | - "lockd: active RPC handle\n"); | |
114 | - clnt->cl_dead = 1; | |
115 | - } else { | |
116 | - rpc_destroy_client(host->h_rpcclnt); | |
117 | - } | |
118 | - } | |
119 | + clnt = host->h_rpcclnt; | |
120 | + if (clnt != NULL) | |
121 | + rpc_shutdown_client(clnt); | |
122 | kfree(host); | |
123 | } | |
124 | ||
125 | @@ -180,8 +178,10 @@ struct nlm_host * | |
126 | nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version, | |
127 | const char *hostname, int hostname_len) | |
128 | { | |
129 | + struct sockaddr_in ssin = {0}; | |
130 | + | |
131 | return nlm_lookup_host(0, sin, proto, version, | |
132 | - hostname, hostname_len); | |
133 | + hostname, hostname_len, &ssin); | |
134 | } | |
135 | ||
136 | /* | |
137 | @@ -191,9 +191,12 @@ struct nlm_host * | |
138 | nlmsvc_lookup_host(struct svc_rqst *rqstp, | |
139 | const char *hostname, int hostname_len) | |
140 | { | |
141 | + struct sockaddr_in ssin = {0}; | |
142 | + | |
143 | + ssin.sin_addr = rqstp->rq_daddr.addr; | |
144 | return nlm_lookup_host(1, svc_addr_in(rqstp), | |
145 | rqstp->rq_prot, rqstp->rq_vers, | |
146 | - hostname, hostname_len); | |
147 | + hostname, hostname_len, &ssin); | |
148 | } | |
149 | ||
150 | /* | |
151 | @@ -204,8 +207,9 @@ nlm_bind_host(struct nlm_host *host) | |
152 | { | |
153 | struct rpc_clnt *clnt; | |
154 | ||
155 | - dprintk("lockd: nlm_bind_host(%08x)\n", | |
156 | - (unsigned)ntohl(host->h_addr.sin_addr.s_addr)); | |
157 | + dprintk("lockd: nlm_bind_host("NIPQUAD_FMT"->"NIPQUAD_FMT")\n", | |
158 | + NIPQUAD(host->h_saddr.sin_addr), | |
159 | + NIPQUAD(host->h_addr.sin_addr)); | |
160 | ||
161 | /* Lock host handle */ | |
162 | mutex_lock(&host->h_mutex); | |
163 | @@ -232,6 +236,7 @@ nlm_bind_host(struct nlm_host *host) | |
164 | .protocol = host->h_proto, | |
165 | .address = (struct sockaddr *)&host->h_addr, | |
166 | .addrsize = sizeof(host->h_addr), | |
167 | + .saddress = (struct sockaddr *)&host->h_saddr, | |
168 | .timeout = &timeparms, | |
169 | .servername = host->h_name, | |
170 | .program = &nlm_program, | |
171 | diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c | |
172 | index 2102e2d..3353ed8 100644 | |
173 | --- a/fs/lockd/mon.c | |
174 | +++ b/fs/lockd/mon.c | |
175 | @@ -61,6 +61,7 @@ nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res) | |
176 | status); | |
177 | else | |
178 | status = 0; | |
179 | + rpc_shutdown_client(clnt); | |
180 | out: | |
181 | return status; | |
182 | } | |
183 | @@ -138,7 +139,6 @@ nsm_create(void) | |
184 | .program = &nsm_program, | |
185 | .version = SM_VERSION, | |
186 | .authflavor = RPC_AUTH_NULL, | |
187 | - .flags = (RPC_CLNT_CREATE_ONESHOT), | |
188 | }; | |
189 | ||
190 | return rpc_create(&args); | |
191 | diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c | |
192 | index 126b1bf..2680932 100644 | |
193 | --- a/fs/lockd/svc.c | |
194 | +++ b/fs/lockd/svc.c | |
195 | @@ -123,9 +123,6 @@ lockd(struct svc_rqst *rqstp) | |
196 | /* Process request with signals blocked, but allow SIGKILL. */ | |
197 | allow_signal(SIGKILL); | |
198 | ||
199 | - /* kick rpciod */ | |
200 | - rpciod_up(); | |
201 | - | |
202 | dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n"); | |
203 | ||
204 | if (!nlm_timeout) | |
205 | @@ -202,9 +199,6 @@ lockd(struct svc_rqst *rqstp) | |
206 | /* Exit the RPC thread */ | |
207 | svc_exit_thread(rqstp); | |
208 | ||
209 | - /* release rpciod */ | |
210 | - rpciod_down(); | |
211 | - | |
212 | /* Release module */ | |
213 | unlock_kernel(); | |
214 | module_put_and_exit(0); | |
215 | diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile | |
216 | index f4580b4..b55cb23 100644 | |
217 | --- a/fs/nfs/Makefile | |
218 | +++ b/fs/nfs/Makefile | |
219 | @@ -6,8 +6,8 @@ obj-$(CONFIG_NFS_FS) += nfs.o | |
220 | ||
221 | nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \ | |
222 | pagelist.o proc.o read.o symlink.o unlink.o \ | |
223 | - write.o namespace.o | |
224 | -nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o | |
225 | + write.o namespace.o mount_clnt.o | |
226 | +nfs-$(CONFIG_ROOT_NFS) += nfsroot.o | |
227 | nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o | |
228 | nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o | |
229 | nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \ | |
230 | diff --git a/fs/nfs/client.c b/fs/nfs/client.c | |
231 | index 881fa49..ccb4550 100644 | |
232 | --- a/fs/nfs/client.c | |
233 | +++ b/fs/nfs/client.c | |
234 | @@ -102,19 +102,10 @@ static struct nfs_client *nfs_alloc_client(const char *hostname, | |
235 | int nfsversion) | |
236 | { | |
237 | struct nfs_client *clp; | |
238 | - int error; | |
239 | ||
240 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) | |
241 | goto error_0; | |
242 | ||
243 | - error = rpciod_up(); | |
244 | - if (error < 0) { | |
245 | - dprintk("%s: couldn't start rpciod! Error = %d\n", | |
246 | - __FUNCTION__, error); | |
247 | - goto error_1; | |
248 | - } | |
249 | - __set_bit(NFS_CS_RPCIOD, &clp->cl_res_state); | |
250 | - | |
251 | if (nfsversion == 4) { | |
252 | if (nfs_callback_up() < 0) | |
253 | goto error_2; | |
254 | @@ -139,8 +130,6 @@ static struct nfs_client *nfs_alloc_client(const char *hostname, | |
255 | #ifdef CONFIG_NFS_V4 | |
256 | init_rwsem(&clp->cl_sem); | |
257 | INIT_LIST_HEAD(&clp->cl_delegations); | |
258 | - INIT_LIST_HEAD(&clp->cl_state_owners); | |
259 | - INIT_LIST_HEAD(&clp->cl_unused); | |
260 | spin_lock_init(&clp->cl_lock); | |
261 | INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); | |
262 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); | |
263 | @@ -154,9 +143,6 @@ error_3: | |
264 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | |
265 | nfs_callback_down(); | |
266 | error_2: | |
267 | - rpciod_down(); | |
268 | - __clear_bit(NFS_CS_RPCIOD, &clp->cl_res_state); | |
269 | -error_1: | |
270 | kfree(clp); | |
271 | error_0: | |
272 | return NULL; | |
273 | @@ -167,16 +153,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp) | |
274 | #ifdef CONFIG_NFS_V4 | |
275 | if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state)) | |
276 | nfs4_kill_renewd(clp); | |
277 | - while (!list_empty(&clp->cl_unused)) { | |
278 | - struct nfs4_state_owner *sp; | |
279 | - | |
280 | - sp = list_entry(clp->cl_unused.next, | |
281 | - struct nfs4_state_owner, | |
282 | - so_list); | |
283 | - list_del(&sp->so_list); | |
284 | - kfree(sp); | |
285 | - } | |
286 | - BUG_ON(!list_empty(&clp->cl_state_owners)); | |
287 | + BUG_ON(!RB_EMPTY_ROOT(&clp->cl_state_owners)); | |
288 | if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) | |
289 | nfs_idmap_delete(clp); | |
290 | #endif | |
291 | @@ -198,9 +175,6 @@ static void nfs_free_client(struct nfs_client *clp) | |
292 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | |
293 | nfs_callback_down(); | |
294 | ||
295 | - if (__test_and_clear_bit(NFS_CS_RPCIOD, &clp->cl_res_state)) | |
296 | - rpciod_down(); | |
297 | - | |
298 | kfree(clp->cl_hostname); | |
299 | kfree(clp); | |
300 | ||
301 | diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c | |
302 | index 7f37d1b..20ac403 100644 | |
303 | --- a/fs/nfs/delegation.c | |
304 | +++ b/fs/nfs/delegation.c | |
305 | @@ -27,6 +27,13 @@ static void nfs_free_delegation(struct nfs_delegation *delegation) | |
306 | kfree(delegation); | |
307 | } | |
308 | ||
309 | +static void nfs_free_delegation_callback(struct rcu_head *head) | |
310 | +{ | |
311 | + struct nfs_delegation *delegation = container_of(head, struct nfs_delegation, rcu); | |
312 | + | |
313 | + nfs_free_delegation(delegation); | |
314 | +} | |
315 | + | |
316 | static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state) | |
317 | { | |
318 | struct inode *inode = state->inode; | |
319 | @@ -57,7 +64,7 @@ out_err: | |
320 | return status; | |
321 | } | |
322 | ||
323 | -static void nfs_delegation_claim_opens(struct inode *inode) | |
324 | +static void nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid) | |
325 | { | |
326 | struct nfs_inode *nfsi = NFS_I(inode); | |
327 | struct nfs_open_context *ctx; | |
328 | @@ -72,9 +79,11 @@ again: | |
329 | continue; | |
330 | if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) | |
331 | continue; | |
332 | + if (memcmp(state->stateid.data, stateid->data, sizeof(state->stateid.data)) != 0) | |
333 | + continue; | |
334 | get_nfs_open_context(ctx); | |
335 | spin_unlock(&inode->i_lock); | |
336 | - err = nfs4_open_delegation_recall(ctx->dentry, state); | |
337 | + err = nfs4_open_delegation_recall(ctx, state, stateid); | |
338 | if (err >= 0) | |
339 | err = nfs_delegation_claim_locks(ctx, state); | |
340 | put_nfs_open_context(ctx); | |
341 | @@ -115,10 +124,6 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |
342 | struct nfs_delegation *delegation; | |
343 | int status = 0; | |
344 | ||
345 | - /* Ensure we first revalidate the attributes and page cache! */ | |
346 | - if ((nfsi->cache_validity & (NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_ATTR))) | |
347 | - __nfs_revalidate_inode(NFS_SERVER(inode), inode); | |
348 | - | |
349 | delegation = kmalloc(sizeof(*delegation), GFP_KERNEL); | |
350 | if (delegation == NULL) | |
351 | return -ENOMEM; | |
352 | @@ -131,10 +136,10 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |
353 | delegation->inode = inode; | |
354 | ||
355 | spin_lock(&clp->cl_lock); | |
356 | - if (nfsi->delegation == NULL) { | |
357 | - list_add(&delegation->super_list, &clp->cl_delegations); | |
358 | - nfsi->delegation = delegation; | |
359 | + if (rcu_dereference(nfsi->delegation) == NULL) { | |
360 | + list_add_rcu(&delegation->super_list, &clp->cl_delegations); | |
361 | nfsi->delegation_state = delegation->type; | |
362 | + rcu_assign_pointer(nfsi->delegation, delegation); | |
363 | delegation = NULL; | |
364 | } else { | |
365 | if (memcmp(&delegation->stateid, &nfsi->delegation->stateid, | |
366 | @@ -145,6 +150,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |
367 | status = -EIO; | |
368 | } | |
369 | } | |
370 | + | |
371 | + /* Ensure we revalidate the attributes and page cache! */ | |
372 | + spin_lock(&inode->i_lock); | |
373 | + nfsi->cache_validity |= NFS_INO_REVAL_FORCED; | |
374 | + spin_unlock(&inode->i_lock); | |
375 | + | |
376 | spin_unlock(&clp->cl_lock); | |
377 | kfree(delegation); | |
378 | return status; | |
379 | @@ -155,7 +166,7 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation * | |
380 | int res = 0; | |
381 | ||
382 | res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid); | |
383 | - nfs_free_delegation(delegation); | |
384 | + call_rcu(&delegation->rcu, nfs_free_delegation_callback); | |
385 | return res; | |
386 | } | |
387 | ||
388 | @@ -170,33 +181,55 @@ static void nfs_msync_inode(struct inode *inode) | |
389 | /* | |
390 | * Basic procedure for returning a delegation to the server | |
391 | */ | |
392 | -int __nfs_inode_return_delegation(struct inode *inode) | |
393 | +static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation) | |
394 | { | |
395 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | |
396 | struct nfs_inode *nfsi = NFS_I(inode); | |
397 | - struct nfs_delegation *delegation; | |
398 | - int res = 0; | |
399 | ||
400 | nfs_msync_inode(inode); | |
401 | down_read(&clp->cl_sem); | |
402 | /* Guard against new delegated open calls */ | |
403 | down_write(&nfsi->rwsem); | |
404 | - spin_lock(&clp->cl_lock); | |
405 | - delegation = nfsi->delegation; | |
406 | - if (delegation != NULL) { | |
407 | - list_del_init(&delegation->super_list); | |
408 | - nfsi->delegation = NULL; | |
409 | - nfsi->delegation_state = 0; | |
410 | - } | |
411 | - spin_unlock(&clp->cl_lock); | |
412 | - nfs_delegation_claim_opens(inode); | |
413 | + nfs_delegation_claim_opens(inode, &delegation->stateid); | |
414 | up_write(&nfsi->rwsem); | |
415 | up_read(&clp->cl_sem); | |
416 | nfs_msync_inode(inode); | |
417 | ||
418 | - if (delegation != NULL) | |
419 | - res = nfs_do_return_delegation(inode, delegation); | |
420 | - return res; | |
421 | + return nfs_do_return_delegation(inode, delegation); | |
422 | +} | |
423 | + | |
424 | +static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) | |
425 | +{ | |
426 | + struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation); | |
427 | + | |
428 | + if (delegation == NULL) | |
429 | + goto nomatch; | |
430 | + if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data, | |
431 | + sizeof(delegation->stateid.data)) != 0) | |
432 | + goto nomatch; | |
433 | + list_del_rcu(&delegation->super_list); | |
434 | + nfsi->delegation_state = 0; | |
435 | + rcu_assign_pointer(nfsi->delegation, NULL); | |
436 | + return delegation; | |
437 | +nomatch: | |
438 | + return NULL; | |
439 | +} | |
440 | + | |
441 | +int nfs_inode_return_delegation(struct inode *inode) | |
442 | +{ | |
443 | + struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | |
444 | + struct nfs_inode *nfsi = NFS_I(inode); | |
445 | + struct nfs_delegation *delegation; | |
446 | + int err = 0; | |
447 | + | |
448 | + if (rcu_dereference(nfsi->delegation) != NULL) { | |
449 | + spin_lock(&clp->cl_lock); | |
450 | + delegation = nfs_detach_delegation_locked(nfsi, NULL); | |
451 | + spin_unlock(&clp->cl_lock); | |
452 | + if (delegation != NULL) | |
453 | + err = __nfs_inode_return_delegation(inode, delegation); | |
454 | + } | |
455 | + return err; | |
456 | } | |
457 | ||
458 | /* | |
459 | @@ -211,19 +244,23 @@ void nfs_return_all_delegations(struct super_block *sb) | |
460 | if (clp == NULL) | |
461 | return; | |
462 | restart: | |
463 | - spin_lock(&clp->cl_lock); | |
464 | - list_for_each_entry(delegation, &clp->cl_delegations, super_list) { | |
465 | + rcu_read_lock(); | |
466 | + list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { | |
467 | if (delegation->inode->i_sb != sb) | |
468 | continue; | |
469 | inode = igrab(delegation->inode); | |
470 | if (inode == NULL) | |
471 | continue; | |
472 | + spin_lock(&clp->cl_lock); | |
473 | + delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); | |
474 | spin_unlock(&clp->cl_lock); | |
475 | - nfs_inode_return_delegation(inode); | |
476 | + rcu_read_unlock(); | |
477 | + if (delegation != NULL) | |
478 | + __nfs_inode_return_delegation(inode, delegation); | |
479 | iput(inode); | |
480 | goto restart; | |
481 | } | |
482 | - spin_unlock(&clp->cl_lock); | |
483 | + rcu_read_unlock(); | |
484 | } | |
485 | ||
486 | static int nfs_do_expire_all_delegations(void *ptr) | |
487 | @@ -234,22 +271,26 @@ static int nfs_do_expire_all_delegations(void *ptr) | |
488 | ||
489 | allow_signal(SIGKILL); | |
490 | restart: | |
491 | - spin_lock(&clp->cl_lock); | |
492 | if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0) | |
493 | goto out; | |
494 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) | |
495 | goto out; | |
496 | - list_for_each_entry(delegation, &clp->cl_delegations, super_list) { | |
497 | + rcu_read_lock(); | |
498 | + list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { | |
499 | inode = igrab(delegation->inode); | |
500 | if (inode == NULL) | |
501 | continue; | |
502 | + spin_lock(&clp->cl_lock); | |
503 | + delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); | |
504 | spin_unlock(&clp->cl_lock); | |
505 | - nfs_inode_return_delegation(inode); | |
506 | + rcu_read_unlock(); | |
507 | + if (delegation) | |
508 | + __nfs_inode_return_delegation(inode, delegation); | |
509 | iput(inode); | |
510 | goto restart; | |
511 | } | |
512 | + rcu_read_unlock(); | |
513 | out: | |
514 | - spin_unlock(&clp->cl_lock); | |
515 | nfs_put_client(clp); | |
516 | module_put_and_exit(0); | |
517 | } | |
518 | @@ -280,17 +321,21 @@ void nfs_handle_cb_pathdown(struct nfs_client *clp) | |
519 | if (clp == NULL) | |
520 | return; | |
521 | restart: | |
522 | - spin_lock(&clp->cl_lock); | |
523 | - list_for_each_entry(delegation, &clp->cl_delegations, super_list) { | |
524 | + rcu_read_lock(); | |
525 | + list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { | |
526 | inode = igrab(delegation->inode); | |
527 | if (inode == NULL) | |
528 | continue; | |
529 | + spin_lock(&clp->cl_lock); | |
530 | + delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); | |
531 | spin_unlock(&clp->cl_lock); | |
532 | - nfs_inode_return_delegation(inode); | |
533 | + rcu_read_unlock(); | |
534 | + if (delegation != NULL) | |
535 | + __nfs_inode_return_delegation(inode, delegation); | |
536 | iput(inode); | |
537 | goto restart; | |
538 | } | |
539 | - spin_unlock(&clp->cl_lock); | |
540 | + rcu_read_unlock(); | |
541 | } | |
542 | ||
543 | struct recall_threadargs { | |
544 | @@ -316,21 +361,14 @@ static int recall_thread(void *data) | |
545 | down_read(&clp->cl_sem); | |
546 | down_write(&nfsi->rwsem); | |
547 | spin_lock(&clp->cl_lock); | |
548 | - delegation = nfsi->delegation; | |
549 | - if (delegation != NULL && memcmp(delegation->stateid.data, | |
550 | - args->stateid->data, | |
551 | - sizeof(delegation->stateid.data)) == 0) { | |
552 | - list_del_init(&delegation->super_list); | |
553 | - nfsi->delegation = NULL; | |
554 | - nfsi->delegation_state = 0; | |
555 | + delegation = nfs_detach_delegation_locked(nfsi, args->stateid); | |
556 | + if (delegation != NULL) | |
557 | args->result = 0; | |
558 | - } else { | |
559 | - delegation = NULL; | |
560 | + else | |
561 | args->result = -ENOENT; | |
562 | - } | |
563 | spin_unlock(&clp->cl_lock); | |
564 | complete(&args->started); | |
565 | - nfs_delegation_claim_opens(inode); | |
566 | + nfs_delegation_claim_opens(inode, args->stateid); | |
567 | up_write(&nfsi->rwsem); | |
568 | up_read(&clp->cl_sem); | |
569 | nfs_msync_inode(inode); | |
570 | @@ -371,14 +409,14 @@ struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs | |
571 | { | |
572 | struct nfs_delegation *delegation; | |
573 | struct inode *res = NULL; | |
574 | - spin_lock(&clp->cl_lock); | |
575 | - list_for_each_entry(delegation, &clp->cl_delegations, super_list) { | |
576 | + rcu_read_lock(); | |
577 | + list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { | |
578 | if (nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) { | |
579 | res = igrab(delegation->inode); | |
580 | break; | |
581 | } | |
582 | } | |
583 | - spin_unlock(&clp->cl_lock); | |
584 | + rcu_read_unlock(); | |
585 | return res; | |
586 | } | |
587 | ||
588 | @@ -388,10 +426,10 @@ struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs | |
589 | void nfs_delegation_mark_reclaim(struct nfs_client *clp) | |
590 | { | |
591 | struct nfs_delegation *delegation; | |
592 | - spin_lock(&clp->cl_lock); | |
593 | - list_for_each_entry(delegation, &clp->cl_delegations, super_list) | |
594 | + rcu_read_lock(); | |
595 | + list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) | |
596 | delegation->flags |= NFS_DELEGATION_NEED_RECLAIM; | |
597 | - spin_unlock(&clp->cl_lock); | |
598 | + rcu_read_unlock(); | |
599 | } | |
600 | ||
601 | /* | |
602 | @@ -399,39 +437,35 @@ void nfs_delegation_mark_reclaim(struct nfs_client *clp) | |
603 | */ | |
604 | void nfs_delegation_reap_unclaimed(struct nfs_client *clp) | |
605 | { | |
606 | - struct nfs_delegation *delegation, *n; | |
607 | - LIST_HEAD(head); | |
608 | - spin_lock(&clp->cl_lock); | |
609 | - list_for_each_entry_safe(delegation, n, &clp->cl_delegations, super_list) { | |
610 | + struct nfs_delegation *delegation; | |
611 | +restart: | |
612 | + rcu_read_lock(); | |
613 | + list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { | |
614 | if ((delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) | |
615 | continue; | |
616 | - list_move(&delegation->super_list, &head); | |
617 | - NFS_I(delegation->inode)->delegation = NULL; | |
618 | - NFS_I(delegation->inode)->delegation_state = 0; | |
619 | - } | |
620 | - spin_unlock(&clp->cl_lock); | |
621 | - while(!list_empty(&head)) { | |
622 | - delegation = list_entry(head.next, struct nfs_delegation, super_list); | |
623 | - list_del(&delegation->super_list); | |
624 | - nfs_free_delegation(delegation); | |
625 | + spin_lock(&clp->cl_lock); | |
626 | + delegation = nfs_detach_delegation_locked(NFS_I(delegation->inode), NULL); | |
627 | + spin_unlock(&clp->cl_lock); | |
628 | + rcu_read_unlock(); | |
629 | + if (delegation != NULL) | |
630 | + call_rcu(&delegation->rcu, nfs_free_delegation_callback); | |
631 | + goto restart; | |
632 | } | |
633 | + rcu_read_unlock(); | |
634 | } | |
635 | ||
636 | int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode) | |
637 | { | |
638 | - struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | |
639 | struct nfs_inode *nfsi = NFS_I(inode); | |
640 | struct nfs_delegation *delegation; | |
641 | - int res = 0; | |
642 | + int ret = 0; | |
643 | ||
644 | - if (nfsi->delegation_state == 0) | |
645 | - return 0; | |
646 | - spin_lock(&clp->cl_lock); | |
647 | - delegation = nfsi->delegation; | |
648 | + rcu_read_lock(); | |
649 | + delegation = rcu_dereference(nfsi->delegation); | |
650 | if (delegation != NULL) { | |
651 | memcpy(dst->data, delegation->stateid.data, sizeof(dst->data)); | |
652 | - res = 1; | |
653 | + ret = 1; | |
654 | } | |
655 | - spin_unlock(&clp->cl_lock); | |
656 | - return res; | |
657 | + rcu_read_unlock(); | |
658 | + return ret; | |
659 | } | |
660 | diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h | |
661 | index 2cfd4b2..5874ce7 100644 | |
662 | --- a/fs/nfs/delegation.h | |
663 | +++ b/fs/nfs/delegation.h | |
664 | @@ -22,11 +22,12 @@ struct nfs_delegation { | |
665 | long flags; | |
666 | loff_t maxsize; | |
667 | __u64 change_attr; | |
668 | + struct rcu_head rcu; | |
669 | }; | |
670 | ||
671 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | |
672 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | |
673 | -int __nfs_inode_return_delegation(struct inode *inode); | |
674 | +int nfs_inode_return_delegation(struct inode *inode); | |
675 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); | |
676 | ||
677 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); | |
678 | @@ -39,27 +40,24 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp); | |
679 | ||
680 | /* NFSv4 delegation-related procedures */ | |
681 | int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid); | |
682 | -int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state); | |
683 | +int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid); | |
684 | int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl); | |
685 | int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode); | |
686 | ||
687 | static inline int nfs_have_delegation(struct inode *inode, int flags) | |
688 | { | |
689 | + struct nfs_delegation *delegation; | |
690 | + int ret = 0; | |
691 | + | |
692 | flags &= FMODE_READ|FMODE_WRITE; | |
693 | - smp_rmb(); | |
694 | - if ((NFS_I(inode)->delegation_state & flags) == flags) | |
695 | - return 1; | |
696 | - return 0; | |
697 | + rcu_read_lock(); | |
698 | + delegation = rcu_dereference(NFS_I(inode)->delegation); | |
699 | + if (delegation != NULL && (delegation->type & flags) == flags) | |
700 | + ret = 1; | |
701 | + rcu_read_unlock(); | |
702 | + return ret; | |
703 | } | |
704 | ||
705 | -static inline int nfs_inode_return_delegation(struct inode *inode) | |
706 | -{ | |
707 | - int err = 0; | |
708 | - | |
709 | - if (NFS_I(inode)->delegation != NULL) | |
710 | - err = __nfs_inode_return_delegation(inode); | |
711 | - return err; | |
712 | -} | |
713 | #else | |
714 | static inline int nfs_have_delegation(struct inode *inode, int flags) | |
715 | { | |
716 | diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c | |
717 | index c27258b..322141f 100644 | |
718 | --- a/fs/nfs/dir.c | |
719 | +++ b/fs/nfs/dir.c | |
720 | @@ -897,14 +897,13 @@ int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd) | |
721 | return (nd->intent.open.flags & O_EXCL) != 0; | |
722 | } | |
723 | ||
724 | -static inline int nfs_reval_fsid(struct vfsmount *mnt, struct inode *dir, | |
725 | - struct nfs_fh *fh, struct nfs_fattr *fattr) | |
726 | +static inline int nfs_reval_fsid(struct inode *dir, const struct nfs_fattr *fattr) | |
727 | { | |
728 | struct nfs_server *server = NFS_SERVER(dir); | |
729 | ||
730 | if (!nfs_fsid_equal(&server->fsid, &fattr->fsid)) | |
731 | - /* Revalidate fsid on root dir */ | |
732 | - return __nfs_revalidate_inode(server, mnt->mnt_root->d_inode); | |
733 | + /* Revalidate fsid using the parent directory */ | |
734 | + return __nfs_revalidate_inode(server, dir); | |
735 | return 0; | |
736 | } | |
737 | ||
738 | @@ -946,7 +945,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |
739 | res = ERR_PTR(error); | |
740 | goto out_unlock; | |
741 | } | |
742 | - error = nfs_reval_fsid(nd->mnt, dir, &fhandle, &fattr); | |
743 | + error = nfs_reval_fsid(dir, &fattr); | |
744 | if (error < 0) { | |
745 | res = ERR_PTR(error); | |
746 | goto out_unlock; | |
747 | @@ -1244,7 +1243,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, | |
748 | attr.ia_mode = mode; | |
749 | attr.ia_valid = ATTR_MODE; | |
750 | ||
751 | - if (nd && (nd->flags & LOOKUP_CREATE)) | |
752 | + if ((nd->flags & LOOKUP_CREATE) != 0) | |
753 | open_flags = nd->intent.open.flags; | |
754 | ||
755 | lock_kernel(); | |
756 | @@ -1535,7 +1534,7 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym | |
757 | ||
758 | lock_kernel(); | |
759 | ||
760 | - page = alloc_page(GFP_KERNEL); | |
761 | + page = alloc_page(GFP_HIGHUSER); | |
762 | if (!page) { | |
763 | unlock_kernel(); | |
764 | return -ENOMEM; | |
765 | @@ -1744,8 +1743,8 @@ int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) | |
766 | struct nfs_inode *nfsi; | |
767 | struct nfs_access_entry *cache; | |
768 | ||
769 | - spin_lock(&nfs_access_lru_lock); | |
770 | restart: | |
771 | + spin_lock(&nfs_access_lru_lock); | |
772 | list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { | |
773 | struct inode *inode; | |
774 | ||
775 | @@ -1770,6 +1769,7 @@ remove_lru_entry: | |
776 | clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags); | |
777 | } | |
778 | spin_unlock(&inode->i_lock); | |
779 | + spin_unlock(&nfs_access_lru_lock); | |
780 | iput(inode); | |
781 | goto restart; | |
782 | } | |
783 | diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c | |
784 | index 00eee87..a5c82b6 100644 | |
785 | --- a/fs/nfs/direct.c | |
786 | +++ b/fs/nfs/direct.c | |
787 | @@ -266,7 +266,7 @@ static const struct rpc_call_ops nfs_read_direct_ops = { | |
788 | static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos) | |
789 | { | |
790 | struct nfs_open_context *ctx = dreq->ctx; | |
791 | - struct inode *inode = ctx->dentry->d_inode; | |
792 | + struct inode *inode = ctx->path.dentry->d_inode; | |
793 | size_t rsize = NFS_SERVER(inode)->rsize; | |
794 | unsigned int pgbase; | |
795 | int result; | |
796 | @@ -295,9 +295,14 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo | |
797 | break; | |
798 | } | |
799 | if ((unsigned)result < data->npages) { | |
800 | - nfs_direct_release_pages(data->pagevec, result); | |
801 | - nfs_readdata_release(data); | |
802 | - break; | |
803 | + bytes = result * PAGE_SIZE; | |
804 | + if (bytes <= pgbase) { | |
805 | + nfs_direct_release_pages(data->pagevec, result); | |
806 | + nfs_readdata_release(data); | |
807 | + break; | |
808 | + } | |
809 | + bytes -= pgbase; | |
810 | + data->npages = result; | |
811 | } | |
812 | ||
813 | get_dreq(dreq); | |
814 | @@ -601,7 +606,7 @@ static const struct rpc_call_ops nfs_write_direct_ops = { | |
815 | static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos, int sync) | |
816 | { | |
817 | struct nfs_open_context *ctx = dreq->ctx; | |
818 | - struct inode *inode = ctx->dentry->d_inode; | |
819 | + struct inode *inode = ctx->path.dentry->d_inode; | |
820 | size_t wsize = NFS_SERVER(inode)->wsize; | |
821 | unsigned int pgbase; | |
822 | int result; | |
823 | @@ -630,9 +635,14 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l | |
824 | break; | |
825 | } | |
826 | if ((unsigned)result < data->npages) { | |
827 | - nfs_direct_release_pages(data->pagevec, result); | |
828 | - nfs_writedata_release(data); | |
829 | - break; | |
830 | + bytes = result * PAGE_SIZE; | |
831 | + if (bytes <= pgbase) { | |
832 | + nfs_direct_release_pages(data->pagevec, result); | |
833 | + nfs_writedata_release(data); | |
834 | + break; | |
835 | + } | |
836 | + bytes -= pgbase; | |
837 | + data->npages = result; | |
838 | } | |
839 | ||
840 | get_dreq(dreq); | |
841 | @@ -763,10 +773,8 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, | |
842 | (unsigned long) count, (long long) pos); | |
843 | ||
844 | if (nr_segs != 1) | |
845 | - return -EINVAL; | |
846 | - | |
847 | - if (count < 0) | |
848 | goto out; | |
849 | + | |
850 | retval = -EFAULT; | |
851 | if (!access_ok(VERIFY_WRITE, buf, count)) | |
852 | goto out; | |
853 | @@ -814,7 +822,7 @@ out: | |
854 | ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, | |
855 | unsigned long nr_segs, loff_t pos) | |
856 | { | |
857 | - ssize_t retval; | |
858 | + ssize_t retval = -EINVAL; | |
859 | struct file *file = iocb->ki_filp; | |
860 | struct address_space *mapping = file->f_mapping; | |
861 | /* XXX: temporary */ | |
862 | @@ -827,7 +835,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, | |
863 | (unsigned long) count, (long long) pos); | |
864 | ||
865 | if (nr_segs != 1) | |
866 | - return -EINVAL; | |
867 | + goto out; | |
868 | ||
869 | retval = generic_write_checks(file, &pos, &count, 0); | |
870 | if (retval) | |
871 | diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c | |
872 | index bd9f5a8..3d9fccf 100644 | |
873 | --- a/fs/nfs/inode.c | |
874 | +++ b/fs/nfs/inode.c | |
875 | @@ -461,14 +461,14 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str | |
876 | ||
877 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); | |
878 | if (ctx != NULL) { | |
879 | - atomic_set(&ctx->count, 1); | |
880 | - ctx->dentry = dget(dentry); | |
881 | - ctx->vfsmnt = mntget(mnt); | |
882 | + ctx->path.dentry = dget(dentry); | |
883 | + ctx->path.mnt = mntget(mnt); | |
884 | ctx->cred = get_rpccred(cred); | |
885 | ctx->state = NULL; | |
886 | ctx->lockowner = current->files; | |
887 | ctx->error = 0; | |
888 | ctx->dir_cookie = 0; | |
889 | + kref_init(&ctx->kref); | |
890 | } | |
891 | return ctx; | |
892 | } | |
893 | @@ -476,27 +476,33 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str | |
894 | struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) | |
895 | { | |
896 | if (ctx != NULL) | |
897 | - atomic_inc(&ctx->count); | |
898 | + kref_get(&ctx->kref); | |
899 | return ctx; | |
900 | } | |
901 | ||
902 | -void put_nfs_open_context(struct nfs_open_context *ctx) | |
903 | +static void nfs_free_open_context(struct kref *kref) | |
904 | { | |
905 | - if (atomic_dec_and_test(&ctx->count)) { | |
906 | - if (!list_empty(&ctx->list)) { | |
907 | - struct inode *inode = ctx->dentry->d_inode; | |
908 | - spin_lock(&inode->i_lock); | |
909 | - list_del(&ctx->list); | |
910 | - spin_unlock(&inode->i_lock); | |
911 | - } | |
912 | - if (ctx->state != NULL) | |
913 | - nfs4_close_state(ctx->state, ctx->mode); | |
914 | - if (ctx->cred != NULL) | |
915 | - put_rpccred(ctx->cred); | |
916 | - dput(ctx->dentry); | |
917 | - mntput(ctx->vfsmnt); | |
918 | - kfree(ctx); | |
919 | + struct nfs_open_context *ctx = container_of(kref, | |
920 | + struct nfs_open_context, kref); | |
921 | + | |
922 | + if (!list_empty(&ctx->list)) { | |
923 | + struct inode *inode = ctx->path.dentry->d_inode; | |
924 | + spin_lock(&inode->i_lock); | |
925 | + list_del(&ctx->list); | |
926 | + spin_unlock(&inode->i_lock); | |
927 | } | |
928 | + if (ctx->state != NULL) | |
929 | + nfs4_close_state(&ctx->path, ctx->state, ctx->mode); | |
930 | + if (ctx->cred != NULL) | |
931 | + put_rpccred(ctx->cred); | |
932 | + dput(ctx->path.dentry); | |
933 | + mntput(ctx->path.mnt); | |
934 | + kfree(ctx); | |
935 | +} | |
936 | + | |
937 | +void put_nfs_open_context(struct nfs_open_context *ctx) | |
938 | +{ | |
939 | + kref_put(&ctx->kref, nfs_free_open_context); | |
940 | } | |
941 | ||
942 | /* | |
943 | @@ -961,8 +967,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |
944 | goto out_changed; | |
945 | ||
946 | server = NFS_SERVER(inode); | |
947 | - /* Update the fsid if and only if this is the root directory */ | |
948 | - if (inode == inode->i_sb->s_root->d_inode | |
949 | + /* Update the fsid? */ | |
950 | + if (S_ISDIR(inode->i_mode) | |
951 | && !nfs_fsid_equal(&server->fsid, &fattr->fsid)) | |
952 | server->fsid = fattr->fsid; | |
953 | ||
954 | @@ -1066,8 +1072,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |
955 | invalid &= ~NFS_INO_INVALID_DATA; | |
956 | if (data_stable) | |
957 | invalid &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME|NFS_INO_REVAL_PAGECACHE); | |
958 | - if (!nfs_have_delegation(inode, FMODE_READ)) | |
959 | + if (!nfs_have_delegation(inode, FMODE_READ) || | |
960 | + (nfsi->cache_validity & NFS_INO_REVAL_FORCED)) | |
961 | nfsi->cache_validity |= invalid; | |
962 | + nfsi->cache_validity &= ~NFS_INO_REVAL_FORCED; | |
963 | ||
964 | return 0; | |
965 | out_changed: | |
966 | @@ -1103,27 +1111,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |
967 | */ | |
968 | void nfs4_clear_inode(struct inode *inode) | |
969 | { | |
970 | - struct nfs_inode *nfsi = NFS_I(inode); | |
971 | - | |
972 | /* If we are holding a delegation, return it! */ | |
973 | nfs_inode_return_delegation(inode); | |
974 | /* First call standard NFS clear_inode() code */ | |
975 | nfs_clear_inode(inode); | |
976 | - /* Now clear out any remaining state */ | |
977 | - while (!list_empty(&nfsi->open_states)) { | |
978 | - struct nfs4_state *state; | |
979 | - | |
980 | - state = list_entry(nfsi->open_states.next, | |
981 | - struct nfs4_state, | |
982 | - inode_states); | |
983 | - dprintk("%s(%s/%Ld): found unclaimed NFSv4 state %p\n", | |
984 | - __FUNCTION__, | |
985 | - inode->i_sb->s_id, | |
986 | - (long long)NFS_FILEID(inode), | |
987 | - state); | |
988 | - BUG_ON(atomic_read(&state->count) != 1); | |
989 | - nfs4_close_state(state, state->state); | |
990 | - } | |
991 | } | |
992 | #endif | |
993 | ||
994 | @@ -1165,15 +1156,11 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag | |
995 | struct nfs_inode *nfsi = (struct nfs_inode *) foo; | |
996 | ||
997 | inode_init_once(&nfsi->vfs_inode); | |
998 | - spin_lock_init(&nfsi->req_lock); | |
999 | - INIT_LIST_HEAD(&nfsi->dirty); | |
1000 | - INIT_LIST_HEAD(&nfsi->commit); | |
1001 | INIT_LIST_HEAD(&nfsi->open_files); | |
1002 | INIT_LIST_HEAD(&nfsi->access_cache_entry_lru); | |
1003 | INIT_LIST_HEAD(&nfsi->access_cache_inode_lru); | |
1004 | INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC); | |
1005 | atomic_set(&nfsi->data_updates, 0); | |
1006 | - nfsi->ndirty = 0; | |
1007 | nfsi->ncommit = 0; | |
1008 | nfsi->npages = 0; | |
1009 | nfs4_init_once(nfsi); | |
1010 | diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h | |
1011 | index ad2b40d..76cf55d 100644 | |
1012 | --- a/fs/nfs/internal.h | |
1013 | +++ b/fs/nfs/internal.h | |
1014 | @@ -183,9 +183,9 @@ unsigned long nfs_block_bits(unsigned long bsize, unsigned char *nrbitsp) | |
1015 | /* | |
1016 | * Calculate the number of 512byte blocks used. | |
1017 | */ | |
1018 | -static inline unsigned long nfs_calc_block_size(u64 tsize) | |
1019 | +static inline blkcnt_t nfs_calc_block_size(u64 tsize) | |
1020 | { | |
1021 | - loff_t used = (tsize + 511) >> 9; | |
1022 | + blkcnt_t used = (tsize + 511) >> 9; | |
1023 | return (used > ULONG_MAX) ? ULONG_MAX : used; | |
1024 | } | |
1025 | ||
1026 | diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c | |
1027 | index ca5a266..8afd9f7 100644 | |
1028 | --- a/fs/nfs/mount_clnt.c | |
1029 | +++ b/fs/nfs/mount_clnt.c | |
1030 | @@ -1,7 +1,5 @@ | |
1031 | /* | |
1032 | - * linux/fs/nfs/mount_clnt.c | |
1033 | - * | |
1034 | - * MOUNT client to support NFSroot. | |
1035 | + * In-kernel MOUNT protocol client | |
1036 | * | |
1037 | * Copyright (C) 1997, Olaf Kirch <okir@monad.swb.de> | |
1038 | */ | |
1039 | @@ -18,33 +16,31 @@ | |
1040 | #include <linux/nfs_fs.h> | |
1041 | ||
1042 | #ifdef RPC_DEBUG | |
1043 | -# define NFSDBG_FACILITY NFSDBG_ROOT | |
1044 | +# define NFSDBG_FACILITY NFSDBG_MOUNT | |
1045 | #endif | |
1046 | ||
1047 | -/* | |
1048 | -#define MOUNT_PROGRAM 100005 | |
1049 | -#define MOUNT_VERSION 1 | |
1050 | -#define MOUNT_MNT 1 | |
1051 | -#define MOUNT_UMNT 3 | |
1052 | - */ | |
1053 | - | |
1054 | -static struct rpc_clnt * mnt_create(char *, struct sockaddr_in *, | |
1055 | - int, int); | |
1056 | static struct rpc_program mnt_program; | |
1057 | ||
1058 | struct mnt_fhstatus { | |
1059 | - unsigned int status; | |
1060 | - struct nfs_fh * fh; | |
1061 | + u32 status; | |
1062 | + struct nfs_fh *fh; | |
1063 | }; | |
1064 | ||
1065 | -/* | |
1066 | - * Obtain an NFS file handle for the given host and path | |
1067 | +/** | |
1068 | + * nfs_mount - Obtain an NFS file handle for the given host and path | |
1069 | + * @addr: pointer to server's address | |
1070 | + * @len: size of server's address | |
1071 | + * @hostname: name of server host, or NULL | |
1072 | + * @path: pointer to string containing export path to mount | |
1073 | + * @version: mount version to use for this request | |
1074 | + * @protocol: transport protocol to use for thie request | |
1075 | + * @fh: pointer to location to place returned file handle | |
1076 | + * | |
1077 | + * Uses default timeout parameters specified by underlying transport. | |
1078 | */ | |
1079 | -int | |
1080 | -nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, | |
1081 | - int version, int protocol) | |
1082 | +int nfs_mount(struct sockaddr *addr, size_t len, char *hostname, char *path, | |
1083 | + int version, int protocol, struct nfs_fh *fh) | |
1084 | { | |
1085 | - struct rpc_clnt *mnt_clnt; | |
1086 | struct mnt_fhstatus result = { | |
1087 | .fh = fh | |
1088 | }; | |
1089 | @@ -52,16 +48,25 @@ nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, | |
1090 | .rpc_argp = path, | |
1091 | .rpc_resp = &result, | |
1092 | }; | |
1093 | - char hostname[32]; | |
1094 | + struct rpc_create_args args = { | |
1095 | + .protocol = protocol, | |
1096 | + .address = addr, | |
1097 | + .addrsize = len, | |
1098 | + .servername = hostname, | |
1099 | + .program = &mnt_program, | |
1100 | + .version = version, | |
1101 | + .authflavor = RPC_AUTH_UNIX, | |
1102 | + .flags = RPC_CLNT_CREATE_INTR, | |
1103 | + }; | |
1104 | + struct rpc_clnt *mnt_clnt; | |
1105 | int status; | |
1106 | ||
1107 | - dprintk("NFS: nfs_mount(%08x:%s)\n", | |
1108 | - (unsigned)ntohl(addr->sin_addr.s_addr), path); | |
1109 | + dprintk("NFS: sending MNT request for %s:%s\n", | |
1110 | + (hostname ? hostname : "server"), path); | |
1111 | ||
1112 | - sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr->sin_addr.s_addr)); | |
1113 | - mnt_clnt = mnt_create(hostname, addr, version, protocol); | |
1114 | + mnt_clnt = rpc_create(&args); | |
1115 | if (IS_ERR(mnt_clnt)) | |
1116 | - return PTR_ERR(mnt_clnt); | |
1117 | + goto out_clnt_err; | |
1118 | ||
1119 | if (version == NFS_MNT3_VERSION) | |
1120 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT]; | |
1121 | @@ -69,33 +74,39 @@ nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, | |
1122 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT]; | |
1123 | ||
1124 | status = rpc_call_sync(mnt_clnt, &msg, 0); | |
1125 | - return status < 0? status : (result.status? -EACCES : 0); | |
1126 | -} | |
1127 | + rpc_shutdown_client(mnt_clnt); | |
1128 | ||
1129 | -static struct rpc_clnt * | |
1130 | -mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version, | |
1131 | - int protocol) | |
1132 | -{ | |
1133 | - struct rpc_create_args args = { | |
1134 | - .protocol = protocol, | |
1135 | - .address = (struct sockaddr *)srvaddr, | |
1136 | - .addrsize = sizeof(*srvaddr), | |
1137 | - .servername = hostname, | |
1138 | - .program = &mnt_program, | |
1139 | - .version = version, | |
1140 | - .authflavor = RPC_AUTH_UNIX, | |
1141 | - .flags = (RPC_CLNT_CREATE_ONESHOT | | |
1142 | - RPC_CLNT_CREATE_INTR), | |
1143 | - }; | |
1144 | + if (status < 0) | |
1145 | + goto out_call_err; | |
1146 | + if (result.status != 0) | |
1147 | + goto out_mnt_err; | |
1148 | + | |
1149 | + dprintk("NFS: MNT request succeeded\n"); | |
1150 | + status = 0; | |
1151 | + | |
1152 | +out: | |
1153 | + return status; | |
1154 | + | |
1155 | +out_clnt_err: | |
1156 | + status = PTR_ERR(mnt_clnt); | |
1157 | + dprintk("NFS: failed to create RPC client, status=%d\n", status); | |
1158 | + goto out; | |
1159 | + | |
1160 | +out_call_err: | |
1161 | + dprintk("NFS: failed to start MNT request, status=%d\n", status); | |
1162 | + goto out; | |
1163 | ||
1164 | - return rpc_create(&args); | |
1165 | +out_mnt_err: | |
1166 | + dprintk("NFS: MNT server returned result %d\n", result.status); | |
1167 | + status = -EACCES; | |
1168 | + goto out; | |
1169 | } | |
1170 | ||
1171 | /* | |
1172 | * XDR encode/decode functions for MOUNT | |
1173 | */ | |
1174 | -static int | |
1175 | -xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, const char *path) | |
1176 | +static int xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, | |
1177 | + const char *path) | |
1178 | { | |
1179 | p = xdr_encode_string(p, path); | |
1180 | ||
1181 | @@ -103,8 +114,8 @@ xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, const char *path) | |
1182 | return 0; | |
1183 | } | |
1184 | ||
1185 | -static int | |
1186 | -xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res) | |
1187 | +static int xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, | |
1188 | + struct mnt_fhstatus *res) | |
1189 | { | |
1190 | struct nfs_fh *fh = res->fh; | |
1191 | ||
1192 | @@ -115,8 +126,8 @@ xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res) | |
1193 | return 0; | |
1194 | } | |
1195 | ||
1196 | -static int | |
1197 | -xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res) | |
1198 | +static int xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, | |
1199 | + struct mnt_fhstatus *res) | |
1200 | { | |
1201 | struct nfs_fh *fh = res->fh; | |
1202 | ||
1203 | @@ -135,53 +146,53 @@ xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res) | |
1204 | #define MNT_fhstatus_sz (1 + 8) | |
1205 | #define MNT_fhstatus3_sz (1 + 16) | |
1206 | ||
1207 | -static struct rpc_procinfo mnt_procedures[] = { | |
1208 | -[MNTPROC_MNT] = { | |
1209 | - .p_proc = MNTPROC_MNT, | |
1210 | - .p_encode = (kxdrproc_t) xdr_encode_dirpath, | |
1211 | - .p_decode = (kxdrproc_t) xdr_decode_fhstatus, | |
1212 | - .p_arglen = MNT_dirpath_sz, | |
1213 | - .p_replen = MNT_fhstatus_sz, | |
1214 | - .p_statidx = MNTPROC_MNT, | |
1215 | - .p_name = "MOUNT", | |
1216 | +static struct rpc_procinfo mnt_procedures[] = { | |
1217 | + [MNTPROC_MNT] = { | |
1218 | + .p_proc = MNTPROC_MNT, | |
1219 | + .p_encode = (kxdrproc_t) xdr_encode_dirpath, | |
1220 | + .p_decode = (kxdrproc_t) xdr_decode_fhstatus, | |
1221 | + .p_arglen = MNT_dirpath_sz, | |
1222 | + .p_replen = MNT_fhstatus_sz, | |
1223 | + .p_statidx = MNTPROC_MNT, | |
1224 | + .p_name = "MOUNT", | |
1225 | }, | |
1226 | }; | |
1227 | ||
1228 | static struct rpc_procinfo mnt3_procedures[] = { | |
1229 | -[MOUNTPROC3_MNT] = { | |
1230 | - .p_proc = MOUNTPROC3_MNT, | |
1231 | - .p_encode = (kxdrproc_t) xdr_encode_dirpath, | |
1232 | - .p_decode = (kxdrproc_t) xdr_decode_fhstatus3, | |
1233 | - .p_arglen = MNT_dirpath_sz, | |
1234 | - .p_replen = MNT_fhstatus3_sz, | |
1235 | - .p_statidx = MOUNTPROC3_MNT, | |
1236 | - .p_name = "MOUNT", | |
1237 | + [MOUNTPROC3_MNT] = { | |
1238 | + .p_proc = MOUNTPROC3_MNT, | |
1239 | + .p_encode = (kxdrproc_t) xdr_encode_dirpath, | |
1240 | + .p_decode = (kxdrproc_t) xdr_decode_fhstatus3, | |
1241 | + .p_arglen = MNT_dirpath_sz, | |
1242 | + .p_replen = MNT_fhstatus3_sz, | |
1243 | + .p_statidx = MOUNTPROC3_MNT, | |
1244 | + .p_name = "MOUNT", | |
1245 | }, | |
1246 | }; | |
1247 | ||
1248 | ||
1249 | -static struct rpc_version mnt_version1 = { | |
1250 | - .number = 1, | |
1251 | - .nrprocs = 2, | |
1252 | - .procs = mnt_procedures | |
1253 | +static struct rpc_version mnt_version1 = { | |
1254 | + .number = 1, | |
1255 | + .nrprocs = 2, | |
1256 | + .procs = mnt_procedures, | |
1257 | }; | |
1258 | ||
1259 | -static struct rpc_version mnt_version3 = { | |
1260 | - .number = 3, | |
1261 | - .nrprocs = 2, | |
1262 | - .procs = mnt3_procedures | |
1263 | +static struct rpc_version mnt_version3 = { | |
1264 | + .number = 3, | |
1265 | + .nrprocs = 2, | |
1266 | + .procs = mnt3_procedures, | |
1267 | }; | |
1268 | ||
1269 | -static struct rpc_version * mnt_version[] = { | |
1270 | +static struct rpc_version *mnt_version[] = { | |
1271 | NULL, | |
1272 | &mnt_version1, | |
1273 | NULL, | |
1274 | &mnt_version3, | |
1275 | }; | |
1276 | ||
1277 | -static struct rpc_stat mnt_stats; | |
1278 | +static struct rpc_stat mnt_stats; | |
1279 | ||
1280 | -static struct rpc_program mnt_program = { | |
1281 | +static struct rpc_program mnt_program = { | |
1282 | .name = "mount", | |
1283 | .number = NFS_MNT_PROGRAM, | |
1284 | .nrvers = ARRAY_SIZE(mnt_version), | |
1285 | diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c | |
1286 | index cd3ca7b..7fcc78f 100644 | |
1287 | --- a/fs/nfs/nfs2xdr.c | |
1288 | +++ b/fs/nfs/nfs2xdr.c | |
1289 | @@ -223,7 +223,7 @@ nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args) | |
1290 | static int | |
1291 | nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) | |
1292 | { | |
1293 | - struct rpc_auth *auth = req->rq_task->tk_auth; | |
1294 | + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | |
1295 | unsigned int replen; | |
1296 | u32 offset = (u32)args->offset; | |
1297 | u32 count = args->count; | |
1298 | @@ -380,7 +380,7 @@ static int | |
1299 | nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args) | |
1300 | { | |
1301 | struct rpc_task *task = req->rq_task; | |
1302 | - struct rpc_auth *auth = task->tk_auth; | |
1303 | + struct rpc_auth *auth = task->tk_msg.rpc_cred->cr_auth; | |
1304 | unsigned int replen; | |
1305 | u32 count = args->count; | |
1306 | ||
1307 | @@ -541,7 +541,7 @@ nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res) | |
1308 | static int | |
1309 | nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args) | |
1310 | { | |
1311 | - struct rpc_auth *auth = req->rq_task->tk_auth; | |
1312 | + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | |
1313 | unsigned int replen; | |
1314 | ||
1315 | p = xdr_encode_fhandle(p, args->fh); | |
1316 | diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c | |
1317 | index 45268d6..814d886 100644 | |
1318 | --- a/fs/nfs/nfs3proc.c | |
1319 | +++ b/fs/nfs/nfs3proc.c | |
1320 | @@ -335,9 +335,7 @@ again: | |
1321 | * not sure this buys us anything (and I'd have | |
1322 | * to revamp the NFSv3 XDR code) */ | |
1323 | status = nfs3_proc_setattr(dentry, &fattr, sattr); | |
1324 | - if (status == 0) | |
1325 | - nfs_setattr_update_inode(dentry->d_inode, sattr); | |
1326 | - nfs_refresh_inode(dentry->d_inode, &fattr); | |
1327 | + nfs_post_op_update_inode(dentry->d_inode, &fattr); | |
1328 | dprintk("NFS reply setattr (post-create): %d\n", status); | |
1329 | } | |
1330 | if (status != 0) | |
1331 | diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c | |
1332 | index b51df8e..b4647a2 100644 | |
1333 | --- a/fs/nfs/nfs3xdr.c | |
1334 | +++ b/fs/nfs/nfs3xdr.c | |
1335 | @@ -319,7 +319,7 @@ nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *arg | |
1336 | static int | |
1337 | nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) | |
1338 | { | |
1339 | - struct rpc_auth *auth = req->rq_task->tk_auth; | |
1340 | + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | |
1341 | unsigned int replen; | |
1342 | u32 count = args->count; | |
1343 | ||
1344 | @@ -458,7 +458,7 @@ nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args) | |
1345 | static int | |
1346 | nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args) | |
1347 | { | |
1348 | - struct rpc_auth *auth = req->rq_task->tk_auth; | |
1349 | + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | |
1350 | unsigned int replen; | |
1351 | u32 count = args->count; | |
1352 | ||
1353 | @@ -643,7 +643,7 @@ static int | |
1354 | nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p, | |
1355 | struct nfs3_getaclargs *args) | |
1356 | { | |
1357 | - struct rpc_auth *auth = req->rq_task->tk_auth; | |
1358 | + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | |
1359 | unsigned int replen; | |
1360 | ||
1361 | p = xdr_encode_fhandle(p, args->fh); | |
1362 | @@ -773,7 +773,7 @@ nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res) | |
1363 | static int | |
1364 | nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args) | |
1365 | { | |
1366 | - struct rpc_auth *auth = req->rq_task->tk_auth; | |
1367 | + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | |
1368 | unsigned int replen; | |
1369 | ||
1370 | p = xdr_encode_fhandle(p, args->fh); | |
1371 | diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h | |
1372 | index cf3a17e..6c028e7 100644 | |
1373 | --- a/fs/nfs/nfs4_fs.h | |
1374 | +++ b/fs/nfs/nfs4_fs.h | |
1375 | @@ -70,19 +70,26 @@ static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status | |
1376 | seqid->flags |= NFS_SEQID_CONFIRMED; | |
1377 | } | |
1378 | ||
1379 | +struct nfs_unique_id { | |
1380 | + struct rb_node rb_node; | |
1381 | + __u64 id; | |
1382 | +}; | |
1383 | + | |
1384 | /* | |
1385 | * NFS4 state_owners and lock_owners are simply labels for ordered | |
1386 | * sequences of RPC calls. Their sole purpose is to provide once-only | |
1387 | * semantics by allowing the server to identify replayed requests. | |
1388 | */ | |
1389 | struct nfs4_state_owner { | |
1390 | - spinlock_t so_lock; | |
1391 | - struct list_head so_list; /* per-clientid list of state_owners */ | |
1392 | + struct nfs_unique_id so_owner_id; | |
1393 | struct nfs_client *so_client; | |
1394 | - u32 so_id; /* 32-bit identifier, unique */ | |
1395 | - atomic_t so_count; | |
1396 | + struct nfs_server *so_server; | |
1397 | + struct rb_node so_client_node; | |
1398 | ||
1399 | struct rpc_cred *so_cred; /* Associated cred */ | |
1400 | + | |
1401 | + spinlock_t so_lock; | |
1402 | + atomic_t so_count; | |
1403 | struct list_head so_states; | |
1404 | struct list_head so_delegations; | |
1405 | struct nfs_seqid_counter so_seqid; | |
1406 | @@ -108,7 +115,7 @@ struct nfs4_lock_state { | |
1407 | #define NFS_LOCK_INITIALIZED 1 | |
1408 | int ls_flags; | |
1409 | struct nfs_seqid_counter ls_seqid; | |
1410 | - u32 ls_id; | |
1411 | + struct nfs_unique_id ls_id; | |
1412 | nfs4_stateid ls_stateid; | |
1413 | atomic_t ls_count; | |
1414 | }; | |
1415 | @@ -116,7 +123,10 @@ struct nfs4_lock_state { | |
1416 | /* bits for nfs4_state->flags */ | |
1417 | enum { | |
1418 | LK_STATE_IN_USE, | |
1419 | - NFS_DELEGATED_STATE, | |
1420 | + NFS_DELEGATED_STATE, /* Current stateid is delegation */ | |
1421 | + NFS_O_RDONLY_STATE, /* OPEN stateid has read-only state */ | |
1422 | + NFS_O_WRONLY_STATE, /* OPEN stateid has write-only state */ | |
1423 | + NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */ | |
1424 | }; | |
1425 | ||
1426 | struct nfs4_state { | |
1427 | @@ -130,11 +140,14 @@ struct nfs4_state { | |
1428 | unsigned long flags; /* Do we hold any locks? */ | |
1429 | spinlock_t state_lock; /* Protects the lock_states list */ | |
1430 | ||
1431 | - nfs4_stateid stateid; | |
1432 | + seqlock_t seqlock; /* Protects the stateid/open_stateid */ | |
1433 | + nfs4_stateid stateid; /* Current stateid: may be delegation */ | |
1434 | + nfs4_stateid open_stateid; /* OPEN stateid */ | |
1435 | ||
1436 | - unsigned int n_rdonly; | |
1437 | - unsigned int n_wronly; | |
1438 | - unsigned int n_rdwr; | |
1439 | + /* The following 3 fields are protected by owner->so_lock */ | |
1440 | + unsigned int n_rdonly; /* Number of read-only references */ | |
1441 | + unsigned int n_wronly; /* Number of write-only references */ | |
1442 | + unsigned int n_rdwr; /* Number of read/write references */ | |
1443 | int state; /* State on the server (R,W, or RW) */ | |
1444 | atomic_t count; | |
1445 | }; | |
1446 | @@ -165,7 +178,7 @@ extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struc | |
1447 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); | |
1448 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); | |
1449 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); | |
1450 | -extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state); | |
1451 | +extern int nfs4_do_close(struct path *path, struct nfs4_state *state); | |
1452 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); | |
1453 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); | |
1454 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); | |
1455 | @@ -189,14 +202,13 @@ extern void nfs4_renew_state(struct work_struct *); | |
1456 | ||
1457 | /* nfs4state.c */ | |
1458 | struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp); | |
1459 | -extern u32 nfs4_alloc_lockowner_id(struct nfs_client *); | |
1460 | ||
1461 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); | |
1462 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); | |
1463 | extern void nfs4_drop_state_owner(struct nfs4_state_owner *); | |
1464 | extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); | |
1465 | extern void nfs4_put_open_state(struct nfs4_state *); | |
1466 | -extern void nfs4_close_state(struct nfs4_state *, mode_t); | |
1467 | +extern void nfs4_close_state(struct path *, struct nfs4_state *, mode_t); | |
1468 | extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t); | |
1469 | extern void nfs4_schedule_state_recovery(struct nfs_client *); | |
1470 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); | |
1471 | @@ -222,7 +234,7 @@ extern struct svc_version nfs4_callback_version1; | |
1472 | ||
1473 | #else | |
1474 | ||
1475 | -#define nfs4_close_state(a, b) do { } while (0) | |
1476 | +#define nfs4_close_state(a, b, c) do { } while (0) | |
1477 | ||
1478 | #endif /* CONFIG_NFS_V4 */ | |
1479 | #endif /* __LINUX_FS_NFS_NFS4_FS.H */ | |
1480 | diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c | |
1481 | index 648e0ac..fee2da8 100644 | |
1482 | --- a/fs/nfs/nfs4proc.c | |
1483 | +++ b/fs/nfs/nfs4proc.c | |
1484 | @@ -65,6 +65,7 @@ static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *) | |
1485 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); | |
1486 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); | |
1487 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp); | |
1488 | +static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags); | |
1489 | ||
1490 | /* Prevent leaks of NFSv4 errors into userland */ | |
1491 | int nfs4_map_errors(int err) | |
1492 | @@ -214,27 +215,39 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | |
1493 | } | |
1494 | ||
1495 | struct nfs4_opendata { | |
1496 | - atomic_t count; | |
1497 | + struct kref kref; | |
1498 | struct nfs_openargs o_arg; | |
1499 | struct nfs_openres o_res; | |
1500 | struct nfs_open_confirmargs c_arg; | |
1501 | struct nfs_open_confirmres c_res; | |
1502 | struct nfs_fattr f_attr; | |
1503 | struct nfs_fattr dir_attr; | |
1504 | - struct dentry *dentry; | |
1505 | + struct path path; | |
1506 | struct dentry *dir; | |
1507 | struct nfs4_state_owner *owner; | |
1508 | + struct nfs4_state *state; | |
1509 | struct iattr attrs; | |
1510 | unsigned long timestamp; | |
1511 | + unsigned int rpc_done : 1; | |
1512 | int rpc_status; | |
1513 | int cancelled; | |
1514 | }; | |
1515 | ||
1516 | -static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |
1517 | + | |
1518 | +static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |
1519 | +{ | |
1520 | + p->o_res.f_attr = &p->f_attr; | |
1521 | + p->o_res.dir_attr = &p->dir_attr; | |
1522 | + p->o_res.server = p->o_arg.server; | |
1523 | + nfs_fattr_init(&p->f_attr); | |
1524 | + nfs_fattr_init(&p->dir_attr); | |
1525 | +} | |
1526 | + | |
1527 | +static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |
1528 | struct nfs4_state_owner *sp, int flags, | |
1529 | const struct iattr *attrs) | |
1530 | { | |
1531 | - struct dentry *parent = dget_parent(dentry); | |
1532 | + struct dentry *parent = dget_parent(path->dentry); | |
1533 | struct inode *dir = parent->d_inode; | |
1534 | struct nfs_server *server = NFS_SERVER(dir); | |
1535 | struct nfs4_opendata *p; | |
1536 | @@ -245,24 +258,19 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |
1537 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | |
1538 | if (p->o_arg.seqid == NULL) | |
1539 | goto err_free; | |
1540 | - atomic_set(&p->count, 1); | |
1541 | - p->dentry = dget(dentry); | |
1542 | + p->path.mnt = mntget(path->mnt); | |
1543 | + p->path.dentry = dget(path->dentry); | |
1544 | p->dir = parent; | |
1545 | p->owner = sp; | |
1546 | atomic_inc(&sp->so_count); | |
1547 | p->o_arg.fh = NFS_FH(dir); | |
1548 | p->o_arg.open_flags = flags, | |
1549 | p->o_arg.clientid = server->nfs_client->cl_clientid; | |
1550 | - p->o_arg.id = sp->so_id; | |
1551 | - p->o_arg.name = &dentry->d_name; | |
1552 | + p->o_arg.id = sp->so_owner_id.id; | |
1553 | + p->o_arg.name = &p->path.dentry->d_name; | |
1554 | p->o_arg.server = server; | |
1555 | p->o_arg.bitmask = server->attr_bitmask; | |
1556 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | |
1557 | - p->o_res.f_attr = &p->f_attr; | |
1558 | - p->o_res.dir_attr = &p->dir_attr; | |
1559 | - p->o_res.server = server; | |
1560 | - nfs_fattr_init(&p->f_attr); | |
1561 | - nfs_fattr_init(&p->dir_attr); | |
1562 | if (flags & O_EXCL) { | |
1563 | u32 *s = (u32 *) p->o_arg.u.verifier.data; | |
1564 | s[0] = jiffies; | |
1565 | @@ -274,6 +282,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | |
1566 | p->c_arg.fh = &p->o_res.fh; | |
1567 | p->c_arg.stateid = &p->o_res.stateid; | |
1568 | p->c_arg.seqid = p->o_arg.seqid; | |
1569 | + nfs4_init_opendata_res(p); | |
1570 | + kref_init(&p->kref); | |
1571 | return p; | |
1572 | err_free: | |
1573 | kfree(p); | |
1574 | @@ -282,27 +292,25 @@ err: | |
1575 | return NULL; | |
1576 | } | |
1577 | ||
1578 | -static void nfs4_opendata_free(struct nfs4_opendata *p) | |
1579 | +static void nfs4_opendata_free(struct kref *kref) | |
1580 | { | |
1581 | - if (p != NULL && atomic_dec_and_test(&p->count)) { | |
1582 | - nfs_free_seqid(p->o_arg.seqid); | |
1583 | - nfs4_put_state_owner(p->owner); | |
1584 | - dput(p->dir); | |
1585 | - dput(p->dentry); | |
1586 | - kfree(p); | |
1587 | - } | |
1588 | + struct nfs4_opendata *p = container_of(kref, | |
1589 | + struct nfs4_opendata, kref); | |
1590 | + | |
1591 | + nfs_free_seqid(p->o_arg.seqid); | |
1592 | + if (p->state != NULL) | |
1593 | + nfs4_put_open_state(p->state); | |
1594 | + nfs4_put_state_owner(p->owner); | |
1595 | + dput(p->dir); | |
1596 | + dput(p->path.dentry); | |
1597 | + mntput(p->path.mnt); | |
1598 | + kfree(p); | |
1599 | } | |
1600 | ||
1601 | -/* Helper for asynchronous RPC calls */ | |
1602 | -static int nfs4_call_async(struct rpc_clnt *clnt, | |
1603 | - const struct rpc_call_ops *tk_ops, void *calldata) | |
1604 | +static void nfs4_opendata_put(struct nfs4_opendata *p) | |
1605 | { | |
1606 | - struct rpc_task *task; | |
1607 | - | |
1608 | - if (!(task = rpc_new_task(clnt, RPC_TASK_ASYNC, tk_ops, calldata))) | |
1609 | - return -ENOMEM; | |
1610 | - rpc_execute(task); | |
1611 | - return 0; | |
1612 | + if (p != NULL) | |
1613 | + kref_put(&p->kref, nfs4_opendata_free); | |
1614 | } | |
1615 | ||
1616 | static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) | |
1617 | @@ -316,7 +324,34 @@ static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task) | |
1618 | return ret; | |
1619 | } | |
1620 | ||
1621 | -static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) | |
1622 | +static int can_open_cached(struct nfs4_state *state, int mode) | |
1623 | +{ | |
1624 | + int ret = 0; | |
1625 | + switch (mode & (FMODE_READ|FMODE_WRITE|O_EXCL)) { | |
1626 | + case FMODE_READ: | |
1627 | + ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0; | |
1628 | + ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; | |
1629 | + break; | |
1630 | + case FMODE_WRITE: | |
1631 | + ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0; | |
1632 | + ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; | |
1633 | + break; | |
1634 | + case FMODE_READ|FMODE_WRITE: | |
1635 | + ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; | |
1636 | + } | |
1637 | + return ret; | |
1638 | +} | |
1639 | + | |
1640 | +static int can_open_delegated(struct nfs_delegation *delegation, mode_t open_flags) | |
1641 | +{ | |
1642 | + if ((delegation->type & open_flags) != open_flags) | |
1643 | + return 0; | |
1644 | + if (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) | |
1645 | + return 0; | |
1646 | + return 1; | |
1647 | +} | |
1648 | + | |
1649 | +static void update_open_stateflags(struct nfs4_state *state, mode_t open_flags) | |
1650 | { | |
1651 | switch (open_flags) { | |
1652 | case FMODE_WRITE: | |
1653 | @@ -328,41 +363,176 @@ static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_ | |
1654 | case FMODE_READ|FMODE_WRITE: | |
1655 | state->n_rdwr++; | |
1656 | } | |
1657 | + nfs4_state_set_mode_locked(state, state->state | open_flags); | |
1658 | } | |
1659 | ||
1660 | -static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | |
1661 | +static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | |
1662 | { | |
1663 | - struct inode *inode = state->inode; | |
1664 | + if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) | |
1665 | + memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data)); | |
1666 | + memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data)); | |
1667 | + switch (open_flags) { | |
1668 | + case FMODE_READ: | |
1669 | + set_bit(NFS_O_RDONLY_STATE, &state->flags); | |
1670 | + break; | |
1671 | + case FMODE_WRITE: | |
1672 | + set_bit(NFS_O_WRONLY_STATE, &state->flags); | |
1673 | + break; | |
1674 | + case FMODE_READ|FMODE_WRITE: | |
1675 | + set_bit(NFS_O_RDWR_STATE, &state->flags); | |
1676 | + } | |
1677 | +} | |
1678 | + | |
1679 | +static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | |
1680 | +{ | |
1681 | + write_seqlock(&state->seqlock); | |
1682 | + nfs_set_open_stateid_locked(state, stateid, open_flags); | |
1683 | + write_sequnlock(&state->seqlock); | |
1684 | +} | |
1685 | ||
1686 | +static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *deleg_stateid, int open_flags) | |
1687 | +{ | |
1688 | open_flags &= (FMODE_READ|FMODE_WRITE); | |
1689 | - /* Protect against nfs4_find_state_byowner() */ | |
1690 | + /* | |
1691 | + * Protect the call to nfs4_state_set_mode_locked and | |
1692 | + * serialise the stateid update | |
1693 | + */ | |
1694 | + write_seqlock(&state->seqlock); | |
1695 | + if (deleg_stateid != NULL) { | |
1696 | + memcpy(state->stateid.data, deleg_stateid->data, sizeof(state->stateid.data)); | |
1697 | + set_bit(NFS_DELEGATED_STATE, &state->flags); | |
1698 | + } | |
1699 | + if (open_stateid != NULL) | |
1700 | + nfs_set_open_stateid_locked(state, open_stateid, open_flags); | |
1701 | + write_sequnlock(&state->seqlock); | |
1702 | spin_lock(&state->owner->so_lock); | |
1703 | - spin_lock(&inode->i_lock); | |
1704 | - memcpy(&state->stateid, stateid, sizeof(state->stateid)); | |
1705 | update_open_stateflags(state, open_flags); | |
1706 | - nfs4_state_set_mode_locked(state, state->state | open_flags); | |
1707 | - spin_unlock(&inode->i_lock); | |
1708 | spin_unlock(&state->owner->so_lock); | |
1709 | } | |
1710 | ||
1711 | +static void nfs4_return_incompatible_delegation(struct inode *inode, mode_t open_flags) | |
1712 | +{ | |
1713 | + struct nfs_delegation *delegation; | |
1714 | + | |
1715 | + rcu_read_lock(); | |
1716 | + delegation = rcu_dereference(NFS_I(inode)->delegation); | |
1717 | + if (delegation == NULL || (delegation->type & open_flags) == open_flags) { | |
1718 | + rcu_read_unlock(); | |
1719 | + return; | |
1720 | + } | |
1721 | + rcu_read_unlock(); | |
1722 | + nfs_inode_return_delegation(inode); | |
1723 | +} | |
1724 | + | |
1725 | +static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) | |
1726 | +{ | |
1727 | + struct nfs4_state *state = opendata->state; | |
1728 | + struct nfs_inode *nfsi = NFS_I(state->inode); | |
1729 | + struct nfs_delegation *delegation; | |
1730 | + int open_mode = opendata->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL); | |
1731 | + nfs4_stateid stateid; | |
1732 | + int ret = -EAGAIN; | |
1733 | + | |
1734 | + rcu_read_lock(); | |
1735 | + delegation = rcu_dereference(nfsi->delegation); | |
1736 | + for (;;) { | |
1737 | + if (can_open_cached(state, open_mode)) { | |
1738 | + spin_lock(&state->owner->so_lock); | |
1739 | + if (can_open_cached(state, open_mode)) { | |
1740 | + update_open_stateflags(state, open_mode); | |
1741 | + spin_unlock(&state->owner->so_lock); | |
1742 | + rcu_read_unlock(); | |
1743 | + goto out_return_state; | |
1744 | + } | |
1745 | + spin_unlock(&state->owner->so_lock); | |
1746 | + } | |
1747 | + if (delegation == NULL) | |
1748 | + break; | |
1749 | + if (!can_open_delegated(delegation, open_mode)) | |
1750 | + break; | |
1751 | + /* Save the delegation */ | |
1752 | + memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data)); | |
1753 | + rcu_read_unlock(); | |
1754 | + lock_kernel(); | |
1755 | + ret = _nfs4_do_access(state->inode, state->owner->so_cred, open_mode); | |
1756 | + unlock_kernel(); | |
1757 | + if (ret != 0) | |
1758 | + goto out; | |
1759 | + ret = -EAGAIN; | |
1760 | + rcu_read_lock(); | |
1761 | + delegation = rcu_dereference(nfsi->delegation); | |
1762 | + /* If no delegation, try a cached open */ | |
1763 | + if (delegation == NULL) | |
1764 | + continue; | |
1765 | + /* Is the delegation still valid? */ | |
1766 | + if (memcmp(stateid.data, delegation->stateid.data, sizeof(stateid.data)) != 0) | |
1767 | + continue; | |
1768 | + rcu_read_unlock(); | |
1769 | + update_open_stateid(state, NULL, &stateid, open_mode); | |
1770 | + goto out_return_state; | |
1771 | + } | |
1772 | + rcu_read_unlock(); | |
1773 | +out: | |
1774 | + return ERR_PTR(ret); | |
1775 | +out_return_state: | |
1776 | + atomic_inc(&state->count); | |
1777 | + return state; | |
1778 | +} | |
1779 | + | |
1780 | static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data) | |
1781 | { | |
1782 | struct inode *inode; | |
1783 | struct nfs4_state *state = NULL; | |
1784 | + struct nfs_delegation *delegation; | |
1785 | + nfs4_stateid *deleg_stateid = NULL; | |
1786 | + int ret; | |
1787 | ||
1788 | - if (!(data->f_attr.valid & NFS_ATTR_FATTR)) | |
1789 | + if (!data->rpc_done) { | |
1790 | + state = nfs4_try_open_cached(data); | |
1791 | goto out; | |
1792 | + } | |
1793 | + | |
1794 | + ret = -EAGAIN; | |
1795 | + if (!(data->f_attr.valid & NFS_ATTR_FATTR)) | |
1796 | + goto err; | |
1797 | inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr); | |
1798 | + ret = PTR_ERR(inode); | |
1799 | if (IS_ERR(inode)) | |
1800 | - goto out; | |
1801 | + goto err; | |
1802 | + ret = -ENOMEM; | |
1803 | state = nfs4_get_open_state(inode, data->owner); | |
1804 | if (state == NULL) | |
1805 | - goto put_inode; | |
1806 | - update_open_stateid(state, &data->o_res.stateid, data->o_arg.open_flags); | |
1807 | -put_inode: | |
1808 | + goto err_put_inode; | |
1809 | + if (data->o_res.delegation_type != 0) { | |
1810 | + int delegation_flags = 0; | |
1811 | + | |
1812 | + rcu_read_lock(); | |
1813 | + delegation = rcu_dereference(NFS_I(inode)->delegation); | |
1814 | + if (delegation) | |
1815 | + delegation_flags = delegation->flags; | |
1816 | + rcu_read_unlock(); | |
1817 | + if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM)) | |
1818 | + nfs_inode_set_delegation(state->inode, | |
1819 | + data->owner->so_cred, | |
1820 | + &data->o_res); | |
1821 | + else | |
1822 | + nfs_inode_reclaim_delegation(state->inode, | |
1823 | + data->owner->so_cred, | |
1824 | + &data->o_res); | |
1825 | + } | |
1826 | + rcu_read_lock(); | |
1827 | + delegation = rcu_dereference(NFS_I(inode)->delegation); | |
1828 | + if (delegation != NULL) | |
1829 | + deleg_stateid = &delegation->stateid; | |
1830 | + update_open_stateid(state, &data->o_res.stateid, deleg_stateid, data->o_arg.open_flags); | |
1831 | + rcu_read_unlock(); | |
1832 | iput(inode); | |
1833 | out: | |
1834 | return state; | |
1835 | +err_put_inode: | |
1836 | + iput(inode); | |
1837 | +err: | |
1838 | + return ERR_PTR(ret); | |
1839 | } | |
1840 | ||
1841 | static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state) | |
1842 | @@ -382,79 +552,66 @@ static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state * | |
1843 | return ERR_PTR(-ENOENT); | |
1844 | } | |
1845 | ||
1846 | -static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, nfs4_stateid *stateid) | |
1847 | +static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, struct nfs4_state **res) | |
1848 | { | |
1849 | + struct nfs4_state *newstate; | |
1850 | int ret; | |
1851 | ||
1852 | opendata->o_arg.open_flags = openflags; | |
1853 | + memset(&opendata->o_res, 0, sizeof(opendata->o_res)); | |
1854 | + memset(&opendata->c_res, 0, sizeof(opendata->c_res)); | |
1855 | + nfs4_init_opendata_res(opendata); | |
1856 | ret = _nfs4_proc_open(opendata); | |
1857 | if (ret != 0) | |
1858 | return ret; | |
1859 | - memcpy(stateid->data, opendata->o_res.stateid.data, | |
1860 | - sizeof(stateid->data)); | |
1861 | + newstate = nfs4_opendata_to_nfs4_state(opendata); | |
1862 | + if (IS_ERR(newstate)) | |
1863 | + return PTR_ERR(newstate); | |
1864 | + nfs4_close_state(&opendata->path, newstate, openflags); | |
1865 | + *res = newstate; | |
1866 | return 0; | |
1867 | } | |
1868 | ||
1869 | static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state) | |
1870 | { | |
1871 | - nfs4_stateid stateid; | |
1872 | struct nfs4_state *newstate; | |
1873 | - int mode = 0; | |
1874 | - int delegation = 0; | |
1875 | int ret; | |
1876 | ||
1877 | /* memory barrier prior to reading state->n_* */ | |
1878 | + clear_bit(NFS_DELEGATED_STATE, &state->flags); | |
1879 | smp_rmb(); | |
1880 | if (state->n_rdwr != 0) { | |
1881 | - ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &stateid); | |
1882 | + ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate); | |
1883 | if (ret != 0) | |
1884 | return ret; | |
1885 | - mode |= FMODE_READ|FMODE_WRITE; | |
1886 | - if (opendata->o_res.delegation_type != 0) | |
1887 | - delegation = opendata->o_res.delegation_type; | |
1888 | - smp_rmb(); | |
1889 | + if (newstate != state) | |
1890 | + return -ESTALE; | |
1891 | } | |
1892 | if (state->n_wronly != 0) { | |
1893 | - ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &stateid); | |
1894 | + ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate); | |
1895 | if (ret != 0) | |
1896 | return ret; | |
1897 | - mode |= FMODE_WRITE; | |
1898 | - if (opendata->o_res.delegation_type != 0) | |
1899 | - delegation = opendata->o_res.delegation_type; | |
1900 | - smp_rmb(); | |
1901 | + if (newstate != state) | |
1902 | + return -ESTALE; | |
1903 | } | |
1904 | if (state->n_rdonly != 0) { | |
1905 | - ret = nfs4_open_recover_helper(opendata, FMODE_READ, &stateid); | |
1906 | + ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate); | |
1907 | if (ret != 0) | |
1908 | return ret; | |
1909 | - mode |= FMODE_READ; | |
1910 | + if (newstate != state) | |
1911 | + return -ESTALE; | |
1912 | } | |
1913 | - clear_bit(NFS_DELEGATED_STATE, &state->flags); | |
1914 | - if (mode == 0) | |
1915 | - return 0; | |
1916 | - if (opendata->o_res.delegation_type == 0) | |
1917 | - opendata->o_res.delegation_type = delegation; | |
1918 | - opendata->o_arg.open_flags |= mode; | |
1919 | - newstate = nfs4_opendata_to_nfs4_state(opendata); | |
1920 | - if (newstate != NULL) { | |
1921 | - if (opendata->o_res.delegation_type != 0) { | |
1922 | - struct nfs_inode *nfsi = NFS_I(newstate->inode); | |
1923 | - int delegation_flags = 0; | |
1924 | - if (nfsi->delegation) | |
1925 | - delegation_flags = nfsi->delegation->flags; | |
1926 | - if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM)) | |
1927 | - nfs_inode_set_delegation(newstate->inode, | |
1928 | - opendata->owner->so_cred, | |
1929 | - &opendata->o_res); | |
1930 | - else | |
1931 | - nfs_inode_reclaim_delegation(newstate->inode, | |
1932 | - opendata->owner->so_cred, | |
1933 | - &opendata->o_res); | |
1934 | - } | |
1935 | - nfs4_close_state(newstate, opendata->o_arg.open_flags); | |
1936 | + /* | |
1937 | + * We may have performed cached opens for all three recoveries. | |
1938 | + * Check if we need to update the current stateid. | |
1939 | + */ | |
1940 | + if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 && | |
1941 | + memcmp(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)) != 0) { | |
1942 | + write_seqlock(&state->seqlock); | |
1943 | + if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) | |
1944 | + memcpy(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)); | |
1945 | + write_sequnlock(&state->seqlock); | |
1946 | } | |
1947 | - if (newstate != state) | |
1948 | - return -ESTALE; | |
1949 | return 0; | |
1950 | } | |
1951 | ||
1952 | @@ -462,41 +619,37 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * | |
1953 | * OPEN_RECLAIM: | |
1954 | * reclaim state on the server after a reboot. | |
1955 | */ | |
1956 | -static int _nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | |
1957 | +static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state) | |
1958 | { | |
1959 | - struct nfs_delegation *delegation = NFS_I(state->inode)->delegation; | |
1960 | + struct nfs_delegation *delegation; | |
1961 | struct nfs4_opendata *opendata; | |
1962 | int delegation_type = 0; | |
1963 | int status; | |
1964 | ||
1965 | - if (delegation != NULL) { | |
1966 | - if (!(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) { | |
1967 | - memcpy(&state->stateid, &delegation->stateid, | |
1968 | - sizeof(state->stateid)); | |
1969 | - set_bit(NFS_DELEGATED_STATE, &state->flags); | |
1970 | - return 0; | |
1971 | - } | |
1972 | - delegation_type = delegation->type; | |
1973 | - } | |
1974 | - opendata = nfs4_opendata_alloc(dentry, sp, 0, NULL); | |
1975 | + opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL); | |
1976 | if (opendata == NULL) | |
1977 | return -ENOMEM; | |
1978 | opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS; | |
1979 | opendata->o_arg.fh = NFS_FH(state->inode); | |
1980 | nfs_copy_fh(&opendata->o_res.fh, opendata->o_arg.fh); | |
1981 | + rcu_read_lock(); | |
1982 | + delegation = rcu_dereference(NFS_I(state->inode)->delegation); | |
1983 | + if (delegation != NULL && (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) != 0) | |
1984 | + delegation_type = delegation->flags; | |
1985 | + rcu_read_unlock(); | |
1986 | opendata->o_arg.u.delegation_type = delegation_type; | |
1987 | status = nfs4_open_recover(opendata, state); | |
1988 | - nfs4_opendata_free(opendata); | |
1989 | + nfs4_opendata_put(opendata); | |
1990 | return status; | |
1991 | } | |
1992 | ||
1993 | -static int nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | |
1994 | +static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state) | |
1995 | { | |
1996 | struct nfs_server *server = NFS_SERVER(state->inode); | |
1997 | struct nfs4_exception exception = { }; | |
1998 | int err; | |
1999 | do { | |
2000 | - err = _nfs4_do_open_reclaim(sp, state, dentry); | |
2001 | + err = _nfs4_do_open_reclaim(ctx, state); | |
2002 | if (err != -NFS4ERR_DELAY) | |
2003 | break; | |
2004 | nfs4_handle_exception(server, err, &exception); | |
2005 | @@ -512,37 +665,35 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta | |
2006 | ctx = nfs4_state_find_open_context(state); | |
2007 | if (IS_ERR(ctx)) | |
2008 | return PTR_ERR(ctx); | |
2009 | - ret = nfs4_do_open_reclaim(sp, state, ctx->dentry); | |
2010 | + ret = nfs4_do_open_reclaim(ctx, state); | |
2011 | put_nfs_open_context(ctx); | |
2012 | return ret; | |
2013 | } | |
2014 | ||
2015 | -static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) | |
2016 | +static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) | |
2017 | { | |
2018 | struct nfs4_state_owner *sp = state->owner; | |
2019 | struct nfs4_opendata *opendata; | |
2020 | int ret; | |
2021 | ||
2022 | - if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) | |
2023 | - return 0; | |
2024 | - opendata = nfs4_opendata_alloc(dentry, sp, 0, NULL); | |
2025 | + opendata = nfs4_opendata_alloc(&ctx->path, sp, 0, NULL); | |
2026 | if (opendata == NULL) | |
2027 | return -ENOMEM; | |
2028 | opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; | |
2029 | - memcpy(opendata->o_arg.u.delegation.data, state->stateid.data, | |
2030 | + memcpy(opendata->o_arg.u.delegation.data, stateid->data, | |
2031 | sizeof(opendata->o_arg.u.delegation.data)); | |
2032 | ret = nfs4_open_recover(opendata, state); | |
2033 | - nfs4_opendata_free(opendata); | |
2034 | + nfs4_opendata_put(opendata); | |
2035 | return ret; | |
2036 | } | |
2037 | ||
2038 | -int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state) | |
2039 | +int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) | |
2040 | { | |
2041 | struct nfs4_exception exception = { }; | |
2042 | - struct nfs_server *server = NFS_SERVER(dentry->d_inode); | |
2043 | + struct nfs_server *server = NFS_SERVER(state->inode); | |
2044 | int err; | |
2045 | do { | |
2046 | - err = _nfs4_open_delegation_recall(dentry, state); | |
2047 | + err = _nfs4_open_delegation_recall(ctx, state, stateid); | |
2048 | switch (err) { | |
2049 | case 0: | |
2050 | return err; | |
2051 | @@ -582,9 +733,10 @@ static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) | |
2052 | memcpy(data->o_res.stateid.data, data->c_res.stateid.data, | |
2053 | sizeof(data->o_res.stateid.data)); | |
2054 | renew_lease(data->o_res.server, data->timestamp); | |
2055 | + data->rpc_done = 1; | |
2056 | } | |
2057 | - nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid); | |
2058 | nfs_confirm_seqid(&data->owner->so_seqid, data->rpc_status); | |
2059 | + nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid); | |
2060 | } | |
2061 | ||
2062 | static void nfs4_open_confirm_release(void *calldata) | |
2063 | @@ -596,14 +748,14 @@ static void nfs4_open_confirm_release(void *calldata) | |
2064 | if (data->cancelled == 0) | |
2065 | goto out_free; | |
2066 | /* In case of error, no cleanup! */ | |
2067 | - if (data->rpc_status != 0) | |
2068 | + if (!data->rpc_done) | |
2069 | goto out_free; | |
2070 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | |
2071 | state = nfs4_opendata_to_nfs4_state(data); | |
2072 | - if (state != NULL) | |
2073 | - nfs4_close_state(state, data->o_arg.open_flags); | |
2074 | + if (!IS_ERR(state)) | |
2075 | + nfs4_close_state(&data->path, state, data->o_arg.open_flags); | |
2076 | out_free: | |
2077 | - nfs4_opendata_free(data); | |
2078 | + nfs4_opendata_put(data); | |
2079 | } | |
2080 | ||
2081 | static const struct rpc_call_ops nfs4_open_confirm_ops = { | |
2082 | @@ -621,12 +773,9 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) | |
2083 | struct rpc_task *task; | |
2084 | int status; | |
2085 | ||
2086 | - atomic_inc(&data->count); | |
2087 | - /* | |
2088 | - * If rpc_run_task() ends up calling ->rpc_release(), we | |
2089 | - * want to ensure that it takes the 'error' code path. | |
2090 | - */ | |
2091 | - data->rpc_status = -ENOMEM; | |
2092 | + kref_get(&data->kref); | |
2093 | + data->rpc_done = 0; | |
2094 | + data->rpc_status = 0; | |
2095 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_confirm_ops, data); | |
2096 | if (IS_ERR(task)) | |
2097 | return PTR_ERR(task); | |
2098 | @@ -653,13 +802,35 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |
2099 | ||
2100 | if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0) | |
2101 | return; | |
2102 | + /* | |
2103 | + * Check if we still need to send an OPEN call, or if we can use | |
2104 | + * a delegation instead. | |
2105 | + */ | |
2106 | + if (data->state != NULL) { | |
2107 | + struct nfs_delegation *delegation; | |
2108 | + | |
2109 | + if (can_open_cached(data->state, data->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL))) | |
2110 | + goto out_no_action; | |
2111 | + rcu_read_lock(); | |
2112 | + delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); | |
2113 | + if (delegation != NULL && | |
2114 | + (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) { | |
2115 | + rcu_read_unlock(); | |
2116 | + goto out_no_action; | |
2117 | + } | |
2118 | + rcu_read_unlock(); | |
2119 | + } | |
2120 | /* Update sequence id. */ | |
2121 | - data->o_arg.id = sp->so_id; | |
2122 | + data->o_arg.id = sp->so_owner_id.id; | |
2123 | data->o_arg.clientid = sp->so_client->cl_clientid; | |
2124 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) | |
2125 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; | |
2126 | data->timestamp = jiffies; | |
2127 | rpc_call_setup(task, &msg, 0); | |
2128 | + return; | |
2129 | +out_no_action: | |
2130 | + task->tk_action = NULL; | |
2131 | + | |
2132 | } | |
2133 | ||
2134 | static void nfs4_open_done(struct rpc_task *task, void *calldata) | |
2135 | @@ -683,8 +854,11 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) | |
2136 | data->rpc_status = -ENOTDIR; | |
2137 | } | |
2138 | renew_lease(data->o_res.server, data->timestamp); | |
2139 | + if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)) | |
2140 | + nfs_confirm_seqid(&data->owner->so_seqid, 0); | |
2141 | } | |
2142 | nfs_increment_open_seqid(data->rpc_status, data->o_arg.seqid); | |
2143 | + data->rpc_done = 1; | |
2144 | } | |
2145 | ||
2146 | static void nfs4_open_release(void *calldata) | |
2147 | @@ -696,17 +870,17 @@ static void nfs4_open_release(void *calldata) | |
2148 | if (data->cancelled == 0) | |
2149 | goto out_free; | |
2150 | /* In case of error, no cleanup! */ | |
2151 | - if (data->rpc_status != 0) | |
2152 | + if (data->rpc_status != 0 || !data->rpc_done) | |
2153 | goto out_free; | |
2154 | /* In case we need an open_confirm, no cleanup! */ | |
2155 | if (data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) | |
2156 | goto out_free; | |
2157 | nfs_confirm_seqid(&data->owner->so_seqid, 0); | |
2158 | state = nfs4_opendata_to_nfs4_state(data); | |
2159 | - if (state != NULL) | |
2160 | - nfs4_close_state(state, data->o_arg.open_flags); | |
2161 | + if (!IS_ERR(state)) | |
2162 | + nfs4_close_state(&data->path, state, data->o_arg.open_flags); | |
2163 | out_free: | |
2164 | - nfs4_opendata_free(data); | |
2165 | + nfs4_opendata_put(data); | |
2166 | } | |
2167 | ||
2168 | static const struct rpc_call_ops nfs4_open_ops = { | |
2169 | @@ -727,12 +901,10 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |
2170 | struct rpc_task *task; | |
2171 | int status; | |
2172 | ||
2173 | - atomic_inc(&data->count); | |
2174 | - /* | |
2175 | - * If rpc_run_task() ends up calling ->rpc_release(), we | |
2176 | - * want to ensure that it takes the 'error' code path. | |
2177 | - */ | |
2178 | - data->rpc_status = -ENOMEM; | |
2179 | + kref_get(&data->kref); | |
2180 | + data->rpc_done = 0; | |
2181 | + data->rpc_status = 0; | |
2182 | + data->cancelled = 0; | |
2183 | task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data); | |
2184 | if (IS_ERR(task)) | |
2185 | return PTR_ERR(task); | |
2186 | @@ -743,7 +915,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |
2187 | } else | |
2188 | status = data->rpc_status; | |
2189 | rpc_put_task(task); | |
2190 | - if (status != 0) | |
2191 | + if (status != 0 || !data->rpc_done) | |
2192 | return status; | |
2193 | ||
2194 | if (o_arg->open_flags & O_CREAT) { | |
2195 | @@ -756,7 +928,6 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |
2196 | if (status != 0) | |
2197 | return status; | |
2198 | } | |
2199 | - nfs_confirm_seqid(&data->owner->so_seqid, 0); | |
2200 | if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) | |
2201 | return server->nfs_client->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr); | |
2202 | return 0; | |
2203 | @@ -772,6 +943,8 @@ static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openf | |
2204 | mask |= MAY_READ; | |
2205 | if (openflags & FMODE_WRITE) | |
2206 | mask |= MAY_WRITE; | |
2207 | + if (openflags & FMODE_EXEC) | |
2208 | + mask |= MAY_EXEC; | |
2209 | status = nfs_access_get_cached(inode, cred, &cache); | |
2210 | if (status == 0) | |
2211 | goto out; | |
2212 | @@ -811,43 +984,32 @@ static int nfs4_recover_expired_lease(struct nfs_server *server) | |
2213 | * reclaim state on the server after a network partition. | |
2214 | * Assumes caller holds the appropriate lock | |
2215 | */ | |
2216 | -static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | |
2217 | +static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state) | |
2218 | { | |
2219 | - struct inode *inode = state->inode; | |
2220 | - struct nfs_delegation *delegation = NFS_I(inode)->delegation; | |
2221 | struct nfs4_opendata *opendata; | |
2222 | - int openflags = state->state & (FMODE_READ|FMODE_WRITE); | |
2223 | int ret; | |
2224 | ||
2225 | - if (delegation != NULL && !(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) { | |
2226 | - ret = _nfs4_do_access(inode, sp->so_cred, openflags); | |
2227 | - if (ret < 0) | |
2228 | - return ret; | |
2229 | - memcpy(&state->stateid, &delegation->stateid, sizeof(state->stateid)); | |
2230 | - set_bit(NFS_DELEGATED_STATE, &state->flags); | |
2231 | - return 0; | |
2232 | - } | |
2233 | - opendata = nfs4_opendata_alloc(dentry, sp, openflags, NULL); | |
2234 | + opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL); | |
2235 | if (opendata == NULL) | |
2236 | return -ENOMEM; | |
2237 | ret = nfs4_open_recover(opendata, state); | |
2238 | if (ret == -ESTALE) { | |
2239 | /* Invalidate the state owner so we don't ever use it again */ | |
2240 | - nfs4_drop_state_owner(sp); | |
2241 | - d_drop(dentry); | |
2242 | + nfs4_drop_state_owner(state->owner); | |
2243 | + d_drop(ctx->path.dentry); | |
2244 | } | |
2245 | - nfs4_opendata_free(opendata); | |
2246 | + nfs4_opendata_put(opendata); | |
2247 | return ret; | |
2248 | } | |
2249 | ||
2250 | -static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry) | |
2251 | +static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state) | |
2252 | { | |
2253 | - struct nfs_server *server = NFS_SERVER(dentry->d_inode); | |
2254 | + struct nfs_server *server = NFS_SERVER(state->inode); | |
2255 | struct nfs4_exception exception = { }; | |
2256 | int err; | |
2257 | ||
2258 | do { | |
2259 | - err = _nfs4_open_expired(sp, state, dentry); | |
2260 | + err = _nfs4_open_expired(ctx, state); | |
2261 | if (err == -NFS4ERR_DELAY) | |
2262 | nfs4_handle_exception(server, err, &exception); | |
2263 | } while (exception.retry); | |
2264 | @@ -862,107 +1024,38 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta | |
2265 | ctx = nfs4_state_find_open_context(state); | |
2266 | if (IS_ERR(ctx)) | |
2267 | return PTR_ERR(ctx); | |
2268 | - ret = nfs4_do_open_expired(sp, state, ctx->dentry); | |
2269 | + ret = nfs4_do_open_expired(ctx, state); | |
2270 | put_nfs_open_context(ctx); | |
2271 | return ret; | |
2272 | } | |
2273 | ||
2274 | /* | |
2275 | - * Returns a referenced nfs4_state if there is an open delegation on the file | |
2276 | + * on an EXCLUSIVE create, the server should send back a bitmask with FATTR4-* | |
2277 | + * fields corresponding to attributes that were used to store the verifier. | |
2278 | + * Make sure we clobber those fields in the later setattr call | |
2279 | */ | |
2280 | -static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred, struct nfs4_state **res) | |
2281 | -{ | |
2282 | - struct nfs_delegation *delegation; | |
2283 | - struct nfs_server *server = NFS_SERVER(inode); | |
2284 | - struct nfs_client *clp = server->nfs_client; | |
2285 | - struct nfs_inode *nfsi = NFS_I(inode); | |
2286 | - struct nfs4_state_owner *sp = NULL; | |
2287 | - struct nfs4_state *state = NULL; | |
2288 | - int open_flags = flags & (FMODE_READ|FMODE_WRITE); | |
2289 | - int err; | |
2290 | - | |
2291 | - err = -ENOMEM; | |
2292 | - if (!(sp = nfs4_get_state_owner(server, cred))) { | |
2293 | - dprintk("%s: nfs4_get_state_owner failed!\n", __FUNCTION__); | |
2294 | - return err; | |
2295 | - } | |
2296 | - err = nfs4_recover_expired_lease(server); | |
2297 | - if (err != 0) | |
2298 | - goto out_put_state_owner; | |
2299 | - /* Protect against reboot recovery - NOTE ORDER! */ | |
2300 | - down_read(&clp->cl_sem); | |
2301 | - /* Protect against delegation recall */ | |
2302 | - down_read(&nfsi->rwsem); | |
2303 | - delegation = NFS_I(inode)->delegation; | |
2304 | - err = -ENOENT; | |
2305 | - if (delegation == NULL || (delegation->type & open_flags) != open_flags) | |
2306 | - goto out_err; | |
2307 | - err = -ENOMEM; | |
2308 | - state = nfs4_get_open_state(inode, sp); | |
2309 | - if (state == NULL) | |
2310 | - goto out_err; | |
2311 | - | |
2312 | - err = -ENOENT; | |
2313 | - if ((state->state & open_flags) == open_flags) { | |
2314 | - spin_lock(&inode->i_lock); | |
2315 | - update_open_stateflags(state, open_flags); | |
2316 | - spin_unlock(&inode->i_lock); | |
2317 | - goto out_ok; | |
2318 | - } else if (state->state != 0) | |
2319 | - goto out_put_open_state; | |
2320 | - | |
2321 | - lock_kernel(); | |
2322 | - err = _nfs4_do_access(inode, cred, open_flags); | |
2323 | - unlock_kernel(); | |
2324 | - if (err != 0) | |
2325 | - goto out_put_open_state; | |
2326 | - set_bit(NFS_DELEGATED_STATE, &state->flags); | |
2327 | - update_open_stateid(state, &delegation->stateid, open_flags); | |
2328 | -out_ok: | |
2329 | - nfs4_put_state_owner(sp); | |
2330 | - up_read(&nfsi->rwsem); | |
2331 | - up_read(&clp->cl_sem); | |
2332 | - *res = state; | |
2333 | - return 0; | |
2334 | -out_put_open_state: | |
2335 | - nfs4_put_open_state(state); | |
2336 | -out_err: | |
2337 | - up_read(&nfsi->rwsem); | |
2338 | - up_read(&clp->cl_sem); | |
2339 | - if (err != -EACCES) | |
2340 | - nfs_inode_return_delegation(inode); | |
2341 | -out_put_state_owner: | |
2342 | - nfs4_put_state_owner(sp); | |
2343 | - return err; | |
2344 | -} | |
2345 | - | |
2346 | -static struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred) | |
2347 | +static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct iattr *sattr) | |
2348 | { | |
2349 | - struct nfs4_exception exception = { }; | |
2350 | - struct nfs4_state *res = ERR_PTR(-EIO); | |
2351 | - int err; | |
2352 | + if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_ACCESS) && | |
2353 | + !(sattr->ia_valid & ATTR_ATIME_SET)) | |
2354 | + sattr->ia_valid |= ATTR_ATIME; | |
2355 | ||
2356 | - do { | |
2357 | - err = _nfs4_open_delegated(inode, flags, cred, &res); | |
2358 | - if (err == 0) | |
2359 | - break; | |
2360 | - res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(inode), | |
2361 | - err, &exception)); | |
2362 | - } while (exception.retry); | |
2363 | - return res; | |
2364 | + if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_MODIFY) && | |
2365 | + !(sattr->ia_valid & ATTR_MTIME_SET)) | |
2366 | + sattr->ia_valid |= ATTR_MTIME; | |
2367 | } | |
2368 | ||
2369 | /* | |
2370 | * Returns a referenced nfs4_state | |
2371 | */ | |
2372 | -static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) | |
2373 | +static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) | |
2374 | { | |
2375 | struct nfs4_state_owner *sp; | |
2376 | struct nfs4_state *state = NULL; | |
2377 | struct nfs_server *server = NFS_SERVER(dir); | |
2378 | struct nfs_client *clp = server->nfs_client; | |
2379 | struct nfs4_opendata *opendata; | |
2380 | - int status; | |
2381 | + int status; | |
2382 | ||
2383 | /* Protect against reboot recovery conflicts */ | |
2384 | status = -ENOMEM; | |
2385 | @@ -973,29 +1066,35 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st | |
2386 | status = nfs4_recover_expired_lease(server); | |
2387 | if (status != 0) | |
2388 | goto err_put_state_owner; | |
2389 | + if (path->dentry->d_inode != NULL) | |
2390 | + nfs4_return_incompatible_delegation(path->dentry->d_inode, flags & (FMODE_READ|FMODE_WRITE)); | |
2391 | down_read(&clp->cl_sem); | |
2392 | status = -ENOMEM; | |
2393 | - opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr); | |
2394 | + opendata = nfs4_opendata_alloc(path, sp, flags, sattr); | |
2395 | if (opendata == NULL) | |
2396 | goto err_release_rwsem; | |
2397 | ||
2398 | + if (path->dentry->d_inode != NULL) | |
2399 | + opendata->state = nfs4_get_open_state(path->dentry->d_inode, sp); | |
2400 | + | |
2401 | status = _nfs4_proc_open(opendata); | |
2402 | if (status != 0) | |
2403 | - goto err_opendata_free; | |
2404 | + goto err_opendata_put; | |
2405 | + | |
2406 | + if (opendata->o_arg.open_flags & O_EXCL) | |
2407 | + nfs4_exclusive_attrset(opendata, sattr); | |
2408 | ||
2409 | - status = -ENOMEM; | |
2410 | state = nfs4_opendata_to_nfs4_state(opendata); | |
2411 | - if (state == NULL) | |
2412 | - goto err_opendata_free; | |
2413 | - if (opendata->o_res.delegation_type != 0) | |
2414 | - nfs_inode_set_delegation(state->inode, cred, &opendata->o_res); | |
2415 | - nfs4_opendata_free(opendata); | |
2416 | + status = PTR_ERR(state); | |
2417 | + if (IS_ERR(state)) | |
2418 | + goto err_opendata_put; | |
2419 | + nfs4_opendata_put(opendata); | |
2420 | nfs4_put_state_owner(sp); | |
2421 | up_read(&clp->cl_sem); | |
2422 | *res = state; | |
2423 | return 0; | |
2424 | -err_opendata_free: | |
2425 | - nfs4_opendata_free(opendata); | |
2426 | +err_opendata_put: | |
2427 | + nfs4_opendata_put(opendata); | |
2428 | err_release_rwsem: | |
2429 | up_read(&clp->cl_sem); | |
2430 | err_put_state_owner: | |
2431 | @@ -1006,14 +1105,14 @@ out_err: | |
2432 | } | |
2433 | ||
2434 | ||
2435 | -static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred) | |
2436 | +static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred) | |
2437 | { | |
2438 | struct nfs4_exception exception = { }; | |
2439 | struct nfs4_state *res; | |
2440 | int status; | |
2441 | ||
2442 | do { | |
2443 | - status = _nfs4_do_open(dir, dentry, flags, sattr, cred, &res); | |
2444 | + status = _nfs4_do_open(dir, path, flags, sattr, cred, &res); | |
2445 | if (status == 0) | |
2446 | break; | |
2447 | /* NOTE: BAD_SEQID means the server and client disagree about the | |
2448 | @@ -1028,7 +1127,9 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, | |
2449 | * the user though... | |
2450 | */ | |
2451 | if (status == -NFS4ERR_BAD_SEQID) { | |
2452 | - printk(KERN_WARNING "NFS: v4 server returned a bad sequence-id error!\n"); | |
2453 | + printk(KERN_WARNING "NFS: v4 server %s " | |
2454 | + " returned a bad sequence-id error!\n", | |
2455 | + NFS_SERVER(dir)->nfs_client->cl_hostname); | |
2456 | exception.retry = 1; | |
2457 | continue; | |
2458 | } | |
2459 | @@ -1042,6 +1143,11 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, | |
2460 | exception.retry = 1; | |
2461 | continue; | |
2462 | } | |
2463 | + if (status == -EAGAIN) { | |
2464 | + /* We must have found a delegation */ | |
2465 | + exception.retry = 1; | |
2466 | + continue; | |
2467 | + } | |
2468 | res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(dir), | |
2469 | status, &exception)); | |
2470 | } while (exception.retry); | |
2471 | @@ -1101,6 +1207,7 @@ static int nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr, | |
2472 | } | |
2473 | ||
2474 | struct nfs4_closedata { | |
2475 | + struct path path; | |
2476 | struct inode *inode; | |
2477 | struct nfs4_state *state; | |
2478 | struct nfs_closeargs arg; | |
2479 | @@ -1117,6 +1224,8 @@ static void nfs4_free_closedata(void *data) | |
2480 | nfs4_put_open_state(calldata->state); | |
2481 | nfs_free_seqid(calldata->arg.seqid); | |
2482 | nfs4_put_state_owner(sp); | |
2483 | + dput(calldata->path.dentry); | |
2484 | + mntput(calldata->path.mnt); | |
2485 | kfree(calldata); | |
2486 | } | |
2487 | ||
2488 | @@ -1134,8 +1243,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |
2489 | nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid); | |
2490 | switch (task->tk_status) { | |
2491 | case 0: | |
2492 | - memcpy(&state->stateid, &calldata->res.stateid, | |
2493 | - sizeof(state->stateid)); | |
2494 | + nfs_set_open_stateid(state, &calldata->res.stateid, calldata->arg.open_flags); | |
2495 | renew_lease(server, calldata->timestamp); | |
2496 | break; | |
2497 | case -NFS4ERR_STALE_STATEID: | |
2498 | @@ -1160,26 +1268,30 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |
2499 | .rpc_resp = &calldata->res, | |
2500 | .rpc_cred = state->owner->so_cred, | |
2501 | }; | |
2502 | - int mode = 0, old_mode; | |
2503 | + int clear_rd, clear_wr, clear_rdwr; | |
2504 | + int mode; | |
2505 | ||
2506 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) | |
2507 | return; | |
2508 | - /* Recalculate the new open mode in case someone reopened the file | |
2509 | - * while we were waiting in line to be scheduled. | |
2510 | - */ | |
2511 | + | |
2512 | + mode = FMODE_READ|FMODE_WRITE; | |
2513 | + clear_rd = clear_wr = clear_rdwr = 0; | |
2514 | spin_lock(&state->owner->so_lock); | |
2515 | - spin_lock(&calldata->inode->i_lock); | |
2516 | - mode = old_mode = state->state; | |
2517 | + /* Calculate the change in open mode */ | |
2518 | if (state->n_rdwr == 0) { | |
2519 | - if (state->n_rdonly == 0) | |
2520 | + if (state->n_rdonly == 0) { | |
2521 | mode &= ~FMODE_READ; | |
2522 | - if (state->n_wronly == 0) | |
2523 | + clear_rd |= test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags); | |
2524 | + clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); | |
2525 | + } | |
2526 | + if (state->n_wronly == 0) { | |
2527 | mode &= ~FMODE_WRITE; | |
2528 | + clear_wr |= test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags); | |
2529 | + clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); | |
2530 | + } | |
2531 | } | |
2532 | - nfs4_state_set_mode_locked(state, mode); | |
2533 | - spin_unlock(&calldata->inode->i_lock); | |
2534 | spin_unlock(&state->owner->so_lock); | |
2535 | - if (mode == old_mode || test_bit(NFS_DELEGATED_STATE, &state->flags)) { | |
2536 | + if (!clear_rd && !clear_wr && !clear_rdwr) { | |
2537 | /* Note: exit _without_ calling nfs4_close_done */ | |
2538 | task->tk_action = NULL; | |
2539 | return; | |
2540 | @@ -1209,19 +1321,21 @@ static const struct rpc_call_ops nfs4_close_ops = { | |
2541 | * | |
2542 | * NOTE: Caller must be holding the sp->so_owner semaphore! | |
2543 | */ | |
2544 | -int nfs4_do_close(struct inode *inode, struct nfs4_state *state) | |
2545 | +int nfs4_do_close(struct path *path, struct nfs4_state *state) | |
2546 | { | |
2547 | - struct nfs_server *server = NFS_SERVER(inode); | |
2548 | + struct nfs_server *server = NFS_SERVER(state->inode); | |
2549 | struct nfs4_closedata *calldata; | |
2550 | + struct nfs4_state_owner *sp = state->owner; | |
2551 | + struct rpc_task *task; | |
2552 | int status = -ENOMEM; | |
2553 | ||
2554 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); | |
2555 | if (calldata == NULL) | |
2556 | goto out; | |
2557 | - calldata->inode = inode; | |
2558 | + calldata->inode = state->inode; | |
2559 | calldata->state = state; | |
2560 | - calldata->arg.fh = NFS_FH(inode); | |
2561 | - calldata->arg.stateid = &state->stateid; | |
2562 | + calldata->arg.fh = NFS_FH(state->inode); | |
2563 | + calldata->arg.stateid = &state->open_stateid; | |
2564 | /* Serialization for the sequence id */ | |
2565 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | |
2566 | if (calldata->arg.seqid == NULL) | |
2567 | @@ -1229,36 +1343,55 @@ int nfs4_do_close(struct inode *inode, struct nfs4_state *state) | |
2568 | calldata->arg.bitmask = server->attr_bitmask; | |
2569 | calldata->res.fattr = &calldata->fattr; | |
2570 | calldata->res.server = server; | |
2571 | + calldata->path.mnt = mntget(path->mnt); | |
2572 | + calldata->path.dentry = dget(path->dentry); | |
2573 | ||
2574 | - status = nfs4_call_async(server->client, &nfs4_close_ops, calldata); | |
2575 | - if (status == 0) | |
2576 | - goto out; | |
2577 | - | |
2578 | - nfs_free_seqid(calldata->arg.seqid); | |
2579 | + task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_close_ops, calldata); | |
2580 | + if (IS_ERR(task)) | |
2581 | + return PTR_ERR(task); | |
2582 | + rpc_put_task(task); | |
2583 | + return 0; | |
2584 | out_free_calldata: | |
2585 | kfree(calldata); | |
2586 | out: | |
2587 | + nfs4_put_open_state(state); | |
2588 | + nfs4_put_state_owner(sp); | |
2589 | return status; | |
2590 | } | |
2591 | ||
2592 | -static int nfs4_intent_set_file(struct nameidata *nd, struct dentry *dentry, struct nfs4_state *state) | |
2593 | +static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state) | |
2594 | { | |
2595 | struct file *filp; | |
2596 | + int ret; | |
2597 | ||
2598 | - filp = lookup_instantiate_filp(nd, dentry, NULL); | |
2599 | + /* If the open_intent is for execute, we have an extra check to make */ | |
2600 | + if (nd->intent.open.flags & FMODE_EXEC) { | |
2601 | + ret = _nfs4_do_access(state->inode, | |
2602 | + state->owner->so_cred, | |
2603 | + nd->intent.open.flags); | |
2604 | + if (ret < 0) | |
2605 | + goto out_close; | |
2606 | + } | |
2607 | + filp = lookup_instantiate_filp(nd, path->dentry, NULL); | |
2608 | if (!IS_ERR(filp)) { | |
2609 | struct nfs_open_context *ctx; | |
2610 | ctx = (struct nfs_open_context *)filp->private_data; | |
2611 | ctx->state = state; | |
2612 | return 0; | |
2613 | } | |
2614 | - nfs4_close_state(state, nd->intent.open.flags); | |
2615 | - return PTR_ERR(filp); | |
2616 | + ret = PTR_ERR(filp); | |
2617 | +out_close: | |
2618 | + nfs4_close_state(path, state, nd->intent.open.flags); | |
2619 | + return ret; | |
2620 | } | |
2621 | ||
2622 | struct dentry * | |
2623 | nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |
2624 | { | |
2625 | + struct path path = { | |
2626 | + .mnt = nd->mnt, | |
2627 | + .dentry = dentry, | |
2628 | + }; | |
2629 | struct iattr attr; | |
2630 | struct rpc_cred *cred; | |
2631 | struct nfs4_state *state; | |
2632 | @@ -1277,7 +1410,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |
2633 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); | |
2634 | if (IS_ERR(cred)) | |
2635 | return (struct dentry *)cred; | |
2636 | - state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); | |
2637 | + state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred); | |
2638 | put_rpccred(cred); | |
2639 | if (IS_ERR(state)) { | |
2640 | if (PTR_ERR(state) == -ENOENT) | |
2641 | @@ -1287,22 +1420,24 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |
2642 | res = d_add_unique(dentry, igrab(state->inode)); | |
2643 | if (res != NULL) | |
2644 | dentry = res; | |
2645 | - nfs4_intent_set_file(nd, dentry, state); | |
2646 | + nfs4_intent_set_file(nd, &path, state); | |
2647 | return res; | |
2648 | } | |
2649 | ||
2650 | int | |
2651 | nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd) | |
2652 | { | |
2653 | + struct path path = { | |
2654 | + .mnt = nd->mnt, | |
2655 | + .dentry = dentry, | |
2656 | + }; | |
2657 | struct rpc_cred *cred; | |
2658 | struct nfs4_state *state; | |
2659 | ||
2660 | cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); | |
2661 | if (IS_ERR(cred)) | |
2662 | return PTR_ERR(cred); | |
2663 | - state = nfs4_open_delegated(dentry->d_inode, openflags, cred); | |
2664 | - if (IS_ERR(state)) | |
2665 | - state = nfs4_do_open(dir, dentry, openflags, NULL, cred); | |
2666 | + state = nfs4_do_open(dir, &path, openflags, NULL, cred); | |
2667 | put_rpccred(cred); | |
2668 | if (IS_ERR(state)) { | |
2669 | switch (PTR_ERR(state)) { | |
2670 | @@ -1318,10 +1453,10 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |
2671 | } | |
2672 | } | |
2673 | if (state->inode == dentry->d_inode) { | |
2674 | - nfs4_intent_set_file(nd, dentry, state); | |
2675 | + nfs4_intent_set_file(nd, &path, state); | |
2676 | return 1; | |
2677 | } | |
2678 | - nfs4_close_state(state, openflags); | |
2679 | + nfs4_close_state(&path, state, openflags); | |
2680 | out_drop: | |
2681 | d_drop(dentry); | |
2682 | return 0; | |
2683 | @@ -1559,8 +1694,6 @@ static int _nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, | |
2684 | dprintk("NFS call lookupfh %s\n", name->name); | |
2685 | status = rpc_call_sync(server->client, &msg, 0); | |
2686 | dprintk("NFS reply lookupfh: %d\n", status); | |
2687 | - if (status == -NFS4ERR_MOVED) | |
2688 | - status = -EREMOTE; | |
2689 | return status; | |
2690 | } | |
2691 | ||
2692 | @@ -1571,10 +1704,13 @@ static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, | |
2693 | struct nfs4_exception exception = { }; | |
2694 | int err; | |
2695 | do { | |
2696 | - err = nfs4_handle_exception(server, | |
2697 | - _nfs4_proc_lookupfh(server, dirfh, name, | |
2698 | - fhandle, fattr), | |
2699 | - &exception); | |
2700 | + err = _nfs4_proc_lookupfh(server, dirfh, name, fhandle, fattr); | |
2701 | + /* FIXME: !!!! */ | |
2702 | + if (err == -NFS4ERR_MOVED) { | |
2703 | + err = -EREMOTE; | |
2704 | + break; | |
2705 | + } | |
2706 | + err = nfs4_handle_exception(server, err, &exception); | |
2707 | } while (exception.retry); | |
2708 | return err; | |
2709 | } | |
2710 | @@ -1582,28 +1718,10 @@ static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh, | |
2711 | static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name, | |
2712 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | |
2713 | { | |
2714 | - int status; | |
2715 | - struct nfs_server *server = NFS_SERVER(dir); | |
2716 | - struct nfs4_lookup_arg args = { | |
2717 | - .bitmask = server->attr_bitmask, | |
2718 | - .dir_fh = NFS_FH(dir), | |
2719 | - .name = name, | |
2720 | - }; | |
2721 | - struct nfs4_lookup_res res = { | |
2722 | - .server = server, | |
2723 | - .fattr = fattr, | |
2724 | - .fh = fhandle, | |
2725 | - }; | |
2726 | - struct rpc_message msg = { | |
2727 | - .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP], | |
2728 | - .rpc_argp = &args, | |
2729 | - .rpc_resp = &res, | |
2730 | - }; | |
2731 | - | |
2732 | - nfs_fattr_init(fattr); | |
2733 | + int status; | |
2734 | ||
2735 | dprintk("NFS call lookup %s\n", name->name); | |
2736 | - status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | |
2737 | + status = _nfs4_proc_lookupfh(NFS_SERVER(dir), NFS_FH(dir), name, fhandle, fattr); | |
2738 | if (status == -NFS4ERR_MOVED) | |
2739 | status = nfs4_get_referral(dir, name, fattr, fhandle); | |
2740 | dprintk("NFS reply lookup: %d\n", status); | |
2741 | @@ -1752,6 +1870,10 @@ static int | |
2742 | nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |
2743 | int flags, struct nameidata *nd) | |
2744 | { | |
2745 | + struct path path = { | |
2746 | + .mnt = nd->mnt, | |
2747 | + .dentry = dentry, | |
2748 | + }; | |
2749 | struct nfs4_state *state; | |
2750 | struct rpc_cred *cred; | |
2751 | int status = 0; | |
2752 | @@ -1761,7 +1883,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |
2753 | status = PTR_ERR(cred); | |
2754 | goto out; | |
2755 | } | |
2756 | - state = nfs4_do_open(dir, dentry, flags, sattr, cred); | |
2757 | + state = nfs4_do_open(dir, &path, flags, sattr, cred); | |
2758 | put_rpccred(cred); | |
2759 | if (IS_ERR(state)) { | |
2760 | status = PTR_ERR(state); | |
2761 | @@ -1773,11 +1895,12 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |
2762 | status = nfs4_do_setattr(state->inode, &fattr, sattr, state); | |
2763 | if (status == 0) | |
2764 | nfs_setattr_update_inode(state->inode, sattr); | |
2765 | + nfs_post_op_update_inode(state->inode, &fattr); | |
2766 | } | |
2767 | - if (status == 0 && nd != NULL && (nd->flags & LOOKUP_OPEN)) | |
2768 | - status = nfs4_intent_set_file(nd, dentry, state); | |
2769 | + if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) | |
2770 | + status = nfs4_intent_set_file(nd, &path, state); | |
2771 | else | |
2772 | - nfs4_close_state(state, flags); | |
2773 | + nfs4_close_state(&path, state, flags); | |
2774 | out: | |
2775 | return status; | |
2776 | } | |
2777 | @@ -3008,7 +3131,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |
2778 | if (status != 0) | |
2779 | goto out; | |
2780 | lsp = request->fl_u.nfs4_fl.owner; | |
2781 | - arg.lock_owner.id = lsp->ls_id; | |
2782 | + arg.lock_owner.id = lsp->ls_id.id; | |
2783 | status = rpc_call_sync(server->client, &msg, 0); | |
2784 | switch (status) { | |
2785 | case 0: | |
2786 | @@ -3152,6 +3275,11 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, | |
2787 | { | |
2788 | struct nfs4_unlockdata *data; | |
2789 | ||
2790 | + /* Ensure this is an unlock - when canceling a lock, the | |
2791 | + * canceled lock is passed in, and it won't be an unlock. | |
2792 | + */ | |
2793 | + fl->fl_type = F_UNLCK; | |
2794 | + | |
2795 | data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid); | |
2796 | if (data == NULL) { | |
2797 | nfs_free_seqid(seqid); | |
2798 | @@ -3222,7 +3350,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |
2799 | goto out_free; | |
2800 | p->arg.lock_stateid = &lsp->ls_stateid; | |
2801 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; | |
2802 | - p->arg.lock_owner.id = lsp->ls_id; | |
2803 | + p->arg.lock_owner.id = lsp->ls_id.id; | |
2804 | p->lsp = lsp; | |
2805 | atomic_inc(&lsp->ls_count); | |
2806 | p->ctx = get_nfs_open_context(ctx); | |
2807 | @@ -3285,7 +3413,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |
2808 | memcpy(data->lsp->ls_stateid.data, data->res.stateid.data, | |
2809 | sizeof(data->lsp->ls_stateid.data)); | |
2810 | data->lsp->ls_flags |= NFS_LOCK_INITIALIZED; | |
2811 | - renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp); | |
2812 | + renew_lease(NFS_SERVER(data->ctx->path.dentry->d_inode), data->timestamp); | |
2813 | } | |
2814 | nfs_increment_lock_seqid(data->rpc_status, data->arg.lock_seqid); | |
2815 | out: | |
2816 | diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c | |
2817 | index 8ed79d5..28551ae 100644 | |
2818 | --- a/fs/nfs/nfs4state.c | |
2819 | +++ b/fs/nfs/nfs4state.c | |
2820 | @@ -38,12 +38,14 @@ | |
2821 | * subsequent patch. | |
2822 | */ | |
2823 | ||
2824 | +#include <linux/kernel.h> | |
2825 | #include <linux/slab.h> | |
2826 | #include <linux/smp_lock.h> | |
2827 | #include <linux/nfs_fs.h> | |
2828 | #include <linux/nfs_idmap.h> | |
2829 | #include <linux/kthread.h> | |
2830 | #include <linux/module.h> | |
2831 | +#include <linux/random.h> | |
2832 | #include <linux/workqueue.h> | |
2833 | #include <linux/bitops.h> | |
2834 | ||
2835 | @@ -69,33 +71,14 @@ static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) | |
2836 | return status; | |
2837 | } | |
2838 | ||
2839 | -u32 | |
2840 | -nfs4_alloc_lockowner_id(struct nfs_client *clp) | |
2841 | -{ | |
2842 | - return clp->cl_lockowner_id ++; | |
2843 | -} | |
2844 | - | |
2845 | -static struct nfs4_state_owner * | |
2846 | -nfs4_client_grab_unused(struct nfs_client *clp, struct rpc_cred *cred) | |
2847 | -{ | |
2848 | - struct nfs4_state_owner *sp = NULL; | |
2849 | - | |
2850 | - if (!list_empty(&clp->cl_unused)) { | |
2851 | - sp = list_entry(clp->cl_unused.next, struct nfs4_state_owner, so_list); | |
2852 | - atomic_inc(&sp->so_count); | |
2853 | - sp->so_cred = cred; | |
2854 | - list_move(&sp->so_list, &clp->cl_state_owners); | |
2855 | - clp->cl_nunused--; | |
2856 | - } | |
2857 | - return sp; | |
2858 | -} | |
2859 | - | |
2860 | struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) | |
2861 | { | |
2862 | struct nfs4_state_owner *sp; | |
2863 | + struct rb_node *pos; | |
2864 | struct rpc_cred *cred = NULL; | |
2865 | ||
2866 | - list_for_each_entry(sp, &clp->cl_state_owners, so_list) { | |
2867 | + for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { | |
2868 | + sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | |
2869 | if (list_empty(&sp->so_states)) | |
2870 | continue; | |
2871 | cred = get_rpccred(sp->so_cred); | |
2872 | @@ -107,32 +90,146 @@ struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) | |
2873 | static struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) | |
2874 | { | |
2875 | struct nfs4_state_owner *sp; | |
2876 | + struct rb_node *pos; | |
2877 | ||
2878 | - if (!list_empty(&clp->cl_state_owners)) { | |
2879 | - sp = list_entry(clp->cl_state_owners.next, | |
2880 | - struct nfs4_state_owner, so_list); | |
2881 | + pos = rb_first(&clp->cl_state_owners); | |
2882 | + if (pos != NULL) { | |
2883 | + sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | |
2884 | return get_rpccred(sp->so_cred); | |
2885 | } | |
2886 | return NULL; | |
2887 | } | |
2888 | ||
2889 | +static void nfs_alloc_unique_id(struct rb_root *root, struct nfs_unique_id *new, | |
2890 | + __u64 minval, int maxbits) | |
2891 | +{ | |
2892 | + struct rb_node **p, *parent; | |
2893 | + struct nfs_unique_id *pos; | |
2894 | + __u64 mask = ~0ULL; | |
2895 | + | |
2896 | + if (maxbits < 64) | |
2897 | + mask = (1ULL << maxbits) - 1ULL; | |
2898 | + | |
2899 | + /* Ensure distribution is more or less flat */ | |
2900 | + get_random_bytes(&new->id, sizeof(new->id)); | |
2901 | + new->id &= mask; | |
2902 | + if (new->id < minval) | |
2903 | + new->id += minval; | |
2904 | +retry: | |
2905 | + p = &root->rb_node; | |
2906 | + parent = NULL; | |
2907 | + | |
2908 | + while (*p != NULL) { | |
2909 | + parent = *p; | |
2910 | + pos = rb_entry(parent, struct nfs_unique_id, rb_node); | |
2911 | + | |
2912 | + if (new->id < pos->id) | |
2913 | + p = &(*p)->rb_left; | |
2914 | + else if (new->id > pos->id) | |
2915 | + p = &(*p)->rb_right; | |
2916 | + else | |
2917 | + goto id_exists; | |
2918 | + } | |
2919 | + rb_link_node(&new->rb_node, parent, p); | |
2920 | + rb_insert_color(&new->rb_node, root); | |
2921 | + return; | |
2922 | +id_exists: | |
2923 | + for (;;) { | |
2924 | + new->id++; | |
2925 | + if (new->id < minval || (new->id & mask) != new->id) { | |
2926 | + new->id = minval; | |
2927 | + break; | |
2928 | + } | |
2929 | + parent = rb_next(parent); | |
2930 | + if (parent == NULL) | |
2931 | + break; | |
2932 | + pos = rb_entry(parent, struct nfs_unique_id, rb_node); | |
2933 | + if (new->id < pos->id) | |
2934 | + break; | |
2935 | + } | |
2936 | + goto retry; | |
2937 | +} | |
2938 | + | |
2939 | +static void nfs_free_unique_id(struct rb_root *root, struct nfs_unique_id *id) | |
2940 | +{ | |
2941 | + rb_erase(&id->rb_node, root); | |
2942 | +} | |
2943 | + | |
2944 | static struct nfs4_state_owner * | |
2945 | -nfs4_find_state_owner(struct nfs_client *clp, struct rpc_cred *cred) | |
2946 | +nfs4_find_state_owner(struct nfs_server *server, struct rpc_cred *cred) | |
2947 | { | |
2948 | + struct nfs_client *clp = server->nfs_client; | |
2949 | + struct rb_node **p = &clp->cl_state_owners.rb_node, | |
2950 | + *parent = NULL; | |
2951 | struct nfs4_state_owner *sp, *res = NULL; | |
2952 | ||
2953 | - list_for_each_entry(sp, &clp->cl_state_owners, so_list) { | |
2954 | - if (sp->so_cred != cred) | |
2955 | + while (*p != NULL) { | |
2956 | + parent = *p; | |
2957 | + sp = rb_entry(parent, struct nfs4_state_owner, so_client_node); | |
2958 | + | |
2959 | + if (server < sp->so_server) { | |
2960 | + p = &parent->rb_left; | |
2961 | continue; | |
2962 | - atomic_inc(&sp->so_count); | |
2963 | - /* Move to the head of the list */ | |
2964 | - list_move(&sp->so_list, &clp->cl_state_owners); | |
2965 | - res = sp; | |
2966 | - break; | |
2967 | + } | |
2968 | + if (server > sp->so_server) { | |
2969 | + p = &parent->rb_right; | |
2970 | + continue; | |
2971 | + } | |
2972 | + if (cred < sp->so_cred) | |
2973 | + p = &parent->rb_left; | |
2974 | + else if (cred > sp->so_cred) | |
2975 | + p = &parent->rb_right; | |
2976 | + else { | |
2977 | + atomic_inc(&sp->so_count); | |
2978 | + res = sp; | |
2979 | + break; | |
2980 | + } | |
2981 | } | |
2982 | return res; | |
2983 | } | |
2984 | ||
2985 | +static struct nfs4_state_owner * | |
2986 | +nfs4_insert_state_owner(struct nfs_client *clp, struct nfs4_state_owner *new) | |
2987 | +{ | |
2988 | + struct rb_node **p = &clp->cl_state_owners.rb_node, | |
2989 | + *parent = NULL; | |
2990 | + struct nfs4_state_owner *sp; | |
2991 | + | |
2992 | + while (*p != NULL) { | |
2993 | + parent = *p; | |
2994 | + sp = rb_entry(parent, struct nfs4_state_owner, so_client_node); | |
2995 | + | |
2996 | + if (new->so_server < sp->so_server) { | |
2997 | + p = &parent->rb_left; | |
2998 | + continue; | |
2999 | + } | |
3000 | + if (new->so_server > sp->so_server) { | |
3001 | + p = &parent->rb_right; | |
3002 | + continue; | |
3003 | + } | |
3004 | + if (new->so_cred < sp->so_cred) | |
3005 | + p = &parent->rb_left; | |
3006 | + else if (new->so_cred > sp->so_cred) | |
3007 | + p = &parent->rb_right; | |
3008 | + else { | |
3009 | + atomic_inc(&sp->so_count); | |
3010 | + return sp; | |
3011 | + } | |
3012 | + } | |
3013 | + nfs_alloc_unique_id(&clp->cl_openowner_id, &new->so_owner_id, 1, 64); | |
3014 | + rb_link_node(&new->so_client_node, parent, p); | |
3015 | + rb_insert_color(&new->so_client_node, &clp->cl_state_owners); | |
3016 | + return new; | |
3017 | +} | |
3018 | + | |
3019 | +static void | |
3020 | +nfs4_remove_state_owner(struct nfs_client *clp, struct nfs4_state_owner *sp) | |
3021 | +{ | |
3022 | + if (!RB_EMPTY_NODE(&sp->so_client_node)) | |
3023 | + rb_erase(&sp->so_client_node, &clp->cl_state_owners); | |
3024 | + nfs_free_unique_id(&clp->cl_openowner_id, &sp->so_owner_id); | |
3025 | +} | |
3026 | + | |
3027 | /* | |
3028 | * nfs4_alloc_state_owner(): this is called on the OPEN or CREATE path to | |
3029 | * create a new state_owner. | |
3030 | @@ -160,10 +257,14 @@ nfs4_alloc_state_owner(void) | |
3031 | void | |
3032 | nfs4_drop_state_owner(struct nfs4_state_owner *sp) | |
3033 | { | |
3034 | - struct nfs_client *clp = sp->so_client; | |
3035 | - spin_lock(&clp->cl_lock); | |
3036 | - list_del_init(&sp->so_list); | |
3037 | - spin_unlock(&clp->cl_lock); | |
3038 | + if (!RB_EMPTY_NODE(&sp->so_client_node)) { | |
3039 | + struct nfs_client *clp = sp->so_client; | |
3040 | + | |
3041 | + spin_lock(&clp->cl_lock); | |
3042 | + rb_erase(&sp->so_client_node, &clp->cl_state_owners); | |
3043 | + RB_CLEAR_NODE(&sp->so_client_node); | |
3044 | + spin_unlock(&clp->cl_lock); | |
3045 | + } | |
3046 | } | |
3047 | ||
3048 | /* | |
3049 | @@ -175,26 +276,25 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct | |
3050 | struct nfs_client *clp = server->nfs_client; | |
3051 | struct nfs4_state_owner *sp, *new; | |
3052 | ||
3053 | - get_rpccred(cred); | |
3054 | - new = nfs4_alloc_state_owner(); | |
3055 | spin_lock(&clp->cl_lock); | |
3056 | - sp = nfs4_find_state_owner(clp, cred); | |
3057 | - if (sp == NULL) | |
3058 | - sp = nfs4_client_grab_unused(clp, cred); | |
3059 | - if (sp == NULL && new != NULL) { | |
3060 | - list_add(&new->so_list, &clp->cl_state_owners); | |
3061 | - new->so_client = clp; | |
3062 | - new->so_id = nfs4_alloc_lockowner_id(clp); | |
3063 | - new->so_cred = cred; | |
3064 | - sp = new; | |
3065 | - new = NULL; | |
3066 | - } | |
3067 | + sp = nfs4_find_state_owner(server, cred); | |
3068 | spin_unlock(&clp->cl_lock); | |
3069 | - kfree(new); | |
3070 | if (sp != NULL) | |
3071 | return sp; | |
3072 | - put_rpccred(cred); | |
3073 | - return NULL; | |
3074 | + new = nfs4_alloc_state_owner(); | |
3075 | + if (new == NULL) | |
3076 | + return NULL; | |
3077 | + new->so_client = clp; | |
3078 | + new->so_server = server; | |
3079 | + new->so_cred = cred; | |
3080 | + spin_lock(&clp->cl_lock); | |
3081 | + sp = nfs4_insert_state_owner(clp, new); | |
3082 | + spin_unlock(&clp->cl_lock); | |
3083 | + if (sp == new) | |
3084 | + get_rpccred(cred); | |
3085 | + else | |
3086 | + kfree(new); | |
3087 | + return sp; | |
3088 | } | |
3089 | ||
3090 | /* | |
3091 | @@ -208,18 +308,7 @@ void nfs4_put_state_owner(struct nfs4_state_owner *sp) | |
3092 | ||
3093 | if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock)) | |
3094 | return; | |
3095 | - if (clp->cl_nunused >= OPENOWNER_POOL_SIZE) | |
3096 | - goto out_free; | |
3097 | - if (list_empty(&sp->so_list)) | |
3098 | - goto out_free; | |
3099 | - list_move(&sp->so_list, &clp->cl_unused); | |
3100 | - clp->cl_nunused++; | |
3101 | - spin_unlock(&clp->cl_lock); | |
3102 | - put_rpccred(cred); | |
3103 | - cred = NULL; | |
3104 | - return; | |
3105 | -out_free: | |
3106 | - list_del(&sp->so_list); | |
3107 | + nfs4_remove_state_owner(clp, sp); | |
3108 | spin_unlock(&clp->cl_lock); | |
3109 | put_rpccred(cred); | |
3110 | kfree(sp); | |
3111 | @@ -236,6 +325,7 @@ nfs4_alloc_open_state(void) | |
3112 | atomic_set(&state->count, 1); | |
3113 | INIT_LIST_HEAD(&state->lock_states); | |
3114 | spin_lock_init(&state->state_lock); | |
3115 | + seqlock_init(&state->seqlock); | |
3116 | return state; | |
3117 | } | |
3118 | ||
3119 | @@ -263,13 +353,10 @@ __nfs4_find_state_byowner(struct inode *inode, struct nfs4_state_owner *owner) | |
3120 | struct nfs4_state *state; | |
3121 | ||
3122 | list_for_each_entry(state, &nfsi->open_states, inode_states) { | |
3123 | - /* Is this in the process of being freed? */ | |
3124 | - if (state->state == 0) | |
3125 | + if (state->owner != owner) | |
3126 | continue; | |
3127 | - if (state->owner == owner) { | |
3128 | - atomic_inc(&state->count); | |
3129 | + if (atomic_inc_not_zero(&state->count)) | |
3130 | return state; | |
3131 | - } | |
3132 | } | |
3133 | return NULL; | |
3134 | } | |
3135 | @@ -341,16 +428,15 @@ void nfs4_put_open_state(struct nfs4_state *state) | |
3136 | /* | |
3137 | * Close the current file. | |
3138 | */ | |
3139 | -void nfs4_close_state(struct nfs4_state *state, mode_t mode) | |
3140 | +void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) | |
3141 | { | |
3142 | - struct inode *inode = state->inode; | |
3143 | struct nfs4_state_owner *owner = state->owner; | |
3144 | - int oldstate, newstate = 0; | |
3145 | + int call_close = 0; | |
3146 | + int newstate; | |
3147 | ||
3148 | atomic_inc(&owner->so_count); | |
3149 | /* Protect against nfs4_find_state() */ | |
3150 | spin_lock(&owner->so_lock); | |
3151 | - spin_lock(&inode->i_lock); | |
3152 | switch (mode & (FMODE_READ | FMODE_WRITE)) { | |
3153 | case FMODE_READ: | |
3154 | state->n_rdonly--; | |
3155 | @@ -361,24 +447,29 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode) | |
3156 | case FMODE_READ|FMODE_WRITE: | |
3157 | state->n_rdwr--; | |
3158 | } | |
3159 | - oldstate = newstate = state->state; | |
3160 | + newstate = FMODE_READ|FMODE_WRITE; | |
3161 | if (state->n_rdwr == 0) { | |
3162 | - if (state->n_rdonly == 0) | |
3163 | + if (state->n_rdonly == 0) { | |
3164 | newstate &= ~FMODE_READ; | |
3165 | - if (state->n_wronly == 0) | |
3166 | + call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags); | |
3167 | + call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags); | |
3168 | + } | |
3169 | + if (state->n_wronly == 0) { | |
3170 | newstate &= ~FMODE_WRITE; | |
3171 | + call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags); | |
3172 | + call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags); | |
3173 | + } | |
3174 | + if (newstate == 0) | |
3175 | + clear_bit(NFS_DELEGATED_STATE, &state->flags); | |
3176 | } | |
3177 | - if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { | |
3178 | - nfs4_state_set_mode_locked(state, newstate); | |
3179 | - oldstate = newstate; | |
3180 | - } | |
3181 | - spin_unlock(&inode->i_lock); | |
3182 | + nfs4_state_set_mode_locked(state, newstate); | |
3183 | spin_unlock(&owner->so_lock); | |
3184 | ||
3185 | - if (oldstate != newstate && nfs4_do_close(inode, state) == 0) | |
3186 | - return; | |
3187 | - nfs4_put_open_state(state); | |
3188 | - nfs4_put_state_owner(owner); | |
3189 | + if (!call_close) { | |
3190 | + nfs4_put_open_state(state); | |
3191 | + nfs4_put_state_owner(owner); | |
3192 | + } else | |
3193 | + nfs4_do_close(path, state); | |
3194 | } | |
3195 | ||
3196 | /* | |
3197 | @@ -415,12 +506,22 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |
3198 | atomic_set(&lsp->ls_count, 1); | |
3199 | lsp->ls_owner = fl_owner; | |
3200 | spin_lock(&clp->cl_lock); | |
3201 | - lsp->ls_id = nfs4_alloc_lockowner_id(clp); | |
3202 | + nfs_alloc_unique_id(&clp->cl_lockowner_id, &lsp->ls_id, 1, 64); | |
3203 | spin_unlock(&clp->cl_lock); | |
3204 | INIT_LIST_HEAD(&lsp->ls_locks); | |
3205 | return lsp; | |
3206 | } | |
3207 | ||
3208 | +static void nfs4_free_lock_state(struct nfs4_lock_state *lsp) | |
3209 | +{ | |
3210 | + struct nfs_client *clp = lsp->ls_state->owner->so_client; | |
3211 | + | |
3212 | + spin_lock(&clp->cl_lock); | |
3213 | + nfs_free_unique_id(&clp->cl_lockowner_id, &lsp->ls_id); | |
3214 | + spin_unlock(&clp->cl_lock); | |
3215 | + kfree(lsp); | |
3216 | +} | |
3217 | + | |
3218 | /* | |
3219 | * Return a compatible lock_state. If no initialized lock_state structure | |
3220 | * exists, return an uninitialized one. | |
3221 | @@ -450,7 +551,8 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_ | |
3222 | return NULL; | |
3223 | } | |
3224 | spin_unlock(&state->state_lock); | |
3225 | - kfree(new); | |
3226 | + if (new != NULL) | |
3227 | + nfs4_free_lock_state(new); | |
3228 | return lsp; | |
3229 | } | |
3230 | ||
3231 | @@ -471,7 +573,7 @@ void nfs4_put_lock_state(struct nfs4_lock_state *lsp) | |
3232 | if (list_empty(&state->lock_states)) | |
3233 | clear_bit(LK_STATE_IN_USE, &state->flags); | |
3234 | spin_unlock(&state->state_lock); | |
3235 | - kfree(lsp); | |
3236 | + nfs4_free_lock_state(lsp); | |
3237 | } | |
3238 | ||
3239 | static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src) | |
3240 | @@ -513,8 +615,12 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl) | |
3241 | void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner) | |
3242 | { | |
3243 | struct nfs4_lock_state *lsp; | |
3244 | + int seq; | |
3245 | ||
3246 | - memcpy(dst, &state->stateid, sizeof(*dst)); | |
3247 | + do { | |
3248 | + seq = read_seqbegin(&state->seqlock); | |
3249 | + memcpy(dst, &state->stateid, sizeof(*dst)); | |
3250 | + } while(read_seqretry(&state->seqlock, seq)); | |
3251 | if (test_bit(LK_STATE_IN_USE, &state->flags) == 0) | |
3252 | return; | |
3253 | ||
3254 | @@ -557,12 +663,18 @@ void nfs_free_seqid(struct nfs_seqid *seqid) | |
3255 | * failed with a seqid incrementing error - | |
3256 | * see comments nfs_fs.h:seqid_mutating_error() | |
3257 | */ | |
3258 | -static inline void nfs_increment_seqid(int status, struct nfs_seqid *seqid) | |
3259 | +static void nfs_increment_seqid(int status, struct nfs_seqid *seqid) | |
3260 | { | |
3261 | switch (status) { | |
3262 | case 0: | |
3263 | break; | |
3264 | case -NFS4ERR_BAD_SEQID: | |
3265 | + if (seqid->sequence->flags & NFS_SEQID_CONFIRMED) | |
3266 | + return; | |
3267 | + printk(KERN_WARNING "NFS: v4 server returned a bad" | |
3268 | + "sequence-id error on an" | |
3269 | + "unconfirmed sequence %p!\n", | |
3270 | + seqid->sequence); | |
3271 | case -NFS4ERR_STALE_CLIENTID: | |
3272 | case -NFS4ERR_STALE_STATEID: | |
3273 | case -NFS4ERR_BAD_STATEID: | |
3274 | @@ -586,7 +698,7 @@ void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) | |
3275 | struct nfs4_state_owner, so_seqid); | |
3276 | nfs4_drop_state_owner(sp); | |
3277 | } | |
3278 | - return nfs_increment_seqid(status, seqid); | |
3279 | + nfs_increment_seqid(status, seqid); | |
3280 | } | |
3281 | ||
3282 | /* | |
3283 | @@ -596,7 +708,7 @@ void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) | |
3284 | */ | |
3285 | void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid) | |
3286 | { | |
3287 | - return nfs_increment_seqid(status, seqid); | |
3288 | + nfs_increment_seqid(status, seqid); | |
3289 | } | |
3290 | ||
3291 | int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task) | |
3292 | @@ -748,15 +860,21 @@ out_err: | |
3293 | static void nfs4_state_mark_reclaim(struct nfs_client *clp) | |
3294 | { | |
3295 | struct nfs4_state_owner *sp; | |
3296 | + struct rb_node *pos; | |
3297 | struct nfs4_state *state; | |
3298 | struct nfs4_lock_state *lock; | |
3299 | ||
3300 | /* Reset all sequence ids to zero */ | |
3301 | - list_for_each_entry(sp, &clp->cl_state_owners, so_list) { | |
3302 | + for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { | |
3303 | + sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | |
3304 | sp->so_seqid.counter = 0; | |
3305 | sp->so_seqid.flags = 0; | |
3306 | spin_lock(&sp->so_lock); | |
3307 | list_for_each_entry(state, &sp->so_states, open_states) { | |
3308 | + clear_bit(NFS_DELEGATED_STATE, &state->flags); | |
3309 | + clear_bit(NFS_O_RDONLY_STATE, &state->flags); | |
3310 | + clear_bit(NFS_O_WRONLY_STATE, &state->flags); | |
3311 | + clear_bit(NFS_O_RDWR_STATE, &state->flags); | |
3312 | list_for_each_entry(lock, &state->lock_states, ls_locks) { | |
3313 | lock->ls_seqid.counter = 0; | |
3314 | lock->ls_seqid.flags = 0; | |
3315 | @@ -771,6 +889,7 @@ static int reclaimer(void *ptr) | |
3316 | { | |
3317 | struct nfs_client *clp = ptr; | |
3318 | struct nfs4_state_owner *sp; | |
3319 | + struct rb_node *pos; | |
3320 | struct nfs4_state_recovery_ops *ops; | |
3321 | struct rpc_cred *cred; | |
3322 | int status = 0; | |
3323 | @@ -816,7 +935,8 @@ restart_loop: | |
3324 | /* Mark all delegations for reclaim */ | |
3325 | nfs_delegation_mark_reclaim(clp); | |
3326 | /* Note: list is protected by exclusive lock on cl->cl_sem */ | |
3327 | - list_for_each_entry(sp, &clp->cl_state_owners, so_list) { | |
3328 | + for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { | |
3329 | + sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | |
3330 | status = nfs4_reclaim_open_state(ops, sp); | |
3331 | if (status < 0) { | |
3332 | if (status == -NFS4ERR_NO_GRACE) { | |
3333 | diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c | |
3334 | index 8003c91..c087384 100644 | |
3335 | --- a/fs/nfs/nfs4xdr.c | |
3336 | +++ b/fs/nfs/nfs4xdr.c | |
3337 | @@ -68,9 +68,10 @@ static int nfs4_stat_to_errno(int); | |
3338 | #endif | |
3339 | ||
3340 | /* lock,open owner id: | |
3341 | - * we currently use size 1 (u32) out of (NFS4_OPAQUE_LIMIT >> 2) | |
3342 | + * we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT >> 2) | |
3343 | */ | |
3344 | -#define owner_id_maxsz (1 + 1) | |
3345 | +#define open_owner_id_maxsz (1 + 4) | |
3346 | +#define lock_owner_id_maxsz (1 + 4) | |
3347 | #define compound_encode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2)) | |
3348 | #define compound_decode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2)) | |
3349 | #define op_encode_hdr_maxsz (1) | |
3350 | @@ -87,9 +88,11 @@ static int nfs4_stat_to_errno(int); | |
3351 | #define encode_getattr_maxsz (op_encode_hdr_maxsz + nfs4_fattr_bitmap_maxsz) | |
3352 | #define nfs4_name_maxsz (1 + ((3 + NFS4_MAXNAMLEN) >> 2)) | |
3353 | #define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2)) | |
3354 | +#define nfs4_owner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) | |
3355 | +#define nfs4_group_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) | |
3356 | /* This is based on getfattr, which uses the most attributes: */ | |
3357 | #define nfs4_fattr_value_maxsz (1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \ | |
3358 | - 3 + 3 + 3 + 2 * nfs4_name_maxsz)) | |
3359 | + 3 + 3 + 3 + nfs4_owner_maxsz + nfs4_group_maxsz)) | |
3360 | #define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \ | |
3361 | nfs4_fattr_value_maxsz) | |
3362 | #define decode_getattr_maxsz (op_decode_hdr_maxsz + nfs4_fattr_maxsz) | |
3363 | @@ -116,8 +119,27 @@ static int nfs4_stat_to_errno(int); | |
3364 | 3 + (NFS4_VERIFIER_SIZE >> 2)) | |
3365 | #define decode_setclientid_confirm_maxsz \ | |
3366 | (op_decode_hdr_maxsz) | |
3367 | -#define encode_lookup_maxsz (op_encode_hdr_maxsz + \ | |
3368 | - 1 + ((3 + NFS4_FHSIZE) >> 2)) | |
3369 | +#define encode_lookup_maxsz (op_encode_hdr_maxsz + nfs4_name_maxsz) | |
3370 | +#define decode_lookup_maxsz (op_decode_hdr_maxsz) | |
3371 | +#define encode_share_access_maxsz \ | |
3372 | + (2) | |
3373 | +#define encode_createmode_maxsz (1 + nfs4_fattr_maxsz) | |
3374 | +#define encode_opentype_maxsz (1 + encode_createmode_maxsz) | |
3375 | +#define encode_claim_null_maxsz (1 + nfs4_name_maxsz) | |
3376 | +#define encode_open_maxsz (op_encode_hdr_maxsz + \ | |
3377 | + 2 + encode_share_access_maxsz + 2 + \ | |
3378 | + open_owner_id_maxsz + \ | |
3379 | + encode_opentype_maxsz + \ | |
3380 | + encode_claim_null_maxsz) | |
3381 | +#define decode_ace_maxsz (3 + nfs4_owner_maxsz) | |
3382 | +#define decode_delegation_maxsz (1 + XDR_QUADLEN(NFS4_STATEID_SIZE) + 1 + \ | |
3383 | + decode_ace_maxsz) | |
3384 | +#define decode_change_info_maxsz (5) | |
3385 | +#define decode_open_maxsz (op_decode_hdr_maxsz + \ | |
3386 | + XDR_QUADLEN(NFS4_STATEID_SIZE) + \ | |
3387 | + decode_change_info_maxsz + 1 + \ | |
3388 | + nfs4_fattr_bitmap_maxsz + \ | |
3389 | + decode_delegation_maxsz) | |
3390 | #define encode_remove_maxsz (op_encode_hdr_maxsz + \ | |
3391 | nfs4_name_maxsz) | |
3392 | #define encode_rename_maxsz (op_encode_hdr_maxsz + \ | |
3393 | @@ -134,9 +156,15 @@ static int nfs4_stat_to_errno(int); | |
3394 | #define encode_create_maxsz (op_encode_hdr_maxsz + \ | |
3395 | 2 + nfs4_name_maxsz + \ | |
3396 | nfs4_fattr_maxsz) | |
3397 | -#define decode_create_maxsz (op_decode_hdr_maxsz + 8) | |
3398 | +#define decode_create_maxsz (op_decode_hdr_maxsz + \ | |
3399 | + decode_change_info_maxsz + \ | |
3400 | + nfs4_fattr_bitmap_maxsz) | |
3401 | #define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4) | |
3402 | #define decode_delegreturn_maxsz (op_decode_hdr_maxsz) | |
3403 | +#define encode_fs_locations_maxsz \ | |
3404 | + (encode_getattr_maxsz) | |
3405 | +#define decode_fs_locations_maxsz \ | |
3406 | + (0) | |
3407 | #define NFS4_enc_compound_sz (1024) /* XXX: large enough? */ | |
3408 | #define NFS4_dec_compound_sz (1024) /* XXX: large enough? */ | |
3409 | #define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \ | |
3410 | @@ -174,16 +202,21 @@ static int nfs4_stat_to_errno(int); | |
3411 | op_decode_hdr_maxsz + 2 + \ | |
3412 | decode_getattr_maxsz) | |
3413 | #define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \ | |
3414 | - encode_putfh_maxsz + \ | |
3415 | - op_encode_hdr_maxsz + \ | |
3416 | - 13 + 3 + 2 + 64 + \ | |
3417 | - encode_getattr_maxsz + \ | |
3418 | - encode_getfh_maxsz) | |
3419 | + encode_putfh_maxsz + \ | |
3420 | + encode_savefh_maxsz + \ | |
3421 | + encode_open_maxsz + \ | |
3422 | + encode_getfh_maxsz + \ | |
3423 | + encode_getattr_maxsz + \ | |
3424 | + encode_restorefh_maxsz + \ | |
3425 | + encode_getattr_maxsz) | |
3426 | #define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \ | |
3427 | - decode_putfh_maxsz + \ | |
3428 | - op_decode_hdr_maxsz + 4 + 5 + 2 + 3 + \ | |
3429 | - decode_getattr_maxsz + \ | |
3430 | - decode_getfh_maxsz) | |
3431 | + decode_putfh_maxsz + \ | |
3432 | + decode_savefh_maxsz + \ | |
3433 | + decode_open_maxsz + \ | |
3434 | + decode_getfh_maxsz + \ | |
3435 | + decode_getattr_maxsz + \ | |
3436 | + decode_restorefh_maxsz + \ | |
3437 | + decode_getattr_maxsz) | |
3438 | #define NFS4_enc_open_confirm_sz \ | |
3439 | (compound_encode_hdr_maxsz + \ | |
3440 | encode_putfh_maxsz + \ | |
3441 | @@ -193,12 +226,12 @@ static int nfs4_stat_to_errno(int); | |
3442 | op_decode_hdr_maxsz + 4) | |
3443 | #define NFS4_enc_open_noattr_sz (compound_encode_hdr_maxsz + \ | |
3444 | encode_putfh_maxsz + \ | |
3445 | - op_encode_hdr_maxsz + \ | |
3446 | - 11) | |
3447 | + encode_open_maxsz + \ | |
3448 | + encode_getattr_maxsz) | |
3449 | #define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \ | |
3450 | decode_putfh_maxsz + \ | |
3451 | - op_decode_hdr_maxsz + \ | |
3452 | - 4 + 5 + 2 + 3) | |
3453 | + decode_open_maxsz + \ | |
3454 | + decode_getattr_maxsz) | |
3455 | #define NFS4_enc_open_downgrade_sz \ | |
3456 | (compound_encode_hdr_maxsz + \ | |
3457 | encode_putfh_maxsz + \ | |
3458 | @@ -256,19 +289,19 @@ static int nfs4_stat_to_errno(int); | |
3459 | op_encode_hdr_maxsz + \ | |
3460 | 1 + 1 + 2 + 2 + \ | |
3461 | 1 + 4 + 1 + 2 + \ | |
3462 | - owner_id_maxsz) | |
3463 | + lock_owner_id_maxsz) | |
3464 | #define NFS4_dec_lock_sz (compound_decode_hdr_maxsz + \ | |
3465 | decode_putfh_maxsz + \ | |
3466 | decode_getattr_maxsz + \ | |
3467 | op_decode_hdr_maxsz + \ | |
3468 | 2 + 2 + 1 + 2 + \ | |
3469 | - owner_id_maxsz) | |
3470 | + lock_owner_id_maxsz) | |
3471 | #define NFS4_enc_lockt_sz (compound_encode_hdr_maxsz + \ | |
3472 | encode_putfh_maxsz + \ | |
3473 | encode_getattr_maxsz + \ | |
3474 | op_encode_hdr_maxsz + \ | |
3475 | 1 + 2 + 2 + 2 + \ | |
3476 | - owner_id_maxsz) | |
3477 | + lock_owner_id_maxsz) | |
3478 | #define NFS4_dec_lockt_sz (NFS4_dec_lock_sz) | |
3479 | #define NFS4_enc_locku_sz (compound_encode_hdr_maxsz + \ | |
3480 | encode_putfh_maxsz + \ | |
3481 | @@ -298,7 +331,7 @@ static int nfs4_stat_to_errno(int); | |
3482 | encode_getfh_maxsz) | |
3483 | #define NFS4_dec_lookup_sz (compound_decode_hdr_maxsz + \ | |
3484 | decode_putfh_maxsz + \ | |
3485 | - op_decode_hdr_maxsz + \ | |
3486 | + decode_lookup_maxsz + \ | |
3487 | decode_getattr_maxsz + \ | |
3488 | decode_getfh_maxsz) | |
3489 | #define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \ | |
3490 | @@ -417,12 +450,13 @@ static int nfs4_stat_to_errno(int); | |
3491 | #define NFS4_enc_fs_locations_sz \ | |
3492 | (compound_encode_hdr_maxsz + \ | |
3493 | encode_putfh_maxsz + \ | |
3494 | - encode_getattr_maxsz) | |
3495 | + encode_lookup_maxsz + \ | |
3496 | + encode_fs_locations_maxsz) | |
3497 | #define NFS4_dec_fs_locations_sz \ | |
3498 | (compound_decode_hdr_maxsz + \ | |
3499 | decode_putfh_maxsz + \ | |
3500 | - op_decode_hdr_maxsz + \ | |
3501 | - nfs4_fattr_bitmap_maxsz) | |
3502 | + decode_lookup_maxsz + \ | |
3503 | + decode_fs_locations_maxsz) | |
3504 | ||
3505 | static struct { | |
3506 | unsigned int mode; | |
3507 | @@ -793,13 +827,14 @@ static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args) | |
3508 | WRITE64(nfs4_lock_length(args->fl)); | |
3509 | WRITE32(args->new_lock_owner); | |
3510 | if (args->new_lock_owner){ | |
3511 | - RESERVE_SPACE(4+NFS4_STATEID_SIZE+20); | |
3512 | + RESERVE_SPACE(4+NFS4_STATEID_SIZE+32); | |
3513 | WRITE32(args->open_seqid->sequence->counter); | |
3514 | WRITEMEM(args->open_stateid->data, NFS4_STATEID_SIZE); | |
3515 | WRITE32(args->lock_seqid->sequence->counter); | |
3516 | WRITE64(args->lock_owner.clientid); | |
3517 | - WRITE32(4); | |
3518 | - WRITE32(args->lock_owner.id); | |
3519 | + WRITE32(16); | |
3520 | + WRITEMEM("lock id:", 8); | |
3521 | + WRITE64(args->lock_owner.id); | |
3522 | } | |
3523 | else { | |
3524 | RESERVE_SPACE(NFS4_STATEID_SIZE+4); | |
3525 | @@ -814,14 +849,15 @@ static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *arg | |
3526 | { | |
3527 | __be32 *p; | |
3528 | ||
3529 | - RESERVE_SPACE(40); | |
3530 | + RESERVE_SPACE(52); | |
3531 | WRITE32(OP_LOCKT); | |
3532 | WRITE32(nfs4_lock_type(args->fl, 0)); | |
3533 | WRITE64(args->fl->fl_start); | |
3534 | WRITE64(nfs4_lock_length(args->fl)); | |
3535 | WRITE64(args->lock_owner.clientid); | |
3536 | - WRITE32(4); | |
3537 | - WRITE32(args->lock_owner.id); | |
3538 | + WRITE32(16); | |
3539 | + WRITEMEM("lock id:", 8); | |
3540 | + WRITE64(args->lock_owner.id); | |
3541 | ||
3542 | return 0; | |
3543 | } | |
3544 | @@ -886,10 +922,11 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena | |
3545 | WRITE32(OP_OPEN); | |
3546 | WRITE32(arg->seqid->sequence->counter); | |
3547 | encode_share_access(xdr, arg->open_flags); | |
3548 | - RESERVE_SPACE(16); | |
3549 | + RESERVE_SPACE(28); | |
3550 | WRITE64(arg->clientid); | |
3551 | - WRITE32(4); | |
3552 | - WRITE32(arg->id); | |
3553 | + WRITE32(16); | |
3554 | + WRITEMEM("open id:", 8); | |
3555 | + WRITE64(arg->id); | |
3556 | } | |
3557 | ||
3558 | static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg) | |
3559 | @@ -1071,7 +1108,7 @@ static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args) | |
3560 | ||
3561 | static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req) | |
3562 | { | |
3563 | - struct rpc_auth *auth = req->rq_task->tk_auth; | |
3564 | + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | |
3565 | uint32_t attrs[2] = { | |
3566 | FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID, | |
3567 | FATTR4_WORD1_MOUNTED_ON_FILEID, | |
3568 | @@ -1117,7 +1154,7 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |
3569 | ||
3570 | static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req) | |
3571 | { | |
3572 | - struct rpc_auth *auth = req->rq_task->tk_auth; | |
3573 | + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | |
3574 | unsigned int replen; | |
3575 | __be32 *p; | |
3576 | ||
3577 | @@ -1735,7 +1772,7 @@ out: | |
3578 | */ | |
3579 | static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) | |
3580 | { | |
3581 | - struct rpc_auth *auth = req->rq_task->tk_auth; | |
3582 | + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | |
3583 | struct xdr_stream xdr; | |
3584 | struct compound_hdr hdr = { | |
3585 | .nops = 2, | |
3586 | @@ -1795,7 +1832,7 @@ nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p, | |
3587 | struct nfs_getaclargs *args) | |
3588 | { | |
3589 | struct xdr_stream xdr; | |
3590 | - struct rpc_auth *auth = req->rq_task->tk_auth; | |
3591 | + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | |
3592 | struct compound_hdr hdr = { | |
3593 | .nops = 2, | |
3594 | }; | |
3595 | @@ -2030,7 +2067,7 @@ static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs | |
3596 | struct compound_hdr hdr = { | |
3597 | .nops = 3, | |
3598 | }; | |
3599 | - struct rpc_auth *auth = req->rq_task->tk_auth; | |
3600 | + struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | |
3601 | int replen; | |
3602 | int status; | |
3603 | ||
3604 | @@ -3269,7 +3306,7 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res) | |
3605 | static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) | |
3606 | { | |
3607 | __be32 *p; | |
3608 | - uint32_t bmlen; | |
3609 | + uint32_t savewords, bmlen, i; | |
3610 | int status; | |
3611 | ||
3612 | status = decode_op_hdr(xdr, OP_OPEN); | |
3613 | @@ -3287,7 +3324,12 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res) | |
3614 | goto xdr_error; | |
3615 | ||
3616 | READ_BUF(bmlen << 2); | |
3617 | - p += bmlen; | |
3618 | + savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE); | |
3619 | + for (i = 0; i < savewords; ++i) | |
3620 | + READ32(res->attrset[i]); | |
3621 | + for (; i < NFS4_BITMAP_SIZE; i++) | |
3622 | + res->attrset[i] = 0; | |
3623 | + | |
3624 | return decode_delegation(xdr, res); | |
3625 | xdr_error: | |
3626 | dprintk("%s: Bitmap too large! Length = %u\n", __FUNCTION__, bmlen); | |
3627 | diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c | |
3628 | index 49d1008..3490322 100644 | |
3629 | --- a/fs/nfs/nfsroot.c | |
3630 | +++ b/fs/nfs/nfsroot.c | |
3631 | @@ -428,7 +428,7 @@ static int __init root_nfs_getport(int program, int version, int proto) | |
3632 | printk(KERN_NOTICE "Looking up port of RPC %d/%d on %u.%u.%u.%u\n", | |
3633 | program, version, NIPQUAD(servaddr)); | |
3634 | set_sockaddr(&sin, servaddr, 0); | |
3635 | - return rpcb_getport_external(&sin, program, version, proto); | |
3636 | + return rpcb_getport_sync(&sin, program, version, proto); | |
3637 | } | |
3638 | ||
3639 | ||
3640 | @@ -496,7 +496,8 @@ static int __init root_nfs_get_handle(void) | |
3641 | NFS_MNT3_VERSION : NFS_MNT_VERSION; | |
3642 | ||
3643 | set_sockaddr(&sin, servaddr, htons(mount_port)); | |
3644 | - status = nfsroot_mount(&sin, nfs_path, &fh, version, protocol); | |
3645 | + status = nfs_mount((struct sockaddr *) &sin, sizeof(sin), NULL, | |
3646 | + nfs_path, version, protocol, &fh); | |
3647 | if (status < 0) | |
3648 | printk(KERN_ERR "Root-NFS: Server returned error %d " | |
3649 | "while mounting %s\n", status, nfs_path); | |
3650 | diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c | |
3651 | index c5bb51a..f56dae5 100644 | |
3652 | --- a/fs/nfs/pagelist.c | |
3653 | +++ b/fs/nfs/pagelist.c | |
3654 | @@ -85,9 +85,8 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode, | |
3655 | req->wb_offset = offset; | |
3656 | req->wb_pgbase = offset; | |
3657 | req->wb_bytes = count; | |
3658 | - atomic_set(&req->wb_count, 1); | |
3659 | req->wb_context = get_nfs_open_context(ctx); | |
3660 | - | |
3661 | + kref_init(&req->wb_kref); | |
3662 | return req; | |
3663 | } | |
3664 | ||
3665 | @@ -109,30 +108,31 @@ void nfs_unlock_request(struct nfs_page *req) | |
3666 | } | |
3667 | ||
3668 | /** | |
3669 | - * nfs_set_page_writeback_locked - Lock a request for writeback | |
3670 | + * nfs_set_page_tag_locked - Tag a request as locked | |
3671 | * @req: | |
3672 | */ | |
3673 | -int nfs_set_page_writeback_locked(struct nfs_page *req) | |
3674 | +static int nfs_set_page_tag_locked(struct nfs_page *req) | |
3675 | { | |
3676 | - struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); | |
3677 | + struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode); | |
3678 | ||
3679 | if (!nfs_lock_request(req)) | |
3680 | return 0; | |
3681 | - radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); | |
3682 | + radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | |
3683 | return 1; | |
3684 | } | |
3685 | ||
3686 | /** | |
3687 | - * nfs_clear_page_writeback - Unlock request and wake up sleepers | |
3688 | + * nfs_clear_page_tag_locked - Clear request tag and wake up sleepers | |
3689 | */ | |
3690 | -void nfs_clear_page_writeback(struct nfs_page *req) | |
3691 | +void nfs_clear_page_tag_locked(struct nfs_page *req) | |
3692 | { | |
3693 | - struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); | |
3694 | + struct inode *inode = req->wb_context->path.dentry->d_inode; | |
3695 | + struct nfs_inode *nfsi = NFS_I(inode); | |
3696 | ||
3697 | if (req->wb_page != NULL) { | |
3698 | - spin_lock(&nfsi->req_lock); | |
3699 | - radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); | |
3700 | - spin_unlock(&nfsi->req_lock); | |
3701 | + spin_lock(&inode->i_lock); | |
3702 | + radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | |
3703 | + spin_unlock(&inode->i_lock); | |
3704 | } | |
3705 | nfs_unlock_request(req); | |
3706 | } | |
3707 | @@ -160,11 +160,9 @@ void nfs_clear_request(struct nfs_page *req) | |
3708 | * | |
3709 | * Note: Should never be called with the spinlock held! | |
3710 | */ | |
3711 | -void | |
3712 | -nfs_release_request(struct nfs_page *req) | |
3713 | +static void nfs_free_request(struct kref *kref) | |
3714 | { | |
3715 | - if (!atomic_dec_and_test(&req->wb_count)) | |
3716 | - return; | |
3717 | + struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref); | |
3718 | ||
3719 | /* Release struct file or cached credential */ | |
3720 | nfs_clear_request(req); | |
3721 | @@ -172,6 +170,11 @@ nfs_release_request(struct nfs_page *req) | |
3722 | nfs_page_free(req); | |
3723 | } | |
3724 | ||
3725 | +void nfs_release_request(struct nfs_page *req) | |
3726 | +{ | |
3727 | + kref_put(&req->wb_kref, nfs_free_request); | |
3728 | +} | |
3729 | + | |
3730 | static int nfs_wait_bit_interruptible(void *word) | |
3731 | { | |
3732 | int ret = 0; | |
3733 | @@ -193,7 +196,7 @@ static int nfs_wait_bit_interruptible(void *word) | |
3734 | int | |
3735 | nfs_wait_on_request(struct nfs_page *req) | |
3736 | { | |
3737 | - struct rpc_clnt *clnt = NFS_CLIENT(req->wb_context->dentry->d_inode); | |
3738 | + struct rpc_clnt *clnt = NFS_CLIENT(req->wb_context->path.dentry->d_inode); | |
3739 | sigset_t oldmask; | |
3740 | int ret = 0; | |
3741 | ||
3742 | @@ -379,20 +382,20 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index) | |
3743 | /** | |
3744 | * nfs_scan_list - Scan a list for matching requests | |
3745 | * @nfsi: NFS inode | |
3746 | - * @head: One of the NFS inode request lists | |
3747 | * @dst: Destination list | |
3748 | * @idx_start: lower bound of page->index to scan | |
3749 | * @npages: idx_start + npages sets the upper bound to scan. | |
3750 | + * @tag: tag to scan for | |
3751 | * | |
3752 | * Moves elements from one of the inode request lists. | |
3753 | * If the number of requests is set to 0, the entire address_space | |
3754 | * starting at index idx_start, is scanned. | |
3755 | * The requests are *not* checked to ensure that they form a contiguous set. | |
3756 | - * You must be holding the inode's req_lock when calling this function | |
3757 | + * You must be holding the inode's i_lock when calling this function | |
3758 | */ | |
3759 | -int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, | |
3760 | +int nfs_scan_list(struct nfs_inode *nfsi, | |
3761 | struct list_head *dst, pgoff_t idx_start, | |
3762 | - unsigned int npages) | |
3763 | + unsigned int npages, int tag) | |
3764 | { | |
3765 | struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES]; | |
3766 | struct nfs_page *req; | |
3767 | @@ -407,9 +410,9 @@ int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, | |
3768 | idx_end = idx_start + npages - 1; | |
3769 | ||
3770 | for (;;) { | |
3771 | - found = radix_tree_gang_lookup(&nfsi->nfs_page_tree, | |
3772 | + found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, | |
3773 | (void **)&pgvec[0], idx_start, | |
3774 | - NFS_SCAN_MAXENTRIES); | |
3775 | + NFS_SCAN_MAXENTRIES, tag); | |
3776 | if (found <= 0) | |
3777 | break; | |
3778 | for (i = 0; i < found; i++) { | |
3779 | @@ -417,15 +420,18 @@ int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, | |
3780 | if (req->wb_index > idx_end) | |
3781 | goto out; | |
3782 | idx_start = req->wb_index + 1; | |
3783 | - if (req->wb_list_head != head) | |
3784 | - continue; | |
3785 | - if (nfs_set_page_writeback_locked(req)) { | |
3786 | + if (nfs_set_page_tag_locked(req)) { | |
3787 | nfs_list_remove_request(req); | |
3788 | + radix_tree_tag_clear(&nfsi->nfs_page_tree, | |
3789 | + req->wb_index, tag); | |
3790 | nfs_list_add_request(req, dst); | |
3791 | res++; | |
3792 | + if (res == INT_MAX) | |
3793 | + goto out; | |
3794 | } | |
3795 | } | |
3796 | - | |
3797 | + /* for latency reduction */ | |
3798 | + cond_resched_lock(&nfsi->vfs_inode.i_lock); | |
3799 | } | |
3800 | out: | |
3801 | return res; | |
3802 | diff --git a/fs/nfs/read.c b/fs/nfs/read.c | |
3803 | index 7bd7cb9..6ae2e58 100644 | |
3804 | --- a/fs/nfs/read.c | |
3805 | +++ b/fs/nfs/read.c | |
3806 | @@ -145,8 +145,8 @@ static void nfs_readpage_release(struct nfs_page *req) | |
3807 | unlock_page(req->wb_page); | |
3808 | ||
3809 | dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", | |
3810 | - req->wb_context->dentry->d_inode->i_sb->s_id, | |
3811 | - (long long)NFS_FILEID(req->wb_context->dentry->d_inode), | |
3812 | + req->wb_context->path.dentry->d_inode->i_sb->s_id, | |
3813 | + (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), | |
3814 | req->wb_bytes, | |
3815 | (long long)req_offset(req)); | |
3816 | nfs_clear_request(req); | |
3817 | @@ -164,7 +164,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |
3818 | int flags; | |
3819 | ||
3820 | data->req = req; | |
3821 | - data->inode = inode = req->wb_context->dentry->d_inode; | |
3822 | + data->inode = inode = req->wb_context->path.dentry->d_inode; | |
3823 | data->cred = req->wb_context->cred; | |
3824 | ||
3825 | data->args.fh = NFS_FH(inode); | |
3826 | @@ -483,17 +483,19 @@ int nfs_readpage(struct file *file, struct page *page) | |
3827 | */ | |
3828 | error = nfs_wb_page(inode, page); | |
3829 | if (error) | |
3830 | - goto out_error; | |
3831 | + goto out_unlock; | |
3832 | + if (PageUptodate(page)) | |
3833 | + goto out_unlock; | |
3834 | ||
3835 | error = -ESTALE; | |
3836 | if (NFS_STALE(inode)) | |
3837 | - goto out_error; | |
3838 | + goto out_unlock; | |
3839 | ||
3840 | if (file == NULL) { | |
3841 | error = -EBADF; | |
3842 | ctx = nfs_find_open_context(inode, NULL, FMODE_READ); | |
3843 | if (ctx == NULL) | |
3844 | - goto out_error; | |
3845 | + goto out_unlock; | |
3846 | } else | |
3847 | ctx = get_nfs_open_context((struct nfs_open_context *) | |
3848 | file->private_data); | |
3849 | @@ -502,8 +504,7 @@ int nfs_readpage(struct file *file, struct page *page) | |
3850 | ||
3851 | put_nfs_open_context(ctx); | |
3852 | return error; | |
3853 | - | |
3854 | -out_error: | |
3855 | +out_unlock: | |
3856 | unlock_page(page); | |
3857 | return error; | |
3858 | } | |
3859 | @@ -520,21 +521,32 @@ readpage_async_filler(void *data, struct page *page) | |
3860 | struct inode *inode = page->mapping->host; | |
3861 | struct nfs_page *new; | |
3862 | unsigned int len; | |
3863 | + int error; | |
3864 | + | |
3865 | + error = nfs_wb_page(inode, page); | |
3866 | + if (error) | |
3867 | + goto out_unlock; | |
3868 | + if (PageUptodate(page)) | |
3869 | + goto out_unlock; | |
3870 | ||
3871 | - nfs_wb_page(inode, page); | |
3872 | len = nfs_page_length(page); | |
3873 | if (len == 0) | |
3874 | return nfs_return_empty_page(page); | |
3875 | + | |
3876 | new = nfs_create_request(desc->ctx, inode, page, 0, len); | |
3877 | - if (IS_ERR(new)) { | |
3878 | - SetPageError(page); | |
3879 | - unlock_page(page); | |
3880 | - return PTR_ERR(new); | |
3881 | - } | |
3882 | + if (IS_ERR(new)) | |
3883 | + goto out_error; | |
3884 | + | |
3885 | if (len < PAGE_CACHE_SIZE) | |
3886 | zero_user_page(page, len, PAGE_CACHE_SIZE - len, KM_USER0); | |
3887 | nfs_pageio_add_request(desc->pgio, new); | |
3888 | return 0; | |
3889 | +out_error: | |
3890 | + error = PTR_ERR(new); | |
3891 | + SetPageError(page); | |
3892 | +out_unlock: | |
3893 | + unlock_page(page); | |
3894 | + return error; | |
3895 | } | |
3896 | ||
3897 | int nfs_readpages(struct file *filp, struct address_space *mapping, | |
3898 | diff --git a/fs/nfs/super.c b/fs/nfs/super.c | |
3899 | index ca20d3c..a2b1af8 100644 | |
3900 | --- a/fs/nfs/super.c | |
3901 | +++ b/fs/nfs/super.c | |
3902 | @@ -45,6 +45,7 @@ | |
3903 | #include <linux/inet.h> | |
3904 | #include <linux/nfs_xdr.h> | |
3905 | #include <linux/magic.h> | |
3906 | +#include <linux/parser.h> | |
3907 | ||
3908 | #include <asm/system.h> | |
3909 | #include <asm/uaccess.h> | |
3910 | @@ -57,6 +58,167 @@ | |
3911 | ||
3912 | #define NFSDBG_FACILITY NFSDBG_VFS | |
3913 | ||
3914 | + | |
3915 | +struct nfs_parsed_mount_data { | |
3916 | + int flags; | |
3917 | + int rsize, wsize; | |
3918 | + int timeo, retrans; | |
3919 | + int acregmin, acregmax, | |
3920 | + acdirmin, acdirmax; | |
3921 | + int namlen; | |
3922 | + unsigned int bsize; | |
3923 | + unsigned int auth_flavor_len; | |
3924 | + rpc_authflavor_t auth_flavors[1]; | |
3925 | + char *client_address; | |
3926 | + | |
3927 | + struct { | |
3928 | + struct sockaddr_in address; | |
3929 | + unsigned int program; | |
3930 | + unsigned int version; | |
3931 | + unsigned short port; | |
3932 | + int protocol; | |
3933 | + } mount_server; | |
3934 | + | |
3935 | + struct { | |
3936 | + struct sockaddr_in address; | |
3937 | + char *hostname; | |
3938 | + char *export_path; | |
3939 | + unsigned int program; | |
3940 | + int protocol; | |
3941 | + } nfs_server; | |
3942 | +}; | |
3943 | + | |
3944 | +enum { | |
3945 | + /* Mount options that take no arguments */ | |
3946 | + Opt_soft, Opt_hard, | |
3947 | + Opt_intr, Opt_nointr, | |
3948 | + Opt_posix, Opt_noposix, | |
3949 | + Opt_cto, Opt_nocto, | |
3950 | + Opt_ac, Opt_noac, | |
3951 | + Opt_lock, Opt_nolock, | |
3952 | + Opt_v2, Opt_v3, | |
3953 | + Opt_udp, Opt_tcp, | |
3954 | + Opt_acl, Opt_noacl, | |
3955 | + Opt_rdirplus, Opt_nordirplus, | |
3956 | + Opt_sharecache, Opt_nosharecache, | |
3957 | + | |
3958 | + /* Mount options that take integer arguments */ | |
3959 | + Opt_port, | |
3960 | + Opt_rsize, Opt_wsize, Opt_bsize, | |
3961 | + Opt_timeo, Opt_retrans, | |
3962 | + Opt_acregmin, Opt_acregmax, | |
3963 | + Opt_acdirmin, Opt_acdirmax, | |
3964 | + Opt_actimeo, | |
3965 | + Opt_namelen, | |
3966 | + Opt_mountport, | |
3967 | + Opt_mountprog, Opt_mountvers, | |
3968 | + Opt_nfsprog, Opt_nfsvers, | |
3969 | + | |
3970 | + /* Mount options that take string arguments */ | |
3971 | + Opt_sec, Opt_proto, Opt_mountproto, | |
3972 | + Opt_addr, Opt_mounthost, Opt_clientaddr, | |
3973 | + | |
3974 | + /* Mount options that are ignored */ | |
3975 | + Opt_userspace, Opt_deprecated, | |
3976 | + | |
3977 | + Opt_err | |
3978 | +}; | |
3979 | + | |
3980 | +static match_table_t nfs_mount_option_tokens = { | |
3981 | + { Opt_userspace, "bg" }, | |
3982 | + { Opt_userspace, "fg" }, | |
3983 | + { Opt_soft, "soft" }, | |
3984 | + { Opt_hard, "hard" }, | |
3985 | + { Opt_intr, "intr" }, | |
3986 | + { Opt_nointr, "nointr" }, | |
3987 | + { Opt_posix, "posix" }, | |
3988 | + { Opt_noposix, "noposix" }, | |
3989 | + { Opt_cto, "cto" }, | |
3990 | + { Opt_nocto, "nocto" }, | |
3991 | + { Opt_ac, "ac" }, | |
3992 | + { Opt_noac, "noac" }, | |
3993 | + { Opt_lock, "lock" }, | |
3994 | + { Opt_nolock, "nolock" }, | |
3995 | + { Opt_v2, "v2" }, | |
3996 | + { Opt_v3, "v3" }, | |
3997 | + { Opt_udp, "udp" }, | |
3998 | + { Opt_tcp, "tcp" }, | |
3999 | + { Opt_acl, "acl" }, | |
4000 | + { Opt_noacl, "noacl" }, | |
4001 | + { Opt_rdirplus, "rdirplus" }, | |
4002 | + { Opt_nordirplus, "nordirplus" }, | |
4003 | + { Opt_sharecache, "sharecache" }, | |
4004 | + { Opt_nosharecache, "nosharecache" }, | |
4005 | + | |
4006 | + { Opt_port, "port=%u" }, | |
4007 | + { Opt_rsize, "rsize=%u" }, | |
4008 | + { Opt_wsize, "wsize=%u" }, | |
4009 | + { Opt_bsize, "bsize=%u" }, | |
4010 | + { Opt_timeo, "timeo=%u" }, | |
4011 | + { Opt_retrans, "retrans=%u" }, | |
4012 | + { Opt_acregmin, "acregmin=%u" }, | |
4013 | + { Opt_acregmax, "acregmax=%u" }, | |
4014 | + { Opt_acdirmin, "acdirmin=%u" }, | |
4015 | + { Opt_acdirmax, "acdirmax=%u" }, | |
4016 | + { Opt_actimeo, "actimeo=%u" }, | |
4017 | + { Opt_userspace, "retry=%u" }, | |
4018 | + { Opt_namelen, "namlen=%u" }, | |
4019 | + { Opt_mountport, "mountport=%u" }, | |
4020 | + { Opt_mountprog, "mountprog=%u" }, | |
4021 | + { Opt_mountvers, "mountvers=%u" }, | |
4022 | + { Opt_nfsprog, "nfsprog=%u" }, | |
4023 | + { Opt_nfsvers, "nfsvers=%u" }, | |
4024 | + { Opt_nfsvers, "vers=%u" }, | |
4025 | + | |
4026 | + { Opt_sec, "sec=%s" }, | |
4027 | + { Opt_proto, "proto=%s" }, | |
4028 | + { Opt_mountproto, "mountproto=%s" }, | |
4029 | + { Opt_addr, "addr=%s" }, | |
4030 | + { Opt_clientaddr, "clientaddr=%s" }, | |
4031 | + { Opt_mounthost, "mounthost=%s" }, | |
4032 | + | |
4033 | + { Opt_err, NULL } | |
4034 | +}; | |
4035 | + | |
4036 | +enum { | |
4037 | + Opt_xprt_udp, Opt_xprt_tcp, | |
4038 | + | |
4039 | + Opt_xprt_err | |
4040 | +}; | |
4041 | + | |
4042 | +static match_table_t nfs_xprt_protocol_tokens = { | |
4043 | + { Opt_xprt_udp, "udp" }, | |
4044 | + { Opt_xprt_tcp, "tcp" }, | |
4045 | + | |
4046 | + { Opt_xprt_err, NULL } | |
4047 | +}; | |
4048 | + | |
4049 | +enum { | |
4050 | + Opt_sec_none, Opt_sec_sys, | |
4051 | + Opt_sec_krb5, Opt_sec_krb5i, Opt_sec_krb5p, | |
4052 | + Opt_sec_lkey, Opt_sec_lkeyi, Opt_sec_lkeyp, | |
4053 | + Opt_sec_spkm, Opt_sec_spkmi, Opt_sec_spkmp, | |
4054 | + | |
4055 | + Opt_sec_err | |
4056 | +}; | |
4057 | + | |
4058 | +static match_table_t nfs_secflavor_tokens = { | |
4059 | + { Opt_sec_none, "none" }, | |
4060 | + { Opt_sec_none, "null" }, | |
4061 | + { Opt_sec_sys, "sys" }, | |
4062 | + | |
4063 | + { Opt_sec_krb5, "krb5" }, | |
4064 | + { Opt_sec_krb5i, "krb5i" }, | |
4065 | + { Opt_sec_krb5p, "krb5p" }, | |
4066 | + | |
4067 | + { Opt_sec_lkey, "lkey" }, | |
4068 | + { Opt_sec_lkeyi, "lkeyi" }, | |
4069 | + { Opt_sec_lkeyp, "lkeyp" }, | |
4070 | + | |
4071 | + { Opt_sec_err, NULL } | |
4072 | +}; | |
4073 | + | |
4074 | + | |
4075 | static void nfs_umount_begin(struct vfsmount *, int); | |
4076 | static int nfs_statfs(struct dentry *, struct kstatfs *); | |
4077 | static int nfs_show_options(struct seq_file *, struct vfsmount *); | |
4078 | @@ -263,11 +425,11 @@ static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour) | |
4079 | { RPC_AUTH_GSS_SPKM, "spkm" }, | |
4080 | { RPC_AUTH_GSS_SPKMI, "spkmi" }, | |
4081 | { RPC_AUTH_GSS_SPKMP, "spkmp" }, | |
4082 | - { -1, "unknown" } | |
4083 | + { UINT_MAX, "unknown" } | |
4084 | }; | |
4085 | int i; | |
4086 | ||
4087 | - for (i=0; sec_flavours[i].flavour != -1; i++) { | |
4088 | + for (i = 0; sec_flavours[i].flavour != UINT_MAX; i++) { | |
4089 | if (sec_flavours[i].flavour == flavour) | |
4090 | break; | |
4091 | } | |
4092 | @@ -291,6 +453,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |
4093 | { NFS_MOUNT_NONLM, ",nolock", "" }, | |
4094 | { NFS_MOUNT_NOACL, ",noacl", "" }, | |
4095 | { NFS_MOUNT_NORDIRPLUS, ",nordirplus", "" }, | |
4096 | + { NFS_MOUNT_UNSHARED, ",nosharecache", ""}, | |
4097 | { 0, NULL, NULL } | |
4098 | }; | |
4099 | const struct proc_nfs_info *nfs_infop; | |
4100 | @@ -430,87 +593,641 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt) | |
4101 | */ | |
4102 | static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags) | |
4103 | { | |
4104 | + struct nfs_server *server = NFS_SB(vfsmnt->mnt_sb); | |
4105 | + struct rpc_clnt *rpc; | |
4106 | + | |
4107 | shrink_submounts(vfsmnt, &nfs_automount_list); | |
4108 | + | |
4109 | + if (!(flags & MNT_FORCE)) | |
4110 | + return; | |
4111 | + /* -EIO all pending I/O */ | |
4112 | + rpc = server->client_acl; | |
4113 | + if (!IS_ERR(rpc)) | |
4114 | + rpc_killall_tasks(rpc); | |
4115 | + rpc = server->client; | |
4116 | + if (!IS_ERR(rpc)) | |
4117 | + rpc_killall_tasks(rpc); | |
4118 | } | |
4119 | ||
4120 | /* | |
4121 | - * Validate the NFS2/NFS3 mount data | |
4122 | - * - fills in the mount root filehandle | |
4123 | + * Sanity-check a server address provided by the mount command | |
4124 | */ | |
4125 | -static int nfs_validate_mount_data(struct nfs_mount_data *data, | |
4126 | - struct nfs_fh *mntfh) | |
4127 | +static int nfs_verify_server_address(struct sockaddr *addr) | |
4128 | { | |
4129 | - if (data == NULL) { | |
4130 | - dprintk("%s: missing data argument\n", __FUNCTION__); | |
4131 | - return -EINVAL; | |
4132 | + switch (addr->sa_family) { | |
4133 | + case AF_INET: { | |
4134 | + struct sockaddr_in *sa = (struct sockaddr_in *) addr; | |
4135 | + if (sa->sin_addr.s_addr != INADDR_ANY) | |
4136 | + return 1; | |
4137 | + break; | |
4138 | + } | |
4139 | } | |
4140 | ||
4141 | - if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) { | |
4142 | - dprintk("%s: bad mount version\n", __FUNCTION__); | |
4143 | - return -EINVAL; | |
4144 | + return 0; | |
4145 | +} | |
4146 | + | |
4147 | +/* | |
4148 | + * Error-check and convert a string of mount options from user space into | |
4149 | + * a data structure | |
4150 | + */ | |
4151 | +static int nfs_parse_mount_options(char *raw, | |
4152 | + struct nfs_parsed_mount_data *mnt) | |
4153 | +{ | |
4154 | + char *p, *string; | |
4155 | + | |
4156 | + if (!raw) { | |
4157 | + dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); | |
4158 | + return 1; | |
4159 | } | |
4160 | + dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw); | |
4161 | ||
4162 | - switch (data->version) { | |
4163 | - case 1: | |
4164 | - data->namlen = 0; | |
4165 | - case 2: | |
4166 | - data->bsize = 0; | |
4167 | - case 3: | |
4168 | - if (data->flags & NFS_MOUNT_VER3) { | |
4169 | - dprintk("%s: mount structure version %d does not support NFSv3\n", | |
4170 | - __FUNCTION__, | |
4171 | - data->version); | |
4172 | - return -EINVAL; | |
4173 | + while ((p = strsep(&raw, ",")) != NULL) { | |
4174 | + substring_t args[MAX_OPT_ARGS]; | |
4175 | + int option, token; | |
4176 | + | |
4177 | + if (!*p) | |
4178 | + continue; | |
4179 | + | |
4180 | + dfprintk(MOUNT, "NFS: parsing nfs mount option '%s'\n", p); | |
4181 | + | |
4182 | + token = match_token(p, nfs_mount_option_tokens, args); | |
4183 | + switch (token) { | |
4184 | + case Opt_soft: | |
4185 | + mnt->flags |= NFS_MOUNT_SOFT; | |
4186 | + break; | |
4187 | + case Opt_hard: | |
4188 | + mnt->flags &= ~NFS_MOUNT_SOFT; | |
4189 | + break; | |
4190 | + case Opt_intr: | |
4191 | + mnt->flags |= NFS_MOUNT_INTR; | |
4192 | + break; | |
4193 | + case Opt_nointr: | |
4194 | + mnt->flags &= ~NFS_MOUNT_INTR; | |
4195 | + break; | |
4196 | + case Opt_posix: | |
4197 | + mnt->flags |= NFS_MOUNT_POSIX; | |
4198 | + break; | |
4199 | + case Opt_noposix: | |
4200 | + mnt->flags &= ~NFS_MOUNT_POSIX; | |
4201 | + break; | |
4202 | + case Opt_cto: | |
4203 | + mnt->flags &= ~NFS_MOUNT_NOCTO; | |
4204 | + break; | |
4205 | + case Opt_nocto: | |
4206 | + mnt->flags |= NFS_MOUNT_NOCTO; | |
4207 | + break; | |
4208 | + case Opt_ac: | |
4209 | + mnt->flags &= ~NFS_MOUNT_NOAC; | |
4210 | + break; | |
4211 | + case Opt_noac: | |
4212 | + mnt->flags |= NFS_MOUNT_NOAC; | |
4213 | + break; | |
4214 | + case Opt_lock: | |
4215 | + mnt->flags &= ~NFS_MOUNT_NONLM; | |
4216 | + break; | |
4217 | + case Opt_nolock: | |
4218 | + mnt->flags |= NFS_MOUNT_NONLM; | |
4219 | + break; | |
4220 | + case Opt_v2: | |
4221 | + mnt->flags &= ~NFS_MOUNT_VER3; | |
4222 | + break; | |
4223 | + case Opt_v3: | |
4224 | + mnt->flags |= NFS_MOUNT_VER3; | |
4225 | + break; | |
4226 | + case Opt_udp: | |
4227 | + mnt->flags &= ~NFS_MOUNT_TCP; | |
4228 | + mnt->nfs_server.protocol = IPPROTO_UDP; | |
4229 | + mnt->timeo = 7; | |
4230 | + mnt->retrans = 5; | |
4231 | + break; | |
4232 | + case Opt_tcp: | |
4233 | + mnt->flags |= NFS_MOUNT_TCP; | |
4234 | + mnt->nfs_server.protocol = IPPROTO_TCP; | |
4235 | + mnt->timeo = 600; | |
4236 | + mnt->retrans = 2; | |
4237 | + break; | |
4238 | + case Opt_acl: | |
4239 | + mnt->flags &= ~NFS_MOUNT_NOACL; | |
4240 | + break; | |
4241 | + case Opt_noacl: | |
4242 | + mnt->flags |= NFS_MOUNT_NOACL; | |
4243 | + break; | |
4244 | + case Opt_rdirplus: | |
4245 | + mnt->flags &= ~NFS_MOUNT_NORDIRPLUS; | |
4246 | + break; | |
4247 | + case Opt_nordirplus: | |
4248 | + mnt->flags |= NFS_MOUNT_NORDIRPLUS; | |
4249 | + break; | |
4250 | + case Opt_sharecache: | |
4251 | + mnt->flags &= ~NFS_MOUNT_UNSHARED; | |
4252 | + break; | |
4253 | + case Opt_nosharecache: | |
4254 | + mnt->flags |= NFS_MOUNT_UNSHARED; | |
4255 | + break; | |
4256 | + | |
4257 | + case Opt_port: | |
4258 | + if (match_int(args, &option)) | |
4259 | + return 0; | |
4260 | + if (option < 0 || option > 65535) | |
4261 | + return 0; | |
4262 | + mnt->nfs_server.address.sin_port = htonl(option); | |
4263 | + break; | |
4264 | + case Opt_rsize: | |
4265 | + if (match_int(args, &mnt->rsize)) | |
4266 | + return 0; | |
4267 | + break; | |
4268 | + case Opt_wsize: | |
4269 | + if (match_int(args, &mnt->wsize)) | |
4270 | + return 0; | |
4271 | + break; | |
4272 | + case Opt_bsize: | |
4273 | + if (match_int(args, &option)) | |
4274 | + return 0; | |
4275 | + if (option < 0) | |
4276 | + return 0; | |
4277 | + mnt->bsize = option; | |
4278 | + break; | |
4279 | + case Opt_timeo: | |
4280 | + if (match_int(args, &mnt->timeo)) | |
4281 | + return 0; | |
4282 | + break; | |
4283 | + case Opt_retrans: | |
4284 | + if (match_int(args, &mnt->retrans)) | |
4285 | + return 0; | |
4286 | + break; | |
4287 | + case Opt_acregmin: | |
4288 | + if (match_int(args, &mnt->acregmin)) | |
4289 | + return 0; | |
4290 | + break; | |
4291 | + case Opt_acregmax: | |
4292 | + if (match_int(args, &mnt->acregmax)) | |
4293 | + return 0; | |
4294 | + break; | |
4295 | + case Opt_acdirmin: | |
4296 | + if (match_int(args, &mnt->acdirmin)) | |
4297 | + return 0; | |
4298 | + break; | |
4299 | + case Opt_acdirmax: | |
4300 | + if (match_int(args, &mnt->acdirmax)) | |
4301 | + return 0; | |
4302 | + break; | |
4303 | + case Opt_actimeo: | |
4304 | + if (match_int(args, &option)) | |
4305 | + return 0; | |
4306 | + if (option < 0) | |
4307 | + return 0; | |
4308 | + mnt->acregmin = | |
4309 | + mnt->acregmax = | |
4310 | + mnt->acdirmin = | |
4311 | + mnt->acdirmax = option; | |
4312 | + break; | |
4313 | + case Opt_namelen: | |
4314 | + if (match_int(args, &mnt->namlen)) | |
4315 | + return 0; | |
4316 | + break; | |
4317 | + case Opt_mountport: | |
4318 | + if (match_int(args, &option)) | |
4319 | + return 0; | |
4320 | + if (option < 0 || option > 65535) | |
4321 | + return 0; | |
4322 | + mnt->mount_server.port = option; | |
4323 | + break; | |
4324 | + case Opt_mountprog: | |
4325 | + if (match_int(args, &option)) | |
4326 | + return 0; | |
4327 | + if (option < 0) | |
4328 | + return 0; | |
4329 | + mnt->mount_server.program = option; | |
4330 | + break; | |
4331 | + case Opt_mountvers: | |
4332 | + if (match_int(args, &option)) | |
4333 | + return 0; | |
4334 | + if (option < 0) | |
4335 | + return 0; | |
4336 | + mnt->mount_server.version = option; | |
4337 | + break; | |
4338 | + case Opt_nfsprog: | |
4339 | + if (match_int(args, &option)) | |
4340 | + return 0; | |
4341 | + if (option < 0) | |
4342 | + return 0; | |
4343 | + mnt->nfs_server.program = option; | |
4344 | + break; | |
4345 | + case Opt_nfsvers: | |
4346 | + if (match_int(args, &option)) | |
4347 | + return 0; | |
4348 | + switch (option) { | |
4349 | + case 2: | |
4350 | + mnt->flags &= ~NFS_MOUNT_VER3; | |
4351 | + break; | |
4352 | + case 3: | |
4353 | + mnt->flags |= NFS_MOUNT_VER3; | |
4354 | + break; | |
4355 | + default: | |
4356 | + goto out_unrec_vers; | |
4357 | } | |
4358 | - data->root.size = NFS2_FHSIZE; | |
4359 | - memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); | |
4360 | - case 4: | |
4361 | - if (data->flags & NFS_MOUNT_SECFLAVOUR) { | |
4362 | - dprintk("%s: mount structure version %d does not support strong security\n", | |
4363 | - __FUNCTION__, | |
4364 | - data->version); | |
4365 | - return -EINVAL; | |
4366 | + break; | |
4367 | + | |
4368 | + case Opt_sec: | |
4369 | + string = match_strdup(args); | |
4370 | + if (string == NULL) | |
4371 | + goto out_nomem; | |
4372 | + token = match_token(string, nfs_secflavor_tokens, args); | |
4373 | + kfree(string); | |
4374 | + | |
4375 | + /* | |
4376 | + * The flags setting is for v2/v3. The flavor_len | |
4377 | + * setting is for v4. v2/v3 also need to know the | |
4378 | + * difference between NULL and UNIX. | |
4379 | + */ | |
4380 | + switch (token) { | |
4381 | + case Opt_sec_none: | |
4382 | + mnt->flags &= ~NFS_MOUNT_SECFLAVOUR; | |
4383 | + mnt->auth_flavor_len = 0; | |
4384 | + mnt->auth_flavors[0] = RPC_AUTH_NULL; | |
4385 | + break; | |
4386 | + case Opt_sec_sys: | |
4387 | + mnt->flags &= ~NFS_MOUNT_SECFLAVOUR; | |
4388 | + mnt->auth_flavor_len = 0; | |
4389 | + mnt->auth_flavors[0] = RPC_AUTH_UNIX; | |
4390 | + break; | |
4391 | + case Opt_sec_krb5: | |
4392 | + mnt->flags |= NFS_MOUNT_SECFLAVOUR; | |
4393 | + mnt->auth_flavor_len = 1; | |
4394 | + mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5; | |
4395 | + break; | |
4396 | + case Opt_sec_krb5i: | |
4397 | + mnt->flags |= NFS_MOUNT_SECFLAVOUR; | |
4398 | + mnt->auth_flavor_len = 1; | |
4399 | + mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I; | |
4400 | + break; | |
4401 | + case Opt_sec_krb5p: | |
4402 | + mnt->flags |= NFS_MOUNT_SECFLAVOUR; | |
4403 | + mnt->auth_flavor_len = 1; | |
4404 | + mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P; | |
4405 | + break; | |
4406 | + case Opt_sec_lkey: | |
4407 | + mnt->flags |= NFS_MOUNT_SECFLAVOUR; | |
4408 | + mnt->auth_flavor_len = 1; | |
4409 | + mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY; | |
4410 | + break; | |
4411 | + case Opt_sec_lkeyi: | |
4412 | + mnt->flags |= NFS_MOUNT_SECFLAVOUR; | |
4413 | + mnt->auth_flavor_len = 1; | |
4414 | + mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI; | |
4415 | + break; | |
4416 | + case Opt_sec_lkeyp: | |
4417 | + mnt->flags |= NFS_MOUNT_SECFLAVOUR; | |
4418 | + mnt->auth_flavor_len = 1; | |
4419 | + mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP; | |
4420 | + break; | |
4421 | + case Opt_sec_spkm: | |
4422 | + mnt->flags |= NFS_MOUNT_SECFLAVOUR; | |
4423 | + mnt->auth_flavor_len = 1; | |
4424 | + mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM; | |
4425 | + break; | |
4426 | + case Opt_sec_spkmi: | |
4427 | + mnt->flags |= NFS_MOUNT_SECFLAVOUR; | |
4428 | + mnt->auth_flavor_len = 1; | |
4429 | + mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI; | |
4430 | + break; | |
4431 | + case Opt_sec_spkmp: | |
4432 | + mnt->flags |= NFS_MOUNT_SECFLAVOUR; | |
4433 | + mnt->auth_flavor_len = 1; | |
4434 | + mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP; | |
4435 | + break; | |
4436 | + default: | |
4437 | + goto out_unrec_sec; | |
4438 | } | |
4439 | - case 5: | |
4440 | - memset(data->context, 0, sizeof(data->context)); | |
4441 | - } | |
4442 | + break; | |
4443 | + case Opt_proto: | |
4444 | + string = match_strdup(args); | |
4445 | + if (string == NULL) | |
4446 | + goto out_nomem; | |
4447 | + token = match_token(string, | |
4448 | + nfs_xprt_protocol_tokens, args); | |
4449 | + kfree(string); | |
4450 | + | |
4451 | + switch (token) { | |
4452 | + case Opt_udp: | |
4453 | + mnt->flags &= ~NFS_MOUNT_TCP; | |
4454 | + mnt->nfs_server.protocol = IPPROTO_UDP; | |
4455 | + mnt->timeo = 7; | |
4456 | + mnt->retrans = 5; | |
4457 | + break; | |
4458 | + case Opt_tcp: | |
4459 | + mnt->flags |= NFS_MOUNT_TCP; | |
4460 | + mnt->nfs_server.protocol = IPPROTO_TCP; | |
4461 | + mnt->timeo = 600; | |
4462 | + mnt->retrans = 2; | |
4463 | + break; | |
4464 | + default: | |
4465 | + goto out_unrec_xprt; | |
4466 | + } | |
4467 | + break; | |
4468 | + case Opt_mountproto: | |
4469 | + string = match_strdup(args); | |
4470 | + if (string == NULL) | |
4471 | + goto out_nomem; | |
4472 | + token = match_token(string, | |
4473 | + nfs_xprt_protocol_tokens, args); | |
4474 | + kfree(string); | |
4475 | + | |
4476 | + switch (token) { | |
4477 | + case Opt_udp: | |
4478 | + mnt->mount_server.protocol = IPPROTO_UDP; | |
4479 | + break; | |
4480 | + case Opt_tcp: | |
4481 | + mnt->mount_server.protocol = IPPROTO_TCP; | |
4482 | + break; | |
4483 | + default: | |
4484 | + goto out_unrec_xprt; | |
4485 | + } | |
4486 | + break; | |
4487 | + case Opt_addr: | |
4488 | + string = match_strdup(args); | |
4489 | + if (string == NULL) | |
4490 | + goto out_nomem; | |
4491 | + mnt->nfs_server.address.sin_family = AF_INET; | |
4492 | + mnt->nfs_server.address.sin_addr.s_addr = | |
4493 | + in_aton(string); | |
4494 | + kfree(string); | |
4495 | + break; | |
4496 | + case Opt_clientaddr: | |
4497 | + string = match_strdup(args); | |
4498 | + if (string == NULL) | |
4499 | + goto out_nomem; | |
4500 | + mnt->client_address = string; | |
4501 | + break; | |
4502 | + case Opt_mounthost: | |
4503 | + string = match_strdup(args); | |
4504 | + if (string == NULL) | |
4505 | + goto out_nomem; | |
4506 | + mnt->mount_server.address.sin_family = AF_INET; | |
4507 | + mnt->mount_server.address.sin_addr.s_addr = | |
4508 | + in_aton(string); | |
4509 | + kfree(string); | |
4510 | + break; | |
4511 | ||
4512 | - /* Set the pseudoflavor */ | |
4513 | - if (!(data->flags & NFS_MOUNT_SECFLAVOUR)) | |
4514 | - data->pseudoflavor = RPC_AUTH_UNIX; | |
4515 | + case Opt_userspace: | |
4516 | + case Opt_deprecated: | |
4517 | + break; | |
4518 | ||
4519 | -#ifndef CONFIG_NFS_V3 | |
4520 | - /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */ | |
4521 | - if (data->flags & NFS_MOUNT_VER3) { | |
4522 | - dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__); | |
4523 | - return -EPROTONOSUPPORT; | |
4524 | + default: | |
4525 | + goto out_unknown; | |
4526 | + } | |
4527 | } | |
4528 | -#endif /* CONFIG_NFS_V3 */ | |
4529 | ||
4530 | - /* We now require that the mount process passes the remote address */ | |
4531 | - if (data->addr.sin_addr.s_addr == INADDR_ANY) { | |
4532 | - dprintk("%s: mount program didn't pass remote address!\n", | |
4533 | - __FUNCTION__); | |
4534 | - return -EINVAL; | |
4535 | + return 1; | |
4536 | + | |
4537 | +out_nomem: | |
4538 | + printk(KERN_INFO "NFS: not enough memory to parse option\n"); | |
4539 | + return 0; | |
4540 | + | |
4541 | +out_unrec_vers: | |
4542 | + printk(KERN_INFO "NFS: unrecognized NFS version number\n"); | |
4543 | + return 0; | |
4544 | + | |
4545 | +out_unrec_xprt: | |
4546 | + printk(KERN_INFO "NFS: unrecognized transport protocol\n"); | |
4547 | + return 0; | |
4548 | + | |
4549 | +out_unrec_sec: | |
4550 | + printk(KERN_INFO "NFS: unrecognized security flavor\n"); | |
4551 | + return 0; | |
4552 | + | |
4553 | +out_unknown: | |
4554 | + printk(KERN_INFO "NFS: unknown mount option: %s\n", p); | |
4555 | + return 0; | |
4556 | +} | |
4557 | + | |
4558 | +/* | |
4559 | + * Use the remote server's MOUNT service to request the NFS file handle | |
4560 | + * corresponding to the provided path. | |
4561 | + */ | |
4562 | +static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |
4563 | + struct nfs_fh *root_fh) | |
4564 | +{ | |
4565 | + struct sockaddr_in sin; | |
4566 | + int status; | |
4567 | + | |
4568 | + if (args->mount_server.version == 0) { | |
4569 | + if (args->flags & NFS_MOUNT_VER3) | |
4570 | + args->mount_server.version = NFS_MNT3_VERSION; | |
4571 | + else | |
4572 | + args->mount_server.version = NFS_MNT_VERSION; | |
4573 | } | |
4574 | ||
4575 | - /* Prepare the root filehandle */ | |
4576 | - if (data->flags & NFS_MOUNT_VER3) | |
4577 | - mntfh->size = data->root.size; | |
4578 | + /* | |
4579 | + * Construct the mount server's address. | |
4580 | + */ | |
4581 | + if (args->mount_server.address.sin_addr.s_addr != INADDR_ANY) | |
4582 | + sin = args->mount_server.address; | |
4583 | else | |
4584 | - mntfh->size = NFS2_FHSIZE; | |
4585 | + sin = args->nfs_server.address; | |
4586 | + if (args->mount_server.port == 0) { | |
4587 | + status = rpcb_getport_sync(&sin, | |
4588 | + args->mount_server.program, | |
4589 | + args->mount_server.version, | |
4590 | + args->mount_server.protocol); | |
4591 | + if (status < 0) | |
4592 | + goto out_err; | |
4593 | + sin.sin_port = htons(status); | |
4594 | + } else | |
4595 | + sin.sin_port = htons(args->mount_server.port); | |
4596 | + | |
4597 | + /* | |
4598 | + * Now ask the mount server to map our export path | |
4599 | + * to a file handle. | |
4600 | + */ | |
4601 | + status = nfs_mount((struct sockaddr *) &sin, | |
4602 | + sizeof(sin), | |
4603 | + args->nfs_server.hostname, | |
4604 | + args->nfs_server.export_path, | |
4605 | + args->mount_server.version, | |
4606 | + args->mount_server.protocol, | |
4607 | + root_fh); | |
4608 | + if (status < 0) | |
4609 | + goto out_err; | |
4610 | + | |
4611 | + return status; | |
4612 | ||
4613 | - if (mntfh->size > sizeof(mntfh->data)) { | |
4614 | - dprintk("%s: invalid root filehandle\n", __FUNCTION__); | |
4615 | - return -EINVAL; | |
4616 | +out_err: | |
4617 | + dfprintk(MOUNT, "NFS: unable to contact server on host " | |
4618 | + NIPQUAD_FMT "\n", NIPQUAD(sin.sin_addr.s_addr)); | |
4619 | + return status; | |
4620 | +} | |
4621 | + | |
4622 | +/* | |
4623 | + * Validate the NFS2/NFS3 mount data | |
4624 | + * - fills in the mount root filehandle | |
4625 | + * | |
4626 | + * For option strings, user space handles the following behaviors: | |
4627 | + * | |
4628 | + * + DNS: mapping server host name to IP address ("addr=" option) | |
4629 | + * | |
4630 | + * + failure mode: how to behave if a mount request can't be handled | |
4631 | + * immediately ("fg/bg" option) | |
4632 | + * | |
4633 | + * + retry: how often to retry a mount request ("retry=" option) | |
4634 | + * | |
4635 | + * + breaking back: trying proto=udp after proto=tcp, v2 after v3, | |
4636 | + * mountproto=tcp after mountproto=udp, and so on | |
4637 | + * | |
4638 | + * XXX: as far as I can tell, changing the NFS program number is not | |
4639 | + * supported in the NFS client. | |
4640 | + */ | |
4641 | +static int nfs_validate_mount_data(struct nfs_mount_data **options, | |
4642 | + struct nfs_fh *mntfh, | |
4643 | + const char *dev_name) | |
4644 | +{ | |
4645 | + struct nfs_mount_data *data = *options; | |
4646 | + | |
4647 | + if (data == NULL) | |
4648 | + goto out_no_data; | |
4649 | + | |
4650 | + switch (data->version) { | |
4651 | + case 1: | |
4652 | + data->namlen = 0; | |
4653 | + case 2: | |
4654 | + data->bsize = 0; | |
4655 | + case 3: | |
4656 | + if (data->flags & NFS_MOUNT_VER3) | |
4657 | + goto out_no_v3; | |
4658 | + data->root.size = NFS2_FHSIZE; | |
4659 | + memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); | |
4660 | + case 4: | |
4661 | + if (data->flags & NFS_MOUNT_SECFLAVOUR) | |
4662 | + goto out_no_sec; | |
4663 | + case 5: | |
4664 | + memset(data->context, 0, sizeof(data->context)); | |
4665 | + case 6: | |
4666 | + if (data->flags & NFS_MOUNT_VER3) | |
4667 | + mntfh->size = data->root.size; | |
4668 | + else | |
4669 | + mntfh->size = NFS2_FHSIZE; | |
4670 | + | |
4671 | + if (mntfh->size > sizeof(mntfh->data)) | |
4672 | + goto out_invalid_fh; | |
4673 | + | |
4674 | + memcpy(mntfh->data, data->root.data, mntfh->size); | |
4675 | + if (mntfh->size < sizeof(mntfh->data)) | |
4676 | + memset(mntfh->data + mntfh->size, 0, | |
4677 | + sizeof(mntfh->data) - mntfh->size); | |
4678 | + break; | |
4679 | + default: { | |
4680 | + unsigned int len; | |
4681 | + char *c; | |
4682 | + int status; | |
4683 | + struct nfs_parsed_mount_data args = { | |
4684 | + .flags = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP), | |
4685 | + .rsize = NFS_MAX_FILE_IO_SIZE, | |
4686 | + .wsize = NFS_MAX_FILE_IO_SIZE, | |
4687 | + .timeo = 600, | |
4688 | + .retrans = 2, | |
4689 | + .acregmin = 3, | |
4690 | + .acregmax = 60, | |
4691 | + .acdirmin = 30, | |
4692 | + .acdirmax = 60, | |
4693 | + .mount_server.protocol = IPPROTO_UDP, | |
4694 | + .mount_server.program = NFS_MNT_PROGRAM, | |
4695 | + .nfs_server.protocol = IPPROTO_TCP, | |
4696 | + .nfs_server.program = NFS_PROGRAM, | |
4697 | + }; | |
4698 | + | |
4699 | + if (nfs_parse_mount_options((char *) *options, &args) == 0) | |
4700 | + return -EINVAL; | |
4701 | + | |
4702 | + data = kzalloc(sizeof(*data), GFP_KERNEL); | |
4703 | + if (data == NULL) | |
4704 | + return -ENOMEM; | |
4705 | + | |
4706 | + /* | |
4707 | + * NB: after this point, caller will free "data" | |
4708 | + * if we return an error | |
4709 | + */ | |
4710 | + *options = data; | |
4711 | + | |
4712 | + c = strchr(dev_name, ':'); | |
4713 | + if (c == NULL) | |
4714 | + return -EINVAL; | |
4715 | + len = c - dev_name - 1; | |
4716 | + if (len > sizeof(data->hostname)) | |
4717 | + return -EINVAL; | |
4718 | + strncpy(data->hostname, dev_name, len); | |
4719 | + args.nfs_server.hostname = data->hostname; | |
4720 | + | |
4721 | + c++; | |
4722 | + if (strlen(c) > NFS_MAXPATHLEN) | |
4723 | + return -EINVAL; | |
4724 | + args.nfs_server.export_path = c; | |
4725 | + | |
4726 | + status = nfs_try_mount(&args, mntfh); | |
4727 | + if (status) | |
4728 | + return -EINVAL; | |
4729 | + | |
4730 | + /* | |
4731 | + * Translate to nfs_mount_data, which nfs_fill_super | |
4732 | + * can deal with. | |
4733 | + */ | |
4734 | + data->version = 6; | |
4735 | + data->flags = args.flags; | |
4736 | + data->rsize = args.rsize; | |
4737 | + data->wsize = args.wsize; | |
4738 | + data->timeo = args.timeo; | |
4739 | + data->retrans = args.retrans; | |
4740 | + data->acregmin = args.acregmin; | |
4741 | + data->acregmax = args.acregmax; | |
4742 | + data->acdirmin = args.acdirmin; | |
4743 | + data->acdirmax = args.acdirmax; | |
4744 | + data->addr = args.nfs_server.address; | |
4745 | + data->namlen = args.namlen; | |
4746 | + data->bsize = args.bsize; | |
4747 | + data->pseudoflavor = args.auth_flavors[0]; | |
4748 | + | |
4749 | + break; | |
4750 | + } | |
4751 | } | |
4752 | ||
4753 | - memcpy(mntfh->data, data->root.data, mntfh->size); | |
4754 | - if (mntfh->size < sizeof(mntfh->data)) | |
4755 | - memset(mntfh->data + mntfh->size, 0, | |
4756 | - sizeof(mntfh->data) - mntfh->size); | |
4757 | + if (!(data->flags & NFS_MOUNT_SECFLAVOUR)) | |
4758 | + data->pseudoflavor = RPC_AUTH_UNIX; | |
4759 | + | |
4760 | +#ifndef CONFIG_NFS_V3 | |
4761 | + if (data->flags & NFS_MOUNT_VER3) | |
4762 | + goto out_v3_not_compiled; | |
4763 | +#endif /* !CONFIG_NFS_V3 */ | |
4764 | + | |
4765 | + if (!nfs_verify_server_address((struct sockaddr *) &data->addr)) | |
4766 | + goto out_no_address; | |
4767 | ||
4768 | return 0; | |
4769 | + | |
4770 | +out_no_data: | |
4771 | + dfprintk(MOUNT, "NFS: mount program didn't pass any mount data\n"); | |
4772 | + return -EINVAL; | |
4773 | + | |
4774 | +out_no_v3: | |
4775 | + dfprintk(MOUNT, "NFS: nfs_mount_data version %d does not support v3\n", | |
4776 | + data->version); | |
4777 | + return -EINVAL; | |
4778 | + | |
4779 | +out_no_sec: | |
4780 | + dfprintk(MOUNT, "NFS: nfs_mount_data version supports only AUTH_SYS\n"); | |
4781 | + return -EINVAL; | |
4782 | + | |
4783 | +#ifndef CONFIG_NFS_V3 | |
4784 | +out_v3_not_compiled: | |
4785 | + dfprintk(MOUNT, "NFS: NFSv3 is not compiled into kernel\n"); | |
4786 | + return -EPROTONOSUPPORT; | |
4787 | +#endif /* !CONFIG_NFS_V3 */ | |
4788 | + | |
4789 | +out_no_address: | |
4790 | + dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n"); | |
4791 | + return -EINVAL; | |
4792 | + | |
4793 | +out_invalid_fh: | |
4794 | + dfprintk(MOUNT, "NFS: invalid root filehandle\n"); | |
4795 | + return -EINVAL; | |
4796 | } | |
4797 | ||
4798 | /* | |
4799 | @@ -600,13 +1317,51 @@ static int nfs_compare_super(struct super_block *sb, void *data) | |
4800 | { | |
4801 | struct nfs_server *server = data, *old = NFS_SB(sb); | |
4802 | ||
4803 | - if (old->nfs_client != server->nfs_client) | |
4804 | + if (memcmp(&old->nfs_client->cl_addr, | |
4805 | + &server->nfs_client->cl_addr, | |
4806 | + sizeof(old->nfs_client->cl_addr)) != 0) | |
4807 | + return 0; | |
4808 | + /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */ | |
4809 | + if (old->flags & NFS_MOUNT_UNSHARED) | |
4810 | return 0; | |
4811 | if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0) | |
4812 | return 0; | |
4813 | return 1; | |
4814 | } | |
4815 | ||
4816 | +#define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS) | |
4817 | + | |
4818 | +static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags) | |
4819 | +{ | |
4820 | + const struct nfs_server *a = s->s_fs_info; | |
4821 | + const struct rpc_clnt *clnt_a = a->client; | |
4822 | + const struct rpc_clnt *clnt_b = b->client; | |
4823 | + | |
4824 | + if ((s->s_flags & NFS_MS_MASK) != (flags & NFS_MS_MASK)) | |
4825 | + goto Ebusy; | |
4826 | + if (a->nfs_client != b->nfs_client) | |
4827 | + goto Ebusy; | |
4828 | + if (a->flags != b->flags) | |
4829 | + goto Ebusy; | |
4830 | + if (a->wsize != b->wsize) | |
4831 | + goto Ebusy; | |
4832 | + if (a->rsize != b->rsize) | |
4833 | + goto Ebusy; | |
4834 | + if (a->acregmin != b->acregmin) | |
4835 | + goto Ebusy; | |
4836 | + if (a->acregmax != b->acregmax) | |
4837 | + goto Ebusy; | |
4838 | + if (a->acdirmin != b->acdirmin) | |
4839 | + goto Ebusy; | |
4840 | + if (a->acdirmax != b->acdirmax) | |
4841 | + goto Ebusy; | |
4842 | + if (clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor) | |
4843 | + goto Ebusy; | |
4844 | + return 0; | |
4845 | +Ebusy: | |
4846 | + return -EBUSY; | |
4847 | +} | |
4848 | + | |
4849 | static int nfs_get_sb(struct file_system_type *fs_type, | |
4850 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | |
4851 | { | |
4852 | @@ -615,30 +1370,37 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |
4853 | struct nfs_fh mntfh; | |
4854 | struct nfs_mount_data *data = raw_data; | |
4855 | struct dentry *mntroot; | |
4856 | + int (*compare_super)(struct super_block *, void *) = nfs_compare_super; | |
4857 | int error; | |
4858 | ||
4859 | /* Validate the mount data */ | |
4860 | - error = nfs_validate_mount_data(data, &mntfh); | |
4861 | + error = nfs_validate_mount_data(&data, &mntfh, dev_name); | |
4862 | if (error < 0) | |
4863 | - return error; | |
4864 | + goto out; | |
4865 | ||
4866 | /* Get a volume representation */ | |
4867 | server = nfs_create_server(data, &mntfh); | |
4868 | if (IS_ERR(server)) { | |
4869 | error = PTR_ERR(server); | |
4870 | - goto out_err_noserver; | |
4871 | + goto out; | |
4872 | } | |
4873 | ||
4874 | + if (server->flags & NFS_MOUNT_UNSHARED) | |
4875 | + compare_super = NULL; | |
4876 | + | |
4877 | /* Get a superblock - note that we may end up sharing one that already exists */ | |
4878 | - s = sget(fs_type, nfs_compare_super, nfs_set_super, server); | |
4879 | + s = sget(fs_type, compare_super, nfs_set_super, server); | |
4880 | if (IS_ERR(s)) { | |
4881 | error = PTR_ERR(s); | |
4882 | goto out_err_nosb; | |
4883 | } | |
4884 | ||
4885 | if (s->s_fs_info != server) { | |
4886 | + error = nfs_compare_mount_options(s, server, flags); | |
4887 | nfs_free_server(server); | |
4888 | server = NULL; | |
4889 | + if (error < 0) | |
4890 | + goto error_splat_super; | |
4891 | } | |
4892 | ||
4893 | if (!s->s_root) { | |
4894 | @@ -656,17 +1418,21 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |
4895 | s->s_flags |= MS_ACTIVE; | |
4896 | mnt->mnt_sb = s; | |
4897 | mnt->mnt_root = mntroot; | |
4898 | - return 0; | |
4899 | + error = 0; | |
4900 | + | |
4901 | +out: | |
4902 | + if (data != raw_data) | |
4903 | + kfree(data); | |
4904 | + return error; | |
4905 | ||
4906 | out_err_nosb: | |
4907 | nfs_free_server(server); | |
4908 | -out_err_noserver: | |
4909 | - return error; | |
4910 | + goto out; | |
4911 | ||
4912 | error_splat_super: | |
4913 | up_write(&s->s_umount); | |
4914 | deactivate_super(s); | |
4915 | - return error; | |
4916 | + goto out; | |
4917 | } | |
4918 | ||
4919 | /* | |
4920 | @@ -691,6 +1457,7 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, | |
4921 | struct super_block *s; | |
4922 | struct nfs_server *server; | |
4923 | struct dentry *mntroot; | |
4924 | + int (*compare_super)(struct super_block *, void *) = nfs_compare_super; | |
4925 | int error; | |
4926 | ||
4927 | dprintk("--> nfs_xdev_get_sb()\n"); | |
4928 | @@ -702,16 +1469,22 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, | |
4929 | goto out_err_noserver; | |
4930 | } | |
4931 | ||
4932 | + if (server->flags & NFS_MOUNT_UNSHARED) | |
4933 | + compare_super = NULL; | |
4934 | + | |
4935 | /* Get a superblock - note that we may end up sharing one that already exists */ | |
4936 | - s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server); | |
4937 | + s = sget(&nfs_fs_type, compare_super, nfs_set_super, server); | |
4938 | if (IS_ERR(s)) { | |
4939 | error = PTR_ERR(s); | |
4940 | goto out_err_nosb; | |
4941 | } | |
4942 | ||
4943 | if (s->s_fs_info != server) { | |
4944 | + error = nfs_compare_mount_options(s, server, flags); | |
4945 | nfs_free_server(server); | |
4946 | server = NULL; | |
4947 | + if (error < 0) | |
4948 | + goto error_splat_super; | |
4949 | } | |
4950 | ||
4951 | if (!s->s_root) { | |
4952 | @@ -772,25 +1545,164 @@ static void nfs4_fill_super(struct super_block *sb) | |
4953 | nfs_initialise_sb(sb); | |
4954 | } | |
4955 | ||
4956 | -static void *nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen) | |
4957 | +/* | |
4958 | + * Validate NFSv4 mount options | |
4959 | + */ | |
4960 | +static int nfs4_validate_mount_data(struct nfs4_mount_data **options, | |
4961 | + const char *dev_name, | |
4962 | + struct sockaddr_in *addr, | |
4963 | + rpc_authflavor_t *authflavour, | |
4964 | + char **hostname, | |
4965 | + char **mntpath, | |
4966 | + char **ip_addr) | |
4967 | { | |
4968 | - void *p = NULL; | |
4969 | - | |
4970 | - if (!src->len) | |
4971 | - return ERR_PTR(-EINVAL); | |
4972 | - if (src->len < maxlen) | |
4973 | - maxlen = src->len; | |
4974 | - if (dst == NULL) { | |
4975 | - p = dst = kmalloc(maxlen + 1, GFP_KERNEL); | |
4976 | - if (p == NULL) | |
4977 | - return ERR_PTR(-ENOMEM); | |
4978 | - } | |
4979 | - if (copy_from_user(dst, src->data, maxlen)) { | |
4980 | - kfree(p); | |
4981 | - return ERR_PTR(-EFAULT); | |
4982 | + struct nfs4_mount_data *data = *options; | |
4983 | + char *c; | |
4984 | + | |
4985 | + if (data == NULL) | |
4986 | + goto out_no_data; | |
4987 | + | |
4988 | + switch (data->version) { | |
4989 | + case 1: | |
4990 | + if (data->host_addrlen != sizeof(*addr)) | |
4991 | + goto out_no_address; | |
4992 | + if (copy_from_user(addr, data->host_addr, sizeof(*addr))) | |
4993 | + return -EFAULT; | |
4994 | + if (addr->sin_port == 0) | |
4995 | + addr->sin_port = htons(NFS_PORT); | |
4996 | + if (!nfs_verify_server_address((struct sockaddr *) addr)) | |
4997 | + goto out_no_address; | |
4998 | + | |
4999 | + switch (data->auth_flavourlen) { | |
5000 | + case 0: | |
5001 | + *authflavour = RPC_AUTH_UNIX; | |
5002 | + break; | |
5003 | + case 1: | |
5004 | + if (copy_from_user(authflavour, data->auth_flavours, | |
5005 | + sizeof(*authflavour))) | |
5006 | + return -EFAULT; | |
5007 | + break; | |
5008 | + default: | |
5009 | + goto out_inval_auth; | |
5010 | + } | |
5011 | + | |
5012 | + c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN); | |
5013 | + if (IS_ERR(c)) | |
5014 | + return PTR_ERR(c); | |
5015 | + *hostname = c; | |
5016 | + | |
5017 | + c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN); | |
5018 | + if (IS_ERR(c)) | |
5019 | + return PTR_ERR(c); | |
5020 | + *mntpath = c; | |
5021 | + dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *mntpath); | |
5022 | + | |
5023 | + c = strndup_user(data->client_addr.data, 16); | |
5024 | + if (IS_ERR(c)) | |
5025 | + return PTR_ERR(c); | |
5026 | + *ip_addr = c; | |
5027 | + | |
5028 | + break; | |
5029 | + default: { | |
5030 | + unsigned int len; | |
5031 | + struct nfs_parsed_mount_data args = { | |
5032 | + .rsize = NFS_MAX_FILE_IO_SIZE, | |
5033 | + .wsize = NFS_MAX_FILE_IO_SIZE, | |
5034 | + .timeo = 600, | |
5035 | + .retrans = 2, | |
5036 | + .acregmin = 3, | |
5037 | + .acregmax = 60, | |
5038 | + .acdirmin = 30, | |
5039 | + .acdirmax = 60, | |
5040 | + .nfs_server.protocol = IPPROTO_TCP, | |
5041 | + }; | |
5042 | + | |
5043 | + if (nfs_parse_mount_options((char *) *options, &args) == 0) | |
5044 | + return -EINVAL; | |
5045 | + | |
5046 | + if (!nfs_verify_server_address((struct sockaddr *) | |
5047 | + &args.nfs_server.address)) | |
5048 | + return -EINVAL; | |
5049 | + *addr = args.nfs_server.address; | |
5050 | + | |
5051 | + switch (args.auth_flavor_len) { | |
5052 | + case 0: | |
5053 | + *authflavour = RPC_AUTH_UNIX; | |
5054 | + break; | |
5055 | + case 1: | |
5056 | + *authflavour = (rpc_authflavor_t) args.auth_flavors[0]; | |
5057 | + break; | |
5058 | + default: | |
5059 | + goto out_inval_auth; | |
5060 | + } | |
5061 | + | |
5062 | + /* | |
5063 | + * Translate to nfs4_mount_data, which nfs4_fill_super | |
5064 | + * can deal with. | |
5065 | + */ | |
5066 | + data = kzalloc(sizeof(*data), GFP_KERNEL); | |
5067 | + if (data == NULL) | |
5068 | + return -ENOMEM; | |
5069 | + *options = data; | |
5070 | + | |
5071 | + data->version = 1; | |
5072 | + data->flags = args.flags & NFS4_MOUNT_FLAGMASK; | |
5073 | + data->rsize = args.rsize; | |
5074 | + data->wsize = args.wsize; | |
5075 | + data->timeo = args.timeo; | |
5076 | + data->retrans = args.retrans; | |
5077 | + data->acregmin = args.acregmin; | |
5078 | + data->acregmax = args.acregmax; | |
5079 | + data->acdirmin = args.acdirmin; | |
5080 | + data->acdirmax = args.acdirmax; | |
5081 | + data->proto = args.nfs_server.protocol; | |
5082 | + | |
5083 | + /* | |
5084 | + * Split "dev_name" into "hostname:mntpath". | |
5085 | + */ | |
5086 | + c = strchr(dev_name, ':'); | |
5087 | + if (c == NULL) | |
5088 | + return -EINVAL; | |
5089 | + /* while calculating len, pretend ':' is '\0' */ | |
5090 | + len = c - dev_name; | |
5091 | + if (len > NFS4_MAXNAMLEN) | |
5092 | + return -EINVAL; | |
5093 | + *hostname = kzalloc(len, GFP_KERNEL); | |
5094 | + if (*hostname == NULL) | |
5095 | + return -ENOMEM; | |
5096 | + strncpy(*hostname, dev_name, len - 1); | |
5097 | + | |
5098 | + c++; /* step over the ':' */ | |
5099 | + len = strlen(c); | |
5100 | + if (len > NFS4_MAXPATHLEN) | |
5101 | + return -EINVAL; | |
5102 | + *mntpath = kzalloc(len + 1, GFP_KERNEL); | |
5103 | + if (*mntpath == NULL) | |
5104 | + return -ENOMEM; | |
5105 | + strncpy(*mntpath, c, len); | |
5106 | + | |
5107 | + dprintk("MNTPATH: %s\n", *mntpath); | |
5108 | + | |
5109 | + *ip_addr = args.client_address; | |
5110 | + | |
5111 | + break; | |
5112 | + } | |
5113 | } | |
5114 | - dst[maxlen] = '\0'; | |
5115 | - return dst; | |
5116 | + | |
5117 | + return 0; | |
5118 | + | |
5119 | +out_no_data: | |
5120 | + dfprintk(MOUNT, "NFS4: mount program didn't pass any mount data\n"); | |
5121 | + return -EINVAL; | |
5122 | + | |
5123 | +out_inval_auth: | |
5124 | + dfprintk(MOUNT, "NFS4: Invalid number of RPC auth flavours %d\n", | |
5125 | + data->auth_flavourlen); | |
5126 | + return -EINVAL; | |
5127 | + | |
5128 | +out_no_address: | |
5129 | + dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); | |
5130 | + return -EINVAL; | |
5131 | } | |
5132 | ||
5133 | /* | |
5134 | @@ -806,81 +1718,29 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |
5135 | rpc_authflavor_t authflavour; | |
5136 | struct nfs_fh mntfh; | |
5137 | struct dentry *mntroot; | |
5138 | - char *mntpath = NULL, *hostname = NULL, ip_addr[16]; | |
5139 | - void *p; | |
5140 | + char *mntpath = NULL, *hostname = NULL, *ip_addr = NULL; | |
5141 | + int (*compare_super)(struct super_block *, void *) = nfs_compare_super; | |
5142 | int error; | |
5143 | ||
5144 | - if (data == NULL) { | |
5145 | - dprintk("%s: missing data argument\n", __FUNCTION__); | |
5146 | - return -EINVAL; | |
5147 | - } | |
5148 | - if (data->version <= 0 || data->version > NFS4_MOUNT_VERSION) { | |
5149 | - dprintk("%s: bad mount version\n", __FUNCTION__); | |
5150 | - return -EINVAL; | |
5151 | - } | |
5152 | - | |
5153 | - /* We now require that the mount process passes the remote address */ | |
5154 | - if (data->host_addrlen != sizeof(addr)) | |
5155 | - return -EINVAL; | |
5156 | - | |
5157 | - if (copy_from_user(&addr, data->host_addr, sizeof(addr))) | |
5158 | - return -EFAULT; | |
5159 | - | |
5160 | - if (addr.sin_family != AF_INET || | |
5161 | - addr.sin_addr.s_addr == INADDR_ANY | |
5162 | - ) { | |
5163 | - dprintk("%s: mount program didn't pass remote IP address!\n", | |
5164 | - __FUNCTION__); | |
5165 | - return -EINVAL; | |
5166 | - } | |
5167 | - /* RFC3530: The default port for NFS is 2049 */ | |
5168 | - if (addr.sin_port == 0) | |
5169 | - addr.sin_port = htons(NFS_PORT); | |
5170 | - | |
5171 | - /* Grab the authentication type */ | |
5172 | - authflavour = RPC_AUTH_UNIX; | |
5173 | - if (data->auth_flavourlen != 0) { | |
5174 | - if (data->auth_flavourlen != 1) { | |
5175 | - dprintk("%s: Invalid number of RPC auth flavours %d.\n", | |
5176 | - __FUNCTION__, data->auth_flavourlen); | |
5177 | - error = -EINVAL; | |
5178 | - goto out_err_noserver; | |
5179 | - } | |
5180 | - | |
5181 | - if (copy_from_user(&authflavour, data->auth_flavours, | |
5182 | - sizeof(authflavour))) { | |
5183 | - error = -EFAULT; | |
5184 | - goto out_err_noserver; | |
5185 | - } | |
5186 | - } | |
5187 | - | |
5188 | - p = nfs_copy_user_string(NULL, &data->hostname, 256); | |
5189 | - if (IS_ERR(p)) | |
5190 | - goto out_err; | |
5191 | - hostname = p; | |
5192 | - | |
5193 | - p = nfs_copy_user_string(NULL, &data->mnt_path, 1024); | |
5194 | - if (IS_ERR(p)) | |
5195 | - goto out_err; | |
5196 | - mntpath = p; | |
5197 | - | |
5198 | - dprintk("MNTPATH: %s\n", mntpath); | |
5199 | - | |
5200 | - p = nfs_copy_user_string(ip_addr, &data->client_addr, | |
5201 | - sizeof(ip_addr) - 1); | |
5202 | - if (IS_ERR(p)) | |
5203 | - goto out_err; | |
5204 | + /* Validate the mount data */ | |
5205 | + error = nfs4_validate_mount_data(&data, dev_name, &addr, &authflavour, | |
5206 | + &hostname, &mntpath, &ip_addr); | |
5207 | + if (error < 0) | |
5208 | + goto out; | |
5209 | ||
5210 | /* Get a volume representation */ | |
5211 | server = nfs4_create_server(data, hostname, &addr, mntpath, ip_addr, | |
5212 | authflavour, &mntfh); | |
5213 | if (IS_ERR(server)) { | |
5214 | error = PTR_ERR(server); | |
5215 | - goto out_err_noserver; | |
5216 | + goto out; | |
5217 | } | |
5218 | ||
5219 | + if (server->flags & NFS4_MOUNT_UNSHARED) | |
5220 | + compare_super = NULL; | |
5221 | + | |
5222 | /* Get a superblock - note that we may end up sharing one that already exists */ | |
5223 | - s = sget(fs_type, nfs_compare_super, nfs_set_super, server); | |
5224 | + s = sget(fs_type, compare_super, nfs_set_super, server); | |
5225 | if (IS_ERR(s)) { | |
5226 | error = PTR_ERR(s); | |
5227 | goto out_free; | |
5228 | @@ -906,25 +1766,22 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |
5229 | s->s_flags |= MS_ACTIVE; | |
5230 | mnt->mnt_sb = s; | |
5231 | mnt->mnt_root = mntroot; | |
5232 | + error = 0; | |
5233 | + | |
5234 | +out: | |
5235 | + kfree(ip_addr); | |
5236 | kfree(mntpath); | |
5237 | kfree(hostname); | |
5238 | - return 0; | |
5239 | - | |
5240 | -out_err: | |
5241 | - error = PTR_ERR(p); | |
5242 | - goto out_err_noserver; | |
5243 | + return error; | |
5244 | ||
5245 | out_free: | |
5246 | nfs_free_server(server); | |
5247 | -out_err_noserver: | |
5248 | - kfree(mntpath); | |
5249 | - kfree(hostname); | |
5250 | - return error; | |
5251 | + goto out; | |
5252 | ||
5253 | error_splat_super: | |
5254 | up_write(&s->s_umount); | |
5255 | deactivate_super(s); | |
5256 | - goto out_err_noserver; | |
5257 | + goto out; | |
5258 | } | |
5259 | ||
5260 | static void nfs4_kill_super(struct super_block *sb) | |
5261 | @@ -949,6 +1806,7 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags, | |
5262 | struct super_block *s; | |
5263 | struct nfs_server *server; | |
5264 | struct dentry *mntroot; | |
5265 | + int (*compare_super)(struct super_block *, void *) = nfs_compare_super; | |
5266 | int error; | |
5267 | ||
5268 | dprintk("--> nfs4_xdev_get_sb()\n"); | |
5269 | @@ -960,8 +1818,11 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags, | |
5270 | goto out_err_noserver; | |
5271 | } | |
5272 | ||
5273 | + if (server->flags & NFS4_MOUNT_UNSHARED) | |
5274 | + compare_super = NULL; | |
5275 | + | |
5276 | /* Get a superblock - note that we may end up sharing one that already exists */ | |
5277 | - s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server); | |
5278 | + s = sget(&nfs_fs_type, compare_super, nfs_set_super, server); | |
5279 | if (IS_ERR(s)) { | |
5280 | error = PTR_ERR(s); | |
5281 | goto out_err_nosb; | |
5282 | @@ -1016,6 +1877,7 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags, | |
5283 | struct nfs_server *server; | |
5284 | struct dentry *mntroot; | |
5285 | struct nfs_fh mntfh; | |
5286 | + int (*compare_super)(struct super_block *, void *) = nfs_compare_super; | |
5287 | int error; | |
5288 | ||
5289 | dprintk("--> nfs4_referral_get_sb()\n"); | |
5290 | @@ -1027,8 +1889,11 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags, | |
5291 | goto out_err_noserver; | |
5292 | } | |
5293 | ||
5294 | + if (server->flags & NFS4_MOUNT_UNSHARED) | |
5295 | + compare_super = NULL; | |
5296 | + | |
5297 | /* Get a superblock - note that we may end up sharing one that already exists */ | |
5298 | - s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server); | |
5299 | + s = sget(&nfs_fs_type, compare_super, nfs_set_super, server); | |
5300 | if (IS_ERR(s)) { | |
5301 | error = PTR_ERR(s); | |
5302 | goto out_err_nosb; | |
5303 | diff --git a/fs/nfs/write.c b/fs/nfs/write.c | |
5304 | index af344a1..73ac992 100644 | |
5305 | --- a/fs/nfs/write.c | |
5306 | +++ b/fs/nfs/write.c | |
5307 | @@ -117,19 +117,19 @@ static struct nfs_page *nfs_page_find_request_locked(struct page *page) | |
5308 | if (PagePrivate(page)) { | |
5309 | req = (struct nfs_page *)page_private(page); | |
5310 | if (req != NULL) | |
5311 | - atomic_inc(&req->wb_count); | |
5312 | + kref_get(&req->wb_kref); | |
5313 | } | |
5314 | return req; | |
5315 | } | |
5316 | ||
5317 | static struct nfs_page *nfs_page_find_request(struct page *page) | |
5318 | { | |
5319 | + struct inode *inode = page->mapping->host; | |
5320 | struct nfs_page *req = NULL; | |
5321 | - spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock; | |
5322 | ||
5323 | - spin_lock(req_lock); | |
5324 | + spin_lock(&inode->i_lock); | |
5325 | req = nfs_page_find_request_locked(page); | |
5326 | - spin_unlock(req_lock); | |
5327 | + spin_unlock(&inode->i_lock); | |
5328 | return req; | |
5329 | } | |
5330 | ||
5331 | @@ -191,8 +191,6 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, | |
5332 | } | |
5333 | /* Update file length */ | |
5334 | nfs_grow_file(page, offset, count); | |
5335 | - /* Set the PG_uptodate flag? */ | |
5336 | - nfs_mark_uptodate(page, offset, count); | |
5337 | nfs_unlock_request(req); | |
5338 | return 0; | |
5339 | } | |
5340 | @@ -253,16 +251,16 @@ static void nfs_end_page_writeback(struct page *page) | |
5341 | static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |
5342 | struct page *page) | |
5343 | { | |
5344 | + struct inode *inode = page->mapping->host; | |
5345 | + struct nfs_inode *nfsi = NFS_I(inode); | |
5346 | struct nfs_page *req; | |
5347 | - struct nfs_inode *nfsi = NFS_I(page->mapping->host); | |
5348 | - spinlock_t *req_lock = &nfsi->req_lock; | |
5349 | int ret; | |
5350 | ||
5351 | - spin_lock(req_lock); | |
5352 | + spin_lock(&inode->i_lock); | |
5353 | for(;;) { | |
5354 | req = nfs_page_find_request_locked(page); | |
5355 | if (req == NULL) { | |
5356 | - spin_unlock(req_lock); | |
5357 | + spin_unlock(&inode->i_lock); | |
5358 | return 1; | |
5359 | } | |
5360 | if (nfs_lock_request_dontget(req)) | |
5361 | @@ -272,28 +270,28 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |
5362 | * succeed provided that someone hasn't already marked the | |
5363 | * request as dirty (in which case we don't care). | |
5364 | */ | |
5365 | - spin_unlock(req_lock); | |
5366 | + spin_unlock(&inode->i_lock); | |
5367 | ret = nfs_wait_on_request(req); | |
5368 | nfs_release_request(req); | |
5369 | if (ret != 0) | |
5370 | return ret; | |
5371 | - spin_lock(req_lock); | |
5372 | + spin_lock(&inode->i_lock); | |
5373 | } | |
5374 | if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { | |
5375 | /* This request is marked for commit */ | |
5376 | - spin_unlock(req_lock); | |
5377 | + spin_unlock(&inode->i_lock); | |
5378 | nfs_unlock_request(req); | |
5379 | nfs_pageio_complete(pgio); | |
5380 | return 1; | |
5381 | } | |
5382 | if (nfs_set_page_writeback(page) != 0) { | |
5383 | - spin_unlock(req_lock); | |
5384 | + spin_unlock(&inode->i_lock); | |
5385 | BUG(); | |
5386 | } | |
5387 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, | |
5388 | - NFS_PAGE_TAG_WRITEBACK); | |
5389 | + NFS_PAGE_TAG_LOCKED); | |
5390 | ret = test_bit(PG_NEED_FLUSH, &req->wb_flags); | |
5391 | - spin_unlock(req_lock); | |
5392 | + spin_unlock(&inode->i_lock); | |
5393 | nfs_pageio_add_request(pgio, req); | |
5394 | return ret; | |
5395 | } | |
5396 | @@ -400,7 +398,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | |
5397 | if (PageDirty(req->wb_page)) | |
5398 | set_bit(PG_NEED_FLUSH, &req->wb_flags); | |
5399 | nfsi->npages++; | |
5400 | - atomic_inc(&req->wb_count); | |
5401 | + kref_get(&req->wb_kref); | |
5402 | return 0; | |
5403 | } | |
5404 | ||
5405 | @@ -409,12 +407,12 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | |
5406 | */ | |
5407 | static void nfs_inode_remove_request(struct nfs_page *req) | |
5408 | { | |
5409 | - struct inode *inode = req->wb_context->dentry->d_inode; | |
5410 | + struct inode *inode = req->wb_context->path.dentry->d_inode; | |
5411 | struct nfs_inode *nfsi = NFS_I(inode); | |
5412 | ||
5413 | BUG_ON (!NFS_WBACK_BUSY(req)); | |
5414 | ||
5415 | - spin_lock(&nfsi->req_lock); | |
5416 | + spin_lock(&inode->i_lock); | |
5417 | set_page_private(req->wb_page, 0); | |
5418 | ClearPagePrivate(req->wb_page); | |
5419 | radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); | |
5420 | @@ -422,11 +420,11 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |
5421 | __set_page_dirty_nobuffers(req->wb_page); | |
5422 | nfsi->npages--; | |
5423 | if (!nfsi->npages) { | |
5424 | - spin_unlock(&nfsi->req_lock); | |
5425 | + spin_unlock(&inode->i_lock); | |
5426 | nfs_end_data_update(inode); | |
5427 | iput(inode); | |
5428 | } else | |
5429 | - spin_unlock(&nfsi->req_lock); | |
5430 | + spin_unlock(&inode->i_lock); | |
5431 | nfs_clear_request(req); | |
5432 | nfs_release_request(req); | |
5433 | } | |
5434 | @@ -457,14 +455,16 @@ nfs_dirty_request(struct nfs_page *req) | |
5435 | static void | |
5436 | nfs_mark_request_commit(struct nfs_page *req) | |
5437 | { | |
5438 | - struct inode *inode = req->wb_context->dentry->d_inode; | |
5439 | + struct inode *inode = req->wb_context->path.dentry->d_inode; | |
5440 | struct nfs_inode *nfsi = NFS_I(inode); | |
5441 | ||
5442 | - spin_lock(&nfsi->req_lock); | |
5443 | - nfs_list_add_request(req, &nfsi->commit); | |
5444 | + spin_lock(&inode->i_lock); | |
5445 | nfsi->ncommit++; | |
5446 | set_bit(PG_NEED_COMMIT, &(req)->wb_flags); | |
5447 | - spin_unlock(&nfsi->req_lock); | |
5448 | + radix_tree_tag_set(&nfsi->nfs_page_tree, | |
5449 | + req->wb_index, | |
5450 | + NFS_PAGE_TAG_COMMIT); | |
5451 | + spin_unlock(&inode->i_lock); | |
5452 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | |
5453 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | |
5454 | } | |
5455 | @@ -526,18 +526,18 @@ static int nfs_wait_on_requests_locked(struct inode *inode, pgoff_t idx_start, u | |
5456 | idx_end = idx_start + npages - 1; | |
5457 | ||
5458 | next = idx_start; | |
5459 | - while (radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&req, next, 1, NFS_PAGE_TAG_WRITEBACK)) { | |
5460 | + while (radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&req, next, 1, NFS_PAGE_TAG_LOCKED)) { | |
5461 | if (req->wb_index > idx_end) | |
5462 | break; | |
5463 | ||
5464 | next = req->wb_index + 1; | |
5465 | BUG_ON(!NFS_WBACK_BUSY(req)); | |
5466 | ||
5467 | - atomic_inc(&req->wb_count); | |
5468 | - spin_unlock(&nfsi->req_lock); | |
5469 | + kref_get(&req->wb_kref); | |
5470 | + spin_unlock(&inode->i_lock); | |
5471 | error = nfs_wait_on_request(req); | |
5472 | nfs_release_request(req); | |
5473 | - spin_lock(&nfsi->req_lock); | |
5474 | + spin_lock(&inode->i_lock); | |
5475 | if (error < 0) | |
5476 | return error; | |
5477 | res++; | |
5478 | @@ -577,10 +577,9 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, u | |
5479 | int res = 0; | |
5480 | ||
5481 | if (nfsi->ncommit != 0) { | |
5482 | - res = nfs_scan_list(nfsi, &nfsi->commit, dst, idx_start, npages); | |
5483 | + res = nfs_scan_list(nfsi, dst, idx_start, npages, | |
5484 | + NFS_PAGE_TAG_COMMIT); | |
5485 | nfsi->ncommit -= res; | |
5486 | - if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit)) | |
5487 | - printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n"); | |
5488 | } | |
5489 | return res; | |
5490 | } | |
5491 | @@ -603,7 +602,6 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |
5492 | { | |
5493 | struct address_space *mapping = page->mapping; | |
5494 | struct inode *inode = mapping->host; | |
5495 | - struct nfs_inode *nfsi = NFS_I(inode); | |
5496 | struct nfs_page *req, *new = NULL; | |
5497 | pgoff_t rqend, end; | |
5498 | ||
5499 | @@ -613,13 +611,13 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |
5500 | /* Loop over all inode entries and see if we find | |
5501 | * A request for the page we wish to update | |
5502 | */ | |
5503 | - spin_lock(&nfsi->req_lock); | |
5504 | + spin_lock(&inode->i_lock); | |
5505 | req = nfs_page_find_request_locked(page); | |
5506 | if (req) { | |
5507 | if (!nfs_lock_request_dontget(req)) { | |
5508 | int error; | |
5509 | ||
5510 | - spin_unlock(&nfsi->req_lock); | |
5511 | + spin_unlock(&inode->i_lock); | |
5512 | error = nfs_wait_on_request(req); | |
5513 | nfs_release_request(req); | |
5514 | if (error < 0) { | |
5515 | @@ -629,7 +627,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |
5516 | } | |
5517 | continue; | |
5518 | } | |
5519 | - spin_unlock(&nfsi->req_lock); | |
5520 | + spin_unlock(&inode->i_lock); | |
5521 | if (new) | |
5522 | nfs_release_request(new); | |
5523 | break; | |
5524 | @@ -640,14 +638,14 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |
5525 | nfs_lock_request_dontget(new); | |
5526 | error = nfs_inode_add_request(inode, new); | |
5527 | if (error) { | |
5528 | - spin_unlock(&nfsi->req_lock); | |
5529 | + spin_unlock(&inode->i_lock); | |
5530 | nfs_unlock_request(new); | |
5531 | return ERR_PTR(error); | |
5532 | } | |
5533 | - spin_unlock(&nfsi->req_lock); | |
5534 | + spin_unlock(&inode->i_lock); | |
5535 | return new; | |
5536 | } | |
5537 | - spin_unlock(&nfsi->req_lock); | |
5538 | + spin_unlock(&inode->i_lock); | |
5539 | ||
5540 | new = nfs_create_request(ctx, inode, page, offset, bytes); | |
5541 | if (IS_ERR(new)) | |
5542 | @@ -751,12 +749,17 @@ int nfs_updatepage(struct file *file, struct page *page, | |
5543 | static void nfs_writepage_release(struct nfs_page *req) | |
5544 | { | |
5545 | ||
5546 | - if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) { | |
5547 | + if (PageError(req->wb_page)) { | |
5548 | + nfs_end_page_writeback(req->wb_page); | |
5549 | + nfs_inode_remove_request(req); | |
5550 | + } else if (!nfs_reschedule_unstable_write(req)) { | |
5551 | + /* Set the PG_uptodate flag */ | |
5552 | + nfs_mark_uptodate(req->wb_page, req->wb_pgbase, req->wb_bytes); | |
5553 | nfs_end_page_writeback(req->wb_page); | |
5554 | nfs_inode_remove_request(req); | |
5555 | } else | |
5556 | nfs_end_page_writeback(req->wb_page); | |
5557 | - nfs_clear_page_writeback(req); | |
5558 | + nfs_clear_page_tag_locked(req); | |
5559 | } | |
5560 | ||
5561 | static inline int flush_task_priority(int how) | |
5562 | @@ -786,7 +789,7 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |
5563 | * NB: take care not to mess about with data->commit et al. */ | |
5564 | ||
5565 | data->req = req; | |
5566 | - data->inode = inode = req->wb_context->dentry->d_inode; | |
5567 | + data->inode = inode = req->wb_context->path.dentry->d_inode; | |
5568 | data->cred = req->wb_context->cred; | |
5569 | ||
5570 | data->args.fh = NFS_FH(inode); | |
5571 | @@ -885,7 +888,7 @@ out_bad: | |
5572 | } | |
5573 | nfs_redirty_request(req); | |
5574 | nfs_end_page_writeback(req->wb_page); | |
5575 | - nfs_clear_page_writeback(req); | |
5576 | + nfs_clear_page_tag_locked(req); | |
5577 | return -ENOMEM; | |
5578 | } | |
5579 | ||
5580 | @@ -928,7 +931,7 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i | |
5581 | nfs_list_remove_request(req); | |
5582 | nfs_redirty_request(req); | |
5583 | nfs_end_page_writeback(req->wb_page); | |
5584 | - nfs_clear_page_writeback(req); | |
5585 | + nfs_clear_page_tag_locked(req); | |
5586 | } | |
5587 | return -ENOMEM; | |
5588 | } | |
5589 | @@ -954,8 +957,8 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) | |
5590 | struct page *page = req->wb_page; | |
5591 | ||
5592 | dprintk("NFS: write (%s/%Ld %d@%Ld)", | |
5593 | - req->wb_context->dentry->d_inode->i_sb->s_id, | |
5594 | - (long long)NFS_FILEID(req->wb_context->dentry->d_inode), | |
5595 | + req->wb_context->path.dentry->d_inode->i_sb->s_id, | |
5596 | + (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), | |
5597 | req->wb_bytes, | |
5598 | (long long)req_offset(req)); | |
5599 | ||
5600 | @@ -970,9 +973,9 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) | |
5601 | } | |
5602 | ||
5603 | if (nfs_write_need_commit(data)) { | |
5604 | - spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock; | |
5605 | + struct inode *inode = page->mapping->host; | |
5606 | ||
5607 | - spin_lock(req_lock); | |
5608 | + spin_lock(&inode->i_lock); | |
5609 | if (test_bit(PG_NEED_RESCHED, &req->wb_flags)) { | |
5610 | /* Do nothing we need to resend the writes */ | |
5611 | } else if (!test_and_set_bit(PG_NEED_COMMIT, &req->wb_flags)) { | |
5612 | @@ -983,7 +986,7 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) | |
5613 | clear_bit(PG_NEED_COMMIT, &req->wb_flags); | |
5614 | dprintk(" server reboot detected\n"); | |
5615 | } | |
5616 | - spin_unlock(req_lock); | |
5617 | + spin_unlock(&inode->i_lock); | |
5618 | } else | |
5619 | dprintk(" OK\n"); | |
5620 | ||
5621 | @@ -1020,8 +1023,8 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) | |
5622 | page = req->wb_page; | |
5623 | ||
5624 | dprintk("NFS: write (%s/%Ld %d@%Ld)", | |
5625 | - req->wb_context->dentry->d_inode->i_sb->s_id, | |
5626 | - (long long)NFS_FILEID(req->wb_context->dentry->d_inode), | |
5627 | + req->wb_context->path.dentry->d_inode->i_sb->s_id, | |
5628 | + (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), | |
5629 | req->wb_bytes, | |
5630 | (long long)req_offset(req)); | |
5631 | ||
5632 | @@ -1039,12 +1042,14 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) | |
5633 | dprintk(" marked for commit\n"); | |
5634 | goto next; | |
5635 | } | |
5636 | + /* Set the PG_uptodate flag? */ | |
5637 | + nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); | |
5638 | dprintk(" OK\n"); | |
5639 | remove_request: | |
5640 | nfs_end_page_writeback(page); | |
5641 | nfs_inode_remove_request(req); | |
5642 | next: | |
5643 | - nfs_clear_page_writeback(req); | |
5644 | + nfs_clear_page_tag_locked(req); | |
5645 | } | |
5646 | } | |
5647 | ||
5648 | @@ -1157,7 +1162,7 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |
5649 | ||
5650 | list_splice_init(head, &data->pages); | |
5651 | first = nfs_list_entry(data->pages.next); | |
5652 | - inode = first->wb_context->dentry->d_inode; | |
5653 | + inode = first->wb_context->path.dentry->d_inode; | |
5654 | ||
5655 | data->inode = inode; | |
5656 | data->cred = first->wb_context->cred; | |
5657 | @@ -1207,7 +1212,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |
5658 | nfs_list_remove_request(req); | |
5659 | nfs_mark_request_commit(req); | |
5660 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | |
5661 | - nfs_clear_page_writeback(req); | |
5662 | + nfs_clear_page_tag_locked(req); | |
5663 | } | |
5664 | return -ENOMEM; | |
5665 | } | |
5666 | @@ -1234,8 +1239,8 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |
5667 | dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | |
5668 | ||
5669 | dprintk("NFS: commit (%s/%Ld %d@%Ld)", | |
5670 | - req->wb_context->dentry->d_inode->i_sb->s_id, | |
5671 | - (long long)NFS_FILEID(req->wb_context->dentry->d_inode), | |
5672 | + req->wb_context->path.dentry->d_inode->i_sb->s_id, | |
5673 | + (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), | |
5674 | req->wb_bytes, | |
5675 | (long long)req_offset(req)); | |
5676 | if (task->tk_status < 0) { | |
5677 | @@ -1249,6 +1254,9 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |
5678 | * returned by the server against all stored verfs. */ | |
5679 | if (!memcmp(req->wb_verf.verifier, data->verf.verifier, sizeof(data->verf.verifier))) { | |
5680 | /* We have a match */ | |
5681 | + /* Set the PG_uptodate flag */ | |
5682 | + nfs_mark_uptodate(req->wb_page, req->wb_pgbase, | |
5683 | + req->wb_bytes); | |
5684 | nfs_inode_remove_request(req); | |
5685 | dprintk(" OK\n"); | |
5686 | goto next; | |
5687 | @@ -1257,7 +1265,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) | |
5688 | dprintk(" mismatch\n"); | |
5689 | nfs_redirty_request(req); | |
5690 | next: | |
5691 | - nfs_clear_page_writeback(req); | |
5692 | + nfs_clear_page_tag_locked(req); | |
5693 | } | |
5694 | } | |
5695 | ||
5696 | @@ -1268,13 +1276,12 @@ static const struct rpc_call_ops nfs_commit_ops = { | |
5697 | ||
5698 | int nfs_commit_inode(struct inode *inode, int how) | |
5699 | { | |
5700 | - struct nfs_inode *nfsi = NFS_I(inode); | |
5701 | LIST_HEAD(head); | |
5702 | int res; | |
5703 | ||
5704 | - spin_lock(&nfsi->req_lock); | |
5705 | + spin_lock(&inode->i_lock); | |
5706 | res = nfs_scan_commit(inode, &head, 0, 0); | |
5707 | - spin_unlock(&nfsi->req_lock); | |
5708 | + spin_unlock(&inode->i_lock); | |
5709 | if (res) { | |
5710 | int error = nfs_commit_list(inode, &head, how); | |
5711 | if (error < 0) | |
5712 | @@ -1292,7 +1299,6 @@ static inline int nfs_commit_list(struct inode *inode, struct list_head *head, i | |
5713 | long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_control *wbc, int how) | |
5714 | { | |
5715 | struct inode *inode = mapping->host; | |
5716 | - struct nfs_inode *nfsi = NFS_I(inode); | |
5717 | pgoff_t idx_start, idx_end; | |
5718 | unsigned int npages = 0; | |
5719 | LIST_HEAD(head); | |
5720 | @@ -1314,7 +1320,7 @@ long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_contr | |
5721 | } | |
5722 | } | |
5723 | how &= ~FLUSH_NOCOMMIT; | |
5724 | - spin_lock(&nfsi->req_lock); | |
5725 | + spin_lock(&inode->i_lock); | |
5726 | do { | |
5727 | ret = nfs_wait_on_requests_locked(inode, idx_start, npages); | |
5728 | if (ret != 0) | |
5729 | @@ -1325,18 +1331,19 @@ long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_contr | |
5730 | if (pages == 0) | |
5731 | break; | |
5732 | if (how & FLUSH_INVALIDATE) { | |
5733 | - spin_unlock(&nfsi->req_lock); | |
5734 | + spin_unlock(&inode->i_lock); | |
5735 | nfs_cancel_commit_list(&head); | |
5736 | ret = pages; | |
5737 | - spin_lock(&nfsi->req_lock); | |
5738 | + spin_lock(&inode->i_lock); | |
5739 | continue; | |
5740 | } | |
5741 | pages += nfs_scan_commit(inode, &head, 0, 0); | |
5742 | - spin_unlock(&nfsi->req_lock); | |
5743 | + spin_unlock(&inode->i_lock); | |
5744 | ret = nfs_commit_list(inode, &head, how); | |
5745 | - spin_lock(&nfsi->req_lock); | |
5746 | + spin_lock(&inode->i_lock); | |
5747 | + | |
5748 | } while (ret >= 0); | |
5749 | - spin_unlock(&nfsi->req_lock); | |
5750 | + spin_unlock(&inode->i_lock); | |
5751 | return ret; | |
5752 | } | |
5753 | ||
5754 | @@ -1430,7 +1437,6 @@ int nfs_set_page_dirty(struct page *page) | |
5755 | { | |
5756 | struct address_space *mapping = page->mapping; | |
5757 | struct inode *inode; | |
5758 | - spinlock_t *req_lock; | |
5759 | struct nfs_page *req; | |
5760 | int ret; | |
5761 | ||
5762 | @@ -1439,18 +1445,17 @@ int nfs_set_page_dirty(struct page *page) | |
5763 | inode = mapping->host; | |
5764 | if (!inode) | |
5765 | goto out_raced; | |
5766 | - req_lock = &NFS_I(inode)->req_lock; | |
5767 | - spin_lock(req_lock); | |
5768 | + spin_lock(&inode->i_lock); | |
5769 | req = nfs_page_find_request_locked(page); | |
5770 | if (req != NULL) { | |
5771 | /* Mark any existing write requests for flushing */ | |
5772 | ret = !test_and_set_bit(PG_NEED_FLUSH, &req->wb_flags); | |
5773 | - spin_unlock(req_lock); | |
5774 | + spin_unlock(&inode->i_lock); | |
5775 | nfs_release_request(req); | |
5776 | return ret; | |
5777 | } | |
5778 | ret = __set_page_dirty_nobuffers(page); | |
5779 | - spin_unlock(req_lock); | |
5780 | + spin_unlock(&inode->i_lock); | |
5781 | return ret; | |
5782 | out_raced: | |
5783 | return !TestSetPageDirty(page); | |
5784 | diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c | |
5785 | index 864090e..5443c52 100644 | |
5786 | --- a/fs/nfsd/nfs4callback.c | |
5787 | +++ b/fs/nfsd/nfs4callback.c | |
5788 | @@ -394,7 +394,6 @@ nfsd4_probe_callback(struct nfs4_client *clp) | |
5789 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], | |
5790 | .rpc_argp = clp, | |
5791 | }; | |
5792 | - char clientname[16]; | |
5793 | int status; | |
5794 | ||
5795 | if (atomic_read(&cb->cb_set)) | |
5796 | @@ -417,11 +416,6 @@ nfsd4_probe_callback(struct nfs4_client *clp) | |
5797 | memset(program->stats, 0, sizeof(cb->cb_stat)); | |
5798 | program->stats->program = program; | |
5799 | ||
5800 | - /* Just here to make some printk's more useful: */ | |
5801 | - snprintf(clientname, sizeof(clientname), | |
5802 | - "%u.%u.%u.%u", NIPQUAD(addr.sin_addr)); | |
5803 | - args.servername = clientname; | |
5804 | - | |
5805 | /* Create RPC client */ | |
5806 | cb->cb_client = rpc_create(&args); | |
5807 | if (IS_ERR(cb->cb_client)) { | |
5808 | @@ -429,29 +423,23 @@ nfsd4_probe_callback(struct nfs4_client *clp) | |
5809 | goto out_err; | |
5810 | } | |
5811 | ||
5812 | - /* Kick rpciod, put the call on the wire. */ | |
5813 | - if (rpciod_up() != 0) | |
5814 | - goto out_clnt; | |
5815 | - | |
5816 | /* the task holds a reference to the nfs4_client struct */ | |
5817 | atomic_inc(&clp->cl_count); | |
5818 | ||
5819 | msg.rpc_cred = nfsd4_lookupcred(clp,0); | |
5820 | if (IS_ERR(msg.rpc_cred)) | |
5821 | - goto out_rpciod; | |
5822 | + goto out_release_clp; | |
5823 | status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL); | |
5824 | put_rpccred(msg.rpc_cred); | |
5825 | ||
5826 | if (status != 0) { | |
5827 | dprintk("NFSD: asynchronous NFSPROC4_CB_NULL failed!\n"); | |
5828 | - goto out_rpciod; | |
5829 | + goto out_release_clp; | |
5830 | } | |
5831 | return; | |
5832 | ||
5833 | -out_rpciod: | |
5834 | +out_release_clp: | |
5835 | atomic_dec(&clp->cl_count); | |
5836 | - rpciod_down(); | |
5837 | -out_clnt: | |
5838 | rpc_shutdown_client(cb->cb_client); | |
5839 | out_err: | |
5840 | cb->cb_client = NULL; | |
5841 | diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c | |
5842 | index 3cc8ce4..8c52913 100644 | |
5843 | --- a/fs/nfsd/nfs4state.c | |
5844 | +++ b/fs/nfsd/nfs4state.c | |
5845 | @@ -378,7 +378,6 @@ shutdown_callback_client(struct nfs4_client *clp) | |
5846 | if (clnt) { | |
5847 | clp->cl_callback.cb_client = NULL; | |
5848 | rpc_shutdown_client(clnt); | |
5849 | - rpciod_down(); | |
5850 | } | |
5851 | } | |
5852 | ||
5853 | diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h | |
5854 | index 05707e2..e2d1ce3 100644 | |
5855 | --- a/include/linux/lockd/lockd.h | |
5856 | +++ b/include/linux/lockd/lockd.h | |
5857 | @@ -39,6 +39,7 @@ | |
5858 | struct nlm_host { | |
5859 | struct hlist_node h_hash; /* doubly linked list */ | |
5860 | struct sockaddr_in h_addr; /* peer address */ | |
5861 | + struct sockaddr_in h_saddr; /* our address (optional) */ | |
5862 | struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */ | |
5863 | char * h_name; /* remote hostname */ | |
5864 | u32 h_version; /* interface version */ | |
5865 | diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h | |
5866 | index 7e7f33a..8726491 100644 | |
5867 | --- a/include/linux/nfs4.h | |
5868 | +++ b/include/linux/nfs4.h | |
5869 | @@ -15,6 +15,7 @@ | |
5870 | ||
5871 | #include <linux/types.h> | |
5872 | ||
5873 | +#define NFS4_BITMAP_SIZE 2 | |
5874 | #define NFS4_VERIFIER_SIZE 8 | |
5875 | #define NFS4_STATEID_SIZE 16 | |
5876 | #define NFS4_FHSIZE 128 | |
5877 | diff --git a/include/linux/nfs4_mount.h b/include/linux/nfs4_mount.h | |
5878 | index 26b4c83..a0dcf66 100644 | |
5879 | --- a/include/linux/nfs4_mount.h | |
5880 | +++ b/include/linux/nfs4_mount.h | |
5881 | @@ -65,6 +65,7 @@ struct nfs4_mount_data { | |
5882 | #define NFS4_MOUNT_NOCTO 0x0010 /* 1 */ | |
5883 | #define NFS4_MOUNT_NOAC 0x0020 /* 1 */ | |
5884 | #define NFS4_MOUNT_STRICTLOCK 0x1000 /* 1 */ | |
5885 | -#define NFS4_MOUNT_FLAGMASK 0xFFFF | |
5886 | +#define NFS4_MOUNT_UNSHARED 0x8000 /* 1 */ | |
5887 | +#define NFS4_MOUNT_FLAGMASK 0x9033 | |
5888 | ||
5889 | #endif | |
5890 | diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h | |
5891 | index 0543439..c098ae1 100644 | |
5892 | --- a/include/linux/nfs_fs.h | |
5893 | +++ b/include/linux/nfs_fs.h | |
5894 | @@ -30,7 +30,9 @@ | |
5895 | #ifdef __KERNEL__ | |
5896 | ||
5897 | #include <linux/in.h> | |
5898 | +#include <linux/kref.h> | |
5899 | #include <linux/mm.h> | |
5900 | +#include <linux/namei.h> | |
5901 | #include <linux/pagemap.h> | |
5902 | #include <linux/rbtree.h> | |
5903 | #include <linux/rwsem.h> | |
5904 | @@ -69,9 +71,8 @@ struct nfs_access_entry { | |
5905 | ||
5906 | struct nfs4_state; | |
5907 | struct nfs_open_context { | |
5908 | - atomic_t count; | |
5909 | - struct vfsmount *vfsmnt; | |
5910 | - struct dentry *dentry; | |
5911 | + struct kref kref; | |
5912 | + struct path path; | |
5913 | struct rpc_cred *cred; | |
5914 | struct nfs4_state *state; | |
5915 | fl_owner_t lockowner; | |
5916 | @@ -155,13 +156,9 @@ struct nfs_inode { | |
5917 | /* | |
5918 | * This is the list of dirty unwritten pages. | |
5919 | */ | |
5920 | - spinlock_t req_lock; | |
5921 | - struct list_head dirty; | |
5922 | - struct list_head commit; | |
5923 | struct radix_tree_root nfs_page_tree; | |
5924 | ||
5925 | - unsigned int ndirty, | |
5926 | - ncommit, | |
5927 | + unsigned long ncommit, | |
5928 | npages; | |
5929 | ||
5930 | /* Open contexts for shared mmap writes */ | |
5931 | @@ -187,6 +184,7 @@ struct nfs_inode { | |
5932 | #define NFS_INO_INVALID_ACCESS 0x0008 /* cached access cred invalid */ | |
5933 | #define NFS_INO_INVALID_ACL 0x0010 /* cached acls are invalid */ | |
5934 | #define NFS_INO_REVAL_PAGECACHE 0x0020 /* must revalidate pagecache */ | |
5935 | +#define NFS_INO_REVAL_FORCED 0x0040 /* force revalidation ignoring a delegation */ | |
5936 | ||
5937 | /* | |
5938 | * Bit offsets in flags field | |
5939 | @@ -496,21 +494,18 @@ static inline void nfs3_forget_cached_acls(struct inode *inode) | |
5940 | ||
5941 | /* | |
5942 | * linux/fs/mount_clnt.c | |
5943 | - * (Used only by nfsroot module) | |
5944 | */ | |
5945 | -extern int nfsroot_mount(struct sockaddr_in *, char *, struct nfs_fh *, | |
5946 | - int, int); | |
5947 | +extern int nfs_mount(struct sockaddr *, size_t, char *, char *, | |
5948 | + int, int, struct nfs_fh *); | |
5949 | ||
5950 | /* | |
5951 | * inline functions | |
5952 | */ | |
5953 | ||
5954 | -static inline loff_t | |
5955 | -nfs_size_to_loff_t(__u64 size) | |
5956 | +static inline loff_t nfs_size_to_loff_t(__u64 size) | |
5957 | { | |
5958 | - loff_t maxsz = (((loff_t) ULONG_MAX) << PAGE_CACHE_SHIFT) + PAGE_CACHE_SIZE - 1; | |
5959 | - if (size > maxsz) | |
5960 | - return maxsz; | |
5961 | + if (size > (__u64) OFFSET_MAX - 1) | |
5962 | + return OFFSET_MAX - 1; | |
5963 | return (loff_t) size; | |
5964 | } | |
5965 | ||
5966 | @@ -557,6 +552,7 @@ extern void * nfs_root_data(void); | |
5967 | #define NFSDBG_ROOT 0x0080 | |
5968 | #define NFSDBG_CALLBACK 0x0100 | |
5969 | #define NFSDBG_CLIENT 0x0200 | |
5970 | +#define NFSDBG_MOUNT 0x0400 | |
5971 | #define NFSDBG_ALL 0xFFFF | |
5972 | ||
5973 | #ifdef __KERNEL__ | |
5974 | diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h | |
5975 | index 52b4378..0cac49b 100644 | |
5976 | --- a/include/linux/nfs_fs_sb.h | |
5977 | +++ b/include/linux/nfs_fs_sb.h | |
5978 | @@ -16,7 +16,6 @@ struct nfs_client { | |
5979 | #define NFS_CS_INITING 1 /* busy initialising */ | |
5980 | int cl_nfsversion; /* NFS protocol version */ | |
5981 | unsigned long cl_res_state; /* NFS resources state */ | |
5982 | -#define NFS_CS_RPCIOD 0 /* - rpciod started */ | |
5983 | #define NFS_CS_CALLBACK 1 /* - callback started */ | |
5984 | #define NFS_CS_IDMAP 2 /* - idmap started */ | |
5985 | #define NFS_CS_RENEWD 3 /* - renewd started */ | |
5986 | @@ -35,7 +34,8 @@ struct nfs_client { | |
5987 | nfs4_verifier cl_confirm; | |
5988 | unsigned long cl_state; | |
5989 | ||
5990 | - u32 cl_lockowner_id; | |
5991 | + struct rb_root cl_openowner_id; | |
5992 | + struct rb_root cl_lockowner_id; | |
5993 | ||
5994 | /* | |
5995 | * The following rwsem ensures exclusive access to the server | |
5996 | @@ -44,9 +44,7 @@ struct nfs_client { | |
5997 | struct rw_semaphore cl_sem; | |
5998 | ||
5999 | struct list_head cl_delegations; | |
6000 | - struct list_head cl_state_owners; | |
6001 | - struct list_head cl_unused; | |
6002 | - int cl_nunused; | |
6003 | + struct rb_root cl_state_owners; | |
6004 | spinlock_t cl_lock; | |
6005 | ||
6006 | unsigned long cl_lease_time; | |
6007 | diff --git a/include/linux/nfs_mount.h b/include/linux/nfs_mount.h | |
6008 | index cc8b9c5..a3ade89 100644 | |
6009 | --- a/include/linux/nfs_mount.h | |
6010 | +++ b/include/linux/nfs_mount.h | |
6011 | @@ -37,7 +37,7 @@ struct nfs_mount_data { | |
6012 | int acdirmin; /* 1 */ | |
6013 | int acdirmax; /* 1 */ | |
6014 | struct sockaddr_in addr; /* 1 */ | |
6015 | - char hostname[256]; /* 1 */ | |
6016 | + char hostname[NFS_MAXNAMLEN + 1]; /* 1 */ | |
6017 | int namlen; /* 2 */ | |
6018 | unsigned int bsize; /* 3 */ | |
6019 | struct nfs3_fh root; /* 4 */ | |
6020 | @@ -62,6 +62,7 @@ struct nfs_mount_data { | |
6021 | #define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */ | |
6022 | #define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */ | |
6023 | #define NFS_MOUNT_NORDIRPLUS 0x4000 /* 5 */ | |
6024 | +#define NFS_MOUNT_UNSHARED 0x8000 /* 5 */ | |
6025 | #define NFS_MOUNT_FLAGMASK 0xFFFF | |
6026 | ||
6027 | #endif | |
6028 | diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h | |
6029 | index bd193af..78e6079 100644 | |
6030 | --- a/include/linux/nfs_page.h | |
6031 | +++ b/include/linux/nfs_page.h | |
6032 | @@ -16,12 +16,13 @@ | |
6033 | #include <linux/sunrpc/auth.h> | |
6034 | #include <linux/nfs_xdr.h> | |
6035 | ||
6036 | -#include <asm/atomic.h> | |
6037 | +#include <linux/kref.h> | |
6038 | ||
6039 | /* | |
6040 | * Valid flags for the radix tree | |
6041 | */ | |
6042 | -#define NFS_PAGE_TAG_WRITEBACK 0 | |
6043 | +#define NFS_PAGE_TAG_LOCKED 0 | |
6044 | +#define NFS_PAGE_TAG_COMMIT 1 | |
6045 | ||
6046 | /* | |
6047 | * Valid flags for a dirty buffer | |
6048 | @@ -33,8 +34,7 @@ | |
6049 | ||
6050 | struct nfs_inode; | |
6051 | struct nfs_page { | |
6052 | - struct list_head wb_list, /* Defines state of page: */ | |
6053 | - *wb_list_head; /* read/write/commit */ | |
6054 | + struct list_head wb_list; /* Defines state of page: */ | |
6055 | struct page *wb_page; /* page to read in/write out */ | |
6056 | struct nfs_open_context *wb_context; /* File state context info */ | |
6057 | atomic_t wb_complete; /* i/os we're waiting for */ | |
6058 | @@ -42,7 +42,7 @@ struct nfs_page { | |
6059 | unsigned int wb_offset, /* Offset & ~PAGE_CACHE_MASK */ | |
6060 | wb_pgbase, /* Start of page data */ | |
6061 | wb_bytes; /* Length of request */ | |
6062 | - atomic_t wb_count; /* reference count */ | |
6063 | + struct kref wb_kref; /* reference count */ | |
6064 | unsigned long wb_flags; | |
6065 | struct nfs_writeverf wb_verf; /* Commit cookie */ | |
6066 | }; | |
6067 | @@ -71,8 +71,8 @@ extern void nfs_clear_request(struct nfs_page *req); | |
6068 | extern void nfs_release_request(struct nfs_page *req); | |
6069 | ||
6070 | ||
6071 | -extern int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, struct list_head *dst, | |
6072 | - pgoff_t idx_start, unsigned int npages); | |
6073 | +extern int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *dst, | |
6074 | + pgoff_t idx_start, unsigned int npages, int tag); | |
6075 | extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc, | |
6076 | struct inode *inode, | |
6077 | int (*doio)(struct inode *, struct list_head *, unsigned int, size_t, int), | |
6078 | @@ -84,12 +84,11 @@ extern void nfs_pageio_complete(struct nfs_pageio_descriptor *desc); | |
6079 | extern void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *, pgoff_t); | |
6080 | extern int nfs_wait_on_request(struct nfs_page *); | |
6081 | extern void nfs_unlock_request(struct nfs_page *req); | |
6082 | -extern int nfs_set_page_writeback_locked(struct nfs_page *req); | |
6083 | -extern void nfs_clear_page_writeback(struct nfs_page *req); | |
6084 | +extern void nfs_clear_page_tag_locked(struct nfs_page *req); | |
6085 | ||
6086 | ||
6087 | /* | |
6088 | - * Lock the page of an asynchronous request without incrementing the wb_count | |
6089 | + * Lock the page of an asynchronous request without getting a new reference | |
6090 | */ | |
6091 | static inline int | |
6092 | nfs_lock_request_dontget(struct nfs_page *req) | |
6093 | @@ -98,14 +97,14 @@ nfs_lock_request_dontget(struct nfs_page *req) | |
6094 | } | |
6095 | ||
6096 | /* | |
6097 | - * Lock the page of an asynchronous request | |
6098 | + * Lock the page of an asynchronous request and take a reference | |
6099 | */ | |
6100 | static inline int | |
6101 | nfs_lock_request(struct nfs_page *req) | |
6102 | { | |
6103 | if (test_and_set_bit(PG_BUSY, &req->wb_flags)) | |
6104 | return 0; | |
6105 | - atomic_inc(&req->wb_count); | |
6106 | + kref_get(&req->wb_kref); | |
6107 | return 1; | |
6108 | } | |
6109 | ||
6110 | @@ -118,7 +117,6 @@ static inline void | |
6111 | nfs_list_add_request(struct nfs_page *req, struct list_head *head) | |
6112 | { | |
6113 | list_add_tail(&req->wb_list, head); | |
6114 | - req->wb_list_head = head; | |
6115 | } | |
6116 | ||
6117 | ||
6118 | @@ -132,7 +130,6 @@ nfs_list_remove_request(struct nfs_page *req) | |
6119 | if (list_empty(&req->wb_list)) | |
6120 | return; | |
6121 | list_del_init(&req->wb_list); | |
6122 | - req->wb_list_head = NULL; | |
6123 | } | |
6124 | ||
6125 | static inline struct nfs_page * | |
6126 | diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h | |
6127 | index 10c26ed..38d7768 100644 | |
6128 | --- a/include/linux/nfs_xdr.h | |
6129 | +++ b/include/linux/nfs_xdr.h | |
6130 | @@ -119,7 +119,7 @@ struct nfs_openargs { | |
6131 | struct nfs_seqid * seqid; | |
6132 | int open_flags; | |
6133 | __u64 clientid; | |
6134 | - __u32 id; | |
6135 | + __u64 id; | |
6136 | union { | |
6137 | struct iattr * attrs; /* UNCHECKED, GUARDED */ | |
6138 | nfs4_verifier verifier; /* EXCLUSIVE */ | |
6139 | @@ -144,6 +144,7 @@ struct nfs_openres { | |
6140 | nfs4_stateid delegation; | |
6141 | __u32 do_recall; | |
6142 | __u64 maxsize; | |
6143 | + __u32 attrset[NFS4_BITMAP_SIZE]; | |
6144 | }; | |
6145 | ||
6146 | /* | |
6147 | @@ -180,7 +181,7 @@ struct nfs_closeres { | |
6148 | * */ | |
6149 | struct nfs_lowner { | |
6150 | __u64 clientid; | |
6151 | - u32 id; | |
6152 | + __u64 id; | |
6153 | }; | |
6154 | ||
6155 | struct nfs_lock_args { | |
6156 | diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h | |
6157 | index 534cdc7..7a69ca3 100644 | |
6158 | --- a/include/linux/sunrpc/auth.h | |
6159 | +++ b/include/linux/sunrpc/auth.h | |
6160 | @@ -16,6 +16,7 @@ | |
6161 | #include <linux/sunrpc/xdr.h> | |
6162 | ||
6163 | #include <asm/atomic.h> | |
6164 | +#include <linux/rcupdate.h> | |
6165 | ||
6166 | /* size of the nodename buffer */ | |
6167 | #define UNX_MAXNODENAME 32 | |
6168 | @@ -30,22 +31,28 @@ struct auth_cred { | |
6169 | /* | |
6170 | * Client user credentials | |
6171 | */ | |
6172 | +struct rpc_auth; | |
6173 | +struct rpc_credops; | |
6174 | struct rpc_cred { | |
6175 | struct hlist_node cr_hash; /* hash chain */ | |
6176 | - struct rpc_credops * cr_ops; | |
6177 | - unsigned long cr_expire; /* when to gc */ | |
6178 | - atomic_t cr_count; /* ref count */ | |
6179 | - unsigned short cr_flags; /* various flags */ | |
6180 | + struct list_head cr_lru; /* lru garbage collection */ | |
6181 | + struct rcu_head cr_rcu; | |
6182 | + struct rpc_auth * cr_auth; | |
6183 | + const struct rpc_credops *cr_ops; | |
6184 | #ifdef RPC_DEBUG | |
6185 | unsigned long cr_magic; /* 0x0f4aa4f0 */ | |
6186 | #endif | |
6187 | + unsigned long cr_expire; /* when to gc */ | |
6188 | + unsigned long cr_flags; /* various flags */ | |
6189 | + atomic_t cr_count; /* ref count */ | |
6190 | ||
6191 | uid_t cr_uid; | |
6192 | ||
6193 | /* per-flavor data */ | |
6194 | }; | |
6195 | -#define RPCAUTH_CRED_NEW 0x0001 | |
6196 | -#define RPCAUTH_CRED_UPTODATE 0x0002 | |
6197 | +#define RPCAUTH_CRED_NEW 0 | |
6198 | +#define RPCAUTH_CRED_UPTODATE 1 | |
6199 | +#define RPCAUTH_CRED_HASHED 2 | |
6200 | ||
6201 | #define RPCAUTH_CRED_MAGIC 0x0f4aa4f0 | |
6202 | ||
6203 | @@ -56,10 +63,10 @@ struct rpc_cred { | |
6204 | #define RPC_CREDCACHE_MASK (RPC_CREDCACHE_NR - 1) | |
6205 | struct rpc_cred_cache { | |
6206 | struct hlist_head hashtable[RPC_CREDCACHE_NR]; | |
6207 | - unsigned long nextgc; /* next garbage collection */ | |
6208 | - unsigned long expire; /* cache expiry interval */ | |
6209 | + spinlock_t lock; | |
6210 | }; | |
6211 | ||
6212 | +struct rpc_authops; | |
6213 | struct rpc_auth { | |
6214 | unsigned int au_cslack; /* call cred size estimate */ | |
6215 | /* guess at number of u32's auth adds before | |
6216 | @@ -69,7 +76,7 @@ struct rpc_auth { | |
6217 | unsigned int au_verfsize; | |
6218 | ||
6219 | unsigned int au_flags; /* various flags */ | |
6220 | - struct rpc_authops * au_ops; /* operations */ | |
6221 | + const struct rpc_authops *au_ops; /* operations */ | |
6222 | rpc_authflavor_t au_flavor; /* pseudoflavor (note may | |
6223 | * differ from the flavor in | |
6224 | * au_ops->au_flavor in gss | |
6225 | @@ -115,17 +122,19 @@ struct rpc_credops { | |
6226 | void *, __be32 *, void *); | |
6227 | }; | |
6228 | ||
6229 | -extern struct rpc_authops authunix_ops; | |
6230 | -extern struct rpc_authops authnull_ops; | |
6231 | -#ifdef CONFIG_SUNRPC_SECURE | |
6232 | -extern struct rpc_authops authdes_ops; | |
6233 | -#endif | |
6234 | +extern const struct rpc_authops authunix_ops; | |
6235 | +extern const struct rpc_authops authnull_ops; | |
6236 | + | |
6237 | +void __init rpc_init_authunix(void); | |
6238 | +void __init rpcauth_init_module(void); | |
6239 | +void __exit rpcauth_remove_module(void); | |
6240 | ||
6241 | -int rpcauth_register(struct rpc_authops *); | |
6242 | -int rpcauth_unregister(struct rpc_authops *); | |
6243 | +int rpcauth_register(const struct rpc_authops *); | |
6244 | +int rpcauth_unregister(const struct rpc_authops *); | |
6245 | struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *); | |
6246 | -void rpcauth_destroy(struct rpc_auth *); | |
6247 | +void rpcauth_release(struct rpc_auth *); | |
6248 | struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int); | |
6249 | +void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *); | |
6250 | struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int); | |
6251 | struct rpc_cred * rpcauth_bindcred(struct rpc_task *); | |
6252 | void rpcauth_holdcred(struct rpc_task *); | |
6253 | @@ -138,8 +147,9 @@ int rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, | |
6254 | int rpcauth_refreshcred(struct rpc_task *); | |
6255 | void rpcauth_invalcred(struct rpc_task *); | |
6256 | int rpcauth_uptodatecred(struct rpc_task *); | |
6257 | -int rpcauth_init_credcache(struct rpc_auth *, unsigned long); | |
6258 | -void rpcauth_free_credcache(struct rpc_auth *); | |
6259 | +int rpcauth_init_credcache(struct rpc_auth *); | |
6260 | +void rpcauth_destroy_credcache(struct rpc_auth *); | |
6261 | +void rpcauth_clear_credcache(struct rpc_cred_cache *); | |
6262 | ||
6263 | static inline | |
6264 | struct rpc_cred * get_rpccred(struct rpc_cred *cred) | |
6265 | diff --git a/include/linux/sunrpc/auth_gss.h b/include/linux/sunrpc/auth_gss.h | |
6266 | index 2db2fbf..67658e1 100644 | |
6267 | --- a/include/linux/sunrpc/auth_gss.h | |
6268 | +++ b/include/linux/sunrpc/auth_gss.h | |
6269 | @@ -75,6 +75,7 @@ struct gss_cl_ctx { | |
6270 | struct xdr_netobj gc_wire_ctx; | |
6271 | u32 gc_win; | |
6272 | unsigned long gc_expiry; | |
6273 | + struct rcu_head gc_rcu; | |
6274 | }; | |
6275 | ||
6276 | struct gss_upcall_msg; | |
6277 | @@ -85,11 +86,6 @@ struct gss_cred { | |
6278 | struct gss_upcall_msg *gc_upcall; | |
6279 | }; | |
6280 | ||
6281 | -#define gc_uid gc_base.cr_uid | |
6282 | -#define gc_count gc_base.cr_count | |
6283 | -#define gc_flags gc_base.cr_flags | |
6284 | -#define gc_expire gc_base.cr_expire | |
6285 | - | |
6286 | #endif /* __KERNEL__ */ | |
6287 | #endif /* _LINUX_SUNRPC_AUTH_GSS_H */ | |
6288 | ||
6289 | diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h | |
6290 | index 6661142..c0d9d14 100644 | |
6291 | --- a/include/linux/sunrpc/clnt.h | |
6292 | +++ b/include/linux/sunrpc/clnt.h | |
6293 | @@ -24,8 +24,10 @@ struct rpc_inode; | |
6294 | * The high-level client handle | |
6295 | */ | |
6296 | struct rpc_clnt { | |
6297 | - atomic_t cl_count; /* Number of clones */ | |
6298 | - atomic_t cl_users; /* number of references */ | |
6299 | + struct kref cl_kref; /* Number of references */ | |
6300 | + struct list_head cl_clients; /* Global list of clients */ | |
6301 | + struct list_head cl_tasks; /* List of tasks */ | |
6302 | + spinlock_t cl_lock; /* spinlock */ | |
6303 | struct rpc_xprt * cl_xprt; /* transport */ | |
6304 | struct rpc_procinfo * cl_procinfo; /* procedure info */ | |
6305 | u32 cl_prog, /* RPC program number */ | |
6306 | @@ -41,9 +43,7 @@ struct rpc_clnt { | |
6307 | unsigned int cl_softrtry : 1,/* soft timeouts */ | |
6308 | cl_intr : 1,/* interruptible */ | |
6309 | cl_discrtry : 1,/* disconnect before retry */ | |
6310 | - cl_autobind : 1,/* use getport() */ | |
6311 | - cl_oneshot : 1,/* dispose after use */ | |
6312 | - cl_dead : 1;/* abandoned */ | |
6313 | + cl_autobind : 1;/* use getport() */ | |
6314 | ||
6315 | struct rpc_rtt * cl_rtt; /* RTO estimator data */ | |
6316 | ||
6317 | @@ -98,6 +98,7 @@ struct rpc_create_args { | |
6318 | int protocol; | |
6319 | struct sockaddr *address; | |
6320 | size_t addrsize; | |
6321 | + struct sockaddr *saddress; | |
6322 | struct rpc_timeout *timeout; | |
6323 | char *servername; | |
6324 | struct rpc_program *program; | |
6325 | @@ -110,20 +111,20 @@ struct rpc_create_args { | |
6326 | #define RPC_CLNT_CREATE_HARDRTRY (1UL << 0) | |
6327 | #define RPC_CLNT_CREATE_INTR (1UL << 1) | |
6328 | #define RPC_CLNT_CREATE_AUTOBIND (1UL << 2) | |
6329 | -#define RPC_CLNT_CREATE_ONESHOT (1UL << 3) | |
6330 | -#define RPC_CLNT_CREATE_NONPRIVPORT (1UL << 4) | |
6331 | -#define RPC_CLNT_CREATE_NOPING (1UL << 5) | |
6332 | -#define RPC_CLNT_CREATE_DISCRTRY (1UL << 6) | |
6333 | +#define RPC_CLNT_CREATE_NONPRIVPORT (1UL << 3) | |
6334 | +#define RPC_CLNT_CREATE_NOPING (1UL << 4) | |
6335 | +#define RPC_CLNT_CREATE_DISCRTRY (1UL << 5) | |
6336 | ||
6337 | struct rpc_clnt *rpc_create(struct rpc_create_args *args); | |
6338 | struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, | |
6339 | struct rpc_program *, int); | |
6340 | struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); | |
6341 | -int rpc_shutdown_client(struct rpc_clnt *); | |
6342 | -int rpc_destroy_client(struct rpc_clnt *); | |
6343 | +void rpc_shutdown_client(struct rpc_clnt *); | |
6344 | void rpc_release_client(struct rpc_clnt *); | |
6345 | + | |
6346 | int rpcb_register(u32, u32, int, unsigned short, int *); | |
6347 | -void rpcb_getport(struct rpc_task *); | |
6348 | +int rpcb_getport_sync(struct sockaddr_in *, __u32, __u32, int); | |
6349 | +void rpcb_getport_async(struct rpc_task *); | |
6350 | ||
6351 | void rpc_call_setup(struct rpc_task *, struct rpc_message *, int); | |
6352 | ||
6353 | @@ -132,20 +133,16 @@ int rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, | |
6354 | void *calldata); | |
6355 | int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, | |
6356 | int flags); | |
6357 | +struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, | |
6358 | + int flags); | |
6359 | void rpc_restart_call(struct rpc_task *); | |
6360 | void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset); | |
6361 | void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset); | |
6362 | void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); | |
6363 | size_t rpc_max_payload(struct rpc_clnt *); | |
6364 | void rpc_force_rebind(struct rpc_clnt *); | |
6365 | -int rpc_ping(struct rpc_clnt *clnt, int flags); | |
6366 | size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); | |
6367 | char * rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t); | |
6368 | ||
6369 | -/* | |
6370 | - * Helper function for NFSroot support | |
6371 | - */ | |
6372 | -int rpcb_getport_external(struct sockaddr_in *, __u32, __u32, int); | |
6373 | - | |
6374 | #endif /* __KERNEL__ */ | |
6375 | #endif /* _LINUX_SUNRPC_CLNT_H */ | |
6376 | diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h | |
6377 | index 5eca9e4..bbac101 100644 | |
6378 | --- a/include/linux/sunrpc/gss_api.h | |
6379 | +++ b/include/linux/sunrpc/gss_api.h | |
6380 | @@ -77,7 +77,7 @@ struct gss_api_mech { | |
6381 | struct module *gm_owner; | |
6382 | struct xdr_netobj gm_oid; | |
6383 | char *gm_name; | |
6384 | - struct gss_api_ops *gm_ops; | |
6385 | + const struct gss_api_ops *gm_ops; | |
6386 | /* pseudoflavors supported by this mechanism: */ | |
6387 | int gm_pf_num; | |
6388 | struct pf_desc * gm_pfs; | |
6389 | diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h | |
6390 | index ad29376..51b977a 100644 | |
6391 | --- a/include/linux/sunrpc/rpc_pipe_fs.h | |
6392 | +++ b/include/linux/sunrpc/rpc_pipe_fs.h | |
6393 | @@ -23,9 +23,11 @@ struct rpc_inode { | |
6394 | void *private; | |
6395 | struct list_head pipe; | |
6396 | struct list_head in_upcall; | |
6397 | + struct list_head in_downcall; | |
6398 | int pipelen; | |
6399 | int nreaders; | |
6400 | int nwriters; | |
6401 | + int nkern_readwriters; | |
6402 | wait_queue_head_t waitq; | |
6403 | #define RPC_PIPE_WAIT_FOR_OPEN 1 | |
6404 | int flags; | |
6405 | diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h | |
6406 | index 2047fb2..8ea077d 100644 | |
6407 | --- a/include/linux/sunrpc/sched.h | |
6408 | +++ b/include/linux/sunrpc/sched.h | |
6409 | @@ -98,7 +98,6 @@ struct rpc_task { | |
6410 | unsigned short tk_pid; /* debugging aid */ | |
6411 | #endif | |
6412 | }; | |
6413 | -#define tk_auth tk_client->cl_auth | |
6414 | #define tk_xprt tk_client->cl_xprt | |
6415 | ||
6416 | /* support walking a list of tasks on a wait queue */ | |
6417 | @@ -110,11 +109,6 @@ struct rpc_task { | |
6418 | if (!list_empty(head) && \ | |
6419 | ((task=list_entry((head)->next, struct rpc_task, u.tk_wait.list)),1)) | |
6420 | ||
6421 | -/* .. and walking list of all tasks */ | |
6422 | -#define alltask_for_each(task, pos, head) \ | |
6423 | - list_for_each(pos, head) \ | |
6424 | - if ((task=list_entry(pos, struct rpc_task, tk_task)),1) | |
6425 | - | |
6426 | typedef void (*rpc_action)(struct rpc_task *); | |
6427 | ||
6428 | struct rpc_call_ops { | |
6429 | diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h | |
6430 | index e21dd93..a53e0fa 100644 | |
6431 | --- a/include/linux/sunrpc/svcsock.h | |
6432 | +++ b/include/linux/sunrpc/svcsock.h | |
6433 | @@ -59,6 +59,7 @@ struct svc_sock { | |
6434 | /* cache of various info for TCP sockets */ | |
6435 | void *sk_info_authunix; | |
6436 | ||
6437 | + struct sockaddr_storage sk_local; /* local address */ | |
6438 | struct sockaddr_storage sk_remote; /* remote peer's address */ | |
6439 | int sk_remotelen; /* length of address */ | |
6440 | }; | |
6441 | diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h | |
6442 | index 34f7590..d11cedd 100644 | |
6443 | --- a/include/linux/sunrpc/xprt.h | |
6444 | +++ b/include/linux/sunrpc/xprt.h | |
6445 | @@ -17,6 +17,8 @@ | |
6446 | #include <linux/sunrpc/xdr.h> | |
6447 | #include <linux/sunrpc/msg_prot.h> | |
6448 | ||
6449 | +#ifdef __KERNEL__ | |
6450 | + | |
6451 | extern unsigned int xprt_udp_slot_table_entries; | |
6452 | extern unsigned int xprt_tcp_slot_table_entries; | |
6453 | ||
6454 | @@ -194,7 +196,13 @@ struct rpc_xprt { | |
6455 | char * address_strings[RPC_DISPLAY_MAX]; | |
6456 | }; | |
6457 | ||
6458 | -#ifdef __KERNEL__ | |
6459 | +struct rpc_xprtsock_create { | |
6460 | + int proto; /* IPPROTO_UDP or IPPROTO_TCP */ | |
6461 | + struct sockaddr * srcaddr; /* optional local address */ | |
6462 | + struct sockaddr * dstaddr; /* remote peer address */ | |
6463 | + size_t addrlen; | |
6464 | + struct rpc_timeout * timeout; /* optional timeout parameters */ | |
6465 | +}; | |
6466 | ||
6467 | /* | |
6468 | * Transport operations used by ULPs | |
6469 | @@ -204,7 +212,7 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long | |
6470 | /* | |
6471 | * Generic internal transport functions | |
6472 | */ | |
6473 | -struct rpc_xprt * xprt_create_transport(int proto, struct sockaddr *addr, size_t size, struct rpc_timeout *toparms); | |
6474 | +struct rpc_xprt * xprt_create_transport(struct rpc_xprtsock_create *args); | |
6475 | void xprt_connect(struct rpc_task *task); | |
6476 | void xprt_reserve(struct rpc_task *task); | |
6477 | int xprt_reserve_xprt(struct rpc_task *task); | |
6478 | @@ -242,8 +250,8 @@ void xprt_disconnect(struct rpc_xprt *xprt); | |
6479 | /* | |
6480 | * Socket transport setup operations | |
6481 | */ | |
6482 | -struct rpc_xprt * xs_setup_udp(struct sockaddr *addr, size_t addrlen, struct rpc_timeout *to); | |
6483 | -struct rpc_xprt * xs_setup_tcp(struct sockaddr *addr, size_t addrlen, struct rpc_timeout *to); | |
6484 | +struct rpc_xprt * xs_setup_udp(struct rpc_xprtsock_create *args); | |
6485 | +struct rpc_xprt * xs_setup_tcp(struct rpc_xprtsock_create *args); | |
6486 | int init_socket_xprt(void); | |
6487 | void cleanup_socket_xprt(void); | |
6488 | ||
6489 | diff --git a/kernel/auditsc.c b/kernel/auditsc.c | |
6490 | index e36481e..ced6541 100644 | |
6491 | --- a/kernel/auditsc.c | |
6492 | +++ b/kernel/auditsc.c | |
6493 | @@ -1500,6 +1500,7 @@ add_names: | |
6494 | context->names[idx].ino = (unsigned long)-1; | |
6495 | } | |
6496 | } | |
6497 | +EXPORT_SYMBOL(__audit_inode_child); | |
6498 | ||
6499 | /** | |
6500 | * auditsc_get_stamp - get local copies of audit_context values | |
6501 | diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c | |
6502 | index 9527f2b..74baf87 100644 | |
6503 | --- a/net/sunrpc/auth.c | |
6504 | +++ b/net/sunrpc/auth.c | |
6505 | @@ -18,12 +18,16 @@ | |
6506 | # define RPCDBG_FACILITY RPCDBG_AUTH | |
6507 | #endif | |
6508 | ||
6509 | -static struct rpc_authops * auth_flavors[RPC_AUTH_MAXFLAVOR] = { | |
6510 | +static DEFINE_SPINLOCK(rpc_authflavor_lock); | |
6511 | +static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = { | |
6512 | &authnull_ops, /* AUTH_NULL */ | |
6513 | &authunix_ops, /* AUTH_UNIX */ | |
6514 | NULL, /* others can be loadable modules */ | |
6515 | }; | |
6516 | ||
6517 | +static LIST_HEAD(cred_unused); | |
6518 | +static unsigned long number_cred_unused; | |
6519 | + | |
6520 | static u32 | |
6521 | pseudoflavor_to_flavor(u32 flavor) { | |
6522 | if (flavor >= RPC_AUTH_MAXFLAVOR) | |
6523 | @@ -32,55 +36,67 @@ pseudoflavor_to_flavor(u32 flavor) { | |
6524 | } | |
6525 | ||
6526 | int | |
6527 | -rpcauth_register(struct rpc_authops *ops) | |
6528 | +rpcauth_register(const struct rpc_authops *ops) | |
6529 | { | |
6530 | rpc_authflavor_t flavor; | |
6531 | + int ret = -EPERM; | |
6532 | ||
6533 | if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) | |
6534 | return -EINVAL; | |
6535 | - if (auth_flavors[flavor] != NULL) | |
6536 | - return -EPERM; /* what else? */ | |
6537 | - auth_flavors[flavor] = ops; | |
6538 | - return 0; | |
6539 | + spin_lock(&rpc_authflavor_lock); | |
6540 | + if (auth_flavors[flavor] == NULL) { | |
6541 | + auth_flavors[flavor] = ops; | |
6542 | + ret = 0; | |
6543 | + } | |
6544 | + spin_unlock(&rpc_authflavor_lock); | |
6545 | + return ret; | |
6546 | } | |
6547 | ||
6548 | int | |
6549 | -rpcauth_unregister(struct rpc_authops *ops) | |
6550 | +rpcauth_unregister(const struct rpc_authops *ops) | |
6551 | { | |
6552 | rpc_authflavor_t flavor; | |
6553 | + int ret = -EPERM; | |
6554 | ||
6555 | if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR) | |
6556 | return -EINVAL; | |
6557 | - if (auth_flavors[flavor] != ops) | |
6558 | - return -EPERM; /* what else? */ | |
6559 | - auth_flavors[flavor] = NULL; | |
6560 | - return 0; | |
6561 | + spin_lock(&rpc_authflavor_lock); | |
6562 | + if (auth_flavors[flavor] == ops) { | |
6563 | + auth_flavors[flavor] = NULL; | |
6564 | + ret = 0; | |
6565 | + } | |
6566 | + spin_unlock(&rpc_authflavor_lock); | |
6567 | + return ret; | |
6568 | } | |
6569 | ||
6570 | struct rpc_auth * | |
6571 | rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt) | |
6572 | { | |
6573 | struct rpc_auth *auth; | |
6574 | - struct rpc_authops *ops; | |
6575 | + const struct rpc_authops *ops; | |
6576 | u32 flavor = pseudoflavor_to_flavor(pseudoflavor); | |
6577 | ||
6578 | auth = ERR_PTR(-EINVAL); | |
6579 | if (flavor >= RPC_AUTH_MAXFLAVOR) | |
6580 | goto out; | |
6581 | ||
6582 | - /* FIXME - auth_flavors[] really needs an rw lock, | |
6583 | - * and module refcounting. */ | |
6584 | #ifdef CONFIG_KMOD | |
6585 | if ((ops = auth_flavors[flavor]) == NULL) | |
6586 | request_module("rpc-auth-%u", flavor); | |
6587 | #endif | |
6588 | - if ((ops = auth_flavors[flavor]) == NULL) | |
6589 | + spin_lock(&rpc_authflavor_lock); | |
6590 | + ops = auth_flavors[flavor]; | |
6591 | + if (ops == NULL || !try_module_get(ops->owner)) { | |
6592 | + spin_unlock(&rpc_authflavor_lock); | |
6593 | goto out; | |
6594 | + } | |
6595 | + spin_unlock(&rpc_authflavor_lock); | |
6596 | auth = ops->create(clnt, pseudoflavor); | |
6597 | + module_put(ops->owner); | |
6598 | if (IS_ERR(auth)) | |
6599 | return auth; | |
6600 | if (clnt->cl_auth) | |
6601 | - rpcauth_destroy(clnt->cl_auth); | |
6602 | + rpcauth_release(clnt->cl_auth); | |
6603 | clnt->cl_auth = auth; | |
6604 | ||
6605 | out: | |
6606 | @@ -88,7 +104,7 @@ out: | |
6607 | } | |
6608 | ||
6609 | void | |
6610 | -rpcauth_destroy(struct rpc_auth *auth) | |
6611 | +rpcauth_release(struct rpc_auth *auth) | |
6612 | { | |
6613 | if (!atomic_dec_and_test(&auth->au_count)) | |
6614 | return; | |
6615 | @@ -97,11 +113,31 @@ rpcauth_destroy(struct rpc_auth *auth) | |
6616 | ||
6617 | static DEFINE_SPINLOCK(rpc_credcache_lock); | |
6618 | ||
6619 | +static void | |
6620 | +rpcauth_unhash_cred_locked(struct rpc_cred *cred) | |
6621 | +{ | |
6622 | + hlist_del_rcu(&cred->cr_hash); | |
6623 | + smp_mb__before_clear_bit(); | |
6624 | + clear_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags); | |
6625 | +} | |
6626 | + | |
6627 | +static void | |
6628 | +rpcauth_unhash_cred(struct rpc_cred *cred) | |
6629 | +{ | |
6630 | + spinlock_t *cache_lock; | |
6631 | + | |
6632 | + cache_lock = &cred->cr_auth->au_credcache->lock; | |
6633 | + spin_lock(cache_lock); | |
6634 | + if (atomic_read(&cred->cr_count) == 0) | |
6635 | + rpcauth_unhash_cred_locked(cred); | |
6636 | + spin_unlock(cache_lock); | |
6637 | +} | |
6638 | + | |
6639 | /* | |
6640 | * Initialize RPC credential cache | |
6641 | */ | |
6642 | int | |
6643 | -rpcauth_init_credcache(struct rpc_auth *auth, unsigned long expire) | |
6644 | +rpcauth_init_credcache(struct rpc_auth *auth) | |
6645 | { | |
6646 | struct rpc_cred_cache *new; | |
6647 | int i; | |
6648 | @@ -111,8 +147,7 @@ rpcauth_init_credcache(struct rpc_auth *auth, unsigned long expire) | |
6649 | return -ENOMEM; | |
6650 | for (i = 0; i < RPC_CREDCACHE_NR; i++) | |
6651 | INIT_HLIST_HEAD(&new->hashtable[i]); | |
6652 | - new->expire = expire; | |
6653 | - new->nextgc = jiffies + (expire >> 1); | |
6654 | + spin_lock_init(&new->lock); | |
6655 | auth->au_credcache = new; | |
6656 | return 0; | |
6657 | } | |
6658 | @@ -121,13 +156,13 @@ rpcauth_init_credcache(struct rpc_auth *auth, unsigned long expire) | |
6659 | * Destroy a list of credentials | |
6660 | */ | |
6661 | static inline | |
6662 | -void rpcauth_destroy_credlist(struct hlist_head *head) | |
6663 | +void rpcauth_destroy_credlist(struct list_head *head) | |
6664 | { | |
6665 | struct rpc_cred *cred; | |
6666 | ||
6667 | - while (!hlist_empty(head)) { | |
6668 | - cred = hlist_entry(head->first, struct rpc_cred, cr_hash); | |
6669 | - hlist_del_init(&cred->cr_hash); | |
6670 | + while (!list_empty(head)) { | |
6671 | + cred = list_entry(head->next, struct rpc_cred, cr_lru); | |
6672 | + list_del_init(&cred->cr_lru); | |
6673 | put_rpccred(cred); | |
6674 | } | |
6675 | } | |
6676 | @@ -137,58 +172,95 @@ void rpcauth_destroy_credlist(struct hlist_head *head) | |
6677 | * that are not referenced. | |
6678 | */ | |
6679 | void | |
6680 | -rpcauth_free_credcache(struct rpc_auth *auth) | |
6681 | +rpcauth_clear_credcache(struct rpc_cred_cache *cache) | |
6682 | { | |
6683 | - struct rpc_cred_cache *cache = auth->au_credcache; | |
6684 | - HLIST_HEAD(free); | |
6685 | - struct hlist_node *pos, *next; | |
6686 | + LIST_HEAD(free); | |
6687 | + struct hlist_head *head; | |
6688 | struct rpc_cred *cred; | |
6689 | int i; | |
6690 | ||
6691 | spin_lock(&rpc_credcache_lock); | |
6692 | + spin_lock(&cache->lock); | |
6693 | for (i = 0; i < RPC_CREDCACHE_NR; i++) { | |
6694 | - hlist_for_each_safe(pos, next, &cache->hashtable[i]) { | |
6695 | - cred = hlist_entry(pos, struct rpc_cred, cr_hash); | |
6696 | - __hlist_del(&cred->cr_hash); | |
6697 | - hlist_add_head(&cred->cr_hash, &free); | |
6698 | + head = &cache->hashtable[i]; | |
6699 | + while (!hlist_empty(head)) { | |
6700 | + cred = hlist_entry(head->first, struct rpc_cred, cr_hash); | |
6701 | + get_rpccred(cred); | |
6702 | + if (!list_empty(&cred->cr_lru)) { | |
6703 | + list_del(&cred->cr_lru); | |
6704 | + number_cred_unused--; | |
6705 | + } | |
6706 | + list_add_tail(&cred->cr_lru, &free); | |
6707 | + rpcauth_unhash_cred_locked(cred); | |
6708 | } | |
6709 | } | |
6710 | + spin_unlock(&cache->lock); | |
6711 | spin_unlock(&rpc_credcache_lock); | |
6712 | rpcauth_destroy_credlist(&free); | |
6713 | } | |
6714 | ||
6715 | -static void | |
6716 | -rpcauth_prune_expired(struct rpc_auth *auth, struct rpc_cred *cred, struct hlist_head *free) | |
6717 | +/* | |
6718 | + * Destroy the RPC credential cache | |
6719 | + */ | |
6720 | +void | |
6721 | +rpcauth_destroy_credcache(struct rpc_auth *auth) | |
6722 | { | |
6723 | - if (atomic_read(&cred->cr_count) != 1) | |
6724 | - return; | |
6725 | - if (time_after(jiffies, cred->cr_expire + auth->au_credcache->expire)) | |
6726 | - cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; | |
6727 | - if (!(cred->cr_flags & RPCAUTH_CRED_UPTODATE)) { | |
6728 | - __hlist_del(&cred->cr_hash); | |
6729 | - hlist_add_head(&cred->cr_hash, free); | |
6730 | + struct rpc_cred_cache *cache = auth->au_credcache; | |
6731 | + | |
6732 | + if (cache) { | |
6733 | + auth->au_credcache = NULL; | |
6734 | + rpcauth_clear_credcache(cache); | |
6735 | + kfree(cache); | |
6736 | } | |
6737 | } | |
6738 | ||
6739 | /* | |
6740 | * Remove stale credentials. Avoid sleeping inside the loop. | |
6741 | */ | |
6742 | -static void | |
6743 | -rpcauth_gc_credcache(struct rpc_auth *auth, struct hlist_head *free) | |
6744 | +static int | |
6745 | +rpcauth_prune_expired(struct list_head *free, int nr_to_scan) | |
6746 | { | |
6747 | - struct rpc_cred_cache *cache = auth->au_credcache; | |
6748 | - struct hlist_node *pos, *next; | |
6749 | - struct rpc_cred *cred; | |
6750 | - int i; | |
6751 | + spinlock_t *cache_lock; | |
6752 | + struct rpc_cred *cred; | |
6753 | ||
6754 | - dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth); | |
6755 | - for (i = 0; i < RPC_CREDCACHE_NR; i++) { | |
6756 | - hlist_for_each_safe(pos, next, &cache->hashtable[i]) { | |
6757 | - cred = hlist_entry(pos, struct rpc_cred, cr_hash); | |
6758 | - rpcauth_prune_expired(auth, cred, free); | |
6759 | + while (!list_empty(&cred_unused)) { | |
6760 | + cred = list_entry(cred_unused.next, struct rpc_cred, cr_lru); | |
6761 | + list_del_init(&cred->cr_lru); | |
6762 | + number_cred_unused--; | |
6763 | + if (atomic_read(&cred->cr_count) != 0) | |
6764 | + continue; | |
6765 | + cache_lock = &cred->cr_auth->au_credcache->lock; | |
6766 | + spin_lock(cache_lock); | |
6767 | + if (atomic_read(&cred->cr_count) == 0) { | |
6768 | + get_rpccred(cred); | |
6769 | + list_add_tail(&cred->cr_lru, free); | |
6770 | + rpcauth_unhash_cred_locked(cred); | |
6771 | + nr_to_scan--; | |
6772 | } | |
6773 | + spin_unlock(cache_lock); | |
6774 | + if (nr_to_scan == 0) | |
6775 | + break; | |
6776 | } | |
6777 | - cache->nextgc = jiffies + cache->expire; | |
6778 | + return nr_to_scan; | |
6779 | +} | |
6780 | + | |
6781 | +/* | |
6782 | + * Run memory cache shrinker. | |
6783 | + */ | |
6784 | +static int | |
6785 | +rpcauth_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) | |
6786 | +{ | |
6787 | + LIST_HEAD(free); | |
6788 | + int res; | |
6789 | + | |
6790 | + if (list_empty(&cred_unused)) | |
6791 | + return 0; | |
6792 | + spin_lock(&rpc_credcache_lock); | |
6793 | + nr_to_scan = rpcauth_prune_expired(&free, nr_to_scan); | |
6794 | + res = (number_cred_unused / 100) * sysctl_vfs_cache_pressure; | |
6795 | + spin_unlock(&rpc_credcache_lock); | |
6796 | + rpcauth_destroy_credlist(&free); | |
6797 | + return res; | |
6798 | } | |
6799 | ||
6800 | /* | |
6801 | @@ -198,53 +270,56 @@ struct rpc_cred * | |
6802 | rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, | |
6803 | int flags) | |
6804 | { | |
6805 | + LIST_HEAD(free); | |
6806 | struct rpc_cred_cache *cache = auth->au_credcache; | |
6807 | - HLIST_HEAD(free); | |
6808 | - struct hlist_node *pos, *next; | |
6809 | - struct rpc_cred *new = NULL, | |
6810 | - *cred = NULL; | |
6811 | + struct hlist_node *pos; | |
6812 | + struct rpc_cred *cred = NULL, | |
6813 | + *entry, *new; | |
6814 | int nr = 0; | |
6815 | ||
6816 | if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) | |
6817 | nr = acred->uid & RPC_CREDCACHE_MASK; | |
6818 | -retry: | |
6819 | - spin_lock(&rpc_credcache_lock); | |
6820 | - if (time_before(cache->nextgc, jiffies)) | |
6821 | - rpcauth_gc_credcache(auth, &free); | |
6822 | - hlist_for_each_safe(pos, next, &cache->hashtable[nr]) { | |
6823 | - struct rpc_cred *entry; | |
6824 | - entry = hlist_entry(pos, struct rpc_cred, cr_hash); | |
6825 | - if (entry->cr_ops->crmatch(acred, entry, flags)) { | |
6826 | - hlist_del(&entry->cr_hash); | |
6827 | - cred = entry; | |
6828 | - break; | |
6829 | + | |
6830 | + rcu_read_lock(); | |
6831 | + hlist_for_each_entry_rcu(entry, pos, &cache->hashtable[nr], cr_hash) { | |
6832 | + if (!entry->cr_ops->crmatch(acred, entry, flags)) | |
6833 | + continue; | |
6834 | + spin_lock(&cache->lock); | |
6835 | + if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) { | |
6836 | + spin_unlock(&cache->lock); | |
6837 | + continue; | |
6838 | } | |
6839 | - rpcauth_prune_expired(auth, entry, &free); | |
6840 | - } | |
6841 | - if (new) { | |
6842 | - if (cred) | |
6843 | - hlist_add_head(&new->cr_hash, &free); | |
6844 | - else | |
6845 | - cred = new; | |
6846 | + cred = get_rpccred(entry); | |
6847 | + spin_unlock(&cache->lock); | |
6848 | + break; | |
6849 | } | |
6850 | - if (cred) { | |
6851 | - hlist_add_head(&cred->cr_hash, &cache->hashtable[nr]); | |
6852 | - get_rpccred(cred); | |
6853 | - } | |
6854 | - spin_unlock(&rpc_credcache_lock); | |
6855 | + rcu_read_unlock(); | |
6856 | ||
6857 | - rpcauth_destroy_credlist(&free); | |
6858 | + if (cred != NULL) | |
6859 | + goto found; | |
6860 | ||
6861 | - if (!cred) { | |
6862 | - new = auth->au_ops->crcreate(auth, acred, flags); | |
6863 | - if (!IS_ERR(new)) { | |
6864 | -#ifdef RPC_DEBUG | |
6865 | - new->cr_magic = RPCAUTH_CRED_MAGIC; | |
6866 | -#endif | |
6867 | - goto retry; | |
6868 | - } else | |
6869 | - cred = new; | |
6870 | - } else if ((cred->cr_flags & RPCAUTH_CRED_NEW) | |
6871 | + new = auth->au_ops->crcreate(auth, acred, flags); | |
6872 | + if (IS_ERR(new)) { | |
6873 | + cred = new; | |
6874 | + goto out; | |
6875 | + } | |
6876 | + | |
6877 | + spin_lock(&cache->lock); | |
6878 | + hlist_for_each_entry(entry, pos, &cache->hashtable[nr], cr_hash) { | |
6879 | + if (!entry->cr_ops->crmatch(acred, entry, flags)) | |
6880 | + continue; | |
6881 | + cred = get_rpccred(entry); | |
6882 | + break; | |
6883 | + } | |
6884 | + if (cred == NULL) { | |
6885 | + cred = new; | |
6886 | + set_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags); | |
6887 | + hlist_add_head_rcu(&cred->cr_hash, &cache->hashtable[nr]); | |
6888 | + } else | |
6889 | + list_add_tail(&new->cr_lru, &free); | |
6890 | + spin_unlock(&cache->lock); | |
6891 | +found: | |
6892 | + if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) | |
6893 | && cred->cr_ops->cr_init != NULL | |
6894 | && !(flags & RPCAUTH_LOOKUP_NEW)) { | |
6895 | int res = cred->cr_ops->cr_init(auth, cred); | |
6896 | @@ -253,8 +328,9 @@ retry: | |
6897 | cred = ERR_PTR(res); | |
6898 | } | |
6899 | } | |
6900 | - | |
6901 | - return (struct rpc_cred *) cred; | |
6902 | + rpcauth_destroy_credlist(&free); | |
6903 | +out: | |
6904 | + return cred; | |
6905 | } | |
6906 | ||
6907 | struct rpc_cred * | |
6908 | @@ -275,10 +351,27 @@ rpcauth_lookupcred(struct rpc_auth *auth, int flags) | |
6909 | return ret; | |
6910 | } | |
6911 | ||
6912 | +void | |
6913 | +rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred, | |
6914 | + struct rpc_auth *auth, const struct rpc_credops *ops) | |
6915 | +{ | |
6916 | + INIT_HLIST_NODE(&cred->cr_hash); | |
6917 | + INIT_LIST_HEAD(&cred->cr_lru); | |
6918 | + atomic_set(&cred->cr_count, 1); | |
6919 | + cred->cr_auth = auth; | |
6920 | + cred->cr_ops = ops; | |
6921 | + cred->cr_expire = jiffies; | |
6922 | +#ifdef RPC_DEBUG | |
6923 | + cred->cr_magic = RPCAUTH_CRED_MAGIC; | |
6924 | +#endif | |
6925 | + cred->cr_uid = acred->uid; | |
6926 | +} | |
6927 | +EXPORT_SYMBOL(rpcauth_init_cred); | |
6928 | + | |
6929 | struct rpc_cred * | |
6930 | rpcauth_bindcred(struct rpc_task *task) | |
6931 | { | |
6932 | - struct rpc_auth *auth = task->tk_auth; | |
6933 | + struct rpc_auth *auth = task->tk_client->cl_auth; | |
6934 | struct auth_cred acred = { | |
6935 | .uid = current->fsuid, | |
6936 | .gid = current->fsgid, | |
6937 | @@ -288,7 +381,7 @@ rpcauth_bindcred(struct rpc_task *task) | |
6938 | int flags = 0; | |
6939 | ||
6940 | dprintk("RPC: %5u looking up %s cred\n", | |
6941 | - task->tk_pid, task->tk_auth->au_ops->au_name); | |
6942 | + task->tk_pid, task->tk_client->cl_auth->au_ops->au_name); | |
6943 | get_group_info(acred.group_info); | |
6944 | if (task->tk_flags & RPC_TASK_ROOTCREDS) | |
6945 | flags |= RPCAUTH_LOOKUP_ROOTCREDS; | |
6946 | @@ -304,19 +397,42 @@ rpcauth_bindcred(struct rpc_task *task) | |
6947 | void | |
6948 | rpcauth_holdcred(struct rpc_task *task) | |
6949 | { | |
6950 | - dprintk("RPC: %5u holding %s cred %p\n", | |
6951 | - task->tk_pid, task->tk_auth->au_ops->au_name, | |
6952 | - task->tk_msg.rpc_cred); | |
6953 | - if (task->tk_msg.rpc_cred) | |
6954 | - get_rpccred(task->tk_msg.rpc_cred); | |
6955 | + struct rpc_cred *cred = task->tk_msg.rpc_cred; | |
6956 | + if (cred != NULL) { | |
6957 | + get_rpccred(cred); | |
6958 | + dprintk("RPC: %5u holding %s cred %p\n", task->tk_pid, | |
6959 | + cred->cr_auth->au_ops->au_name, cred); | |
6960 | + } | |
6961 | } | |
6962 | ||
6963 | void | |
6964 | put_rpccred(struct rpc_cred *cred) | |
6965 | { | |
6966 | - cred->cr_expire = jiffies; | |
6967 | + /* Fast path for unhashed credentials */ | |
6968 | + if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) | |
6969 | + goto need_lock; | |
6970 | + | |
6971 | if (!atomic_dec_and_test(&cred->cr_count)) | |
6972 | return; | |
6973 | + goto out_destroy; | |
6974 | +need_lock: | |
6975 | + if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock)) | |
6976 | + return; | |
6977 | + if (!list_empty(&cred->cr_lru)) { | |
6978 | + number_cred_unused--; | |
6979 | + list_del_init(&cred->cr_lru); | |
6980 | + } | |
6981 | + if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) | |
6982 | + rpcauth_unhash_cred(cred); | |
6983 | + else if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) { | |
6984 | + cred->cr_expire = jiffies; | |
6985 | + list_add_tail(&cred->cr_lru, &cred_unused); | |
6986 | + number_cred_unused++; | |
6987 | + spin_unlock(&rpc_credcache_lock); | |
6988 | + return; | |
6989 | + } | |
6990 | + spin_unlock(&rpc_credcache_lock); | |
6991 | +out_destroy: | |
6992 | cred->cr_ops->crdestroy(cred); | |
6993 | } | |
6994 | ||
6995 | @@ -326,7 +442,7 @@ rpcauth_unbindcred(struct rpc_task *task) | |
6996 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | |
6997 | ||
6998 | dprintk("RPC: %5u releasing %s cred %p\n", | |
6999 | - task->tk_pid, task->tk_auth->au_ops->au_name, cred); | |
7000 | + task->tk_pid, cred->cr_auth->au_ops->au_name, cred); | |
7001 | ||
7002 | put_rpccred(cred); | |
7003 | task->tk_msg.rpc_cred = NULL; | |
7004 | @@ -338,7 +454,7 @@ rpcauth_marshcred(struct rpc_task *task, __be32 *p) | |
7005 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | |
7006 | ||
7007 | dprintk("RPC: %5u marshaling %s cred %p\n", | |
7008 | - task->tk_pid, task->tk_auth->au_ops->au_name, cred); | |
7009 | + task->tk_pid, cred->cr_auth->au_ops->au_name, cred); | |
7010 | ||
7011 | return cred->cr_ops->crmarshal(task, p); | |
7012 | } | |
7013 | @@ -349,7 +465,7 @@ rpcauth_checkverf(struct rpc_task *task, __be32 *p) | |
7014 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | |
7015 | ||
7016 | dprintk("RPC: %5u validating %s cred %p\n", | |
7017 | - task->tk_pid, task->tk_auth->au_ops->au_name, cred); | |
7018 | + task->tk_pid, cred->cr_auth->au_ops->au_name, cred); | |
7019 | ||
7020 | return cred->cr_ops->crvalidate(task, p); | |
7021 | } | |
7022 | @@ -390,7 +506,7 @@ rpcauth_refreshcred(struct rpc_task *task) | |
7023 | int err; | |
7024 | ||
7025 | dprintk("RPC: %5u refreshing %s cred %p\n", | |
7026 | - task->tk_pid, task->tk_auth->au_ops->au_name, cred); | |
7027 | + task->tk_pid, cred->cr_auth->au_ops->au_name, cred); | |
7028 | ||
7029 | err = cred->cr_ops->crrefresh(task); | |
7030 | if (err < 0) | |
7031 | @@ -401,17 +517,34 @@ rpcauth_refreshcred(struct rpc_task *task) | |
7032 | void | |
7033 | rpcauth_invalcred(struct rpc_task *task) | |
7034 | { | |
7035 | + struct rpc_cred *cred = task->tk_msg.rpc_cred; | |
7036 | + | |
7037 | dprintk("RPC: %5u invalidating %s cred %p\n", | |
7038 | - task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred); | |
7039 | - spin_lock(&rpc_credcache_lock); | |
7040 | - if (task->tk_msg.rpc_cred) | |
7041 | - task->tk_msg.rpc_cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; | |
7042 | - spin_unlock(&rpc_credcache_lock); | |
7043 | + task->tk_pid, cred->cr_auth->au_ops->au_name, cred); | |
7044 | + if (cred) | |
7045 | + clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | |
7046 | } | |
7047 | ||
7048 | int | |
7049 | rpcauth_uptodatecred(struct rpc_task *task) | |
7050 | { | |
7051 | - return !(task->tk_msg.rpc_cred) || | |
7052 | - (task->tk_msg.rpc_cred->cr_flags & RPCAUTH_CRED_UPTODATE); | |
7053 | + struct rpc_cred *cred = task->tk_msg.rpc_cred; | |
7054 | + | |
7055 | + return cred == NULL || | |
7056 | + test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0; | |
7057 | +} | |
7058 | + | |
7059 | + | |
7060 | +static struct shrinker *rpc_cred_shrinker; | |
7061 | + | |
7062 | +void __init rpcauth_init_module(void) | |
7063 | +{ | |
7064 | + rpc_init_authunix(); | |
7065 | + rpc_cred_shrinker = set_shrinker(DEFAULT_SEEKS, rpcauth_cache_shrinker); | |
7066 | +} | |
7067 | + | |
7068 | +void __exit rpcauth_remove_module(void) | |
7069 | +{ | |
7070 | + if (rpc_cred_shrinker != NULL) | |
7071 | + remove_shrinker(rpc_cred_shrinker); | |
7072 | } | |
7073 | diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c | |
7074 | index 4e4ccc5..17d460f 100644 | |
7075 | --- a/net/sunrpc/auth_gss/auth_gss.c | |
7076 | +++ b/net/sunrpc/auth_gss/auth_gss.c | |
7077 | @@ -54,9 +54,10 @@ | |
7078 | #include <linux/sunrpc/gss_api.h> | |
7079 | #include <asm/uaccess.h> | |
7080 | ||
7081 | -static struct rpc_authops authgss_ops; | |
7082 | +static const struct rpc_authops authgss_ops; | |
7083 | ||
7084 | -static struct rpc_credops gss_credops; | |
7085 | +static const struct rpc_credops gss_credops; | |
7086 | +static const struct rpc_credops gss_nullops; | |
7087 | ||
7088 | #ifdef RPC_DEBUG | |
7089 | # define RPCDBG_FACILITY RPCDBG_AUTH | |
7090 | @@ -64,7 +65,6 @@ static struct rpc_credops gss_credops; | |
7091 | ||
7092 | #define NFS_NGROUPS 16 | |
7093 | ||
7094 | -#define GSS_CRED_EXPIRE (60 * HZ) /* XXX: reasonable? */ | |
7095 | #define GSS_CRED_SLACK 1024 /* XXX: unused */ | |
7096 | /* length of a krb5 verifier (48), plus data added before arguments when | |
7097 | * using integrity (two 4-byte integers): */ | |
7098 | @@ -79,19 +79,16 @@ static struct rpc_credops gss_credops; | |
7099 | /* dump the buffer in `emacs-hexl' style */ | |
7100 | #define isprint(c) ((c > 0x1f) && (c < 0x7f)) | |
7101 | ||
7102 | -static DEFINE_RWLOCK(gss_ctx_lock); | |
7103 | - | |
7104 | struct gss_auth { | |
7105 | + struct kref kref; | |
7106 | struct rpc_auth rpc_auth; | |
7107 | struct gss_api_mech *mech; | |
7108 | enum rpc_gss_svc service; | |
7109 | - struct list_head upcalls; | |
7110 | struct rpc_clnt *client; | |
7111 | struct dentry *dentry; | |
7112 | - spinlock_t lock; | |
7113 | }; | |
7114 | ||
7115 | -static void gss_destroy_ctx(struct gss_cl_ctx *); | |
7116 | +static void gss_free_ctx(struct gss_cl_ctx *); | |
7117 | static struct rpc_pipe_ops gss_upcall_ops; | |
7118 | ||
7119 | static inline struct gss_cl_ctx * | |
7120 | @@ -105,20 +102,24 @@ static inline void | |
7121 | gss_put_ctx(struct gss_cl_ctx *ctx) | |
7122 | { | |
7123 | if (atomic_dec_and_test(&ctx->count)) | |
7124 | - gss_destroy_ctx(ctx); | |
7125 | + gss_free_ctx(ctx); | |
7126 | } | |
7127 | ||
7128 | +/* gss_cred_set_ctx: | |
7129 | + * called by gss_upcall_callback and gss_create_upcall in order | |
7130 | + * to set the gss context. The actual exchange of an old context | |
7131 | + * and a new one is protected by the inode->i_lock. | |
7132 | + */ | |
7133 | static void | |
7134 | gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) | |
7135 | { | |
7136 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | |
7137 | struct gss_cl_ctx *old; | |
7138 | - write_lock(&gss_ctx_lock); | |
7139 | + | |
7140 | old = gss_cred->gc_ctx; | |
7141 | - gss_cred->gc_ctx = ctx; | |
7142 | - cred->cr_flags |= RPCAUTH_CRED_UPTODATE; | |
7143 | - cred->cr_flags &= ~RPCAUTH_CRED_NEW; | |
7144 | - write_unlock(&gss_ctx_lock); | |
7145 | + rcu_assign_pointer(gss_cred->gc_ctx, ctx); | |
7146 | + set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | |
7147 | + clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags); | |
7148 | if (old) | |
7149 | gss_put_ctx(old); | |
7150 | } | |
7151 | @@ -129,10 +130,10 @@ gss_cred_is_uptodate_ctx(struct rpc_cred *cred) | |
7152 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | |
7153 | int res = 0; | |
7154 | ||
7155 | - read_lock(&gss_ctx_lock); | |
7156 | - if ((cred->cr_flags & RPCAUTH_CRED_UPTODATE) && gss_cred->gc_ctx) | |
7157 | + rcu_read_lock(); | |
7158 | + if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) && gss_cred->gc_ctx) | |
7159 | res = 1; | |
7160 | - read_unlock(&gss_ctx_lock); | |
7161 | + rcu_read_unlock(); | |
7162 | return res; | |
7163 | } | |
7164 | ||
7165 | @@ -171,10 +172,10 @@ gss_cred_get_ctx(struct rpc_cred *cred) | |
7166 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | |
7167 | struct gss_cl_ctx *ctx = NULL; | |
7168 | ||
7169 | - read_lock(&gss_ctx_lock); | |
7170 | + rcu_read_lock(); | |
7171 | if (gss_cred->gc_ctx) | |
7172 | ctx = gss_get_ctx(gss_cred->gc_ctx); | |
7173 | - read_unlock(&gss_ctx_lock); | |
7174 | + rcu_read_unlock(); | |
7175 | return ctx; | |
7176 | } | |
7177 | ||
7178 | @@ -269,10 +270,10 @@ gss_release_msg(struct gss_upcall_msg *gss_msg) | |
7179 | } | |
7180 | ||
7181 | static struct gss_upcall_msg * | |
7182 | -__gss_find_upcall(struct gss_auth *gss_auth, uid_t uid) | |
7183 | +__gss_find_upcall(struct rpc_inode *rpci, uid_t uid) | |
7184 | { | |
7185 | struct gss_upcall_msg *pos; | |
7186 | - list_for_each_entry(pos, &gss_auth->upcalls, list) { | |
7187 | + list_for_each_entry(pos, &rpci->in_downcall, list) { | |
7188 | if (pos->uid != uid) | |
7189 | continue; | |
7190 | atomic_inc(&pos->count); | |
7191 | @@ -290,24 +291,24 @@ __gss_find_upcall(struct gss_auth *gss_auth, uid_t uid) | |
7192 | static inline struct gss_upcall_msg * | |
7193 | gss_add_msg(struct gss_auth *gss_auth, struct gss_upcall_msg *gss_msg) | |
7194 | { | |
7195 | + struct inode *inode = gss_auth->dentry->d_inode; | |
7196 | + struct rpc_inode *rpci = RPC_I(inode); | |
7197 | struct gss_upcall_msg *old; | |
7198 | ||
7199 | - spin_lock(&gss_auth->lock); | |
7200 | - old = __gss_find_upcall(gss_auth, gss_msg->uid); | |
7201 | + spin_lock(&inode->i_lock); | |
7202 | + old = __gss_find_upcall(rpci, gss_msg->uid); | |
7203 | if (old == NULL) { | |
7204 | atomic_inc(&gss_msg->count); | |
7205 | - list_add(&gss_msg->list, &gss_auth->upcalls); | |
7206 | + list_add(&gss_msg->list, &rpci->in_downcall); | |
7207 | } else | |
7208 | gss_msg = old; | |
7209 | - spin_unlock(&gss_auth->lock); | |
7210 | + spin_unlock(&inode->i_lock); | |
7211 | return gss_msg; | |
7212 | } | |
7213 | ||
7214 | static void | |
7215 | __gss_unhash_msg(struct gss_upcall_msg *gss_msg) | |
7216 | { | |
7217 | - if (list_empty(&gss_msg->list)) | |
7218 | - return; | |
7219 | list_del_init(&gss_msg->list); | |
7220 | rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno); | |
7221 | wake_up_all(&gss_msg->waitqueue); | |
7222 | @@ -318,10 +319,14 @@ static void | |
7223 | gss_unhash_msg(struct gss_upcall_msg *gss_msg) | |
7224 | { | |
7225 | struct gss_auth *gss_auth = gss_msg->auth; | |
7226 | + struct inode *inode = gss_auth->dentry->d_inode; | |
7227 | ||
7228 | - spin_lock(&gss_auth->lock); | |
7229 | - __gss_unhash_msg(gss_msg); | |
7230 | - spin_unlock(&gss_auth->lock); | |
7231 | + if (list_empty(&gss_msg->list)) | |
7232 | + return; | |
7233 | + spin_lock(&inode->i_lock); | |
7234 | + if (!list_empty(&gss_msg->list)) | |
7235 | + __gss_unhash_msg(gss_msg); | |
7236 | + spin_unlock(&inode->i_lock); | |
7237 | } | |
7238 | ||
7239 | static void | |
7240 | @@ -330,16 +335,16 @@ gss_upcall_callback(struct rpc_task *task) | |
7241 | struct gss_cred *gss_cred = container_of(task->tk_msg.rpc_cred, | |
7242 | struct gss_cred, gc_base); | |
7243 | struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall; | |
7244 | + struct inode *inode = gss_msg->auth->dentry->d_inode; | |
7245 | ||
7246 | - BUG_ON(gss_msg == NULL); | |
7247 | + spin_lock(&inode->i_lock); | |
7248 | if (gss_msg->ctx) | |
7249 | gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx)); | |
7250 | else | |
7251 | task->tk_status = gss_msg->msg.errno; | |
7252 | - spin_lock(&gss_msg->auth->lock); | |
7253 | gss_cred->gc_upcall = NULL; | |
7254 | rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno); | |
7255 | - spin_unlock(&gss_msg->auth->lock); | |
7256 | + spin_unlock(&inode->i_lock); | |
7257 | gss_release_msg(gss_msg); | |
7258 | } | |
7259 | ||
7260 | @@ -386,11 +391,12 @@ static inline int | |
7261 | gss_refresh_upcall(struct rpc_task *task) | |
7262 | { | |
7263 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | |
7264 | - struct gss_auth *gss_auth = container_of(task->tk_client->cl_auth, | |
7265 | + struct gss_auth *gss_auth = container_of(cred->cr_auth, | |
7266 | struct gss_auth, rpc_auth); | |
7267 | struct gss_cred *gss_cred = container_of(cred, | |
7268 | struct gss_cred, gc_base); | |
7269 | struct gss_upcall_msg *gss_msg; | |
7270 | + struct inode *inode = gss_auth->dentry->d_inode; | |
7271 | int err = 0; | |
7272 | ||
7273 | dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid, | |
7274 | @@ -400,7 +406,7 @@ gss_refresh_upcall(struct rpc_task *task) | |
7275 | err = PTR_ERR(gss_msg); | |
7276 | goto out; | |
7277 | } | |
7278 | - spin_lock(&gss_auth->lock); | |
7279 | + spin_lock(&inode->i_lock); | |
7280 | if (gss_cred->gc_upcall != NULL) | |
7281 | rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL, NULL); | |
7282 | else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) { | |
7283 | @@ -411,7 +417,7 @@ gss_refresh_upcall(struct rpc_task *task) | |
7284 | rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback, NULL); | |
7285 | } else | |
7286 | err = gss_msg->msg.errno; | |
7287 | - spin_unlock(&gss_auth->lock); | |
7288 | + spin_unlock(&inode->i_lock); | |
7289 | gss_release_msg(gss_msg); | |
7290 | out: | |
7291 | dprintk("RPC: %5u gss_refresh_upcall for uid %u result %d\n", | |
7292 | @@ -422,6 +428,7 @@ out: | |
7293 | static inline int | |
7294 | gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | |
7295 | { | |
7296 | + struct inode *inode = gss_auth->dentry->d_inode; | |
7297 | struct rpc_cred *cred = &gss_cred->gc_base; | |
7298 | struct gss_upcall_msg *gss_msg; | |
7299 | DEFINE_WAIT(wait); | |
7300 | @@ -435,12 +442,11 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | |
7301 | } | |
7302 | for (;;) { | |
7303 | prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_INTERRUPTIBLE); | |
7304 | - spin_lock(&gss_auth->lock); | |
7305 | + spin_lock(&inode->i_lock); | |
7306 | if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) { | |
7307 | - spin_unlock(&gss_auth->lock); | |
7308 | break; | |
7309 | } | |
7310 | - spin_unlock(&gss_auth->lock); | |
7311 | + spin_unlock(&inode->i_lock); | |
7312 | if (signalled()) { | |
7313 | err = -ERESTARTSYS; | |
7314 | goto out_intr; | |
7315 | @@ -451,6 +457,7 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | |
7316 | gss_cred_set_ctx(cred, gss_get_ctx(gss_msg->ctx)); | |
7317 | else | |
7318 | err = gss_msg->msg.errno; | |
7319 | + spin_unlock(&inode->i_lock); | |
7320 | out_intr: | |
7321 | finish_wait(&gss_msg->waitqueue, &wait); | |
7322 | gss_release_msg(gss_msg); | |
7323 | @@ -489,12 +496,11 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | |
7324 | const void *p, *end; | |
7325 | void *buf; | |
7326 | struct rpc_clnt *clnt; | |
7327 | - struct gss_auth *gss_auth; | |
7328 | - struct rpc_cred *cred; | |
7329 | struct gss_upcall_msg *gss_msg; | |
7330 | + struct inode *inode = filp->f_path.dentry->d_inode; | |
7331 | struct gss_cl_ctx *ctx; | |
7332 | uid_t uid; | |
7333 | - int err = -EFBIG; | |
7334 | + ssize_t err = -EFBIG; | |
7335 | ||
7336 | if (mlen > MSG_BUF_MAXSIZE) | |
7337 | goto out; | |
7338 | @@ -503,7 +509,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | |
7339 | if (!buf) | |
7340 | goto out; | |
7341 | ||
7342 | - clnt = RPC_I(filp->f_path.dentry->d_inode)->private; | |
7343 | + clnt = RPC_I(inode)->private; | |
7344 | err = -EFAULT; | |
7345 | if (copy_from_user(buf, src, mlen)) | |
7346 | goto err; | |
7347 | @@ -519,43 +525,38 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | |
7348 | ctx = gss_alloc_context(); | |
7349 | if (ctx == NULL) | |
7350 | goto err; | |
7351 | - err = 0; | |
7352 | - gss_auth = container_of(clnt->cl_auth, struct gss_auth, rpc_auth); | |
7353 | - p = gss_fill_context(p, end, ctx, gss_auth->mech); | |
7354 | + | |
7355 | + err = -ENOENT; | |
7356 | + /* Find a matching upcall */ | |
7357 | + spin_lock(&inode->i_lock); | |
7358 | + gss_msg = __gss_find_upcall(RPC_I(inode), uid); | |
7359 | + if (gss_msg == NULL) { | |
7360 | + spin_unlock(&inode->i_lock); | |
7361 | + goto err_put_ctx; | |
7362 | + } | |
7363 | + list_del_init(&gss_msg->list); | |
7364 | + spin_unlock(&inode->i_lock); | |
7365 | + | |
7366 | + p = gss_fill_context(p, end, ctx, gss_msg->auth->mech); | |
7367 | if (IS_ERR(p)) { | |
7368 | err = PTR_ERR(p); | |
7369 | - if (err != -EACCES) | |
7370 | - goto err_put_ctx; | |
7371 | - } | |
7372 | - spin_lock(&gss_auth->lock); | |
7373 | - gss_msg = __gss_find_upcall(gss_auth, uid); | |
7374 | - if (gss_msg) { | |
7375 | - if (err == 0 && gss_msg->ctx == NULL) | |
7376 | - gss_msg->ctx = gss_get_ctx(ctx); | |
7377 | - gss_msg->msg.errno = err; | |
7378 | - __gss_unhash_msg(gss_msg); | |
7379 | - spin_unlock(&gss_auth->lock); | |
7380 | - gss_release_msg(gss_msg); | |
7381 | - } else { | |
7382 | - struct auth_cred acred = { .uid = uid }; | |
7383 | - spin_unlock(&gss_auth->lock); | |
7384 | - cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, RPCAUTH_LOOKUP_NEW); | |
7385 | - if (IS_ERR(cred)) { | |
7386 | - err = PTR_ERR(cred); | |
7387 | - goto err_put_ctx; | |
7388 | - } | |
7389 | - gss_cred_set_ctx(cred, gss_get_ctx(ctx)); | |
7390 | + gss_msg->msg.errno = (err == -EACCES) ? -EACCES : -EAGAIN; | |
7391 | + goto err_release_msg; | |
7392 | } | |
7393 | - gss_put_ctx(ctx); | |
7394 | - kfree(buf); | |
7395 | - dprintk("RPC: gss_pipe_downcall returning length %Zu\n", mlen); | |
7396 | - return mlen; | |
7397 | + gss_msg->ctx = gss_get_ctx(ctx); | |
7398 | + err = mlen; | |
7399 | + | |
7400 | +err_release_msg: | |
7401 | + spin_lock(&inode->i_lock); | |
7402 | + __gss_unhash_msg(gss_msg); | |
7403 | + spin_unlock(&inode->i_lock); | |
7404 | + gss_release_msg(gss_msg); | |
7405 | err_put_ctx: | |
7406 | gss_put_ctx(ctx); | |
7407 | err: | |
7408 | kfree(buf); | |
7409 | out: | |
7410 | - dprintk("RPC: gss_pipe_downcall returning %d\n", err); | |
7411 | + dprintk("RPC: gss_pipe_downcall returning %Zd\n", err); | |
7412 | return err; | |
7413 | } | |
7414 | ||
7415 | @@ -563,27 +564,21 @@ static void | |
7416 | gss_pipe_release(struct inode *inode) | |
7417 | { | |
7418 | struct rpc_inode *rpci = RPC_I(inode); | |
7419 | - struct rpc_clnt *clnt; | |
7420 | - struct rpc_auth *auth; | |
7421 | - struct gss_auth *gss_auth; | |
7422 | + struct gss_upcall_msg *gss_msg; | |
7423 | ||
7424 | - clnt = rpci->private; | |
7425 | - auth = clnt->cl_auth; | |
7426 | - gss_auth = container_of(auth, struct gss_auth, rpc_auth); | |
7427 | - spin_lock(&gss_auth->lock); | |
7428 | - while (!list_empty(&gss_auth->upcalls)) { | |
7429 | - struct gss_upcall_msg *gss_msg; | |
7430 | + spin_lock(&inode->i_lock); | |
7431 | + while (!list_empty(&rpci->in_downcall)) { | |
7432 | ||
7433 | - gss_msg = list_entry(gss_auth->upcalls.next, | |
7434 | + gss_msg = list_entry(rpci->in_downcall.next, | |
7435 | struct gss_upcall_msg, list); | |
7436 | gss_msg->msg.errno = -EPIPE; | |
7437 | atomic_inc(&gss_msg->count); | |
7438 | __gss_unhash_msg(gss_msg); | |
7439 | - spin_unlock(&gss_auth->lock); | |
7440 | + spin_unlock(&inode->i_lock); | |
7441 | gss_release_msg(gss_msg); | |
7442 | - spin_lock(&gss_auth->lock); | |
7443 | + spin_lock(&inode->i_lock); | |
7444 | } | |
7445 | - spin_unlock(&gss_auth->lock); | |
7446 | + spin_unlock(&inode->i_lock); | |
7447 | } | |
7448 | ||
7449 | static void | |
7450 | @@ -637,18 +632,13 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | |
7451 | gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor); | |
7452 | if (gss_auth->service == 0) | |
7453 | goto err_put_mech; | |
7454 | - INIT_LIST_HEAD(&gss_auth->upcalls); | |
7455 | - spin_lock_init(&gss_auth->lock); | |
7456 | auth = &gss_auth->rpc_auth; | |
7457 | auth->au_cslack = GSS_CRED_SLACK >> 2; | |
7458 | auth->au_rslack = GSS_VERF_SLACK >> 2; | |
7459 | auth->au_ops = &authgss_ops; | |
7460 | auth->au_flavor = flavor; | |
7461 | atomic_set(&auth->au_count, 1); | |
7462 | - | |
7463 | - err = rpcauth_init_credcache(auth, GSS_CRED_EXPIRE); | |
7464 | - if (err) | |
7465 | - goto err_put_mech; | |
7466 | + kref_init(&gss_auth->kref); | |
7467 | ||
7468 | gss_auth->dentry = rpc_mkpipe(clnt->cl_dentry, gss_auth->mech->gm_name, | |
7469 | clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); | |
7470 | @@ -657,7 +647,13 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | |
7471 | goto err_put_mech; | |
7472 | } | |
7473 | ||
7474 | + err = rpcauth_init_credcache(auth); | |
7475 | + if (err) | |
7476 | + goto err_unlink_pipe; | |
7477 | + | |
7478 | return auth; | |
7479 | +err_unlink_pipe: | |
7480 | + rpc_unlink(gss_auth->dentry); | |
7481 | err_put_mech: | |
7482 | gss_mech_put(gss_auth->mech); | |
7483 | err_free: | |
7484 | @@ -668,6 +664,25 @@ out_dec: | |
7485 | } | |
7486 | ||
7487 | static void | |
7488 | +gss_free(struct gss_auth *gss_auth) | |
7489 | +{ | |
7490 | + rpc_unlink(gss_auth->dentry); | |
7491 | + gss_auth->dentry = NULL; | |
7492 | + gss_mech_put(gss_auth->mech); | |
7493 | + | |
7494 | + kfree(gss_auth); | |
7495 | + module_put(THIS_MODULE); | |
7496 | +} | |
7497 | + | |
7498 | +static void | |
7499 | +gss_free_callback(struct kref *kref) | |
7500 | +{ | |
7501 | + struct gss_auth *gss_auth = container_of(kref, struct gss_auth, kref); | |
7502 | + | |
7503 | + gss_free(gss_auth); | |
7504 | +} | |
7505 | + | |
7506 | +static void | |
7507 | gss_destroy(struct rpc_auth *auth) | |
7508 | { | |
7509 | struct gss_auth *gss_auth; | |
7510 | @@ -675,23 +690,51 @@ gss_destroy(struct rpc_auth *auth) | |
7511 | dprintk("RPC: destroying GSS authenticator %p flavor %d\n", | |
7512 | auth, auth->au_flavor); | |
7513 | ||
7514 | + rpcauth_destroy_credcache(auth); | |
7515 | + | |
7516 | gss_auth = container_of(auth, struct gss_auth, rpc_auth); | |
7517 | - rpc_unlink(gss_auth->dentry); | |
7518 | - gss_auth->dentry = NULL; | |
7519 | - gss_mech_put(gss_auth->mech); | |
7520 | + kref_put(&gss_auth->kref, gss_free_callback); | |
7521 | +} | |
7522 | ||
7523 | - rpcauth_free_credcache(auth); | |
7524 | - kfree(gss_auth); | |
7525 | - module_put(THIS_MODULE); | |
7526 | +/* | |
7527 | + * gss_destroying_context will cause the RPCSEC_GSS to send a NULL RPC call | |
7528 | + * to the server with the GSS control procedure field set to | |
7529 | + * RPC_GSS_PROC_DESTROY. This should normally cause the server to release | |
7530 | + * all RPCSEC_GSS state associated with that context. | |
7531 | + */ | |
7532 | +static int | |
7533 | +gss_destroying_context(struct rpc_cred *cred) | |
7534 | +{ | |
7535 | + struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | |
7536 | + struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); | |
7537 | + struct rpc_task *task; | |
7538 | + | |
7539 | + if (gss_cred->gc_ctx == NULL || | |
7540 | + gss_cred->gc_ctx->gc_proc == RPC_GSS_PROC_DESTROY) | |
7541 | + return 0; | |
7542 | + | |
7543 | + gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY; | |
7544 | + cred->cr_ops = &gss_nullops; | |
7545 | + | |
7546 | + /* Take a reference to ensure the cred will be destroyed either | |
7547 | + * by the RPC call or by the put_rpccred() below */ | |
7548 | + get_rpccred(cred); | |
7549 | + | |
7550 | + task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC); | |
7551 | + if (!IS_ERR(task)) | |
7552 | + rpc_put_task(task); | |
7553 | + | |
7554 | + put_rpccred(cred); | |
7555 | + return 1; | |
7556 | } | |
7557 | ||
7558 | -/* gss_destroy_cred (and gss_destroy_ctx) are used to clean up after failure | |
7559 | +/* gss_destroy_cred (and gss_free_ctx) are used to clean up after failure | |
7560 | * to create a new cred or context, so they check that things have been | |
7561 | * allocated before freeing them. */ | |
7562 | static void | |
7563 | -gss_destroy_ctx(struct gss_cl_ctx *ctx) | |
7564 | +gss_do_free_ctx(struct gss_cl_ctx *ctx) | |
7565 | { | |
7566 | - dprintk("RPC: gss_destroy_ctx\n"); | |
7567 | + dprintk("RPC: gss_free_ctx\n"); | |
7568 | ||
7569 | if (ctx->gc_gss_ctx) | |
7570 | gss_delete_sec_context(&ctx->gc_gss_ctx); | |
7571 | @@ -701,15 +744,46 @@ gss_destroy_ctx(struct gss_cl_ctx *ctx) | |
7572 | } | |
7573 | ||
7574 | static void | |
7575 | -gss_destroy_cred(struct rpc_cred *rc) | |
7576 | +gss_free_ctx_callback(struct rcu_head *head) | |
7577 | { | |
7578 | - struct gss_cred *cred = container_of(rc, struct gss_cred, gc_base); | |
7579 | + struct gss_cl_ctx *ctx = container_of(head, struct gss_cl_ctx, gc_rcu); | |
7580 | + gss_do_free_ctx(ctx); | |
7581 | +} | |
7582 | ||
7583 | - dprintk("RPC: gss_destroy_cred \n"); | |
7584 | +static void | |
7585 | +gss_free_ctx(struct gss_cl_ctx *ctx) | |
7586 | +{ | |
7587 | + call_rcu(&ctx->gc_rcu, gss_free_ctx_callback); | |
7588 | +} | |
7589 | ||
7590 | - if (cred->gc_ctx) | |
7591 | - gss_put_ctx(cred->gc_ctx); | |
7592 | - kfree(cred); | |
7593 | +static void | |
7594 | +gss_free_cred(struct gss_cred *gss_cred) | |
7595 | +{ | |
7596 | + dprintk("RPC: gss_free_cred %p\n", gss_cred); | |
7597 | + kfree(gss_cred); | |
7598 | +} | |
7599 | + | |
7600 | +static void | |
7601 | +gss_free_cred_callback(struct rcu_head *head) | |
7602 | +{ | |
7603 | + struct gss_cred *gss_cred = container_of(head, struct gss_cred, gc_base.cr_rcu); | |
7604 | + gss_free_cred(gss_cred); | |
7605 | +} | |
7606 | + | |
7607 | +static void | |
7608 | +gss_destroy_cred(struct rpc_cred *cred) | |
7609 | +{ | |
7610 | + struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | |
7611 | + struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); | |
7612 | + struct gss_cl_ctx *ctx = gss_cred->gc_ctx; | |
7613 | + | |
7614 | + if (gss_destroying_context(cred)) | |
7615 | + return; | |
7616 | + rcu_assign_pointer(gss_cred->gc_ctx, NULL); | |
7617 | + call_rcu(&cred->cr_rcu, gss_free_cred_callback); | |
7618 | + if (ctx) | |
7619 | + gss_put_ctx(ctx); | |
7620 | + kref_put(&gss_auth->kref, gss_free_callback); | |
7621 | } | |
7622 | ||
7623 | /* | |
7624 | @@ -734,16 +808,14 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) | |
7625 | if (!(cred = kzalloc(sizeof(*cred), GFP_KERNEL))) | |
7626 | goto out_err; | |
7627 | ||
7628 | - atomic_set(&cred->gc_count, 1); | |
7629 | - cred->gc_uid = acred->uid; | |
7630 | + rpcauth_init_cred(&cred->gc_base, acred, auth, &gss_credops); | |
7631 | /* | |
7632 | * Note: in order to force a call to call_refresh(), we deliberately | |
7633 | * fail to flag the credential as RPCAUTH_CRED_UPTODATE. | |
7634 | */ | |
7635 | - cred->gc_flags = 0; | |
7636 | - cred->gc_base.cr_ops = &gss_credops; | |
7637 | - cred->gc_base.cr_flags = RPCAUTH_CRED_NEW; | |
7638 | + cred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_NEW; | |
7639 | cred->gc_service = gss_auth->service; | |
7640 | + kref_get(&gss_auth->kref); | |
7641 | return &cred->gc_base; | |
7642 | ||
7643 | out_err: | |
7644 | @@ -774,7 +846,7 @@ gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags) | |
7645 | * we don't really care if the credential has expired or not, | |
7646 | * since the caller should be prepared to reinitialise it. | |
7647 | */ | |
7648 | - if ((flags & RPCAUTH_LOOKUP_NEW) && (rc->cr_flags & RPCAUTH_CRED_NEW)) | |
7649 | + if ((flags & RPCAUTH_LOOKUP_NEW) && test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags)) | |
7650 | goto out; | |
7651 | /* Don't match with creds that have expired. */ | |
7652 | if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry)) | |
7653 | @@ -830,7 +902,7 @@ gss_marshal(struct rpc_task *task, __be32 *p) | |
7654 | mic.data = (u8 *)(p + 1); | |
7655 | maj_stat = gss_get_mic(ctx->gc_gss_ctx, &verf_buf, &mic); | |
7656 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) { | |
7657 | - cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; | |
7658 | + clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | |
7659 | } else if (maj_stat != 0) { | |
7660 | printk("gss_marshal: gss_get_mic FAILED (%d)\n", maj_stat); | |
7661 | goto out_put_ctx; | |
7662 | @@ -855,6 +927,13 @@ gss_refresh(struct rpc_task *task) | |
7663 | return 0; | |
7664 | } | |
7665 | ||
7666 | +/* Dummy refresh routine: used only when destroying the context */ | |
7667 | +static int | |
7668 | +gss_refresh_null(struct rpc_task *task) | |
7669 | +{ | |
7670 | + return -EACCES; | |
7671 | +} | |
7672 | + | |
7673 | static __be32 * | |
7674 | gss_validate(struct rpc_task *task, __be32 *p) | |
7675 | { | |
7676 | @@ -883,12 +962,15 @@ gss_validate(struct rpc_task *task, __be32 *p) | |
7677 | ||
7678 | maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic); | |
7679 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | |
7680 | - cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; | |
7681 | - if (maj_stat) | |
7682 | + clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | |
7683 | + if (maj_stat) { | |
7684 | + dprintk("RPC: %5u gss_validate: gss_verify_mic returned" | |
7685 | + "error 0x%08x\n", task->tk_pid, maj_stat); | |
7686 | goto out_bad; | |
7687 | + } | |
7688 | /* We leave it to unwrap to calculate au_rslack. For now we just | |
7689 | * calculate the length of the verifier: */ | |
7690 | - task->tk_auth->au_verfsize = XDR_QUADLEN(len) + 2; | |
7691 | + cred->cr_auth->au_verfsize = XDR_QUADLEN(len) + 2; | |
7692 | gss_put_ctx(ctx); | |
7693 | dprintk("RPC: %5u gss_validate: gss_verify_mic succeeded.\n", | |
7694 | task->tk_pid); | |
7695 | @@ -937,7 +1019,7 @@ gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | |
7696 | maj_stat = gss_get_mic(ctx->gc_gss_ctx, &integ_buf, &mic); | |
7697 | status = -EIO; /* XXX? */ | |
7698 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | |
7699 | - cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; | |
7700 | + clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | |
7701 | else if (maj_stat) | |
7702 | return status; | |
7703 | q = xdr_encode_opaque(p, NULL, mic.len); | |
7704 | @@ -1036,7 +1118,7 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | |
7705 | /* We're assuming that when GSS_S_CONTEXT_EXPIRED, the encryption was | |
7706 | * done anyway, so it's safe to put the request on the wire: */ | |
7707 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | |
7708 | - cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; | |
7709 | + clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | |
7710 | else if (maj_stat) | |
7711 | return status; | |
7712 | ||
7713 | @@ -1123,7 +1205,7 @@ gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | |
7714 | ||
7715 | maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf, &mic); | |
7716 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | |
7717 | - cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; | |
7718 | + clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | |
7719 | if (maj_stat != GSS_S_COMPLETE) | |
7720 | return status; | |
7721 | return 0; | |
7722 | @@ -1148,7 +1230,7 @@ gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | |
7723 | ||
7724 | maj_stat = gss_unwrap(ctx->gc_gss_ctx, offset, rcv_buf); | |
7725 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | |
7726 | - cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; | |
7727 | + clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | |
7728 | if (maj_stat != GSS_S_COMPLETE) | |
7729 | return status; | |
7730 | if (ntohl(*(*p)++) != rqstp->rq_seqno) | |
7731 | @@ -1188,7 +1270,7 @@ gss_unwrap_resp(struct rpc_task *task, | |
7732 | break; | |
7733 | } | |
7734 | /* take into account extra slack for integrity and privacy cases: */ | |
7735 | - task->tk_auth->au_rslack = task->tk_auth->au_verfsize + (p - savedp) | |
7736 | + cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + (p - savedp) | |
7737 | + (savedlen - head->iov_len); | |
7738 | out_decode: | |
7739 | status = decode(rqstp, p, obj); | |
7740 | @@ -1199,7 +1281,7 @@ out: | |
7741 | return status; | |
7742 | } | |
7743 | ||
7744 | -static struct rpc_authops authgss_ops = { | |
7745 | +static const struct rpc_authops authgss_ops = { | |
7746 | .owner = THIS_MODULE, | |
7747 | .au_flavor = RPC_AUTH_GSS, | |
7748 | #ifdef RPC_DEBUG | |
7749 | @@ -1211,7 +1293,7 @@ static struct rpc_authops authgss_ops = { | |
7750 | .crcreate = gss_create_cred | |
7751 | }; | |
7752 | ||
7753 | -static struct rpc_credops gss_credops = { | |
7754 | +static const struct rpc_credops gss_credops = { | |
7755 | .cr_name = "AUTH_GSS", | |
7756 | .crdestroy = gss_destroy_cred, | |
7757 | .cr_init = gss_cred_init, | |
7758 | @@ -1223,6 +1305,17 @@ static struct rpc_credops gss_credops = { | |
7759 | .crunwrap_resp = gss_unwrap_resp, | |
7760 | }; | |
7761 | ||
7762 | +static const struct rpc_credops gss_nullops = { | |
7763 | + .cr_name = "AUTH_GSS", | |
7764 | + .crdestroy = gss_destroy_cred, | |
7765 | + .crmatch = gss_match, | |
7766 | + .crmarshal = gss_marshal, | |
7767 | + .crrefresh = gss_refresh_null, | |
7768 | + .crvalidate = gss_validate, | |
7769 | + .crwrap_req = gss_wrap_req, | |
7770 | + .crunwrap_resp = gss_unwrap_resp, | |
7771 | +}; | |
7772 | + | |
7773 | static struct rpc_pipe_ops gss_upcall_ops = { | |
7774 | .upcall = gss_pipe_upcall, | |
7775 | .downcall = gss_pipe_downcall, | |
7776 | diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c | |
7777 | index 7b19432..71b9dae 100644 | |
7778 | --- a/net/sunrpc/auth_gss/gss_krb5_mech.c | |
7779 | +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c | |
7780 | @@ -201,7 +201,7 @@ gss_delete_sec_context_kerberos(void *internal_ctx) { | |
7781 | kfree(kctx); | |
7782 | } | |
7783 | ||
7784 | -static struct gss_api_ops gss_kerberos_ops = { | |
7785 | +static const struct gss_api_ops gss_kerberos_ops = { | |
7786 | .gss_import_sec_context = gss_import_sec_context_kerberos, | |
7787 | .gss_get_mic = gss_get_mic_kerberos, | |
7788 | .gss_verify_mic = gss_verify_mic_kerberos, | |
7789 | diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c | |
7790 | index 7e15aa6..577d590 100644 | |
7791 | --- a/net/sunrpc/auth_gss/gss_spkm3_mech.c | |
7792 | +++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c | |
7793 | @@ -202,7 +202,7 @@ gss_get_mic_spkm3(struct gss_ctx *ctx, | |
7794 | return err; | |
7795 | } | |
7796 | ||
7797 | -static struct gss_api_ops gss_spkm3_ops = { | |
7798 | +static const struct gss_api_ops gss_spkm3_ops = { | |
7799 | .gss_import_sec_context = gss_import_sec_context_spkm3, | |
7800 | .gss_get_mic = gss_get_mic_spkm3, | |
7801 | .gss_verify_mic = gss_verify_mic_spkm3, | |
7802 | diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c | |
7803 | index 3df9fcc..537d0e8 100644 | |
7804 | --- a/net/sunrpc/auth_null.c | |
7805 | +++ b/net/sunrpc/auth_null.c | |
7806 | @@ -76,7 +76,7 @@ nul_marshal(struct rpc_task *task, __be32 *p) | |
7807 | static int | |
7808 | nul_refresh(struct rpc_task *task) | |
7809 | { | |
7810 | - task->tk_msg.rpc_cred->cr_flags |= RPCAUTH_CRED_UPTODATE; | |
7811 | + set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_msg.rpc_cred->cr_flags); | |
7812 | return 0; | |
7813 | } | |
7814 | ||
7815 | @@ -101,7 +101,7 @@ nul_validate(struct rpc_task *task, __be32 *p) | |
7816 | return p; | |
7817 | } | |
7818 | ||
7819 | -struct rpc_authops authnull_ops = { | |
7820 | +const struct rpc_authops authnull_ops = { | |
7821 | .owner = THIS_MODULE, | |
7822 | .au_flavor = RPC_AUTH_NULL, | |
7823 | #ifdef RPC_DEBUG | |
7824 | @@ -122,7 +122,7 @@ struct rpc_auth null_auth = { | |
7825 | }; | |
7826 | ||
7827 | static | |
7828 | -struct rpc_credops null_credops = { | |
7829 | +const struct rpc_credops null_credops = { | |
7830 | .cr_name = "AUTH_NULL", | |
7831 | .crdestroy = nul_destroy_cred, | |
7832 | .crmatch = nul_match, | |
7833 | @@ -133,9 +133,11 @@ struct rpc_credops null_credops = { | |
7834 | ||
7835 | static | |
7836 | struct rpc_cred null_cred = { | |
7837 | + .cr_lru = LIST_HEAD_INIT(null_cred.cr_lru), | |
7838 | + .cr_auth = &null_auth, | |
7839 | .cr_ops = &null_credops, | |
7840 | .cr_count = ATOMIC_INIT(1), | |
7841 | - .cr_flags = RPCAUTH_CRED_UPTODATE, | |
7842 | + .cr_flags = 1UL << RPCAUTH_CRED_UPTODATE, | |
7843 | #ifdef RPC_DEBUG | |
7844 | .cr_magic = RPCAUTH_CRED_MAGIC, | |
7845 | #endif | |
7846 | diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c | |
7847 | index 4e7733a..5ed91e5 100644 | |
7848 | --- a/net/sunrpc/auth_unix.c | |
7849 | +++ b/net/sunrpc/auth_unix.c | |
7850 | @@ -20,11 +20,6 @@ struct unx_cred { | |
7851 | gid_t uc_gids[NFS_NGROUPS]; | |
7852 | }; | |
7853 | #define uc_uid uc_base.cr_uid | |
7854 | -#define uc_count uc_base.cr_count | |
7855 | -#define uc_flags uc_base.cr_flags | |
7856 | -#define uc_expire uc_base.cr_expire | |
7857 | - | |
7858 | -#define UNX_CRED_EXPIRE (60 * HZ) | |
7859 | ||
7860 | #define UNX_WRITESLACK (21 + (UNX_MAXNODENAME >> 2)) | |
7861 | ||
7862 | @@ -34,15 +29,14 @@ struct unx_cred { | |
7863 | ||
7864 | static struct rpc_auth unix_auth; | |
7865 | static struct rpc_cred_cache unix_cred_cache; | |
7866 | -static struct rpc_credops unix_credops; | |
7867 | +static const struct rpc_credops unix_credops; | |
7868 | ||
7869 | static struct rpc_auth * | |
7870 | unx_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | |
7871 | { | |
7872 | dprintk("RPC: creating UNIX authenticator for client %p\n", | |
7873 | clnt); | |
7874 | - if (atomic_inc_return(&unix_auth.au_count) == 0) | |
7875 | - unix_cred_cache.nextgc = jiffies + (unix_cred_cache.expire >> 1); | |
7876 | + atomic_inc(&unix_auth.au_count); | |
7877 | return &unix_auth; | |
7878 | } | |
7879 | ||
7880 | @@ -50,7 +44,7 @@ static void | |
7881 | unx_destroy(struct rpc_auth *auth) | |
7882 | { | |
7883 | dprintk("RPC: destroying UNIX authenticator %p\n", auth); | |
7884 | - rpcauth_free_credcache(auth); | |
7885 | + rpcauth_clear_credcache(auth->au_credcache); | |
7886 | } | |
7887 | ||
7888 | /* | |
7889 | @@ -74,8 +68,8 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) | |
7890 | if (!(cred = kmalloc(sizeof(*cred), GFP_KERNEL))) | |
7891 | return ERR_PTR(-ENOMEM); | |
7892 | ||
7893 | - atomic_set(&cred->uc_count, 1); | |
7894 | - cred->uc_flags = RPCAUTH_CRED_UPTODATE; | |
7895 | + rpcauth_init_cred(&cred->uc_base, acred, auth, &unix_credops); | |
7896 | + cred->uc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE; | |
7897 | if (flags & RPCAUTH_LOOKUP_ROOTCREDS) { | |
7898 | cred->uc_uid = 0; | |
7899 | cred->uc_gid = 0; | |
7900 | @@ -85,22 +79,34 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) | |
7901 | if (groups > NFS_NGROUPS) | |
7902 | groups = NFS_NGROUPS; | |
7903 | ||
7904 | - cred->uc_uid = acred->uid; | |
7905 | cred->uc_gid = acred->gid; | |
7906 | for (i = 0; i < groups; i++) | |
7907 | cred->uc_gids[i] = GROUP_AT(acred->group_info, i); | |
7908 | if (i < NFS_NGROUPS) | |
7909 | cred->uc_gids[i] = NOGROUP; | |
7910 | } | |
7911 | - cred->uc_base.cr_ops = &unix_credops; | |
7912 | ||
7913 | - return (struct rpc_cred *) cred; | |
7914 | + return &cred->uc_base; | |
7915 | +} | |
7916 | + | |
7917 | +static void | |
7918 | +unx_free_cred(struct unx_cred *unx_cred) | |
7919 | +{ | |
7920 | + dprintk("RPC: unx_free_cred %p\n", unx_cred); | |
7921 | + kfree(unx_cred); | |
7922 | +} | |
7923 | + | |
7924 | +static void | |
7925 | +unx_free_cred_callback(struct rcu_head *head) | |
7926 | +{ | |
7927 | + struct unx_cred *unx_cred = container_of(head, struct unx_cred, uc_base.cr_rcu); | |
7928 | + unx_free_cred(unx_cred); | |
7929 | } | |
7930 | ||
7931 | static void | |
7932 | unx_destroy_cred(struct rpc_cred *cred) | |
7933 | { | |
7934 | - kfree(cred); | |
7935 | + call_rcu(&cred->cr_rcu, unx_free_cred_callback); | |
7936 | } | |
7937 | ||
7938 | /* | |
7939 | @@ -111,7 +117,7 @@ unx_destroy_cred(struct rpc_cred *cred) | |
7940 | static int | |
7941 | unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags) | |
7942 | { | |
7943 | - struct unx_cred *cred = (struct unx_cred *) rcred; | |
7944 | + struct unx_cred *cred = container_of(rcred, struct unx_cred, uc_base); | |
7945 | int i; | |
7946 | ||
7947 | if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) { | |
7948 | @@ -142,7 +148,7 @@ static __be32 * | |
7949 | unx_marshal(struct rpc_task *task, __be32 *p) | |
7950 | { | |
7951 | struct rpc_clnt *clnt = task->tk_client; | |
7952 | - struct unx_cred *cred = (struct unx_cred *) task->tk_msg.rpc_cred; | |
7953 | + struct unx_cred *cred = container_of(task->tk_msg.rpc_cred, struct unx_cred, uc_base); | |
7954 | __be32 *base, *hold; | |
7955 | int i; | |
7956 | ||
7957 | @@ -175,7 +181,7 @@ unx_marshal(struct rpc_task *task, __be32 *p) | |
7958 | static int | |
7959 | unx_refresh(struct rpc_task *task) | |
7960 | { | |
7961 | - task->tk_msg.rpc_cred->cr_flags |= RPCAUTH_CRED_UPTODATE; | |
7962 | + set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_msg.rpc_cred->cr_flags); | |
7963 | return 0; | |
7964 | } | |
7965 | ||
7966 | @@ -198,13 +204,18 @@ unx_validate(struct rpc_task *task, __be32 *p) | |
7967 | printk("RPC: giant verf size: %u\n", size); | |
7968 | return NULL; | |
7969 | } | |
7970 | - task->tk_auth->au_rslack = (size >> 2) + 2; | |
7971 | + task->tk_msg.rpc_cred->cr_auth->au_rslack = (size >> 2) + 2; | |
7972 | p += (size >> 2); | |
7973 | ||
7974 | return p; | |
7975 | } | |
7976 | ||
7977 | -struct rpc_authops authunix_ops = { | |
7978 | +void __init rpc_init_authunix(void) | |
7979 | +{ | |
7980 | + spin_lock_init(&unix_cred_cache.lock); | |
7981 | +} | |
7982 | + | |
7983 | +const struct rpc_authops authunix_ops = { | |
7984 | .owner = THIS_MODULE, | |
7985 | .au_flavor = RPC_AUTH_UNIX, | |
7986 | #ifdef RPC_DEBUG | |
7987 | @@ -218,7 +229,6 @@ struct rpc_authops authunix_ops = { | |
7988 | ||
7989 | static | |
7990 | struct rpc_cred_cache unix_cred_cache = { | |
7991 | - .expire = UNX_CRED_EXPIRE, | |
7992 | }; | |
7993 | ||
7994 | static | |
7995 | @@ -232,7 +242,7 @@ struct rpc_auth unix_auth = { | |
7996 | }; | |
7997 | ||
7998 | static | |
7999 | -struct rpc_credops unix_credops = { | |
8000 | +const struct rpc_credops unix_credops = { | |
8001 | .cr_name = "AUTH_UNIX", | |
8002 | .crdestroy = unx_destroy_cred, | |
8003 | .crmatch = unx_match, | |
8004 | diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c | |
8005 | index d8fbee4..5d3fe7b 100644 | |
8006 | --- a/net/sunrpc/clnt.c | |
8007 | +++ b/net/sunrpc/clnt.c | |
8008 | @@ -44,6 +44,12 @@ | |
8009 | dprintk("RPC: %5u %s (status %d)\n", t->tk_pid, \ | |
8010 | __FUNCTION__, t->tk_status) | |
8011 | ||
8012 | +/* | |
8013 | + * All RPC clients are linked into this list | |
8014 | + */ | |
8015 | +static LIST_HEAD(all_clients); | |
8016 | +static DEFINE_SPINLOCK(rpc_client_lock); | |
8017 | + | |
8018 | static DECLARE_WAIT_QUEUE_HEAD(destroy_wait); | |
8019 | ||
8020 | ||
8021 | @@ -66,6 +72,21 @@ static void call_connect_status(struct rpc_task *task); | |
8022 | static __be32 * call_header(struct rpc_task *task); | |
8023 | static __be32 * call_verify(struct rpc_task *task); | |
8024 | ||
8025 | +static int rpc_ping(struct rpc_clnt *clnt, int flags); | |
8026 | + | |
8027 | +static void rpc_register_client(struct rpc_clnt *clnt) | |
8028 | +{ | |
8029 | + spin_lock(&rpc_client_lock); | |
8030 | + list_add(&clnt->cl_clients, &all_clients); | |
8031 | + spin_unlock(&rpc_client_lock); | |
8032 | +} | |
8033 | + | |
8034 | +static void rpc_unregister_client(struct rpc_clnt *clnt) | |
8035 | +{ | |
8036 | + spin_lock(&rpc_client_lock); | |
8037 | + list_del(&clnt->cl_clients); | |
8038 | + spin_unlock(&rpc_client_lock); | |
8039 | +} | |
8040 | ||
8041 | static int | |
8042 | rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) | |
8043 | @@ -111,6 +132,9 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s | |
8044 | dprintk("RPC: creating %s client for %s (xprt %p)\n", | |
8045 | program->name, servname, xprt); | |
8046 | ||
8047 | + err = rpciod_up(); | |
8048 | + if (err) | |
8049 | + goto out_no_rpciod; | |
8050 | err = -EINVAL; | |
8051 | if (!xprt) | |
8052 | goto out_no_xprt; | |
8053 | @@ -121,8 +145,6 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s | |
8054 | clnt = kzalloc(sizeof(*clnt), GFP_KERNEL); | |
8055 | if (!clnt) | |
8056 | goto out_err; | |
8057 | - atomic_set(&clnt->cl_users, 0); | |
8058 | - atomic_set(&clnt->cl_count, 1); | |
8059 | clnt->cl_parent = clnt; | |
8060 | ||
8061 | clnt->cl_server = clnt->cl_inline_name; | |
8062 | @@ -148,6 +170,8 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s | |
8063 | if (clnt->cl_metrics == NULL) | |
8064 | goto out_no_stats; | |
8065 | clnt->cl_program = program; | |
8066 | + INIT_LIST_HEAD(&clnt->cl_tasks); | |
8067 | + spin_lock_init(&clnt->cl_lock); | |
8068 | ||
8069 | if (!xprt_bound(clnt->cl_xprt)) | |
8070 | clnt->cl_autobind = 1; | |
8071 | @@ -155,6 +179,8 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s | |
8072 | clnt->cl_rtt = &clnt->cl_rtt_default; | |
8073 | rpc_init_rtt(&clnt->cl_rtt_default, xprt->timeout.to_initval); | |
8074 | ||
8075 | + kref_init(&clnt->cl_kref); | |
8076 | + | |
8077 | err = rpc_setup_pipedir(clnt, program->pipe_dir_name); | |
8078 | if (err < 0) | |
8079 | goto out_no_path; | |
8080 | @@ -172,6 +198,7 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s | |
8081 | if (clnt->cl_nodelen > UNX_MAXNODENAME) | |
8082 | clnt->cl_nodelen = UNX_MAXNODENAME; | |
8083 | memcpy(clnt->cl_nodename, utsname()->nodename, clnt->cl_nodelen); | |
8084 | + rpc_register_client(clnt); | |
8085 | return clnt; | |
8086 | ||
8087 | out_no_auth: | |
8088 | @@ -188,6 +215,8 @@ out_no_stats: | |
8089 | out_err: | |
8090 | xprt_put(xprt); | |
8091 | out_no_xprt: | |
8092 | + rpciod_down(); | |
8093 | +out_no_rpciod: | |
8094 | return ERR_PTR(err); | |
8095 | } | |
8096 | ||
8097 | @@ -205,13 +234,32 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) | |
8098 | { | |
8099 | struct rpc_xprt *xprt; | |
8100 | struct rpc_clnt *clnt; | |
8101 | + struct rpc_xprtsock_create xprtargs = { | |
8102 | + .proto = args->protocol, | |
8103 | + .srcaddr = args->saddress, | |
8104 | + .dstaddr = args->address, | |
8105 | + .addrlen = args->addrsize, | |
8106 | + .timeout = args->timeout | |
8107 | + }; | |
8108 | + char servername[20]; | |
8109 | ||
8110 | - xprt = xprt_create_transport(args->protocol, args->address, | |
8111 | - args->addrsize, args->timeout); | |
8112 | + xprt = xprt_create_transport(&xprtargs); | |
8113 | if (IS_ERR(xprt)) | |
8114 | return (struct rpc_clnt *)xprt; | |
8115 | ||
8116 | /* | |
8117 | + * If the caller chooses not to specify a hostname, whip | |
8118 | + * up a string representation of the passed-in address. | |
8119 | + */ | |
8120 | + if (args->servername == NULL) { | |
8121 | + struct sockaddr_in *addr = | |
8122 | + (struct sockaddr_in *) &args->address; | |
8123 | + snprintf(servername, sizeof(servername), NIPQUAD_FMT, | |
8124 | + NIPQUAD(addr->sin_addr.s_addr)); | |
8125 | + args->servername = servername; | |
8126 | + } | |
8127 | + | |
8128 | + /* | |
8129 | * By default, kernel RPC client connects from a reserved port. | |
8130 | * CAP_NET_BIND_SERVICE will not be set for unprivileged requesters, | |
8131 | * but it is always enabled for rpciod, which handles the connect | |
8132 | @@ -245,8 +293,6 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) | |
8133 | clnt->cl_intr = 1; | |
8134 | if (args->flags & RPC_CLNT_CREATE_AUTOBIND) | |
8135 | clnt->cl_autobind = 1; | |
8136 | - if (args->flags & RPC_CLNT_CREATE_ONESHOT) | |
8137 | - clnt->cl_oneshot = 1; | |
8138 | if (args->flags & RPC_CLNT_CREATE_DISCRTRY) | |
8139 | clnt->cl_discrtry = 1; | |
8140 | ||
8141 | @@ -268,24 +314,25 @@ rpc_clone_client(struct rpc_clnt *clnt) | |
8142 | new = kmemdup(clnt, sizeof(*new), GFP_KERNEL); | |
8143 | if (!new) | |
8144 | goto out_no_clnt; | |
8145 | - atomic_set(&new->cl_count, 1); | |
8146 | - atomic_set(&new->cl_users, 0); | |
8147 | + new->cl_parent = clnt; | |
8148 | + /* Turn off autobind on clones */ | |
8149 | + new->cl_autobind = 0; | |
8150 | + INIT_LIST_HEAD(&new->cl_tasks); | |
8151 | + spin_lock_init(&new->cl_lock); | |
8152 | + rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); | |
8153 | new->cl_metrics = rpc_alloc_iostats(clnt); | |
8154 | if (new->cl_metrics == NULL) | |
8155 | goto out_no_stats; | |
8156 | + kref_init(&new->cl_kref); | |
8157 | err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name); | |
8158 | if (err != 0) | |
8159 | goto out_no_path; | |
8160 | - new->cl_parent = clnt; | |
8161 | - atomic_inc(&clnt->cl_count); | |
8162 | - new->cl_xprt = xprt_get(clnt->cl_xprt); | |
8163 | - /* Turn off autobind on clones */ | |
8164 | - new->cl_autobind = 0; | |
8165 | - new->cl_oneshot = 0; | |
8166 | - new->cl_dead = 0; | |
8167 | - rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); | |
8168 | if (new->cl_auth) | |
8169 | atomic_inc(&new->cl_auth->au_count); | |
8170 | + xprt_get(clnt->cl_xprt); | |
8171 | + kref_get(&clnt->cl_kref); | |
8172 | + rpc_register_client(new); | |
8173 | + rpciod_up(); | |
8174 | return new; | |
8175 | out_no_path: | |
8176 | rpc_free_iostats(new->cl_metrics); | |
8177 | @@ -298,86 +345,86 @@ out_no_clnt: | |
8178 | ||
8179 | /* | |
8180 | * Properly shut down an RPC client, terminating all outstanding | |
8181 | - * requests. Note that we must be certain that cl_oneshot and | |
8182 | - * cl_dead are cleared, or else the client would be destroyed | |
8183 | - * when the last task releases it. | |
8184 | + * requests. | |
8185 | */ | |
8186 | -int | |
8187 | -rpc_shutdown_client(struct rpc_clnt *clnt) | |
8188 | +void rpc_shutdown_client(struct rpc_clnt *clnt) | |
8189 | { | |
8190 | - dprintk("RPC: shutting down %s client for %s, tasks=%d\n", | |
8191 | - clnt->cl_protname, clnt->cl_server, | |
8192 | - atomic_read(&clnt->cl_users)); | |
8193 | - | |
8194 | - while (atomic_read(&clnt->cl_users) > 0) { | |
8195 | - /* Don't let rpc_release_client destroy us */ | |
8196 | - clnt->cl_oneshot = 0; | |
8197 | - clnt->cl_dead = 0; | |
8198 | + dprintk("RPC: shutting down %s client for %s\n", | |
8199 | + clnt->cl_protname, clnt->cl_server); | |
8200 | + | |
8201 | + while (!list_empty(&clnt->cl_tasks)) { | |
8202 | rpc_killall_tasks(clnt); | |
8203 | wait_event_timeout(destroy_wait, | |
8204 | - !atomic_read(&clnt->cl_users), 1*HZ); | |
8205 | - } | |
8206 | - | |
8207 | - if (atomic_read(&clnt->cl_users) < 0) { | |
8208 | - printk(KERN_ERR "RPC: rpc_shutdown_client clnt %p tasks=%d\n", | |
8209 | - clnt, atomic_read(&clnt->cl_users)); | |
8210 | -#ifdef RPC_DEBUG | |
8211 | - rpc_show_tasks(); | |
8212 | -#endif | |
8213 | - BUG(); | |
8214 | + list_empty(&clnt->cl_tasks), 1*HZ); | |
8215 | } | |
8216 | ||
8217 | - return rpc_destroy_client(clnt); | |
8218 | + rpc_release_client(clnt); | |
8219 | } | |
8220 | ||
8221 | /* | |
8222 | - * Delete an RPC client | |
8223 | + * Free an RPC client | |
8224 | */ | |
8225 | -int | |
8226 | -rpc_destroy_client(struct rpc_clnt *clnt) | |
8227 | +static void | |
8228 | +rpc_free_client(struct kref *kref) | |
8229 | { | |
8230 | - if (!atomic_dec_and_test(&clnt->cl_count)) | |
8231 | - return 1; | |
8232 | - BUG_ON(atomic_read(&clnt->cl_users) != 0); | |
8233 | + struct rpc_clnt *clnt = container_of(kref, struct rpc_clnt, cl_kref); | |
8234 | ||
8235 | dprintk("RPC: destroying %s client for %s\n", | |
8236 | clnt->cl_protname, clnt->cl_server); | |
8237 | - if (clnt->cl_auth) { | |
8238 | - rpcauth_destroy(clnt->cl_auth); | |
8239 | - clnt->cl_auth = NULL; | |
8240 | - } | |
8241 | if (!IS_ERR(clnt->cl_dentry)) { | |
8242 | rpc_rmdir(clnt->cl_dentry); | |
8243 | rpc_put_mount(); | |
8244 | } | |
8245 | if (clnt->cl_parent != clnt) { | |
8246 | - rpc_destroy_client(clnt->cl_parent); | |
8247 | + rpc_release_client(clnt->cl_parent); | |
8248 | goto out_free; | |
8249 | } | |
8250 | if (clnt->cl_server != clnt->cl_inline_name) | |
8251 | kfree(clnt->cl_server); | |
8252 | out_free: | |
8253 | + rpc_unregister_client(clnt); | |
8254 | rpc_free_iostats(clnt->cl_metrics); | |
8255 | clnt->cl_metrics = NULL; | |
8256 | xprt_put(clnt->cl_xprt); | |
8257 | + rpciod_down(); | |
8258 | kfree(clnt); | |
8259 | - return 0; | |
8260 | } | |
8261 | ||
8262 | /* | |
8263 | - * Release an RPC client | |
8264 | + * Free an RPC client | |
8265 | + */ | |
8266 | +static void | |
8267 | +rpc_free_auth(struct kref *kref) | |
8268 | +{ | |
8269 | + struct rpc_clnt *clnt = container_of(kref, struct rpc_clnt, cl_kref); | |
8270 | + | |
8271 | + if (clnt->cl_auth == NULL) { | |
8272 | + rpc_free_client(kref); | |
8273 | + return; | |
8274 | + } | |
8275 | + | |
8276 | + /* | |
8277 | + * Note: RPCSEC_GSS may need to send NULL RPC calls in order to | |
8278 | + * release remaining GSS contexts. This mechanism ensures | |
8279 | + * that it can do so safely. | |
8280 | + */ | |
8281 | + kref_init(kref); | |
8282 | + rpcauth_release(clnt->cl_auth); | |
8283 | + clnt->cl_auth = NULL; | |
8284 | + kref_put(kref, rpc_free_client); | |
8285 | +} | |
8286 | + | |
8287 | +/* | |
8288 | + * Release reference to the RPC client | |
8289 | */ | |
8290 | void | |
8291 | rpc_release_client(struct rpc_clnt *clnt) | |
8292 | { | |
8293 | - dprintk("RPC: rpc_release_client(%p, %d)\n", | |
8294 | - clnt, atomic_read(&clnt->cl_users)); | |
8295 | + dprintk("RPC: rpc_release_client(%p)\n", clnt); | |
8296 | ||
8297 | - if (!atomic_dec_and_test(&clnt->cl_users)) | |
8298 | - return; | |
8299 | - wake_up(&destroy_wait); | |
8300 | - if (clnt->cl_oneshot || clnt->cl_dead) | |
8301 | - rpc_destroy_client(clnt); | |
8302 | + if (list_empty(&clnt->cl_tasks)) | |
8303 | + wake_up(&destroy_wait); | |
8304 | + kref_put(&clnt->cl_kref, rpc_free_auth); | |
8305 | } | |
8306 | ||
8307 | /** | |
8308 | @@ -468,82 +515,96 @@ void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset) | |
8309 | rpc_restore_sigmask(oldset); | |
8310 | } | |
8311 | ||
8312 | -/* | |
8313 | - * New rpc_call implementation | |
8314 | +static | |
8315 | +struct rpc_task *rpc_do_run_task(struct rpc_clnt *clnt, | |
8316 | + struct rpc_message *msg, | |
8317 | + int flags, | |
8318 | + const struct rpc_call_ops *ops, | |
8319 | + void *data) | |
8320 | +{ | |
8321 | + struct rpc_task *task, *ret; | |
8322 | + sigset_t oldset; | |
8323 | + | |
8324 | + task = rpc_new_task(clnt, flags, ops, data); | |
8325 | + if (task == NULL) { | |
8326 | + rpc_release_calldata(ops, data); | |
8327 | + return ERR_PTR(-ENOMEM); | |
8328 | + } | |
8329 | + | |
8330 | + /* Mask signals on synchronous RPC calls and RPCSEC_GSS upcalls */ | |
8331 | + rpc_task_sigmask(task, &oldset); | |
8332 | + if (msg != NULL) { | |
8333 | + rpc_call_setup(task, msg, 0); | |
8334 | + if (task->tk_status != 0) { | |
8335 | + ret = ERR_PTR(task->tk_status); | |
8336 | + rpc_put_task(task); | |
8337 | + goto out; | |
8338 | + } | |
8339 | + } | |
8340 | + atomic_inc(&task->tk_count); | |
8341 | + rpc_execute(task); | |
8342 | + ret = task; | |
8343 | +out: | |
8344 | + rpc_restore_sigmask(&oldset); | |
8345 | + return ret; | |
8346 | +} | |
8347 | + | |
8348 | +/** | |
8349 | + * rpc_call_sync - Perform a synchronous RPC call | |
8350 | + * @clnt: pointer to RPC client | |
8351 | + * @msg: RPC call parameters | |
8352 | + * @flags: RPC call flags | |
8353 | */ | |
8354 | int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) | |
8355 | { | |
8356 | struct rpc_task *task; | |
8357 | - sigset_t oldset; | |
8358 | - int status; | |
8359 | - | |
8360 | - /* If this client is slain all further I/O fails */ | |
8361 | - if (clnt->cl_dead) | |
8362 | - return -EIO; | |
8363 | + int status; | |
8364 | ||
8365 | BUG_ON(flags & RPC_TASK_ASYNC); | |
8366 | ||
8367 | - task = rpc_new_task(clnt, flags, &rpc_default_ops, NULL); | |
8368 | - if (task == NULL) | |
8369 | - return -ENOMEM; | |
8370 | - | |
8371 | - /* Mask signals on RPC calls _and_ GSS_AUTH upcalls */ | |
8372 | - rpc_task_sigmask(task, &oldset); | |
8373 | - | |
8374 | - /* Set up the call info struct and execute the task */ | |
8375 | - rpc_call_setup(task, msg, 0); | |
8376 | - if (task->tk_status == 0) { | |
8377 | - atomic_inc(&task->tk_count); | |
8378 | - rpc_execute(task); | |
8379 | - } | |
8380 | + task = rpc_do_run_task(clnt, msg, flags, &rpc_default_ops, NULL); | |
8381 | + if (IS_ERR(task)) | |
8382 | + return PTR_ERR(task); | |
8383 | status = task->tk_status; | |
8384 | rpc_put_task(task); | |
8385 | - rpc_restore_sigmask(&oldset); | |
8386 | return status; | |
8387 | } | |
8388 | ||
8389 | -/* | |
8390 | - * New rpc_call implementation | |
8391 | +/** | |
8392 | + * rpc_call_async - Perform an asynchronous RPC call | |
8393 | + * @clnt: pointer to RPC client | |
8394 | + * @msg: RPC call parameters | |
8395 | + * @flags: RPC call flags | |
8396 | + * @ops: RPC call ops | |
8397 | + * @data: user call data | |
8398 | */ | |
8399 | int | |
8400 | rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags, | |
8401 | const struct rpc_call_ops *tk_ops, void *data) | |
8402 | { | |
8403 | struct rpc_task *task; | |
8404 | - sigset_t oldset; | |
8405 | - int status; | |
8406 | - | |
8407 | - /* If this client is slain all further I/O fails */ | |
8408 | - status = -EIO; | |
8409 | - if (clnt->cl_dead) | |
8410 | - goto out_release; | |
8411 | - | |
8412 | - flags |= RPC_TASK_ASYNC; | |
8413 | - | |
8414 | - /* Create/initialize a new RPC task */ | |
8415 | - status = -ENOMEM; | |
8416 | - if (!(task = rpc_new_task(clnt, flags, tk_ops, data))) | |
8417 | - goto out_release; | |
8418 | - | |
8419 | - /* Mask signals on GSS_AUTH upcalls */ | |
8420 | - rpc_task_sigmask(task, &oldset); | |
8421 | ||
8422 | - rpc_call_setup(task, msg, 0); | |
8423 | - | |
8424 | - /* Set up the call info struct and execute the task */ | |
8425 | - status = task->tk_status; | |
8426 | - if (status == 0) | |
8427 | - rpc_execute(task); | |
8428 | - else | |
8429 | - rpc_put_task(task); | |
8430 | - | |
8431 | - rpc_restore_sigmask(&oldset); | |
8432 | - return status; | |
8433 | -out_release: | |
8434 | - rpc_release_calldata(tk_ops, data); | |
8435 | - return status; | |
8436 | + task = rpc_do_run_task(clnt, msg, flags|RPC_TASK_ASYNC, tk_ops, data); | |
8437 | + if (IS_ERR(task)) | |
8438 | + return PTR_ERR(task); | |
8439 | + rpc_put_task(task); | |
8440 | + return 0; | |
8441 | } | |
8442 | ||
8443 | +/** | |
8444 | + * rpc_run_task - Allocate a new RPC task, then run rpc_execute against it | |
8445 | + * @clnt: pointer to RPC client | |
8446 | + * @flags: RPC flags | |
8447 | + * @ops: RPC call ops | |
8448 | + * @data: user call data | |
8449 | + */ | |
8450 | +struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags, | |
8451 | + const struct rpc_call_ops *tk_ops, | |
8452 | + void *data) | |
8453 | +{ | |
8454 | + return rpc_do_run_task(clnt, NULL, flags, tk_ops, data); | |
8455 | +} | |
8456 | +EXPORT_SYMBOL(rpc_run_task); | |
8457 | ||
8458 | void | |
8459 | rpc_call_setup(struct rpc_task *task, struct rpc_message *msg, int flags) | |
8460 | @@ -745,7 +806,7 @@ call_reserveresult(struct rpc_task *task) | |
8461 | static void | |
8462 | call_allocate(struct rpc_task *task) | |
8463 | { | |
8464 | - unsigned int slack = task->tk_auth->au_cslack; | |
8465 | + unsigned int slack = task->tk_msg.rpc_cred->cr_auth->au_cslack; | |
8466 | struct rpc_rqst *req = task->tk_rqstp; | |
8467 | struct rpc_xprt *xprt = task->tk_xprt; | |
8468 | struct rpc_procinfo *proc = task->tk_msg.rpc_proc; | |
8469 | @@ -1273,9 +1334,9 @@ call_verify(struct rpc_task *task) | |
8470 | * - if it isn't pointer subtraction in the NFS client may give | |
8471 | * undefined results | |
8472 | */ | |
8473 | - printk(KERN_WARNING | |
8474 | - "call_verify: XDR representation not a multiple of" | |
8475 | - " 4 bytes: 0x%x\n", task->tk_rqstp->rq_rcv_buf.len); | |
8476 | + dprintk("RPC: %5u %s: XDR representation not a multiple of" | |
8477 | + " 4 bytes: 0x%x\n", task->tk_pid, __FUNCTION__, | |
8478 | + task->tk_rqstp->rq_rcv_buf.len); | |
8479 | goto out_eio; | |
8480 | } | |
8481 | if ((len -= 3) < 0) | |
8482 | @@ -1283,7 +1344,8 @@ call_verify(struct rpc_task *task) | |
8483 | p += 1; /* skip XID */ | |
8484 | ||
8485 | if ((n = ntohl(*p++)) != RPC_REPLY) { | |
8486 | - printk(KERN_WARNING "call_verify: not an RPC reply: %x\n", n); | |
8487 | + dprintk("RPC: %5u %s: not an RPC reply: %x\n", | |
8488 | + task->tk_pid, __FUNCTION__, n); | |
8489 | goto out_garbage; | |
8490 | } | |
8491 | if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) { | |
8492 | @@ -1334,7 +1396,8 @@ call_verify(struct rpc_task *task) | |
8493 | "authentication.\n", task->tk_client->cl_server); | |
8494 | break; | |
8495 | default: | |
8496 | - printk(KERN_WARNING "call_verify: unknown auth error: %x\n", n); | |
8497 | + dprintk("RPC: %5u %s: unknown auth error: %x\n", | |
8498 | + task->tk_pid, __FUNCTION__, n); | |
8499 | error = -EIO; | |
8500 | } | |
8501 | dprintk("RPC: %5u %s: call rejected %d\n", | |
8502 | @@ -1342,7 +1405,8 @@ call_verify(struct rpc_task *task) | |
8503 | goto out_err; | |
8504 | } | |
8505 | if (!(p = rpcauth_checkverf(task, p))) { | |
8506 | - printk(KERN_WARNING "call_verify: auth check failed\n"); | |
8507 | + dprintk("RPC: %5u %s: auth check failed\n", | |
8508 | + task->tk_pid, __FUNCTION__); | |
8509 | goto out_garbage; /* bad verifier, retry */ | |
8510 | } | |
8511 | len = p - (__be32 *)iov->iov_base - 1; | |
8512 | @@ -1381,7 +1445,8 @@ call_verify(struct rpc_task *task) | |
8513 | task->tk_pid, __FUNCTION__); | |
8514 | break; /* retry */ | |
8515 | default: | |
8516 | - printk(KERN_WARNING "call_verify: server accept status: %x\n", n); | |
8517 | + dprintk("RPC: %5u %s: server accept status: %x\n", | |
8518 | + task->tk_pid, __FUNCTION__, n); | |
8519 | /* Also retry */ | |
8520 | } | |
8521 | ||
8522 | @@ -1395,14 +1460,16 @@ out_garbage: | |
8523 | out_retry: | |
8524 | return ERR_PTR(-EAGAIN); | |
8525 | } | |
8526 | - printk(KERN_WARNING "RPC %s: retry failed, exit EIO\n", __FUNCTION__); | |
8527 | out_eio: | |
8528 | error = -EIO; | |
8529 | out_err: | |
8530 | rpc_exit(task, error); | |
8531 | + dprintk("RPC: %5u %s: call failed with error %d\n", task->tk_pid, | |
8532 | + __FUNCTION__, error); | |
8533 | return ERR_PTR(error); | |
8534 | out_overflow: | |
8535 | - printk(KERN_WARNING "RPC %s: server reply was truncated.\n", __FUNCTION__); | |
8536 | + dprintk("RPC: %5u %s: server reply was truncated.\n", task->tk_pid, | |
8537 | + __FUNCTION__); | |
8538 | goto out_garbage; | |
8539 | } | |
8540 | ||
8541 | @@ -1421,7 +1488,7 @@ static struct rpc_procinfo rpcproc_null = { | |
8542 | .p_decode = rpcproc_decode_null, | |
8543 | }; | |
8544 | ||
8545 | -int rpc_ping(struct rpc_clnt *clnt, int flags) | |
8546 | +static int rpc_ping(struct rpc_clnt *clnt, int flags) | |
8547 | { | |
8548 | struct rpc_message msg = { | |
8549 | .rpc_proc = &rpcproc_null, | |
8550 | @@ -1432,3 +1499,51 @@ int rpc_ping(struct rpc_clnt *clnt, int flags) | |
8551 | put_rpccred(msg.rpc_cred); | |
8552 | return err; | |
8553 | } | |
8554 | + | |
8555 | +struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int flags) | |
8556 | +{ | |
8557 | + struct rpc_message msg = { | |
8558 | + .rpc_proc = &rpcproc_null, | |
8559 | + .rpc_cred = cred, | |
8560 | + }; | |
8561 | + return rpc_do_run_task(clnt, &msg, flags, &rpc_default_ops, NULL); | |
8562 | +} | |
8563 | +EXPORT_SYMBOL(rpc_call_null); | |
8564 | + | |
8565 | +#ifdef RPC_DEBUG | |
8566 | +void rpc_show_tasks(void) | |
8567 | +{ | |
8568 | + struct rpc_clnt *clnt; | |
8569 | + struct rpc_task *t; | |
8570 | + | |
8571 | + spin_lock(&rpc_client_lock); | |
8572 | + if (list_empty(&all_clients)) | |
8573 | + goto out; | |
8574 | + printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout " | |
8575 | + "-rpcwait -action- ---ops--\n"); | |
8576 | + list_for_each_entry(clnt, &all_clients, cl_clients) { | |
8577 | + if (list_empty(&clnt->cl_tasks)) | |
8578 | + continue; | |
8579 | + spin_lock(&clnt->cl_lock); | |
8580 | + list_for_each_entry(t, &clnt->cl_tasks, tk_task) { | |
8581 | + const char *rpc_waitq = "none"; | |
8582 | + | |
8583 | + if (RPC_IS_QUEUED(t)) | |
8584 | + rpc_waitq = rpc_qname(t->u.tk_wait.rpc_waitq); | |
8585 | + | |
8586 | + printk("%5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p\n", | |
8587 | + t->tk_pid, | |
8588 | + (t->tk_msg.rpc_proc ? t->tk_msg.rpc_proc->p_proc : -1), | |
8589 | + t->tk_flags, t->tk_status, | |
8590 | + t->tk_client, | |
8591 | + (t->tk_client ? t->tk_client->cl_prog : 0), | |
8592 | + t->tk_rqstp, t->tk_timeout, | |
8593 | + rpc_waitq, | |
8594 | + t->tk_action, t->tk_ops); | |
8595 | + } | |
8596 | + spin_unlock(&clnt->cl_lock); | |
8597 | + } | |
8598 | +out: | |
8599 | + spin_unlock(&rpc_client_lock); | |
8600 | +} | |
8601 | +#endif | |
8602 | diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c | |
8603 | index 5887457..22e25b5 100644 | |
8604 | --- a/net/sunrpc/rpc_pipe.c | |
8605 | +++ b/net/sunrpc/rpc_pipe.c | |
8606 | @@ -14,7 +14,7 @@ | |
8607 | #include <linux/pagemap.h> | |
8608 | #include <linux/mount.h> | |
8609 | #include <linux/namei.h> | |
8610 | -#include <linux/dnotify.h> | |
8611 | +#include <linux/fsnotify.h> | |
8612 | #include <linux/kernel.h> | |
8613 | ||
8614 | #include <asm/ioctls.h> | |
8615 | @@ -344,7 +344,7 @@ rpc_info_open(struct inode *inode, struct file *file) | |
8616 | mutex_lock(&inode->i_mutex); | |
8617 | clnt = RPC_I(inode)->private; | |
8618 | if (clnt) { | |
8619 | - atomic_inc(&clnt->cl_users); | |
8620 | + kref_get(&clnt->cl_kref); | |
8621 | m->private = clnt; | |
8622 | } else { | |
8623 | single_release(inode, file); | |
8624 | @@ -448,6 +448,15 @@ void rpc_put_mount(void) | |
8625 | simple_release_fs(&rpc_mount, &rpc_mount_count); | |
8626 | } | |
8627 | ||
8628 | +static int rpc_delete_dentry(struct dentry *dentry) | |
8629 | +{ | |
8630 | + return 1; | |
8631 | +} | |
8632 | + | |
8633 | +static struct dentry_operations rpc_dentry_operations = { | |
8634 | + .d_delete = rpc_delete_dentry, | |
8635 | +}; | |
8636 | + | |
8637 | static int | |
8638 | rpc_lookup_parent(char *path, struct nameidata *nd) | |
8639 | { | |
8640 | @@ -506,7 +515,7 @@ rpc_get_inode(struct super_block *sb, int mode) | |
8641 | * FIXME: This probably has races. | |
8642 | */ | |
8643 | static void | |
8644 | -rpc_depopulate(struct dentry *parent) | |
8645 | +rpc_depopulate(struct dentry *parent, int start, int eof) | |
8646 | { | |
8647 | struct inode *dir = parent->d_inode; | |
8648 | struct list_head *pos, *next; | |
8649 | @@ -518,6 +527,10 @@ repeat: | |
8650 | spin_lock(&dcache_lock); | |
8651 | list_for_each_safe(pos, next, &parent->d_subdirs) { | |
8652 | dentry = list_entry(pos, struct dentry, d_u.d_child); | |
8653 | + if (!dentry->d_inode || | |
8654 | + dentry->d_inode->i_ino < start || | |
8655 | + dentry->d_inode->i_ino >= eof) | |
8656 | + continue; | |
8657 | spin_lock(&dentry->d_lock); | |
8658 | if (!d_unhashed(dentry)) { | |
8659 | dget_locked(dentry); | |
8660 | @@ -533,11 +546,11 @@ repeat: | |
8661 | if (n) { | |
8662 | do { | |
8663 | dentry = dvec[--n]; | |
8664 | - if (dentry->d_inode) { | |
8665 | - rpc_close_pipes(dentry->d_inode); | |
8666 | + if (S_ISREG(dentry->d_inode->i_mode)) | |
8667 | simple_unlink(dir, dentry); | |
8668 | - } | |
8669 | - inode_dir_notify(dir, DN_DELETE); | |
8670 | + else if (S_ISDIR(dentry->d_inode->i_mode)) | |
8671 | + simple_rmdir(dir, dentry); | |
8672 | + d_delete(dentry); | |
8673 | dput(dentry); | |
8674 | } while (n); | |
8675 | goto repeat; | |
8676 | @@ -560,6 +573,7 @@ rpc_populate(struct dentry *parent, | |
8677 | dentry = d_alloc_name(parent, files[i].name); | |
8678 | if (!dentry) | |
8679 | goto out_bad; | |
8680 | + dentry->d_op = &rpc_dentry_operations; | |
8681 | mode = files[i].mode; | |
8682 | inode = rpc_get_inode(dir->i_sb, mode); | |
8683 | if (!inode) { | |
8684 | @@ -574,6 +588,7 @@ rpc_populate(struct dentry *parent, | |
8685 | if (S_ISDIR(mode)) | |
8686 | inc_nlink(dir); | |
8687 | d_add(dentry, inode); | |
8688 | + fsnotify_create(dir, dentry); | |
8689 | } | |
8690 | mutex_unlock(&dir->i_mutex); | |
8691 | return 0; | |
8692 | @@ -595,7 +610,7 @@ __rpc_mkdir(struct inode *dir, struct dentry *dentry) | |
8693 | inode->i_ino = iunique(dir->i_sb, 100); | |
8694 | d_instantiate(dentry, inode); | |
8695 | inc_nlink(dir); | |
8696 | - inode_dir_notify(dir, DN_CREATE); | |
8697 | + fsnotify_mkdir(dir, dentry); | |
8698 | return 0; | |
8699 | out_err: | |
8700 | printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n", | |
8701 | @@ -607,21 +622,14 @@ static int | |
8702 | __rpc_rmdir(struct inode *dir, struct dentry *dentry) | |
8703 | { | |
8704 | int error; | |
8705 | - | |
8706 | - shrink_dcache_parent(dentry); | |
8707 | - if (d_unhashed(dentry)) | |
8708 | - return 0; | |
8709 | - if ((error = simple_rmdir(dir, dentry)) != 0) | |
8710 | - return error; | |
8711 | - if (!error) { | |
8712 | - inode_dir_notify(dir, DN_DELETE); | |
8713 | - d_drop(dentry); | |
8714 | - } | |
8715 | - return 0; | |
8716 | + error = simple_rmdir(dir, dentry); | |
8717 | + if (!error) | |
8718 | + d_delete(dentry); | |
8719 | + return error; | |
8720 | } | |
8721 | ||
8722 | static struct dentry * | |
8723 | -rpc_lookup_create(struct dentry *parent, const char *name, int len) | |
8724 | +rpc_lookup_create(struct dentry *parent, const char *name, int len, int exclusive) | |
8725 | { | |
8726 | struct inode *dir = parent->d_inode; | |
8727 | struct dentry *dentry; | |
8728 | @@ -630,7 +638,9 @@ rpc_lookup_create(struct dentry *parent, const char *name, int len) | |
8729 | dentry = lookup_one_len(name, parent, len); | |
8730 | if (IS_ERR(dentry)) | |
8731 | goto out_err; | |
8732 | - if (dentry->d_inode) { | |
8733 | + if (!dentry->d_inode) | |
8734 | + dentry->d_op = &rpc_dentry_operations; | |
8735 | + else if (exclusive) { | |
8736 | dput(dentry); | |
8737 | dentry = ERR_PTR(-EEXIST); | |
8738 | goto out_err; | |
8739 | @@ -649,7 +659,7 @@ rpc_lookup_negative(char *path, struct nameidata *nd) | |
8740 | ||
8741 | if ((error = rpc_lookup_parent(path, nd)) != 0) | |
8742 | return ERR_PTR(error); | |
8743 | - dentry = rpc_lookup_create(nd->dentry, nd->last.name, nd->last.len); | |
8744 | + dentry = rpc_lookup_create(nd->dentry, nd->last.name, nd->last.len, 1); | |
8745 | if (IS_ERR(dentry)) | |
8746 | rpc_release_path(nd); | |
8747 | return dentry; | |
8748 | @@ -681,7 +691,7 @@ out: | |
8749 | rpc_release_path(&nd); | |
8750 | return dentry; | |
8751 | err_depopulate: | |
8752 | - rpc_depopulate(dentry); | |
8753 | + rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF); | |
8754 | __rpc_rmdir(dir, dentry); | |
8755 | err_dput: | |
8756 | dput(dentry); | |
8757 | @@ -701,7 +711,7 @@ rpc_rmdir(struct dentry *dentry) | |
8758 | parent = dget_parent(dentry); | |
8759 | dir = parent->d_inode; | |
8760 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); | |
8761 | - rpc_depopulate(dentry); | |
8762 | + rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF); | |
8763 | error = __rpc_rmdir(dir, dentry); | |
8764 | dput(dentry); | |
8765 | mutex_unlock(&dir->i_mutex); | |
8766 | @@ -716,10 +726,21 @@ rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pi | |
8767 | struct inode *dir, *inode; | |
8768 | struct rpc_inode *rpci; | |
8769 | ||
8770 | - dentry = rpc_lookup_create(parent, name, strlen(name)); | |
8771 | + dentry = rpc_lookup_create(parent, name, strlen(name), 0); | |
8772 | if (IS_ERR(dentry)) | |
8773 | return dentry; | |
8774 | dir = parent->d_inode; | |
8775 | + if (dentry->d_inode) { | |
8776 | + rpci = RPC_I(dentry->d_inode); | |
8777 | + if (rpci->private != private || | |
8778 | + rpci->ops != ops || | |
8779 | + rpci->flags != flags) { | |
8780 | + dput (dentry); | |
8781 | + dentry = ERR_PTR(-EBUSY); | |
8782 | + } | |
8783 | + rpci->nkern_readwriters++; | |
8784 | + goto out; | |
8785 | + } | |
8786 | inode = rpc_get_inode(dir->i_sb, S_IFIFO | S_IRUSR | S_IWUSR); | |
8787 | if (!inode) | |
8788 | goto err_dput; | |
8789 | @@ -730,7 +751,8 @@ rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pi | |
8790 | rpci->private = private; | |
8791 | rpci->flags = flags; | |
8792 | rpci->ops = ops; | |
8793 | - inode_dir_notify(dir, DN_CREATE); | |
8794 | + rpci->nkern_readwriters = 1; | |
8795 | + fsnotify_create(dir, dentry); | |
8796 | dget(dentry); | |
8797 | out: | |
8798 | mutex_unlock(&dir->i_mutex); | |
8799 | @@ -754,13 +776,11 @@ rpc_unlink(struct dentry *dentry) | |
8800 | parent = dget_parent(dentry); | |
8801 | dir = parent->d_inode; | |
8802 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); | |
8803 | - if (!d_unhashed(dentry)) { | |
8804 | - d_drop(dentry); | |
8805 | - if (dentry->d_inode) { | |
8806 | - rpc_close_pipes(dentry->d_inode); | |
8807 | - error = simple_unlink(dir, dentry); | |
8808 | - } | |
8809 | - inode_dir_notify(dir, DN_DELETE); | |
8810 | + if (--RPC_I(dentry->d_inode)->nkern_readwriters == 0) { | |
8811 | + rpc_close_pipes(dentry->d_inode); | |
8812 | + error = simple_unlink(dir, dentry); | |
8813 | + if (!error) | |
8814 | + d_delete(dentry); | |
8815 | } | |
8816 | dput(dentry); | |
8817 | mutex_unlock(&dir->i_mutex); | |
8818 | @@ -833,6 +853,7 @@ init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) | |
8819 | rpci->nreaders = 0; | |
8820 | rpci->nwriters = 0; | |
8821 | INIT_LIST_HEAD(&rpci->in_upcall); | |
8822 | + INIT_LIST_HEAD(&rpci->in_downcall); | |
8823 | INIT_LIST_HEAD(&rpci->pipe); | |
8824 | rpci->pipelen = 0; | |
8825 | init_waitqueue_head(&rpci->waitq); | |
8826 | diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c | |
8827 | index 6c7aa8a..d1740db 100644 | |
8828 | --- a/net/sunrpc/rpcb_clnt.c | |
8829 | +++ b/net/sunrpc/rpcb_clnt.c | |
8830 | @@ -12,6 +12,8 @@ | |
8831 | * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> | |
8832 | */ | |
8833 | ||
8834 | +#include <linux/module.h> | |
8835 | + | |
8836 | #include <linux/types.h> | |
8837 | #include <linux/socket.h> | |
8838 | #include <linux/kernel.h> | |
8839 | @@ -184,8 +186,8 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, | |
8840 | .program = &rpcb_program, | |
8841 | .version = version, | |
8842 | .authflavor = RPC_AUTH_UNIX, | |
8843 | - .flags = (RPC_CLNT_CREATE_ONESHOT | | |
8844 | - RPC_CLNT_CREATE_NOPING), | |
8845 | + .flags = (RPC_CLNT_CREATE_NOPING | | |
8846 | + RPC_CLNT_CREATE_INTR), | |
8847 | }; | |
8848 | ||
8849 | ((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT); | |
8850 | @@ -238,6 +240,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) | |
8851 | ||
8852 | error = rpc_call_sync(rpcb_clnt, &msg, 0); | |
8853 | ||
8854 | + rpc_shutdown_client(rpcb_clnt); | |
8855 | if (error < 0) | |
8856 | printk(KERN_WARNING "RPC: failed to contact local rpcbind " | |
8857 | "server (errno %d).\n", -error); | |
8858 | @@ -246,21 +249,20 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay) | |
8859 | return error; | |
8860 | } | |
8861 | ||
8862 | -#ifdef CONFIG_ROOT_NFS | |
8863 | /** | |
8864 | - * rpcb_getport_external - obtain the port for an RPC service on a given host | |
8865 | + * rpcb_getport_sync - obtain the port for an RPC service on a given host | |
8866 | * @sin: address of remote peer | |
8867 | * @prog: RPC program number to bind | |
8868 | * @vers: RPC version number to bind | |
8869 | * @prot: transport protocol to use to make this request | |
8870 | * | |
8871 | * Called from outside the RPC client in a synchronous task context. | |
8872 | + * Uses default timeout parameters specified by underlying transport. | |
8873 | * | |
8874 | - * For now, this supports only version 2 queries, but is used only by | |
8875 | - * mount_clnt for NFS_ROOT. | |
8876 | + * XXX: Needs to support IPv6, and rpcbind versions 3 and 4 | |
8877 | */ | |
8878 | -int rpcb_getport_external(struct sockaddr_in *sin, __u32 prog, | |
8879 | - __u32 vers, int prot) | |
8880 | +int rpcb_getport_sync(struct sockaddr_in *sin, __u32 prog, | |
8881 | + __u32 vers, int prot) | |
8882 | { | |
8883 | struct rpcbind_args map = { | |
8884 | .r_prog = prog, | |
8885 | @@ -277,15 +279,16 @@ int rpcb_getport_external(struct sockaddr_in *sin, __u32 prog, | |
8886 | char hostname[40]; | |
8887 | int status; | |
8888 | ||
8889 | - dprintk("RPC: rpcb_getport_external(%u.%u.%u.%u, %u, %u, %d)\n", | |
8890 | - NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot); | |
8891 | + dprintk("RPC: %s(" NIPQUAD_FMT ", %u, %u, %d)\n", | |
8892 | + __FUNCTION__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot); | |
8893 | ||
8894 | - sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr)); | |
8895 | + sprintf(hostname, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr)); | |
8896 | rpcb_clnt = rpcb_create(hostname, (struct sockaddr *)sin, prot, 2, 0); | |
8897 | if (IS_ERR(rpcb_clnt)) | |
8898 | return PTR_ERR(rpcb_clnt); | |
8899 | ||
8900 | status = rpc_call_sync(rpcb_clnt, &msg, 0); | |
8901 | + rpc_shutdown_client(rpcb_clnt); | |
8902 | ||
8903 | if (status >= 0) { | |
8904 | if (map.r_port != 0) | |
8905 | @@ -294,16 +297,16 @@ int rpcb_getport_external(struct sockaddr_in *sin, __u32 prog, | |
8906 | } | |
8907 | return status; | |
8908 | } | |
8909 | -#endif | |
8910 | +EXPORT_SYMBOL_GPL(rpcb_getport_sync); | |
8911 | ||
8912 | /** | |
8913 | - * rpcb_getport - obtain the port for a given RPC service on a given host | |
8914 | + * rpcb_getport_async - obtain the port for a given RPC service on a given host | |
8915 | * @task: task that is waiting for portmapper request | |
8916 | * | |
8917 | * This one can be called for an ongoing RPC request, and can be used in | |
8918 | * an async (rpciod) context. | |
8919 | */ | |
8920 | -void rpcb_getport(struct rpc_task *task) | |
8921 | +void rpcb_getport_async(struct rpc_task *task) | |
8922 | { | |
8923 | struct rpc_clnt *clnt = task->tk_client; | |
8924 | int bind_version; | |
8925 | @@ -314,17 +317,17 @@ void rpcb_getport(struct rpc_task *task) | |
8926 | struct sockaddr addr; | |
8927 | int status; | |
8928 | ||
8929 | - dprintk("RPC: %5u rpcb_getport(%s, %u, %u, %d)\n", | |
8930 | - task->tk_pid, clnt->cl_server, | |
8931 | - clnt->cl_prog, clnt->cl_vers, xprt->prot); | |
8932 | + dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", | |
8933 | + task->tk_pid, __FUNCTION__, | |
8934 | + clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot); | |
8935 | ||
8936 | /* Autobind on cloned rpc clients is discouraged */ | |
8937 | BUG_ON(clnt->cl_parent != clnt); | |
8938 | ||
8939 | if (xprt_test_and_set_binding(xprt)) { | |
8940 | status = -EACCES; /* tell caller to check again */ | |
8941 | - dprintk("RPC: %5u rpcb_getport waiting for another binder\n", | |
8942 | - task->tk_pid); | |
8943 | + dprintk("RPC: %5u %s: waiting for another binder\n", | |
8944 | + task->tk_pid, __FUNCTION__); | |
8945 | goto bailout_nowake; | |
8946 | } | |
8947 | ||
8948 | @@ -335,27 +338,28 @@ void rpcb_getport(struct rpc_task *task) | |
8949 | /* Someone else may have bound if we slept */ | |
8950 | if (xprt_bound(xprt)) { | |
8951 | status = 0; | |
8952 | - dprintk("RPC: %5u rpcb_getport already bound\n", task->tk_pid); | |
8953 | + dprintk("RPC: %5u %s: already bound\n", | |
8954 | + task->tk_pid, __FUNCTION__); | |
8955 | goto bailout_nofree; | |
8956 | } | |
8957 | ||
8958 | if (rpcb_next_version[xprt->bind_index].rpc_proc == NULL) { | |
8959 | xprt->bind_index = 0; | |
8960 | status = -EACCES; /* tell caller to try again later */ | |
8961 | - dprintk("RPC: %5u rpcb_getport no more getport versions " | |
8962 | - "available\n", task->tk_pid); | |
8963 | + dprintk("RPC: %5u %s: no more getport versions available\n", | |
8964 | + task->tk_pid, __FUNCTION__); | |
8965 | goto bailout_nofree; | |
8966 | } | |
8967 | bind_version = rpcb_next_version[xprt->bind_index].rpc_vers; | |
8968 | ||
8969 | - dprintk("RPC: %5u rpcb_getport trying rpcbind version %u\n", | |
8970 | - task->tk_pid, bind_version); | |
8971 | + dprintk("RPC: %5u %s: trying rpcbind version %u\n", | |
8972 | + task->tk_pid, __FUNCTION__, bind_version); | |
8973 | ||
8974 | map = kzalloc(sizeof(struct rpcbind_args), GFP_ATOMIC); | |
8975 | if (!map) { | |
8976 | status = -ENOMEM; | |
8977 | - dprintk("RPC: %5u rpcb_getport no memory available\n", | |
8978 | - task->tk_pid); | |
8979 | + dprintk("RPC: %5u %s: no memory available\n", | |
8980 | + task->tk_pid, __FUNCTION__); | |
8981 | goto bailout_nofree; | |
8982 | } | |
8983 | map->r_prog = clnt->cl_prog; | |
8984 | @@ -373,16 +377,17 @@ void rpcb_getport(struct rpc_task *task) | |
8985 | rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot, bind_version, 0); | |
8986 | if (IS_ERR(rpcb_clnt)) { | |
8987 | status = PTR_ERR(rpcb_clnt); | |
8988 | - dprintk("RPC: %5u rpcb_getport rpcb_create failed, error %ld\n", | |
8989 | - task->tk_pid, PTR_ERR(rpcb_clnt)); | |
8990 | + dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n", | |
8991 | + task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt)); | |
8992 | goto bailout; | |
8993 | } | |
8994 | ||
8995 | child = rpc_run_task(rpcb_clnt, RPC_TASK_ASYNC, &rpcb_getport_ops, map); | |
8996 | + rpc_release_client(rpcb_clnt); | |
8997 | if (IS_ERR(child)) { | |
8998 | status = -EIO; | |
8999 | - dprintk("RPC: %5u rpcb_getport rpc_run_task failed\n", | |
9000 | - task->tk_pid); | |
9001 | + dprintk("RPC: %5u %s: rpc_run_task failed\n", | |
9002 | + task->tk_pid, __FUNCTION__); | |
9003 | goto bailout_nofree; | |
9004 | } | |
9005 | rpc_put_task(child); | |
9006 | diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c | |
9007 | index 944d753..2ac43c4 100644 | |
9008 | --- a/net/sunrpc/sched.c | |
9009 | +++ b/net/sunrpc/sched.c | |
9010 | @@ -25,7 +25,6 @@ | |
9011 | #ifdef RPC_DEBUG | |
9012 | #define RPCDBG_FACILITY RPCDBG_SCHED | |
9013 | #define RPC_TASK_MAGIC_ID 0xf00baa | |
9014 | -static int rpc_task_id; | |
9015 | #endif | |
9016 | ||
9017 | /* | |
9018 | @@ -40,7 +39,6 @@ static mempool_t *rpc_task_mempool __read_mostly; | |
9019 | static mempool_t *rpc_buffer_mempool __read_mostly; | |
9020 | ||
9021 | static void __rpc_default_timer(struct rpc_task *task); | |
9022 | -static void rpciod_killall(void); | |
9023 | static void rpc_async_schedule(struct work_struct *); | |
9024 | static void rpc_release_task(struct rpc_task *task); | |
9025 | ||
9026 | @@ -50,23 +48,13 @@ static void rpc_release_task(struct rpc_task *task); | |
9027 | static RPC_WAITQ(delay_queue, "delayq"); | |
9028 | ||
9029 | /* | |
9030 | - * All RPC tasks are linked into this list | |
9031 | - */ | |
9032 | -static LIST_HEAD(all_tasks); | |
9033 | - | |
9034 | -/* | |
9035 | * rpciod-related stuff | |
9036 | */ | |
9037 | static DEFINE_MUTEX(rpciod_mutex); | |
9038 | -static unsigned int rpciod_users; | |
9039 | +static atomic_t rpciod_users = ATOMIC_INIT(0); | |
9040 | struct workqueue_struct *rpciod_workqueue; | |
9041 | ||
9042 | /* | |
9043 | - * Spinlock for other critical sections of code. | |
9044 | - */ | |
9045 | -static DEFINE_SPINLOCK(rpc_sched_lock); | |
9046 | - | |
9047 | -/* | |
9048 | * Disable the timer for a given RPC task. Should be called with | |
9049 | * queue->lock and bh_disabled in order to avoid races within | |
9050 | * rpc_run_timer(). | |
9051 | @@ -267,18 +255,33 @@ static int rpc_wait_bit_interruptible(void *word) | |
9052 | return 0; | |
9053 | } | |
9054 | ||
9055 | +#ifdef RPC_DEBUG | |
9056 | +static void rpc_task_set_debuginfo(struct rpc_task *task) | |
9057 | +{ | |
9058 | + static atomic_t rpc_pid; | |
9059 | + | |
9060 | + task->tk_magic = RPC_TASK_MAGIC_ID; | |
9061 | + task->tk_pid = atomic_inc_return(&rpc_pid); | |
9062 | +} | |
9063 | +#else | |
9064 | +static inline void rpc_task_set_debuginfo(struct rpc_task *task) | |
9065 | +{ | |
9066 | +} | |
9067 | +#endif | |
9068 | + | |
9069 | static void rpc_set_active(struct rpc_task *task) | |
9070 | { | |
9071 | + struct rpc_clnt *clnt; | |
9072 | if (test_and_set_bit(RPC_TASK_ACTIVE, &task->tk_runstate) != 0) | |
9073 | return; | |
9074 | - spin_lock(&rpc_sched_lock); | |
9075 | -#ifdef RPC_DEBUG | |
9076 | - task->tk_magic = RPC_TASK_MAGIC_ID; | |
9077 | - task->tk_pid = rpc_task_id++; | |
9078 | -#endif | |
9079 | + rpc_task_set_debuginfo(task); | |
9080 | /* Add to global list of all tasks */ | |
9081 | - list_add_tail(&task->tk_task, &all_tasks); | |
9082 | - spin_unlock(&rpc_sched_lock); | |
9083 | + clnt = task->tk_client; | |
9084 | + if (clnt != NULL) { | |
9085 | + spin_lock(&clnt->cl_lock); | |
9086 | + list_add_tail(&task->tk_task, &clnt->cl_tasks); | |
9087 | + spin_unlock(&clnt->cl_lock); | |
9088 | + } | |
9089 | } | |
9090 | ||
9091 | /* | |
9092 | @@ -818,6 +821,7 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, cons | |
9093 | if (tk_ops->rpc_call_prepare != NULL) | |
9094 | task->tk_action = rpc_prepare_task; | |
9095 | task->tk_calldata = calldata; | |
9096 | + INIT_LIST_HEAD(&task->tk_task); | |
9097 | ||
9098 | /* Initialize retry counters */ | |
9099 | task->tk_garb_retry = 2; | |
9100 | @@ -830,7 +834,7 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, cons | |
9101 | task->tk_workqueue = rpciod_workqueue; | |
9102 | ||
9103 | if (clnt) { | |
9104 | - atomic_inc(&clnt->cl_users); | |
9105 | + kref_get(&clnt->cl_kref); | |
9106 | if (clnt->cl_softrtry) | |
9107 | task->tk_flags |= RPC_TASK_SOFT; | |
9108 | if (!clnt->cl_intr) | |
9109 | @@ -860,9 +864,7 @@ static void rpc_free_task(struct rcu_head *rcu) | |
9110 | } | |
9111 | ||
9112 | /* | |
9113 | - * Create a new task for the specified client. We have to | |
9114 | - * clean up after an allocation failure, as the client may | |
9115 | - * have specified "oneshot". | |
9116 | + * Create a new task for the specified client. | |
9117 | */ | |
9118 | struct rpc_task *rpc_new_task(struct rpc_clnt *clnt, int flags, const struct rpc_call_ops *tk_ops, void *calldata) | |
9119 | { | |
9120 | @@ -870,7 +872,7 @@ struct rpc_task *rpc_new_task(struct rpc_clnt *clnt, int flags, const struct rpc | |
9121 | ||
9122 | task = rpc_alloc_task(); | |
9123 | if (!task) | |
9124 | - goto cleanup; | |
9125 | + goto out; | |
9126 | ||
9127 | rpc_init_task(task, clnt, flags, tk_ops, calldata); | |
9128 | ||
9129 | @@ -878,16 +880,6 @@ struct rpc_task *rpc_new_task(struct rpc_clnt *clnt, int flags, const struct rpc | |
9130 | task->tk_flags |= RPC_TASK_DYNAMIC; | |
9131 | out: | |
9132 | return task; | |
9133 | - | |
9134 | -cleanup: | |
9135 | - /* Check whether to release the client */ | |
9136 | - if (clnt) { | |
9137 | - printk("rpc_new_task: failed, users=%d, oneshot=%d\n", | |
9138 | - atomic_read(&clnt->cl_users), clnt->cl_oneshot); | |
9139 | - atomic_inc(&clnt->cl_users); /* pretend we were used ... */ | |
9140 | - rpc_release_client(clnt); | |
9141 | - } | |
9142 | - goto out; | |
9143 | } | |
9144 | ||
9145 | ||
9146 | @@ -920,11 +912,13 @@ static void rpc_release_task(struct rpc_task *task) | |
9147 | #endif | |
9148 | dprintk("RPC: %5u release task\n", task->tk_pid); | |
9149 | ||
9150 | - /* Remove from global task list */ | |
9151 | - spin_lock(&rpc_sched_lock); | |
9152 | - list_del(&task->tk_task); | |
9153 | - spin_unlock(&rpc_sched_lock); | |
9154 | - | |
9155 | + if (!list_empty(&task->tk_task)) { | |
9156 | + struct rpc_clnt *clnt = task->tk_client; | |
9157 | + /* Remove from client task list */ | |
9158 | + spin_lock(&clnt->cl_lock); | |
9159 | + list_del(&task->tk_task); | |
9160 | + spin_unlock(&clnt->cl_lock); | |
9161 | + } | |
9162 | BUG_ON (RPC_IS_QUEUED(task)); | |
9163 | ||
9164 | /* Synchronously delete any running timer */ | |
9165 | @@ -939,29 +933,6 @@ static void rpc_release_task(struct rpc_task *task) | |
9166 | rpc_put_task(task); | |
9167 | } | |
9168 | ||
9169 | -/** | |
9170 | - * rpc_run_task - Allocate a new RPC task, then run rpc_execute against it | |
9171 | - * @clnt: pointer to RPC client | |
9172 | - * @flags: RPC flags | |
9173 | - * @ops: RPC call ops | |
9174 | - * @data: user call data | |
9175 | - */ | |
9176 | -struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags, | |
9177 | - const struct rpc_call_ops *ops, | |
9178 | - void *data) | |
9179 | -{ | |
9180 | - struct rpc_task *task; | |
9181 | - task = rpc_new_task(clnt, flags, ops, data); | |
9182 | - if (task == NULL) { | |
9183 | - rpc_release_calldata(ops, data); | |
9184 | - return ERR_PTR(-ENOMEM); | |
9185 | - } | |
9186 | - atomic_inc(&task->tk_count); | |
9187 | - rpc_execute(task); | |
9188 | - return task; | |
9189 | -} | |
9190 | -EXPORT_SYMBOL(rpc_run_task); | |
9191 | - | |
9192 | /* | |
9193 | * Kill all tasks for the given client. | |
9194 | * XXX: kill their descendants as well? | |
9195 | @@ -969,44 +940,25 @@ EXPORT_SYMBOL(rpc_run_task); | |
9196 | void rpc_killall_tasks(struct rpc_clnt *clnt) | |
9197 | { | |
9198 | struct rpc_task *rovr; | |
9199 | - struct list_head *le; | |
9200 | ||
9201 | - dprintk("RPC: killing all tasks for client %p\n", clnt); | |
9202 | ||
9203 | + if (list_empty(&clnt->cl_tasks)) | |
9204 | + return; | |
9205 | + dprintk("RPC: killing all tasks for client %p\n", clnt); | |
9206 | /* | |
9207 | * Spin lock all_tasks to prevent changes... | |
9208 | */ | |
9209 | - spin_lock(&rpc_sched_lock); | |
9210 | - alltask_for_each(rovr, le, &all_tasks) { | |
9211 | + spin_lock(&clnt->cl_lock); | |
9212 | + list_for_each_entry(rovr, &clnt->cl_tasks, tk_task) { | |
9213 | if (! RPC_IS_ACTIVATED(rovr)) | |
9214 | continue; | |
9215 | - if (!clnt || rovr->tk_client == clnt) { | |
9216 | + if (!(rovr->tk_flags & RPC_TASK_KILLED)) { | |
9217 | rovr->tk_flags |= RPC_TASK_KILLED; | |
9218 | rpc_exit(rovr, -EIO); | |
9219 | rpc_wake_up_task(rovr); | |
9220 | } | |
9221 | } | |
9222 | - spin_unlock(&rpc_sched_lock); | |
9223 | -} | |
9224 | - | |
9225 | -static void rpciod_killall(void) | |
9226 | -{ | |
9227 | - unsigned long flags; | |
9228 | - | |
9229 | - while (!list_empty(&all_tasks)) { | |
9230 | - clear_thread_flag(TIF_SIGPENDING); | |
9231 | - rpc_killall_tasks(NULL); | |
9232 | - flush_workqueue(rpciod_workqueue); | |
9233 | - if (!list_empty(&all_tasks)) { | |
9234 | - dprintk("RPC: rpciod_killall: waiting for tasks " | |
9235 | - "to exit\n"); | |
9236 | - yield(); | |
9237 | - } | |
9238 | - } | |
9239 | - | |
9240 | - spin_lock_irqsave(¤t->sighand->siglock, flags); | |
9241 | - recalc_sigpending(); | |
9242 | - spin_unlock_irqrestore(¤t->sighand->siglock, flags); | |
9243 | + spin_unlock(&clnt->cl_lock); | |
9244 | } | |
9245 | ||
9246 | /* | |
9247 | @@ -1018,28 +970,27 @@ rpciod_up(void) | |
9248 | struct workqueue_struct *wq; | |
9249 | int error = 0; | |
9250 | ||
9251 | + if (atomic_inc_not_zero(&rpciod_users)) | |
9252 | + return 0; | |
9253 | + | |
9254 | mutex_lock(&rpciod_mutex); | |
9255 | - dprintk("RPC: rpciod_up: users %u\n", rpciod_users); | |
9256 | - rpciod_users++; | |
9257 | - if (rpciod_workqueue) | |
9258 | - goto out; | |
9259 | - /* | |
9260 | - * If there's no pid, we should be the first user. | |
9261 | - */ | |
9262 | - if (rpciod_users > 1) | |
9263 | - printk(KERN_WARNING "rpciod_up: no workqueue, %u users??\n", rpciod_users); | |
9264 | + | |
9265 | + /* Guard against races with rpciod_down() */ | |
9266 | + if (rpciod_workqueue != NULL) | |
9267 | + goto out_ok; | |
9268 | /* | |
9269 | * Create the rpciod thread and wait for it to start. | |
9270 | */ | |
9271 | + dprintk("RPC: creating workqueue rpciod\n"); | |
9272 | error = -ENOMEM; | |
9273 | wq = create_workqueue("rpciod"); | |
9274 | - if (wq == NULL) { | |
9275 | - printk(KERN_WARNING "rpciod_up: create workqueue failed, error=%d\n", error); | |
9276 | - rpciod_users--; | |
9277 | + if (wq == NULL) | |
9278 | goto out; | |
9279 | - } | |
9280 | + | |
9281 | rpciod_workqueue = wq; | |
9282 | error = 0; | |
9283 | +out_ok: | |
9284 | + atomic_inc(&rpciod_users); | |
9285 | out: | |
9286 | mutex_unlock(&rpciod_mutex); | |
9287 | return error; | |
9288 | @@ -1048,59 +999,19 @@ out: | |
9289 | void | |
9290 | rpciod_down(void) | |
9291 | { | |
9292 | + if (!atomic_dec_and_test(&rpciod_users)) | |
9293 | + return; | |
9294 | + | |
9295 | mutex_lock(&rpciod_mutex); | |
9296 | - dprintk("RPC: rpciod_down sema %u\n", rpciod_users); | |
9297 | - if (rpciod_users) { | |
9298 | - if (--rpciod_users) | |
9299 | - goto out; | |
9300 | - } else | |
9301 | - printk(KERN_WARNING "rpciod_down: no users??\n"); | |
9302 | + dprintk("RPC: destroying workqueue rpciod\n"); | |
9303 | ||
9304 | - if (!rpciod_workqueue) { | |
9305 | - dprintk("RPC: rpciod_down: Nothing to do!\n"); | |
9306 | - goto out; | |
9307 | + if (atomic_read(&rpciod_users) == 0 && rpciod_workqueue != NULL) { | |
9308 | + destroy_workqueue(rpciod_workqueue); | |
9309 | + rpciod_workqueue = NULL; | |
9310 | } | |
9311 | - rpciod_killall(); | |
9312 | - | |
9313 | - destroy_workqueue(rpciod_workqueue); | |
9314 | - rpciod_workqueue = NULL; | |
9315 | - out: | |
9316 | mutex_unlock(&rpciod_mutex); | |
9317 | } | |
9318 | ||
9319 | -#ifdef RPC_DEBUG | |
9320 | -void rpc_show_tasks(void) | |
9321 | -{ | |
9322 | - struct list_head *le; | |
9323 | - struct rpc_task *t; | |
9324 | - | |
9325 | - spin_lock(&rpc_sched_lock); | |
9326 | - if (list_empty(&all_tasks)) { | |
9327 | - spin_unlock(&rpc_sched_lock); | |
9328 | - return; | |
9329 | - } | |
9330 | - printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout " | |
9331 | - "-rpcwait -action- ---ops--\n"); | |
9332 | - alltask_for_each(t, le, &all_tasks) { | |
9333 | - const char *rpc_waitq = "none"; | |
9334 | - | |
9335 | - if (RPC_IS_QUEUED(t)) | |
9336 | - rpc_waitq = rpc_qname(t->u.tk_wait.rpc_waitq); | |
9337 | - | |
9338 | - printk("%5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p\n", | |
9339 | - t->tk_pid, | |
9340 | - (t->tk_msg.rpc_proc ? t->tk_msg.rpc_proc->p_proc : -1), | |
9341 | - t->tk_flags, t->tk_status, | |
9342 | - t->tk_client, | |
9343 | - (t->tk_client ? t->tk_client->cl_prog : 0), | |
9344 | - t->tk_rqstp, t->tk_timeout, | |
9345 | - rpc_waitq, | |
9346 | - t->tk_action, t->tk_ops); | |
9347 | - } | |
9348 | - spin_unlock(&rpc_sched_lock); | |
9349 | -} | |
9350 | -#endif | |
9351 | - | |
9352 | void | |
9353 | rpc_destroy_mempool(void) | |
9354 | { | |
9355 | diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c | |
9356 | index 73075de..384c4ad 100644 | |
9357 | --- a/net/sunrpc/sunrpc_syms.c | |
9358 | +++ b/net/sunrpc/sunrpc_syms.c | |
9359 | @@ -28,15 +28,11 @@ EXPORT_SYMBOL(rpc_init_task); | |
9360 | EXPORT_SYMBOL(rpc_sleep_on); | |
9361 | EXPORT_SYMBOL(rpc_wake_up_next); | |
9362 | EXPORT_SYMBOL(rpc_wake_up_task); | |
9363 | -EXPORT_SYMBOL(rpciod_down); | |
9364 | -EXPORT_SYMBOL(rpciod_up); | |
9365 | -EXPORT_SYMBOL(rpc_new_task); | |
9366 | EXPORT_SYMBOL(rpc_wake_up_status); | |
9367 | ||
9368 | /* RPC client functions */ | |
9369 | EXPORT_SYMBOL(rpc_clone_client); | |
9370 | EXPORT_SYMBOL(rpc_bind_new_program); | |
9371 | -EXPORT_SYMBOL(rpc_destroy_client); | |
9372 | EXPORT_SYMBOL(rpc_shutdown_client); | |
9373 | EXPORT_SYMBOL(rpc_killall_tasks); | |
9374 | EXPORT_SYMBOL(rpc_call_sync); | |
9375 | @@ -61,7 +57,7 @@ EXPORT_SYMBOL(rpcauth_unregister); | |
9376 | EXPORT_SYMBOL(rpcauth_create); | |
9377 | EXPORT_SYMBOL(rpcauth_lookupcred); | |
9378 | EXPORT_SYMBOL(rpcauth_lookup_credcache); | |
9379 | -EXPORT_SYMBOL(rpcauth_free_credcache); | |
9380 | +EXPORT_SYMBOL(rpcauth_destroy_credcache); | |
9381 | EXPORT_SYMBOL(rpcauth_init_credcache); | |
9382 | EXPORT_SYMBOL(put_rpccred); | |
9383 | ||
9384 | @@ -156,6 +152,7 @@ init_sunrpc(void) | |
9385 | cache_register(&ip_map_cache); | |
9386 | cache_register(&unix_gid_cache); | |
9387 | init_socket_xprt(); | |
9388 | + rpcauth_init_module(); | |
9389 | out: | |
9390 | return err; | |
9391 | } | |
9392 | @@ -163,6 +160,7 @@ out: | |
9393 | static void __exit | |
9394 | cleanup_sunrpc(void) | |
9395 | { | |
9396 | + rpcauth_remove_module(); | |
9397 | cleanup_socket_xprt(); | |
9398 | unregister_rpc_pipefs(); | |
9399 | rpc_destroy_mempool(); | |
9400 | diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c | |
9401 | index 5baf48d..64b9b8c 100644 | |
9402 | --- a/net/sunrpc/svcsock.c | |
9403 | +++ b/net/sunrpc/svcsock.c | |
9404 | @@ -644,6 +644,7 @@ svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, int nr, int buflen) | |
9405 | struct msghdr msg = { | |
9406 | .msg_flags = MSG_DONTWAIT, | |
9407 | }; | |
9408 | + struct sockaddr *sin; | |
9409 | int len; | |
9410 | ||
9411 | len = kernel_recvmsg(svsk->sk_sock, &msg, iov, nr, buflen, | |
9412 | @@ -654,6 +655,19 @@ svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, int nr, int buflen) | |
9413 | memcpy(&rqstp->rq_addr, &svsk->sk_remote, svsk->sk_remotelen); | |
9414 | rqstp->rq_addrlen = svsk->sk_remotelen; | |
9415 | ||
9416 | + /* Destination address in request is needed for binding the | |
9417 | + * source address in RPC callbacks later. | |
9418 | + */ | |
9419 | + sin = (struct sockaddr *)&svsk->sk_local; | |
9420 | + switch (sin->sa_family) { | |
9421 | + case AF_INET: | |
9422 | + rqstp->rq_daddr.addr = ((struct sockaddr_in *)sin)->sin_addr; | |
9423 | + break; | |
9424 | + case AF_INET6: | |
9425 | + rqstp->rq_daddr.addr6 = ((struct sockaddr_in6 *)sin)->sin6_addr; | |
9426 | + break; | |
9427 | + } | |
9428 | + | |
9429 | dprintk("svc: socket %p recvfrom(%p, %Zu) = %d\n", | |
9430 | svsk, iov[0].iov_base, iov[0].iov_len, len); | |
9431 | ||
9432 | @@ -1064,6 +1078,12 @@ svc_tcp_accept(struct svc_sock *svsk) | |
9433 | goto failed; | |
9434 | memcpy(&newsvsk->sk_remote, sin, slen); | |
9435 | newsvsk->sk_remotelen = slen; | |
9436 | + err = kernel_getsockname(newsock, sin, &slen); | |
9437 | + if (unlikely(err < 0)) { | |
9438 | + dprintk("svc_tcp_accept: kernel_getsockname error %d\n", -err); | |
9439 | + slen = offsetof(struct sockaddr, sa_data); | |
9440 | + } | |
9441 | + memcpy(&newsvsk->sk_local, sin, slen); | |
9442 | ||
9443 | svc_sock_received(newsvsk); | |
9444 | ||
9445 | diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c | |
9446 | index 5b05b73..c8c2edc 100644 | |
9447 | --- a/net/sunrpc/xprt.c | |
9448 | +++ b/net/sunrpc/xprt.c | |
9449 | @@ -127,7 +127,7 @@ static void xprt_clear_locked(struct rpc_xprt *xprt) | |
9450 | clear_bit(XPRT_LOCKED, &xprt->state); | |
9451 | smp_mb__after_clear_bit(); | |
9452 | } else | |
9453 | - schedule_work(&xprt->task_cleanup); | |
9454 | + queue_work(rpciod_workqueue, &xprt->task_cleanup); | |
9455 | } | |
9456 | ||
9457 | /* | |
9458 | @@ -515,7 +515,7 @@ xprt_init_autodisconnect(unsigned long data) | |
9459 | if (xprt_connecting(xprt)) | |
9460 | xprt_release_write(xprt, NULL); | |
9461 | else | |
9462 | - schedule_work(&xprt->task_cleanup); | |
9463 | + queue_work(rpciod_workqueue, &xprt->task_cleanup); | |
9464 | return; | |
9465 | out_abort: | |
9466 | spin_unlock(&xprt->transport_lock); | |
9467 | @@ -886,27 +886,24 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long i | |
9468 | ||
9469 | /** | |
9470 | * xprt_create_transport - create an RPC transport | |
9471 | - * @proto: requested transport protocol | |
9472 | - * @ap: remote peer address | |
9473 | - * @size: length of address | |
9474 | - * @to: timeout parameters | |
9475 | + * @args: rpc transport creation arguments | |
9476 | * | |
9477 | */ | |
9478 | -struct rpc_xprt *xprt_create_transport(int proto, struct sockaddr *ap, size_t size, struct rpc_timeout *to) | |
9479 | +struct rpc_xprt *xprt_create_transport(struct rpc_xprtsock_create *args) | |
9480 | { | |
9481 | struct rpc_xprt *xprt; | |
9482 | struct rpc_rqst *req; | |
9483 | ||
9484 | - switch (proto) { | |
9485 | + switch (args->proto) { | |
9486 | case IPPROTO_UDP: | |
9487 | - xprt = xs_setup_udp(ap, size, to); | |
9488 | + xprt = xs_setup_udp(args); | |
9489 | break; | |
9490 | case IPPROTO_TCP: | |
9491 | - xprt = xs_setup_tcp(ap, size, to); | |
9492 | + xprt = xs_setup_tcp(args); | |
9493 | break; | |
9494 | default: | |
9495 | printk(KERN_ERR "RPC: unrecognized transport protocol: %d\n", | |
9496 | - proto); | |
9497 | + args->proto); | |
9498 | return ERR_PTR(-EIO); | |
9499 | } | |
9500 | if (IS_ERR(xprt)) { | |
9501 | diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c | |
9502 | index cc33c58..4ae7eed 100644 | |
9503 | --- a/net/sunrpc/xprtsock.c | |
9504 | +++ b/net/sunrpc/xprtsock.c | |
9505 | @@ -235,6 +235,7 @@ struct sock_xprt { | |
9506 | * Connection of transports | |
9507 | */ | |
9508 | struct delayed_work connect_worker; | |
9509 | + struct sockaddr_storage addr; | |
9510 | unsigned short port; | |
9511 | ||
9512 | /* | |
9513 | @@ -653,8 +654,7 @@ static void xs_destroy(struct rpc_xprt *xprt) | |
9514 | ||
9515 | dprintk("RPC: xs_destroy xprt %p\n", xprt); | |
9516 | ||
9517 | - cancel_delayed_work(&transport->connect_worker); | |
9518 | - flush_scheduled_work(); | |
9519 | + cancel_rearming_delayed_work(&transport->connect_worker); | |
9520 | ||
9521 | xprt_disconnect(xprt); | |
9522 | xs_close(xprt); | |
9523 | @@ -1001,7 +1001,7 @@ static void xs_tcp_state_change(struct sock *sk) | |
9524 | /* Try to schedule an autoclose RPC calls */ | |
9525 | set_bit(XPRT_CLOSE_WAIT, &xprt->state); | |
9526 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0) | |
9527 | - schedule_work(&xprt->task_cleanup); | |
9528 | + queue_work(rpciod_workqueue, &xprt->task_cleanup); | |
9529 | default: | |
9530 | xprt_disconnect(xprt); | |
9531 | } | |
9532 | @@ -1146,31 +1146,36 @@ static void xs_set_port(struct rpc_xprt *xprt, unsigned short port) | |
9533 | sap->sin_port = htons(port); | |
9534 | } | |
9535 | ||
9536 | -static int xs_bindresvport(struct sock_xprt *transport, struct socket *sock) | |
9537 | +static int xs_bind(struct sock_xprt *transport, struct socket *sock) | |
9538 | { | |
9539 | struct sockaddr_in myaddr = { | |
9540 | .sin_family = AF_INET, | |
9541 | }; | |
9542 | + struct sockaddr_in *sa; | |
9543 | int err; | |
9544 | unsigned short port = transport->port; | |
9545 | ||
9546 | + if (!transport->xprt.resvport) | |
9547 | + port = 0; | |
9548 | + sa = (struct sockaddr_in *)&transport->addr; | |
9549 | + myaddr.sin_addr = sa->sin_addr; | |
9550 | do { | |
9551 | myaddr.sin_port = htons(port); | |
9552 | err = kernel_bind(sock, (struct sockaddr *) &myaddr, | |
9553 | sizeof(myaddr)); | |
9554 | + if (!transport->xprt.resvport) | |
9555 | + break; | |
9556 | if (err == 0) { | |
9557 | transport->port = port; | |
9558 | - dprintk("RPC: xs_bindresvport bound to port %u\n", | |
9559 | - port); | |
9560 | - return 0; | |
9561 | + break; | |
9562 | } | |
9563 | if (port <= xprt_min_resvport) | |
9564 | port = xprt_max_resvport; | |
9565 | else | |
9566 | port--; | |
9567 | } while (err == -EADDRINUSE && port != transport->port); | |
9568 | - | |
9569 | - dprintk("RPC: can't bind to reserved port (%d).\n", -err); | |
9570 | + dprintk("RPC: xs_bind "NIPQUAD_FMT":%u: %s (%d)\n", | |
9571 | + NIPQUAD(myaddr.sin_addr), port, err ? "failed" : "ok", err); | |
9572 | return err; | |
9573 | } | |
9574 | ||
9575 | @@ -1229,7 +1234,7 @@ static void xs_udp_connect_worker(struct work_struct *work) | |
9576 | } | |
9577 | xs_reclassify_socket(sock); | |
9578 | ||
9579 | - if (xprt->resvport && xs_bindresvport(transport, sock) < 0) { | |
9580 | + if (xs_bind(transport, sock)) { | |
9581 | sock_release(sock); | |
9582 | goto out; | |
9583 | } | |
9584 | @@ -1316,7 +1321,7 @@ static void xs_tcp_connect_worker(struct work_struct *work) | |
9585 | } | |
9586 | xs_reclassify_socket(sock); | |
9587 | ||
9588 | - if (xprt->resvport && xs_bindresvport(transport, sock) < 0) { | |
9589 | + if (xs_bind(transport, sock)) { | |
9590 | sock_release(sock); | |
9591 | goto out; | |
9592 | } | |
9593 | @@ -1410,18 +1415,16 @@ static void xs_connect(struct rpc_task *task) | |
9594 | dprintk("RPC: xs_connect delayed xprt %p for %lu " | |
9595 | "seconds\n", | |
9596 | xprt, xprt->reestablish_timeout / HZ); | |
9597 | - schedule_delayed_work(&transport->connect_worker, | |
9598 | - xprt->reestablish_timeout); | |
9599 | + queue_delayed_work(rpciod_workqueue, | |
9600 | + &transport->connect_worker, | |
9601 | + xprt->reestablish_timeout); | |
9602 | xprt->reestablish_timeout <<= 1; | |
9603 | if (xprt->reestablish_timeout > XS_TCP_MAX_REEST_TO) | |
9604 | xprt->reestablish_timeout = XS_TCP_MAX_REEST_TO; | |
9605 | } else { | |
9606 | dprintk("RPC: xs_connect scheduled xprt %p\n", xprt); | |
9607 | - schedule_delayed_work(&transport->connect_worker, 0); | |
9608 | - | |
9609 | - /* flush_scheduled_work can sleep... */ | |
9610 | - if (!RPC_IS_ASYNC(task)) | |
9611 | - flush_scheduled_work(); | |
9612 | + queue_delayed_work(rpciod_workqueue, | |
9613 | + &transport->connect_worker, 0); | |
9614 | } | |
9615 | } | |
9616 | ||
9617 | @@ -1476,7 +1479,7 @@ static struct rpc_xprt_ops xs_udp_ops = { | |
9618 | .set_buffer_size = xs_udp_set_buffer_size, | |
9619 | .reserve_xprt = xprt_reserve_xprt_cong, | |
9620 | .release_xprt = xprt_release_xprt_cong, | |
9621 | - .rpcbind = rpcb_getport, | |
9622 | + .rpcbind = rpcb_getport_async, | |
9623 | .set_port = xs_set_port, | |
9624 | .connect = xs_connect, | |
9625 | .buf_alloc = rpc_malloc, | |
9626 | @@ -1493,7 +1496,7 @@ static struct rpc_xprt_ops xs_udp_ops = { | |
9627 | static struct rpc_xprt_ops xs_tcp_ops = { | |
9628 | .reserve_xprt = xprt_reserve_xprt, | |
9629 | .release_xprt = xs_tcp_release_xprt, | |
9630 | - .rpcbind = rpcb_getport, | |
9631 | + .rpcbind = rpcb_getport_async, | |
9632 | .set_port = xs_set_port, | |
9633 | .connect = xs_connect, | |
9634 | .buf_alloc = rpc_malloc, | |
9635 | @@ -1505,12 +1508,12 @@ static struct rpc_xprt_ops xs_tcp_ops = { | |
9636 | .print_stats = xs_tcp_print_stats, | |
9637 | }; | |
9638 | ||
9639 | -static struct rpc_xprt *xs_setup_xprt(struct sockaddr *addr, size_t addrlen, unsigned int slot_table_size) | |
9640 | +static struct rpc_xprt *xs_setup_xprt(struct rpc_xprtsock_create *args, unsigned int slot_table_size) | |
9641 | { | |
9642 | struct rpc_xprt *xprt; | |
9643 | struct sock_xprt *new; | |
9644 | ||
9645 | - if (addrlen > sizeof(xprt->addr)) { | |
9646 | + if (args->addrlen > sizeof(xprt->addr)) { | |
9647 | dprintk("RPC: xs_setup_xprt: address too large\n"); | |
9648 | return ERR_PTR(-EBADF); | |
9649 | } | |
9650 | @@ -1532,8 +1535,10 @@ static struct rpc_xprt *xs_setup_xprt(struct sockaddr *addr, size_t addrlen, uns | |
9651 | return ERR_PTR(-ENOMEM); | |
9652 | } | |
9653 | ||
9654 | - memcpy(&xprt->addr, addr, addrlen); | |
9655 | - xprt->addrlen = addrlen; | |
9656 | + memcpy(&xprt->addr, args->dstaddr, args->addrlen); | |
9657 | + xprt->addrlen = args->addrlen; | |
9658 | + if (args->srcaddr) | |
9659 | + memcpy(&new->addr, args->srcaddr, args->addrlen); | |
9660 | new->port = xs_get_random_port(); | |
9661 | ||
9662 | return xprt; | |
9663 | @@ -1541,22 +1546,20 @@ static struct rpc_xprt *xs_setup_xprt(struct sockaddr *addr, size_t addrlen, uns | |
9664 | ||
9665 | /** | |
9666 | * xs_setup_udp - Set up transport to use a UDP socket | |
9667 | - * @addr: address of remote server | |
9668 | - * @addrlen: length of address in bytes | |
9669 | - * @to: timeout parameters | |
9670 | + * @args: rpc transport creation arguments | |
9671 | * | |
9672 | */ | |
9673 | -struct rpc_xprt *xs_setup_udp(struct sockaddr *addr, size_t addrlen, struct rpc_timeout *to) | |
9674 | +struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args) | |
9675 | { | |
9676 | struct rpc_xprt *xprt; | |
9677 | struct sock_xprt *transport; | |
9678 | ||
9679 | - xprt = xs_setup_xprt(addr, addrlen, xprt_udp_slot_table_entries); | |
9680 | + xprt = xs_setup_xprt(args, xprt_udp_slot_table_entries); | |
9681 | if (IS_ERR(xprt)) | |
9682 | return xprt; | |
9683 | transport = container_of(xprt, struct sock_xprt, xprt); | |
9684 | ||
9685 | - if (ntohs(((struct sockaddr_in *)addr)->sin_port) != 0) | |
9686 | + if (ntohs(((struct sockaddr_in *)args->dstaddr)->sin_port) != 0) | |
9687 | xprt_set_bound(xprt); | |
9688 | ||
9689 | xprt->prot = IPPROTO_UDP; | |
9690 | @@ -1572,8 +1575,8 @@ struct rpc_xprt *xs_setup_udp(struct sockaddr *addr, size_t addrlen, struct rpc_ | |
9691 | ||
9692 | xprt->ops = &xs_udp_ops; | |
9693 | ||
9694 | - if (to) | |
9695 | - xprt->timeout = *to; | |
9696 | + if (args->timeout) | |
9697 | + xprt->timeout = *args->timeout; | |
9698 | else | |
9699 | xprt_set_timeout(&xprt->timeout, 5, 5 * HZ); | |
9700 | ||
9701 | @@ -1586,22 +1589,20 @@ struct rpc_xprt *xs_setup_udp(struct sockaddr *addr, size_t addrlen, struct rpc_ | |
9702 | ||
9703 | /** | |
9704 | * xs_setup_tcp - Set up transport to use a TCP socket | |
9705 | - * @addr: address of remote server | |
9706 | - * @addrlen: length of address in bytes | |
9707 | - * @to: timeout parameters | |
9708 | + * @args: rpc transport creation arguments | |
9709 | * | |
9710 | */ | |
9711 | -struct rpc_xprt *xs_setup_tcp(struct sockaddr *addr, size_t addrlen, struct rpc_timeout *to) | |
9712 | +struct rpc_xprt *xs_setup_tcp(struct rpc_xprtsock_create *args) | |
9713 | { | |
9714 | struct rpc_xprt *xprt; | |
9715 | struct sock_xprt *transport; | |
9716 | ||
9717 | - xprt = xs_setup_xprt(addr, addrlen, xprt_tcp_slot_table_entries); | |
9718 | + xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries); | |
9719 | if (IS_ERR(xprt)) | |
9720 | return xprt; | |
9721 | transport = container_of(xprt, struct sock_xprt, xprt); | |
9722 | ||
9723 | - if (ntohs(((struct sockaddr_in *)addr)->sin_port) != 0) | |
9724 | + if (ntohs(((struct sockaddr_in *)args->dstaddr)->sin_port) != 0) | |
9725 | xprt_set_bound(xprt); | |
9726 | ||
9727 | xprt->prot = IPPROTO_TCP; | |
9728 | @@ -1616,8 +1617,8 @@ struct rpc_xprt *xs_setup_tcp(struct sockaddr *addr, size_t addrlen, struct rpc_ | |
9729 | ||
9730 | xprt->ops = &xs_tcp_ops; | |
9731 | ||
9732 | - if (to) | |
9733 | - xprt->timeout = *to; | |
9734 | + if (args->timeout) | |
9735 | + xprt->timeout = *args->timeout; | |
9736 | else | |
9737 | xprt_set_timeout(&xprt->timeout, 2, 60 * HZ); | |
9738 |