diff options
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs3proc.c | 8 | ||||
-rw-r--r-- | fs/nfsd/nfs4callback.c | 57 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 381 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 3 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 24 | ||||
-rw-r--r-- | fs/nfsd/nfsd.h | 1 | ||||
-rw-r--r-- | fs/nfsd/nfsproc.c | 4 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 151 | ||||
-rw-r--r-- | fs/nfsd/state.h | 40 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 79 | ||||
-rw-r--r-- | fs/nfsd/vfs.h | 4 |
11 files changed, 465 insertions, 287 deletions
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 3d68f45a37b9..5b7e3021e06b 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c | |||
@@ -168,7 +168,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, | |||
168 | svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4); | 168 | svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4); |
169 | 169 | ||
170 | fh_copy(&resp->fh, &argp->fh); | 170 | fh_copy(&resp->fh, &argp->fh); |
171 | nfserr = nfsd_read(rqstp, &resp->fh, NULL, | 171 | nfserr = nfsd_read(rqstp, &resp->fh, |
172 | argp->offset, | 172 | argp->offset, |
173 | rqstp->rq_vec, argp->vlen, | 173 | rqstp->rq_vec, argp->vlen, |
174 | &resp->count); | 174 | &resp->count); |
@@ -271,7 +271,7 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp, | |||
271 | fh_init(&resp->fh, NFS3_FHSIZE); | 271 | fh_init(&resp->fh, NFS3_FHSIZE); |
272 | nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, | 272 | nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, |
273 | &argp->attrs, S_IFDIR, 0, &resp->fh); | 273 | &argp->attrs, S_IFDIR, 0, &resp->fh); |
274 | 274 | fh_unlock(&resp->dirfh); | |
275 | RETURN_STATUS(nfserr); | 275 | RETURN_STATUS(nfserr); |
276 | } | 276 | } |
277 | 277 | ||
@@ -327,7 +327,7 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp, | |||
327 | type = nfs3_ftypes[argp->ftype]; | 327 | type = nfs3_ftypes[argp->ftype]; |
328 | nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, | 328 | nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, |
329 | &argp->attrs, type, rdev, &resp->fh); | 329 | &argp->attrs, type, rdev, &resp->fh); |
330 | 330 | fh_unlock(&resp->dirfh); | |
331 | RETURN_STATUS(nfserr); | 331 | RETURN_STATUS(nfserr); |
332 | } | 332 | } |
333 | 333 | ||
@@ -348,6 +348,7 @@ nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, | |||
348 | /* Unlink. -S_IFDIR means file must not be a directory */ | 348 | /* Unlink. -S_IFDIR means file must not be a directory */ |
349 | fh_copy(&resp->fh, &argp->fh); | 349 | fh_copy(&resp->fh, &argp->fh); |
350 | nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len); | 350 | nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len); |
351 | fh_unlock(&resp->fh); | ||
351 | RETURN_STATUS(nfserr); | 352 | RETURN_STATUS(nfserr); |
352 | } | 353 | } |
353 | 354 | ||
@@ -367,6 +368,7 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp, | |||
367 | 368 | ||
368 | fh_copy(&resp->fh, &argp->fh); | 369 | fh_copy(&resp->fh, &argp->fh); |
369 | nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len); | 370 | nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len); |
371 | fh_unlock(&resp->fh); | ||
370 | RETURN_STATUS(nfserr); | 372 | RETURN_STATUS(nfserr); |
371 | } | 373 | } |
372 | 374 | ||
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index eb78e7e22077..988cbb3a19b6 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -143,8 +143,6 @@ struct nfs4_cb_compound_hdr { | |||
143 | u32 minorversion; | 143 | u32 minorversion; |
144 | /* res */ | 144 | /* res */ |
145 | int status; | 145 | int status; |
146 | u32 taglen; | ||
147 | char *tag; | ||
148 | }; | 146 | }; |
149 | 147 | ||
150 | static struct { | 148 | static struct { |
@@ -205,6 +203,16 @@ nfs_cb_stat_to_errno(int stat) | |||
205 | */ | 203 | */ |
206 | 204 | ||
207 | static void | 205 | static void |
206 | encode_stateid(struct xdr_stream *xdr, stateid_t *sid) | ||
207 | { | ||
208 | __be32 *p; | ||
209 | |||
210 | RESERVE_SPACE(sizeof(stateid_t)); | ||
211 | WRITE32(sid->si_generation); | ||
212 | WRITEMEM(&sid->si_opaque, sizeof(stateid_opaque_t)); | ||
213 | } | ||
214 | |||
215 | static void | ||
208 | encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) | 216 | encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) |
209 | { | 217 | { |
210 | __be32 * p; | 218 | __be32 * p; |
@@ -229,10 +237,10 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_delegation *dp, | |||
229 | __be32 *p; | 237 | __be32 *p; |
230 | int len = dp->dl_fh.fh_size; | 238 | int len = dp->dl_fh.fh_size; |
231 | 239 | ||
232 | RESERVE_SPACE(12+sizeof(dp->dl_stateid) + len); | 240 | RESERVE_SPACE(4); |
233 | WRITE32(OP_CB_RECALL); | 241 | WRITE32(OP_CB_RECALL); |
234 | WRITE32(dp->dl_stateid.si_generation); | 242 | encode_stateid(xdr, &dp->dl_stateid); |
235 | WRITEMEM(&dp->dl_stateid.si_opaque, sizeof(stateid_opaque_t)); | 243 | RESERVE_SPACE(8 + (XDR_QUADLEN(len) << 2)); |
236 | WRITE32(0); /* truncate optimization not implemented */ | 244 | WRITE32(0); /* truncate optimization not implemented */ |
237 | WRITE32(len); | 245 | WRITE32(len); |
238 | WRITEMEM(&dp->dl_fh.fh_base, len); | 246 | WRITEMEM(&dp->dl_fh.fh_base, len); |
@@ -293,13 +301,14 @@ nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, | |||
293 | static int | 301 | static int |
294 | decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){ | 302 | decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){ |
295 | __be32 *p; | 303 | __be32 *p; |
304 | u32 taglen; | ||
296 | 305 | ||
297 | READ_BUF(8); | 306 | READ_BUF(8); |
298 | READ32(hdr->status); | 307 | READ32(hdr->status); |
299 | READ32(hdr->taglen); | 308 | /* We've got no use for the tag; ignore it: */ |
300 | READ_BUF(hdr->taglen + 4); | 309 | READ32(taglen); |
301 | hdr->tag = (char *)p; | 310 | READ_BUF(taglen + 4); |
302 | p += XDR_QUADLEN(hdr->taglen); | 311 | p += XDR_QUADLEN(taglen); |
303 | READ32(hdr->nops); | 312 | READ32(hdr->nops); |
304 | return 0; | 313 | return 0; |
305 | } | 314 | } |
@@ -667,28 +676,28 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) | |||
667 | } | 676 | } |
668 | 677 | ||
669 | switch (task->tk_status) { | 678 | switch (task->tk_status) { |
670 | case -EIO: | 679 | case 0: |
680 | return; | ||
681 | case -EBADHANDLE: | ||
682 | case -NFS4ERR_BAD_STATEID: | ||
683 | /* Race: client probably got cb_recall | ||
684 | * before open reply granting delegation */ | ||
685 | break; | ||
686 | default: | ||
671 | /* Network partition? */ | 687 | /* Network partition? */ |
672 | atomic_set(&clp->cl_cb_set, 0); | 688 | atomic_set(&clp->cl_cb_set, 0); |
673 | warn_no_callback_path(clp, task->tk_status); | 689 | warn_no_callback_path(clp, task->tk_status); |
674 | if (current_rpc_client != task->tk_client) { | 690 | if (current_rpc_client != task->tk_client) { |
675 | /* queue a callback on the new connection: */ | 691 | /* queue a callback on the new connection: */ |
692 | atomic_inc(&dp->dl_count); | ||
676 | nfsd4_cb_recall(dp); | 693 | nfsd4_cb_recall(dp); |
677 | return; | 694 | return; |
678 | } | 695 | } |
679 | case -EBADHANDLE: | ||
680 | case -NFS4ERR_BAD_STATEID: | ||
681 | /* Race: client probably got cb_recall | ||
682 | * before open reply granting delegation */ | ||
683 | break; | ||
684 | default: | ||
685 | /* success, or error we can't handle */ | ||
686 | return; | ||
687 | } | 696 | } |
688 | if (dp->dl_retries--) { | 697 | if (dp->dl_retries--) { |
689 | rpc_delay(task, 2*HZ); | 698 | rpc_delay(task, 2*HZ); |
690 | task->tk_status = 0; | 699 | task->tk_status = 0; |
691 | rpc_restart_call(task); | 700 | rpc_restart_call_prepare(task); |
692 | return; | 701 | return; |
693 | } else { | 702 | } else { |
694 | atomic_set(&clp->cl_cb_set, 0); | 703 | atomic_set(&clp->cl_cb_set, 0); |
@@ -752,18 +761,16 @@ static void _nfsd4_cb_recall(struct nfs4_delegation *dp) | |||
752 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], | 761 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], |
753 | .rpc_cred = callback_cred | 762 | .rpc_cred = callback_cred |
754 | }; | 763 | }; |
755 | int status; | ||
756 | 764 | ||
757 | if (clnt == NULL) | 765 | if (clnt == NULL) { |
766 | nfs4_put_delegation(dp); | ||
758 | return; /* Client is shutting down; give up. */ | 767 | return; /* Client is shutting down; give up. */ |
768 | } | ||
759 | 769 | ||
760 | args->args_op = dp; | 770 | args->args_op = dp; |
761 | msg.rpc_argp = args; | 771 | msg.rpc_argp = args; |
762 | dp->dl_retries = 1; | 772 | dp->dl_retries = 1; |
763 | status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT, | 773 | rpc_call_async(clnt, &msg, RPC_TASK_SOFT, &nfsd4_cb_recall_ops, dp); |
764 | &nfsd4_cb_recall_ops, dp); | ||
765 | if (status) | ||
766 | nfs4_put_delegation(dp); | ||
767 | } | 774 | } |
768 | 775 | ||
769 | void nfsd4_do_callback_rpc(struct work_struct *w) | 776 | void nfsd4_do_callback_rpc(struct work_struct *w) |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 4a2734758778..2e7357104cfd 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -51,7 +51,6 @@ static time_t boot_time; | |||
51 | static u32 current_ownerid = 1; | 51 | static u32 current_ownerid = 1; |
52 | static u32 current_fileid = 1; | 52 | static u32 current_fileid = 1; |
53 | static u32 current_delegid = 1; | 53 | static u32 current_delegid = 1; |
54 | static u32 nfs4_init; | ||
55 | static stateid_t zerostateid; /* bits all 0 */ | 54 | static stateid_t zerostateid; /* bits all 0 */ |
56 | static stateid_t onestateid; /* bits all 1 */ | 55 | static stateid_t onestateid; /* bits all 1 */ |
57 | static u64 current_sessionid = 1; | 56 | static u64 current_sessionid = 1; |
@@ -163,6 +162,46 @@ static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE]; | |||
163 | static struct list_head file_hashtbl[FILE_HASH_SIZE]; | 162 | static struct list_head file_hashtbl[FILE_HASH_SIZE]; |
164 | static struct list_head stateid_hashtbl[STATEID_HASH_SIZE]; | 163 | static struct list_head stateid_hashtbl[STATEID_HASH_SIZE]; |
165 | 164 | ||
165 | static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag) | ||
166 | { | ||
167 | BUG_ON(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR])); | ||
168 | atomic_inc(&fp->fi_access[oflag]); | ||
169 | } | ||
170 | |||
171 | static void nfs4_file_get_access(struct nfs4_file *fp, int oflag) | ||
172 | { | ||
173 | if (oflag == O_RDWR) { | ||
174 | __nfs4_file_get_access(fp, O_RDONLY); | ||
175 | __nfs4_file_get_access(fp, O_WRONLY); | ||
176 | } else | ||
177 | __nfs4_file_get_access(fp, oflag); | ||
178 | } | ||
179 | |||
180 | static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag) | ||
181 | { | ||
182 | if (fp->fi_fds[oflag]) { | ||
183 | fput(fp->fi_fds[oflag]); | ||
184 | fp->fi_fds[oflag] = NULL; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) | ||
189 | { | ||
190 | if (atomic_dec_and_test(&fp->fi_access[oflag])) { | ||
191 | nfs4_file_put_fd(fp, O_RDWR); | ||
192 | nfs4_file_put_fd(fp, oflag); | ||
193 | } | ||
194 | } | ||
195 | |||
196 | static void nfs4_file_put_access(struct nfs4_file *fp, int oflag) | ||
197 | { | ||
198 | if (oflag == O_RDWR) { | ||
199 | __nfs4_file_put_access(fp, O_RDONLY); | ||
200 | __nfs4_file_put_access(fp, O_WRONLY); | ||
201 | } else | ||
202 | __nfs4_file_put_access(fp, oflag); | ||
203 | } | ||
204 | |||
166 | static struct nfs4_delegation * | 205 | static struct nfs4_delegation * |
167 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) | 206 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) |
168 | { | 207 | { |
@@ -171,6 +210,13 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
171 | struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn; | 210 | struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn; |
172 | 211 | ||
173 | dprintk("NFSD alloc_init_deleg\n"); | 212 | dprintk("NFSD alloc_init_deleg\n"); |
213 | /* | ||
214 | * Major work on the lease subsystem (for example, to support | ||
215 | * calbacks on stat) will be required before we can support | ||
216 | * write delegations properly. | ||
217 | */ | ||
218 | if (type != NFS4_OPEN_DELEGATE_READ) | ||
219 | return NULL; | ||
174 | if (fp->fi_had_conflict) | 220 | if (fp->fi_had_conflict) |
175 | return NULL; | 221 | return NULL; |
176 | if (num_delegations > max_delegations) | 222 | if (num_delegations > max_delegations) |
@@ -185,9 +231,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
185 | dp->dl_client = clp; | 231 | dp->dl_client = clp; |
186 | get_nfs4_file(fp); | 232 | get_nfs4_file(fp); |
187 | dp->dl_file = fp; | 233 | dp->dl_file = fp; |
234 | nfs4_file_get_access(fp, O_RDONLY); | ||
188 | dp->dl_flock = NULL; | 235 | dp->dl_flock = NULL; |
189 | get_file(stp->st_vfs_file); | ||
190 | dp->dl_vfs_file = stp->st_vfs_file; | ||
191 | dp->dl_type = type; | 236 | dp->dl_type = type; |
192 | dp->dl_ident = cb->cb_ident; | 237 | dp->dl_ident = cb->cb_ident; |
193 | dp->dl_stateid.si_boot = boot_time; | 238 | dp->dl_stateid.si_boot = boot_time; |
@@ -222,15 +267,12 @@ nfs4_put_delegation(struct nfs4_delegation *dp) | |||
222 | static void | 267 | static void |
223 | nfs4_close_delegation(struct nfs4_delegation *dp) | 268 | nfs4_close_delegation(struct nfs4_delegation *dp) |
224 | { | 269 | { |
225 | struct file *filp = dp->dl_vfs_file; | 270 | struct file *filp = find_readable_file(dp->dl_file); |
226 | 271 | ||
227 | dprintk("NFSD: close_delegation dp %p\n",dp); | 272 | dprintk("NFSD: close_delegation dp %p\n",dp); |
228 | dp->dl_vfs_file = NULL; | ||
229 | /* The following nfsd_close may not actually close the file, | ||
230 | * but we want to remove the lease in any case. */ | ||
231 | if (dp->dl_flock) | 273 | if (dp->dl_flock) |
232 | vfs_setlease(filp, F_UNLCK, &dp->dl_flock); | 274 | vfs_setlease(filp, F_UNLCK, &dp->dl_flock); |
233 | nfsd_close(filp); | 275 | nfs4_file_put_access(dp->dl_file, O_RDONLY); |
234 | } | 276 | } |
235 | 277 | ||
236 | /* Called under the state lock. */ | 278 | /* Called under the state lock. */ |
@@ -302,8 +344,12 @@ static void free_generic_stateid(struct nfs4_stateid *stp) | |||
302 | 344 | ||
303 | static void release_lock_stateid(struct nfs4_stateid *stp) | 345 | static void release_lock_stateid(struct nfs4_stateid *stp) |
304 | { | 346 | { |
347 | struct file *file; | ||
348 | |||
305 | unhash_generic_stateid(stp); | 349 | unhash_generic_stateid(stp); |
306 | locks_remove_posix(stp->st_vfs_file, (fl_owner_t)stp->st_stateowner); | 350 | file = find_any_file(stp->st_file); |
351 | if (file) | ||
352 | locks_remove_posix(file, (fl_owner_t)stp->st_stateowner); | ||
307 | free_generic_stateid(stp); | 353 | free_generic_stateid(stp); |
308 | } | 354 | } |
309 | 355 | ||
@@ -341,11 +387,85 @@ release_stateid_lockowners(struct nfs4_stateid *open_stp) | |||
341 | } | 387 | } |
342 | } | 388 | } |
343 | 389 | ||
390 | /* | ||
391 | * We store the NONE, READ, WRITE, and BOTH bits separately in the | ||
392 | * st_{access,deny}_bmap field of the stateid, in order to track not | ||
393 | * only what share bits are currently in force, but also what | ||
394 | * combinations of share bits previous opens have used. This allows us | ||
395 | * to enforce the recommendation of rfc 3530 14.2.19 that the server | ||
396 | * return an error if the client attempt to downgrade to a combination | ||
397 | * of share bits not explicable by closing some of its previous opens. | ||
398 | * | ||
399 | * XXX: This enforcement is actually incomplete, since we don't keep | ||
400 | * track of access/deny bit combinations; so, e.g., we allow: | ||
401 | * | ||
402 | * OPEN allow read, deny write | ||
403 | * OPEN allow both, deny none | ||
404 | * DOWNGRADE allow read, deny none | ||
405 | * | ||
406 | * which we should reject. | ||
407 | */ | ||
408 | static void | ||
409 | set_access(unsigned int *access, unsigned long bmap) { | ||
410 | int i; | ||
411 | |||
412 | *access = 0; | ||
413 | for (i = 1; i < 4; i++) { | ||
414 | if (test_bit(i, &bmap)) | ||
415 | *access |= i; | ||
416 | } | ||
417 | } | ||
418 | |||
419 | static void | ||
420 | set_deny(unsigned int *deny, unsigned long bmap) { | ||
421 | int i; | ||
422 | |||
423 | *deny = 0; | ||
424 | for (i = 0; i < 4; i++) { | ||
425 | if (test_bit(i, &bmap)) | ||
426 | *deny |= i ; | ||
427 | } | ||
428 | } | ||
429 | |||
430 | static int | ||
431 | test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) { | ||
432 | unsigned int access, deny; | ||
433 | |||
434 | set_access(&access, stp->st_access_bmap); | ||
435 | set_deny(&deny, stp->st_deny_bmap); | ||
436 | if ((access & open->op_share_deny) || (deny & open->op_share_access)) | ||
437 | return 0; | ||
438 | return 1; | ||
439 | } | ||
440 | |||
441 | static int nfs4_access_to_omode(u32 access) | ||
442 | { | ||
443 | switch (access) { | ||
444 | case NFS4_SHARE_ACCESS_READ: | ||
445 | return O_RDONLY; | ||
446 | case NFS4_SHARE_ACCESS_WRITE: | ||
447 | return O_WRONLY; | ||
448 | case NFS4_SHARE_ACCESS_BOTH: | ||
449 | return O_RDWR; | ||
450 | } | ||
451 | BUG(); | ||
452 | } | ||
453 | |||
454 | static int nfs4_access_bmap_to_omode(struct nfs4_stateid *stp) | ||
455 | { | ||
456 | unsigned int access; | ||
457 | |||
458 | set_access(&access, stp->st_access_bmap); | ||
459 | return nfs4_access_to_omode(access); | ||
460 | } | ||
461 | |||
344 | static void release_open_stateid(struct nfs4_stateid *stp) | 462 | static void release_open_stateid(struct nfs4_stateid *stp) |
345 | { | 463 | { |
464 | int oflag = nfs4_access_bmap_to_omode(stp); | ||
465 | |||
346 | unhash_generic_stateid(stp); | 466 | unhash_generic_stateid(stp); |
347 | release_stateid_lockowners(stp); | 467 | release_stateid_lockowners(stp); |
348 | nfsd_close(stp->st_vfs_file); | 468 | nfs4_file_put_access(stp->st_file, oflag); |
349 | free_generic_stateid(stp); | 469 | free_generic_stateid(stp); |
350 | } | 470 | } |
351 | 471 | ||
@@ -457,7 +577,7 @@ static int set_forechannel_drc_size(struct nfsd4_channel_attrs *fchan) | |||
457 | spin_unlock(&nfsd_drc_lock); | 577 | spin_unlock(&nfsd_drc_lock); |
458 | 578 | ||
459 | if (fchan->maxreqs == 0) | 579 | if (fchan->maxreqs == 0) |
460 | return nfserr_serverfault; | 580 | return nfserr_jukebox; |
461 | 581 | ||
462 | fchan->maxresp_cached = size + NFSD_MIN_HDR_SEQ_SZ; | 582 | fchan->maxresp_cached = size + NFSD_MIN_HDR_SEQ_SZ; |
463 | return 0; | 583 | return 0; |
@@ -542,7 +662,7 @@ alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, | |||
542 | BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot) | 662 | BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot) |
543 | + sizeof(struct nfsd4_session) > PAGE_SIZE); | 663 | + sizeof(struct nfsd4_session) > PAGE_SIZE); |
544 | 664 | ||
545 | status = nfserr_serverfault; | 665 | status = nfserr_jukebox; |
546 | /* allocate struct nfsd4_session and slot table pointers in one piece */ | 666 | /* allocate struct nfsd4_session and slot table pointers in one piece */ |
547 | slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot *); | 667 | slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot *); |
548 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); | 668 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); |
@@ -591,10 +711,8 @@ find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid) | |||
591 | 711 | ||
592 | dump_sessionid(__func__, sessionid); | 712 | dump_sessionid(__func__, sessionid); |
593 | idx = hash_sessionid(sessionid); | 713 | idx = hash_sessionid(sessionid); |
594 | dprintk("%s: idx is %d\n", __func__, idx); | ||
595 | /* Search in the appropriate list */ | 714 | /* Search in the appropriate list */ |
596 | list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) { | 715 | list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) { |
597 | dump_sessionid("list traversal", &elem->se_sessionid); | ||
598 | if (!memcmp(elem->se_sessionid.data, sessionid->data, | 716 | if (!memcmp(elem->se_sessionid.data, sessionid->data, |
599 | NFS4_MAX_SESSIONID_LEN)) { | 717 | NFS4_MAX_SESSIONID_LEN)) { |
600 | return elem; | 718 | return elem; |
@@ -714,7 +832,6 @@ release_session_client(struct nfsd4_session *session) | |||
714 | } else | 832 | } else |
715 | renew_client_locked(clp); | 833 | renew_client_locked(clp); |
716 | spin_unlock(&client_lock); | 834 | spin_unlock(&client_lock); |
717 | nfsd4_put_session(session); | ||
718 | } | 835 | } |
719 | 836 | ||
720 | /* must be called under the client_lock */ | 837 | /* must be called under the client_lock */ |
@@ -1220,7 +1337,7 @@ out_new: | |||
1220 | /* Normal case */ | 1337 | /* Normal case */ |
1221 | new = create_client(exid->clname, dname, rqstp, &verf); | 1338 | new = create_client(exid->clname, dname, rqstp, &verf); |
1222 | if (new == NULL) { | 1339 | if (new == NULL) { |
1223 | status = nfserr_serverfault; | 1340 | status = nfserr_jukebox; |
1224 | goto out; | 1341 | goto out; |
1225 | } | 1342 | } |
1226 | 1343 | ||
@@ -1760,6 +1877,8 @@ alloc_init_file(struct inode *ino) | |||
1760 | fp->fi_inode = igrab(ino); | 1877 | fp->fi_inode = igrab(ino); |
1761 | fp->fi_id = current_fileid++; | 1878 | fp->fi_id = current_fileid++; |
1762 | fp->fi_had_conflict = false; | 1879 | fp->fi_had_conflict = false; |
1880 | memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); | ||
1881 | memset(fp->fi_access, 0, sizeof(fp->fi_access)); | ||
1763 | spin_lock(&recall_lock); | 1882 | spin_lock(&recall_lock); |
1764 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); | 1883 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); |
1765 | spin_unlock(&recall_lock); | 1884 | spin_unlock(&recall_lock); |
@@ -1971,57 +2090,6 @@ static inline int deny_valid(u32 x) | |||
1971 | } | 2090 | } |
1972 | 2091 | ||
1973 | /* | 2092 | /* |
1974 | * We store the NONE, READ, WRITE, and BOTH bits separately in the | ||
1975 | * st_{access,deny}_bmap field of the stateid, in order to track not | ||
1976 | * only what share bits are currently in force, but also what | ||
1977 | * combinations of share bits previous opens have used. This allows us | ||
1978 | * to enforce the recommendation of rfc 3530 14.2.19 that the server | ||
1979 | * return an error if the client attempt to downgrade to a combination | ||
1980 | * of share bits not explicable by closing some of its previous opens. | ||
1981 | * | ||
1982 | * XXX: This enforcement is actually incomplete, since we don't keep | ||
1983 | * track of access/deny bit combinations; so, e.g., we allow: | ||
1984 | * | ||
1985 | * OPEN allow read, deny write | ||
1986 | * OPEN allow both, deny none | ||
1987 | * DOWNGRADE allow read, deny none | ||
1988 | * | ||
1989 | * which we should reject. | ||
1990 | */ | ||
1991 | static void | ||
1992 | set_access(unsigned int *access, unsigned long bmap) { | ||
1993 | int i; | ||
1994 | |||
1995 | *access = 0; | ||
1996 | for (i = 1; i < 4; i++) { | ||
1997 | if (test_bit(i, &bmap)) | ||
1998 | *access |= i; | ||
1999 | } | ||
2000 | } | ||
2001 | |||
2002 | static void | ||
2003 | set_deny(unsigned int *deny, unsigned long bmap) { | ||
2004 | int i; | ||
2005 | |||
2006 | *deny = 0; | ||
2007 | for (i = 0; i < 4; i++) { | ||
2008 | if (test_bit(i, &bmap)) | ||
2009 | *deny |= i ; | ||
2010 | } | ||
2011 | } | ||
2012 | |||
2013 | static int | ||
2014 | test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) { | ||
2015 | unsigned int access, deny; | ||
2016 | |||
2017 | set_access(&access, stp->st_access_bmap); | ||
2018 | set_deny(&deny, stp->st_deny_bmap); | ||
2019 | if ((access & open->op_share_deny) || (deny & open->op_share_access)) | ||
2020 | return 0; | ||
2021 | return 1; | ||
2022 | } | ||
2023 | |||
2024 | /* | ||
2025 | * Called to check deny when READ with all zero stateid or | 2093 | * Called to check deny when READ with all zero stateid or |
2026 | * WRITE with all zero or all one stateid | 2094 | * WRITE with all zero or all one stateid |
2027 | */ | 2095 | */ |
@@ -2052,14 +2120,12 @@ out: | |||
2052 | } | 2120 | } |
2053 | 2121 | ||
2054 | static inline void | 2122 | static inline void |
2055 | nfs4_file_downgrade(struct file *filp, unsigned int share_access) | 2123 | nfs4_file_downgrade(struct nfs4_file *fp, unsigned int share_access) |
2056 | { | 2124 | { |
2057 | if (share_access & NFS4_SHARE_ACCESS_WRITE) { | 2125 | if (share_access & NFS4_SHARE_ACCESS_WRITE) |
2058 | drop_file_write_access(filp); | 2126 | nfs4_file_put_access(fp, O_WRONLY); |
2059 | spin_lock(&filp->f_lock); | 2127 | if (share_access & NFS4_SHARE_ACCESS_READ) |
2060 | filp->f_mode = (filp->f_mode | FMODE_READ) & ~FMODE_WRITE; | 2128 | nfs4_file_put_access(fp, O_RDONLY); |
2061 | spin_unlock(&filp->f_lock); | ||
2062 | } | ||
2063 | } | 2129 | } |
2064 | 2130 | ||
2065 | /* | 2131 | /* |
@@ -2255,6 +2321,13 @@ find_delegation_file(struct nfs4_file *fp, stateid_t *stid) | |||
2255 | return NULL; | 2321 | return NULL; |
2256 | } | 2322 | } |
2257 | 2323 | ||
2324 | int share_access_to_flags(u32 share_access) | ||
2325 | { | ||
2326 | share_access &= ~NFS4_SHARE_WANT_MASK; | ||
2327 | |||
2328 | return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; | ||
2329 | } | ||
2330 | |||
2258 | static __be32 | 2331 | static __be32 |
2259 | nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, | 2332 | nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, |
2260 | struct nfs4_delegation **dp) | 2333 | struct nfs4_delegation **dp) |
@@ -2265,8 +2338,7 @@ nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, | |||
2265 | *dp = find_delegation_file(fp, &open->op_delegate_stateid); | 2338 | *dp = find_delegation_file(fp, &open->op_delegate_stateid); |
2266 | if (*dp == NULL) | 2339 | if (*dp == NULL) |
2267 | goto out; | 2340 | goto out; |
2268 | flags = open->op_share_access == NFS4_SHARE_ACCESS_READ ? | 2341 | flags = share_access_to_flags(open->op_share_access); |
2269 | RD_STATE : WR_STATE; | ||
2270 | status = nfs4_check_delegmode(*dp, flags); | 2342 | status = nfs4_check_delegmode(*dp, flags); |
2271 | if (status) | 2343 | if (status) |
2272 | *dp = NULL; | 2344 | *dp = NULL; |
@@ -2308,30 +2380,53 @@ nfs4_alloc_stateid(void) | |||
2308 | return kmem_cache_alloc(stateid_slab, GFP_KERNEL); | 2380 | return kmem_cache_alloc(stateid_slab, GFP_KERNEL); |
2309 | } | 2381 | } |
2310 | 2382 | ||
2383 | static inline int nfs4_access_to_access(u32 nfs4_access) | ||
2384 | { | ||
2385 | int flags = 0; | ||
2386 | |||
2387 | if (nfs4_access & NFS4_SHARE_ACCESS_READ) | ||
2388 | flags |= NFSD_MAY_READ; | ||
2389 | if (nfs4_access & NFS4_SHARE_ACCESS_WRITE) | ||
2390 | flags |= NFSD_MAY_WRITE; | ||
2391 | return flags; | ||
2392 | } | ||
2393 | |||
2394 | static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file | ||
2395 | *fp, struct svc_fh *cur_fh, u32 nfs4_access) | ||
2396 | { | ||
2397 | __be32 status; | ||
2398 | int oflag = nfs4_access_to_omode(nfs4_access); | ||
2399 | int access = nfs4_access_to_access(nfs4_access); | ||
2400 | |||
2401 | if (!fp->fi_fds[oflag]) { | ||
2402 | status = nfsd_open(rqstp, cur_fh, S_IFREG, access, | ||
2403 | &fp->fi_fds[oflag]); | ||
2404 | if (status == nfserr_dropit) | ||
2405 | status = nfserr_jukebox; | ||
2406 | if (status) | ||
2407 | return status; | ||
2408 | } | ||
2409 | nfs4_file_get_access(fp, oflag); | ||
2410 | |||
2411 | return nfs_ok; | ||
2412 | } | ||
2413 | |||
2311 | static __be32 | 2414 | static __be32 |
2312 | nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, | 2415 | nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, |
2313 | struct nfs4_delegation *dp, | 2416 | struct nfs4_file *fp, struct svc_fh *cur_fh, |
2314 | struct svc_fh *cur_fh, int flags) | 2417 | struct nfsd4_open *open) |
2315 | { | 2418 | { |
2316 | struct nfs4_stateid *stp; | 2419 | struct nfs4_stateid *stp; |
2420 | __be32 status; | ||
2317 | 2421 | ||
2318 | stp = nfs4_alloc_stateid(); | 2422 | stp = nfs4_alloc_stateid(); |
2319 | if (stp == NULL) | 2423 | if (stp == NULL) |
2320 | return nfserr_resource; | 2424 | return nfserr_resource; |
2321 | 2425 | ||
2322 | if (dp) { | 2426 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open->op_share_access); |
2323 | get_file(dp->dl_vfs_file); | 2427 | if (status) { |
2324 | stp->st_vfs_file = dp->dl_vfs_file; | 2428 | kmem_cache_free(stateid_slab, stp); |
2325 | } else { | 2429 | return status; |
2326 | __be32 status; | ||
2327 | status = nfsd_open(rqstp, cur_fh, S_IFREG, flags, | ||
2328 | &stp->st_vfs_file); | ||
2329 | if (status) { | ||
2330 | if (status == nfserr_dropit) | ||
2331 | status = nfserr_jukebox; | ||
2332 | kmem_cache_free(stateid_slab, stp); | ||
2333 | return status; | ||
2334 | } | ||
2335 | } | 2430 | } |
2336 | *stpp = stp; | 2431 | *stpp = stp; |
2337 | return 0; | 2432 | return 0; |
@@ -2353,35 +2448,30 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, | |||
2353 | } | 2448 | } |
2354 | 2449 | ||
2355 | static __be32 | 2450 | static __be32 |
2356 | nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open) | 2451 | nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open) |
2357 | { | 2452 | { |
2358 | struct file *filp = stp->st_vfs_file; | 2453 | u32 op_share_access, new_access; |
2359 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
2360 | unsigned int share_access, new_writer; | ||
2361 | __be32 status; | 2454 | __be32 status; |
2362 | 2455 | ||
2363 | set_access(&share_access, stp->st_access_bmap); | 2456 | set_access(&new_access, stp->st_access_bmap); |
2364 | new_writer = (~share_access) & open->op_share_access | 2457 | new_access = (~new_access) & open->op_share_access & ~NFS4_SHARE_WANT_MASK; |
2365 | & NFS4_SHARE_ACCESS_WRITE; | 2458 | |
2366 | 2459 | if (new_access) { | |
2367 | if (new_writer) { | 2460 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, new_access); |
2368 | int err = get_write_access(inode); | 2461 | if (status) |
2369 | if (err) | 2462 | return status; |
2370 | return nfserrno(err); | ||
2371 | err = mnt_want_write(cur_fh->fh_export->ex_path.mnt); | ||
2372 | if (err) | ||
2373 | return nfserrno(err); | ||
2374 | file_take_write(filp); | ||
2375 | } | 2463 | } |
2376 | status = nfsd4_truncate(rqstp, cur_fh, open); | 2464 | status = nfsd4_truncate(rqstp, cur_fh, open); |
2377 | if (status) { | 2465 | if (status) { |
2378 | if (new_writer) | 2466 | if (new_access) { |
2379 | put_write_access(inode); | 2467 | int oflag = nfs4_access_to_omode(new_access); |
2468 | nfs4_file_put_access(fp, oflag); | ||
2469 | } | ||
2380 | return status; | 2470 | return status; |
2381 | } | 2471 | } |
2382 | /* remember the open */ | 2472 | /* remember the open */ |
2383 | filp->f_mode |= open->op_share_access; | 2473 | op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK; |
2384 | __set_bit(open->op_share_access, &stp->st_access_bmap); | 2474 | __set_bit(op_share_access, &stp->st_access_bmap); |
2385 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); | 2475 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); |
2386 | 2476 | ||
2387 | return nfs_ok; | 2477 | return nfs_ok; |
@@ -2444,13 +2534,14 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2444 | fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; | 2534 | fl.fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; |
2445 | fl.fl_end = OFFSET_MAX; | 2535 | fl.fl_end = OFFSET_MAX; |
2446 | fl.fl_owner = (fl_owner_t)dp; | 2536 | fl.fl_owner = (fl_owner_t)dp; |
2447 | fl.fl_file = stp->st_vfs_file; | 2537 | fl.fl_file = find_readable_file(stp->st_file); |
2538 | BUG_ON(!fl.fl_file); | ||
2448 | fl.fl_pid = current->tgid; | 2539 | fl.fl_pid = current->tgid; |
2449 | 2540 | ||
2450 | /* vfs_setlease checks to see if delegation should be handed out. | 2541 | /* vfs_setlease checks to see if delegation should be handed out. |
2451 | * the lock_manager callbacks fl_mylease and fl_change are used | 2542 | * the lock_manager callbacks fl_mylease and fl_change are used |
2452 | */ | 2543 | */ |
2453 | if ((status = vfs_setlease(stp->st_vfs_file, fl.fl_type, &flp))) { | 2544 | if ((status = vfs_setlease(fl.fl_file, fl.fl_type, &flp))) { |
2454 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); | 2545 | dprintk("NFSD: setlease failed [%d], no delegation\n", status); |
2455 | unhash_delegation(dp); | 2546 | unhash_delegation(dp); |
2456 | flag = NFS4_OPEN_DELEGATE_NONE; | 2547 | flag = NFS4_OPEN_DELEGATE_NONE; |
@@ -2514,18 +2605,12 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
2514 | */ | 2605 | */ |
2515 | if (stp) { | 2606 | if (stp) { |
2516 | /* Stateid was found, this is an OPEN upgrade */ | 2607 | /* Stateid was found, this is an OPEN upgrade */ |
2517 | status = nfs4_upgrade_open(rqstp, current_fh, stp, open); | 2608 | status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); |
2518 | if (status) | 2609 | if (status) |
2519 | goto out; | 2610 | goto out; |
2520 | update_stateid(&stp->st_stateid); | 2611 | update_stateid(&stp->st_stateid); |
2521 | } else { | 2612 | } else { |
2522 | /* Stateid was not found, this is a new OPEN */ | 2613 | status = nfs4_new_open(rqstp, &stp, fp, current_fh, open); |
2523 | int flags = 0; | ||
2524 | if (open->op_share_access & NFS4_SHARE_ACCESS_READ) | ||
2525 | flags |= NFSD_MAY_READ; | ||
2526 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) | ||
2527 | flags |= NFSD_MAY_WRITE; | ||
2528 | status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags); | ||
2529 | if (status) | 2614 | if (status) |
2530 | goto out; | 2615 | goto out; |
2531 | init_stateid(stp, fp, open); | 2616 | init_stateid(stp, fp, open); |
@@ -2727,7 +2812,7 @@ search_close_lru(u32 st_id, int flags) | |||
2727 | static inline int | 2812 | static inline int |
2728 | nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) | 2813 | nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) |
2729 | { | 2814 | { |
2730 | return fhp->fh_dentry->d_inode != stp->st_vfs_file->f_path.dentry->d_inode; | 2815 | return fhp->fh_dentry->d_inode != stp->st_file->fi_inode; |
2731 | } | 2816 | } |
2732 | 2817 | ||
2733 | static int | 2818 | static int |
@@ -2760,6 +2845,9 @@ __be32 nfs4_check_openmode(struct nfs4_stateid *stp, int flags) | |||
2760 | { | 2845 | { |
2761 | __be32 status = nfserr_openmode; | 2846 | __be32 status = nfserr_openmode; |
2762 | 2847 | ||
2848 | /* For lock stateid's, we test the parent open, not the lock: */ | ||
2849 | if (stp->st_openstp) | ||
2850 | stp = stp->st_openstp; | ||
2763 | if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap))) | 2851 | if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap))) |
2764 | goto out; | 2852 | goto out; |
2765 | if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap))) | 2853 | if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap))) |
@@ -2872,7 +2960,8 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2872 | goto out; | 2960 | goto out; |
2873 | renew_client(dp->dl_client); | 2961 | renew_client(dp->dl_client); |
2874 | if (filpp) | 2962 | if (filpp) |
2875 | *filpp = dp->dl_vfs_file; | 2963 | *filpp = find_readable_file(dp->dl_file); |
2964 | BUG_ON(!*filpp); | ||
2876 | } else { /* open or lock stateid */ | 2965 | } else { /* open or lock stateid */ |
2877 | stp = find_stateid(stateid, flags); | 2966 | stp = find_stateid(stateid, flags); |
2878 | if (!stp) | 2967 | if (!stp) |
@@ -2889,8 +2978,13 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2889 | if (status) | 2978 | if (status) |
2890 | goto out; | 2979 | goto out; |
2891 | renew_client(stp->st_stateowner->so_client); | 2980 | renew_client(stp->st_stateowner->so_client); |
2892 | if (filpp) | 2981 | if (filpp) { |
2893 | *filpp = stp->st_vfs_file; | 2982 | if (flags & RD_STATE) |
2983 | *filpp = find_readable_file(stp->st_file); | ||
2984 | else | ||
2985 | *filpp = find_writeable_file(stp->st_file); | ||
2986 | BUG_ON(!*filpp); /* assured by check_openmode */ | ||
2987 | } | ||
2894 | } | 2988 | } |
2895 | status = nfs_ok; | 2989 | status = nfs_ok; |
2896 | out: | 2990 | out: |
@@ -3126,8 +3220,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
3126 | goto out; | 3220 | goto out; |
3127 | } | 3221 | } |
3128 | set_access(&share_access, stp->st_access_bmap); | 3222 | set_access(&share_access, stp->st_access_bmap); |
3129 | nfs4_file_downgrade(stp->st_vfs_file, | 3223 | nfs4_file_downgrade(stp->st_file, share_access & ~od->od_share_access); |
3130 | share_access & ~od->od_share_access); | ||
3131 | 3224 | ||
3132 | reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap); | 3225 | reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap); |
3133 | reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); | 3226 | reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); |
@@ -3346,11 +3439,9 @@ static inline void | |||
3346 | nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) | 3439 | nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) |
3347 | { | 3440 | { |
3348 | struct nfs4_stateowner *sop; | 3441 | struct nfs4_stateowner *sop; |
3349 | unsigned int hval; | ||
3350 | 3442 | ||
3351 | if (fl->fl_lmops == &nfsd_posix_mng_ops) { | 3443 | if (fl->fl_lmops == &nfsd_posix_mng_ops) { |
3352 | sop = (struct nfs4_stateowner *) fl->fl_owner; | 3444 | sop = (struct nfs4_stateowner *) fl->fl_owner; |
3353 | hval = lockownerid_hashval(sop->so_id); | ||
3354 | kref_get(&sop->so_ref); | 3445 | kref_get(&sop->so_ref); |
3355 | deny->ld_sop = sop; | 3446 | deny->ld_sop = sop; |
3356 | deny->ld_clientid = sop->so_client->cl_clientid; | 3447 | deny->ld_clientid = sop->so_client->cl_clientid; |
@@ -3446,8 +3537,6 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc | |||
3446 | stp->st_stateid.si_stateownerid = sop->so_id; | 3537 | stp->st_stateid.si_stateownerid = sop->so_id; |
3447 | stp->st_stateid.si_fileid = fp->fi_id; | 3538 | stp->st_stateid.si_fileid = fp->fi_id; |
3448 | stp->st_stateid.si_generation = 0; | 3539 | stp->st_stateid.si_generation = 0; |
3449 | stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */ | ||
3450 | stp->st_access_bmap = open_stp->st_access_bmap; | ||
3451 | stp->st_deny_bmap = open_stp->st_deny_bmap; | 3540 | stp->st_deny_bmap = open_stp->st_deny_bmap; |
3452 | stp->st_openstp = open_stp; | 3541 | stp->st_openstp = open_stp; |
3453 | 3542 | ||
@@ -3547,7 +3636,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3547 | lock_sop = lock->lk_replay_owner; | 3636 | lock_sop = lock->lk_replay_owner; |
3548 | } | 3637 | } |
3549 | /* lock->lk_replay_owner and lock_stp have been created or found */ | 3638 | /* lock->lk_replay_owner and lock_stp have been created or found */ |
3550 | filp = lock_stp->st_vfs_file; | ||
3551 | 3639 | ||
3552 | status = nfserr_grace; | 3640 | status = nfserr_grace; |
3553 | if (locks_in_grace() && !lock->lk_reclaim) | 3641 | if (locks_in_grace() && !lock->lk_reclaim) |
@@ -3560,11 +3648,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3560 | switch (lock->lk_type) { | 3648 | switch (lock->lk_type) { |
3561 | case NFS4_READ_LT: | 3649 | case NFS4_READ_LT: |
3562 | case NFS4_READW_LT: | 3650 | case NFS4_READW_LT: |
3651 | filp = find_readable_file(lock_stp->st_file); | ||
3563 | file_lock.fl_type = F_RDLCK; | 3652 | file_lock.fl_type = F_RDLCK; |
3564 | cmd = F_SETLK; | 3653 | cmd = F_SETLK; |
3565 | break; | 3654 | break; |
3566 | case NFS4_WRITE_LT: | 3655 | case NFS4_WRITE_LT: |
3567 | case NFS4_WRITEW_LT: | 3656 | case NFS4_WRITEW_LT: |
3657 | filp = find_writeable_file(lock_stp->st_file); | ||
3568 | file_lock.fl_type = F_WRLCK; | 3658 | file_lock.fl_type = F_WRLCK; |
3569 | cmd = F_SETLK; | 3659 | cmd = F_SETLK; |
3570 | break; | 3660 | break; |
@@ -3572,6 +3662,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3572 | status = nfserr_inval; | 3662 | status = nfserr_inval; |
3573 | goto out; | 3663 | goto out; |
3574 | } | 3664 | } |
3665 | if (!filp) { | ||
3666 | status = nfserr_openmode; | ||
3667 | goto out; | ||
3668 | } | ||
3575 | file_lock.fl_owner = (fl_owner_t)lock_sop; | 3669 | file_lock.fl_owner = (fl_owner_t)lock_sop; |
3576 | file_lock.fl_pid = current->tgid; | 3670 | file_lock.fl_pid = current->tgid; |
3577 | file_lock.fl_file = filp; | 3671 | file_lock.fl_file = filp; |
@@ -3740,7 +3834,11 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3740 | &locku->lu_stateowner, &stp, NULL))) | 3834 | &locku->lu_stateowner, &stp, NULL))) |
3741 | goto out; | 3835 | goto out; |
3742 | 3836 | ||
3743 | filp = stp->st_vfs_file; | 3837 | filp = find_any_file(stp->st_file); |
3838 | if (!filp) { | ||
3839 | status = nfserr_lock_range; | ||
3840 | goto out; | ||
3841 | } | ||
3744 | BUG_ON(!filp); | 3842 | BUG_ON(!filp); |
3745 | locks_init_lock(&file_lock); | 3843 | locks_init_lock(&file_lock); |
3746 | file_lock.fl_type = F_UNLCK; | 3844 | file_lock.fl_type = F_UNLCK; |
@@ -3787,10 +3885,10 @@ out_nfserr: | |||
3787 | * 0: no locks held by lockowner | 3885 | * 0: no locks held by lockowner |
3788 | */ | 3886 | */ |
3789 | static int | 3887 | static int |
3790 | check_for_locks(struct file *filp, struct nfs4_stateowner *lowner) | 3888 | check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner) |
3791 | { | 3889 | { |
3792 | struct file_lock **flpp; | 3890 | struct file_lock **flpp; |
3793 | struct inode *inode = filp->f_path.dentry->d_inode; | 3891 | struct inode *inode = filp->fi_inode; |
3794 | int status = 0; | 3892 | int status = 0; |
3795 | 3893 | ||
3796 | lock_kernel(); | 3894 | lock_kernel(); |
@@ -3841,7 +3939,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, | |||
3841 | continue; | 3939 | continue; |
3842 | list_for_each_entry(stp, &sop->so_stateids, | 3940 | list_for_each_entry(stp, &sop->so_stateids, |
3843 | st_perstateowner) { | 3941 | st_perstateowner) { |
3844 | if (check_for_locks(stp->st_vfs_file, sop)) | 3942 | if (check_for_locks(stp->st_file, sop)) |
3845 | goto out; | 3943 | goto out; |
3846 | /* Note: so_perclient unused for lockowners, | 3944 | /* Note: so_perclient unused for lockowners, |
3847 | * so it's OK to fool with here. */ | 3945 | * so it's OK to fool with here. */ |
@@ -4066,16 +4164,8 @@ out_free_laundry: | |||
4066 | int | 4164 | int |
4067 | nfs4_state_start(void) | 4165 | nfs4_state_start(void) |
4068 | { | 4166 | { |
4069 | int ret; | ||
4070 | |||
4071 | if (nfs4_init) | ||
4072 | return 0; | ||
4073 | nfsd4_load_reboot_recovery_data(); | 4167 | nfsd4_load_reboot_recovery_data(); |
4074 | ret = __nfs4_state_start(); | 4168 | return __nfs4_state_start(); |
4075 | if (ret) | ||
4076 | return ret; | ||
4077 | nfs4_init = 1; | ||
4078 | return 0; | ||
4079 | } | 4169 | } |
4080 | 4170 | ||
4081 | static void | 4171 | static void |
@@ -4110,7 +4200,6 @@ __nfs4_state_shutdown(void) | |||
4110 | } | 4200 | } |
4111 | 4201 | ||
4112 | nfsd4_shutdown_recdir(); | 4202 | nfsd4_shutdown_recdir(); |
4113 | nfs4_init = 0; | ||
4114 | } | 4203 | } |
4115 | 4204 | ||
4116 | void | 4205 | void |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index ac17a7080239..f8931acb05f3 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -2630,7 +2630,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
2630 | } | 2630 | } |
2631 | read->rd_vlen = v; | 2631 | read->rd_vlen = v; |
2632 | 2632 | ||
2633 | nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp, read->rd_filp, | 2633 | nfserr = nfsd_read_file(read->rd_rqstp, read->rd_fhp, read->rd_filp, |
2634 | read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen, | 2634 | read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen, |
2635 | &maxcount); | 2635 | &maxcount); |
2636 | 2636 | ||
@@ -3325,6 +3325,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo | |||
3325 | } | 3325 | } |
3326 | /* Renew the clientid on success and on replay */ | 3326 | /* Renew the clientid on success and on replay */ |
3327 | release_session_client(cs->session); | 3327 | release_session_client(cs->session); |
3328 | nfsd4_put_session(cs->session); | ||
3328 | } | 3329 | } |
3329 | return 1; | 3330 | return 1; |
3330 | } | 3331 | } |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 508941c23af7..b53b1d042f1f 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -949,15 +949,12 @@ static ssize_t __write_ports_addfd(char *buf) | |||
949 | if (err != 0) | 949 | if (err != 0) |
950 | return err; | 950 | return err; |
951 | 951 | ||
952 | err = lockd_up(); | ||
953 | if (err != 0) | ||
954 | goto out; | ||
955 | |||
956 | err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); | 952 | err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); |
957 | if (err < 0) | 953 | if (err < 0) { |
958 | lockd_down(); | 954 | svc_destroy(nfsd_serv); |
955 | return err; | ||
956 | } | ||
959 | 957 | ||
960 | out: | ||
961 | /* Decrease the count, but don't shut down the service */ | 958 | /* Decrease the count, but don't shut down the service */ |
962 | nfsd_serv->sv_nrthreads--; | 959 | nfsd_serv->sv_nrthreads--; |
963 | return err; | 960 | return err; |
@@ -978,9 +975,6 @@ static ssize_t __write_ports_delfd(char *buf) | |||
978 | if (nfsd_serv != NULL) | 975 | if (nfsd_serv != NULL) |
979 | len = svc_sock_names(nfsd_serv, buf, | 976 | len = svc_sock_names(nfsd_serv, buf, |
980 | SIMPLE_TRANSACTION_LIMIT, toclose); | 977 | SIMPLE_TRANSACTION_LIMIT, toclose); |
981 | if (len >= 0) | ||
982 | lockd_down(); | ||
983 | |||
984 | kfree(toclose); | 978 | kfree(toclose); |
985 | return len; | 979 | return len; |
986 | } | 980 | } |
@@ -1014,6 +1008,9 @@ static ssize_t __write_ports_addxprt(char *buf) | |||
1014 | PF_INET6, port, SVC_SOCK_ANONYMOUS); | 1008 | PF_INET6, port, SVC_SOCK_ANONYMOUS); |
1015 | if (err < 0 && err != -EAFNOSUPPORT) | 1009 | if (err < 0 && err != -EAFNOSUPPORT) |
1016 | goto out_close; | 1010 | goto out_close; |
1011 | |||
1012 | /* Decrease the count, but don't shut down the service */ | ||
1013 | nfsd_serv->sv_nrthreads--; | ||
1017 | return 0; | 1014 | return 0; |
1018 | out_close: | 1015 | out_close: |
1019 | xprt = svc_find_xprt(nfsd_serv, transport, PF_INET, port); | 1016 | xprt = svc_find_xprt(nfsd_serv, transport, PF_INET, port); |
@@ -1022,8 +1019,7 @@ out_close: | |||
1022 | svc_xprt_put(xprt); | 1019 | svc_xprt_put(xprt); |
1023 | } | 1020 | } |
1024 | out_err: | 1021 | out_err: |
1025 | /* Decrease the count, but don't shut down the service */ | 1022 | svc_destroy(nfsd_serv); |
1026 | nfsd_serv->sv_nrthreads--; | ||
1027 | return err; | 1023 | return err; |
1028 | } | 1024 | } |
1029 | 1025 | ||
@@ -1194,7 +1190,7 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) | |||
1194 | bsize = NFSSVC_MAXBLKSIZE; | 1190 | bsize = NFSSVC_MAXBLKSIZE; |
1195 | bsize &= ~(1024-1); | 1191 | bsize &= ~(1024-1); |
1196 | mutex_lock(&nfsd_mutex); | 1192 | mutex_lock(&nfsd_mutex); |
1197 | if (nfsd_serv && nfsd_serv->sv_nrthreads) { | 1193 | if (nfsd_serv) { |
1198 | mutex_unlock(&nfsd_mutex); | 1194 | mutex_unlock(&nfsd_mutex); |
1199 | return -EBUSY; | 1195 | return -EBUSY; |
1200 | } | 1196 | } |
@@ -1310,6 +1306,8 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size) | |||
1310 | return -EINVAL; | 1306 | return -EINVAL; |
1311 | 1307 | ||
1312 | status = nfs4_reset_recoverydir(recdir); | 1308 | status = nfs4_reset_recoverydir(recdir); |
1309 | if (status) | ||
1310 | return status; | ||
1313 | } | 1311 | } |
1314 | 1312 | ||
1315 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n", | 1313 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n", |
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 72377761270e..b76ac3a82e39 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h | |||
@@ -153,6 +153,7 @@ void nfsd_lockd_shutdown(void); | |||
153 | #define nfserr_bad_seqid cpu_to_be32(NFSERR_BAD_SEQID) | 153 | #define nfserr_bad_seqid cpu_to_be32(NFSERR_BAD_SEQID) |
154 | #define nfserr_symlink cpu_to_be32(NFSERR_SYMLINK) | 154 | #define nfserr_symlink cpu_to_be32(NFSERR_SYMLINK) |
155 | #define nfserr_not_same cpu_to_be32(NFSERR_NOT_SAME) | 155 | #define nfserr_not_same cpu_to_be32(NFSERR_NOT_SAME) |
156 | #define nfserr_lock_range cpu_to_be32(NFSERR_LOCK_RANGE) | ||
156 | #define nfserr_restorefh cpu_to_be32(NFSERR_RESTOREFH) | 157 | #define nfserr_restorefh cpu_to_be32(NFSERR_RESTOREFH) |
157 | #define nfserr_attrnotsupp cpu_to_be32(NFSERR_ATTRNOTSUPP) | 158 | #define nfserr_attrnotsupp cpu_to_be32(NFSERR_ATTRNOTSUPP) |
158 | #define nfserr_bad_xdr cpu_to_be32(NFSERR_BAD_XDR) | 159 | #define nfserr_bad_xdr cpu_to_be32(NFSERR_BAD_XDR) |
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index a047ad6111ef..08e17264784b 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c | |||
@@ -144,7 +144,7 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp, | |||
144 | svc_reserve_auth(rqstp, (19<<2) + argp->count + 4); | 144 | svc_reserve_auth(rqstp, (19<<2) + argp->count + 4); |
145 | 145 | ||
146 | resp->count = argp->count; | 146 | resp->count = argp->count; |
147 | nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL, | 147 | nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), |
148 | argp->offset, | 148 | argp->offset, |
149 | rqstp->rq_vec, argp->vlen, | 149 | rqstp->rq_vec, argp->vlen, |
150 | &resp->count); | 150 | &resp->count); |
@@ -290,7 +290,6 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, | |||
290 | * gospel of sun micro | 290 | * gospel of sun micro |
291 | */ | 291 | */ |
292 | if (type != S_IFREG) { | 292 | if (type != S_IFREG) { |
293 | int is_borc = 0; | ||
294 | if (type != S_IFBLK && type != S_IFCHR) { | 293 | if (type != S_IFBLK && type != S_IFCHR) { |
295 | rdev = 0; | 294 | rdev = 0; |
296 | } else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) { | 295 | } else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) { |
@@ -298,7 +297,6 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, | |||
298 | type = S_IFIFO; | 297 | type = S_IFIFO; |
299 | } else { | 298 | } else { |
300 | /* Okay, char or block special */ | 299 | /* Okay, char or block special */ |
301 | is_borc = 1; | ||
302 | if (!rdev) | 300 | if (!rdev) |
303 | rdev = wanted; | 301 | rdev = wanted; |
304 | } | 302 | } |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 06b2a26edfe0..e2c43464f237 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -180,15 +180,80 @@ int nfsd_nrthreads(void) | |||
180 | return rv; | 180 | return rv; |
181 | } | 181 | } |
182 | 182 | ||
183 | static int nfsd_init_socks(int port) | ||
184 | { | ||
185 | int error; | ||
186 | if (!list_empty(&nfsd_serv->sv_permsocks)) | ||
187 | return 0; | ||
188 | |||
189 | error = svc_create_xprt(nfsd_serv, "udp", PF_INET, port, | ||
190 | SVC_SOCK_DEFAULTS); | ||
191 | if (error < 0) | ||
192 | return error; | ||
193 | |||
194 | error = svc_create_xprt(nfsd_serv, "tcp", PF_INET, port, | ||
195 | SVC_SOCK_DEFAULTS); | ||
196 | if (error < 0) | ||
197 | return error; | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static bool nfsd_up = false; | ||
203 | |||
204 | static int nfsd_startup(unsigned short port, int nrservs) | ||
205 | { | ||
206 | int ret; | ||
207 | |||
208 | if (nfsd_up) | ||
209 | return 0; | ||
210 | /* | ||
211 | * Readahead param cache - will no-op if it already exists. | ||
212 | * (Note therefore results will be suboptimal if number of | ||
213 | * threads is modified after nfsd start.) | ||
214 | */ | ||
215 | ret = nfsd_racache_init(2*nrservs); | ||
216 | if (ret) | ||
217 | return ret; | ||
218 | ret = nfsd_init_socks(port); | ||
219 | if (ret) | ||
220 | goto out_racache; | ||
221 | ret = lockd_up(); | ||
222 | if (ret) | ||
223 | goto out_racache; | ||
224 | ret = nfs4_state_start(); | ||
225 | if (ret) | ||
226 | goto out_lockd; | ||
227 | nfsd_up = true; | ||
228 | return 0; | ||
229 | out_lockd: | ||
230 | lockd_down(); | ||
231 | out_racache: | ||
232 | nfsd_racache_shutdown(); | ||
233 | return ret; | ||
234 | } | ||
235 | |||
236 | static void nfsd_shutdown(void) | ||
237 | { | ||
238 | /* | ||
239 | * write_ports can create the server without actually starting | ||
240 | * any threads--if we get shut down before any threads are | ||
241 | * started, then nfsd_last_thread will be run before any of this | ||
242 | * other initialization has been done. | ||
243 | */ | ||
244 | if (!nfsd_up) | ||
245 | return; | ||
246 | nfs4_state_shutdown(); | ||
247 | lockd_down(); | ||
248 | nfsd_racache_shutdown(); | ||
249 | nfsd_up = false; | ||
250 | } | ||
251 | |||
183 | static void nfsd_last_thread(struct svc_serv *serv) | 252 | static void nfsd_last_thread(struct svc_serv *serv) |
184 | { | 253 | { |
185 | /* When last nfsd thread exits we need to do some clean-up */ | 254 | /* When last nfsd thread exits we need to do some clean-up */ |
186 | struct svc_xprt *xprt; | ||
187 | list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) | ||
188 | lockd_down(); | ||
189 | nfsd_serv = NULL; | 255 | nfsd_serv = NULL; |
190 | nfsd_racache_shutdown(); | 256 | nfsd_shutdown(); |
191 | nfs4_state_shutdown(); | ||
192 | 257 | ||
193 | printk(KERN_WARNING "nfsd: last server has exited, flushing export " | 258 | printk(KERN_WARNING "nfsd: last server has exited, flushing export " |
194 | "cache\n"); | 259 | "cache\n"); |
@@ -263,45 +328,18 @@ int nfsd_create_serv(void) | |||
263 | nfsd_max_blksize >= 8*1024*2) | 328 | nfsd_max_blksize >= 8*1024*2) |
264 | nfsd_max_blksize /= 2; | 329 | nfsd_max_blksize /= 2; |
265 | } | 330 | } |
331 | nfsd_reset_versions(); | ||
266 | 332 | ||
267 | nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, | 333 | nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, |
268 | nfsd_last_thread, nfsd, THIS_MODULE); | 334 | nfsd_last_thread, nfsd, THIS_MODULE); |
269 | if (nfsd_serv == NULL) | 335 | if (nfsd_serv == NULL) |
270 | err = -ENOMEM; | 336 | return -ENOMEM; |
271 | else | ||
272 | set_max_drc(); | ||
273 | 337 | ||
338 | set_max_drc(); | ||
274 | do_gettimeofday(&nfssvc_boot); /* record boot time */ | 339 | do_gettimeofday(&nfssvc_boot); /* record boot time */ |
275 | return err; | 340 | return err; |
276 | } | 341 | } |
277 | 342 | ||
278 | static int nfsd_init_socks(int port) | ||
279 | { | ||
280 | int error; | ||
281 | if (!list_empty(&nfsd_serv->sv_permsocks)) | ||
282 | return 0; | ||
283 | |||
284 | error = svc_create_xprt(nfsd_serv, "udp", PF_INET, port, | ||
285 | SVC_SOCK_DEFAULTS); | ||
286 | if (error < 0) | ||
287 | return error; | ||
288 | |||
289 | error = lockd_up(); | ||
290 | if (error < 0) | ||
291 | return error; | ||
292 | |||
293 | error = svc_create_xprt(nfsd_serv, "tcp", PF_INET, port, | ||
294 | SVC_SOCK_DEFAULTS); | ||
295 | if (error < 0) | ||
296 | return error; | ||
297 | |||
298 | error = lockd_up(); | ||
299 | if (error < 0) | ||
300 | return error; | ||
301 | |||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | int nfsd_nrpools(void) | 343 | int nfsd_nrpools(void) |
306 | { | 344 | { |
307 | if (nfsd_serv == NULL) | 345 | if (nfsd_serv == NULL) |
@@ -376,10 +414,16 @@ int nfsd_set_nrthreads(int n, int *nthreads) | |||
376 | return err; | 414 | return err; |
377 | } | 415 | } |
378 | 416 | ||
417 | /* | ||
418 | * Adjust the number of threads and return the new number of threads. | ||
419 | * This is also the function that starts the server if necessary, if | ||
420 | * this is the first time nrservs is nonzero. | ||
421 | */ | ||
379 | int | 422 | int |
380 | nfsd_svc(unsigned short port, int nrservs) | 423 | nfsd_svc(unsigned short port, int nrservs) |
381 | { | 424 | { |
382 | int error; | 425 | int error; |
426 | bool nfsd_up_before; | ||
383 | 427 | ||
384 | mutex_lock(&nfsd_mutex); | 428 | mutex_lock(&nfsd_mutex); |
385 | dprintk("nfsd: creating service\n"); | 429 | dprintk("nfsd: creating service\n"); |
@@ -391,34 +435,29 @@ nfsd_svc(unsigned short port, int nrservs) | |||
391 | if (nrservs == 0 && nfsd_serv == NULL) | 435 | if (nrservs == 0 && nfsd_serv == NULL) |
392 | goto out; | 436 | goto out; |
393 | 437 | ||
394 | /* Readahead param cache - will no-op if it already exists */ | 438 | error = nfsd_create_serv(); |
395 | error = nfsd_racache_init(2*nrservs); | ||
396 | if (error<0) | ||
397 | goto out; | ||
398 | error = nfs4_state_start(); | ||
399 | if (error) | 439 | if (error) |
400 | goto out; | 440 | goto out; |
401 | 441 | ||
402 | nfsd_reset_versions(); | 442 | nfsd_up_before = nfsd_up; |
403 | |||
404 | error = nfsd_create_serv(); | ||
405 | 443 | ||
444 | error = nfsd_startup(port, nrservs); | ||
406 | if (error) | 445 | if (error) |
407 | goto out; | 446 | goto out_destroy; |
408 | error = nfsd_init_socks(port); | ||
409 | if (error) | ||
410 | goto failure; | ||
411 | |||
412 | error = svc_set_num_threads(nfsd_serv, NULL, nrservs); | 447 | error = svc_set_num_threads(nfsd_serv, NULL, nrservs); |
413 | if (error == 0) | 448 | if (error) |
414 | /* We are holding a reference to nfsd_serv which | 449 | goto out_shutdown; |
415 | * we don't want to count in the return value, | 450 | /* We are holding a reference to nfsd_serv which |
416 | * so subtract 1 | 451 | * we don't want to count in the return value, |
417 | */ | 452 | * so subtract 1 |
418 | error = nfsd_serv->sv_nrthreads - 1; | 453 | */ |
419 | failure: | 454 | error = nfsd_serv->sv_nrthreads - 1; |
455 | out_shutdown: | ||
456 | if (error < 0 && !nfsd_up_before) | ||
457 | nfsd_shutdown(); | ||
458 | out_destroy: | ||
420 | svc_destroy(nfsd_serv); /* Release server */ | 459 | svc_destroy(nfsd_serv); /* Release server */ |
421 | out: | 460 | out: |
422 | mutex_unlock(&nfsd_mutex); | 461 | mutex_unlock(&nfsd_mutex); |
423 | return error; | 462 | return error; |
424 | } | 463 | } |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 006c84230c7c..7731a75971dd 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -88,7 +88,6 @@ struct nfs4_delegation { | |||
88 | struct nfs4_client *dl_client; | 88 | struct nfs4_client *dl_client; |
89 | struct nfs4_file *dl_file; | 89 | struct nfs4_file *dl_file; |
90 | struct file_lock *dl_flock; | 90 | struct file_lock *dl_flock; |
91 | struct file *dl_vfs_file; | ||
92 | u32 dl_type; | 91 | u32 dl_type; |
93 | time_t dl_time; | 92 | time_t dl_time; |
94 | /* For recall: */ | 93 | /* For recall: */ |
@@ -342,12 +341,50 @@ struct nfs4_file { | |||
342 | struct list_head fi_hash; /* hash by "struct inode *" */ | 341 | struct list_head fi_hash; /* hash by "struct inode *" */ |
343 | struct list_head fi_stateids; | 342 | struct list_head fi_stateids; |
344 | struct list_head fi_delegations; | 343 | struct list_head fi_delegations; |
344 | /* One each for O_RDONLY, O_WRONLY, O_RDWR: */ | ||
345 | struct file * fi_fds[3]; | ||
346 | /* One each for O_RDONLY, O_WRONLY: */ | ||
347 | atomic_t fi_access[2]; | ||
348 | /* | ||
349 | * Each open stateid contributes 1 to either fi_readers or | ||
350 | * fi_writers, or both, depending on the open mode. A | ||
351 | * delegation also takes an fi_readers reference. Lock | ||
352 | * stateid's take none. | ||
353 | */ | ||
354 | atomic_t fi_readers; | ||
355 | atomic_t fi_writers; | ||
345 | struct inode *fi_inode; | 356 | struct inode *fi_inode; |
346 | u32 fi_id; /* used with stateowner->so_id | 357 | u32 fi_id; /* used with stateowner->so_id |
347 | * for stateid_hashtbl hash */ | 358 | * for stateid_hashtbl hash */ |
348 | bool fi_had_conflict; | 359 | bool fi_had_conflict; |
349 | }; | 360 | }; |
350 | 361 | ||
362 | /* XXX: for first cut may fall back on returning file that doesn't work | ||
363 | * at all? */ | ||
364 | static inline struct file *find_writeable_file(struct nfs4_file *f) | ||
365 | { | ||
366 | if (f->fi_fds[O_RDWR]) | ||
367 | return f->fi_fds[O_RDWR]; | ||
368 | return f->fi_fds[O_WRONLY]; | ||
369 | } | ||
370 | |||
371 | static inline struct file *find_readable_file(struct nfs4_file *f) | ||
372 | { | ||
373 | if (f->fi_fds[O_RDWR]) | ||
374 | return f->fi_fds[O_RDWR]; | ||
375 | return f->fi_fds[O_RDONLY]; | ||
376 | } | ||
377 | |||
378 | static inline struct file *find_any_file(struct nfs4_file *f) | ||
379 | { | ||
380 | if (f->fi_fds[O_RDWR]) | ||
381 | return f->fi_fds[O_RDWR]; | ||
382 | else if (f->fi_fds[O_RDWR]) | ||
383 | return f->fi_fds[O_WRONLY]; | ||
384 | else | ||
385 | return f->fi_fds[O_RDONLY]; | ||
386 | } | ||
387 | |||
351 | /* | 388 | /* |
352 | * nfs4_stateid can either be an open stateid or (eventually) a lock stateid | 389 | * nfs4_stateid can either be an open stateid or (eventually) a lock stateid |
353 | * | 390 | * |
@@ -373,7 +410,6 @@ struct nfs4_stateid { | |||
373 | struct nfs4_stateowner * st_stateowner; | 410 | struct nfs4_stateowner * st_stateowner; |
374 | struct nfs4_file * st_file; | 411 | struct nfs4_file * st_file; |
375 | stateid_t st_stateid; | 412 | stateid_t st_stateid; |
376 | struct file * st_vfs_file; | ||
377 | unsigned long st_access_bmap; | 413 | unsigned long st_access_bmap; |
378 | unsigned long st_deny_bmap; | 414 | unsigned long st_deny_bmap; |
379 | struct nfs4_stateid * st_openstp; | 415 | struct nfs4_stateid * st_openstp; |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 3c111120b619..9df85a13af28 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -604,7 +604,7 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_ac | |||
604 | return error; | 604 | return error; |
605 | } | 605 | } |
606 | 606 | ||
607 | #endif /* defined(CONFIG_NFS_V4) */ | 607 | #endif /* defined(CONFIG_NFSD_V4) */ |
608 | 608 | ||
609 | #ifdef CONFIG_NFSD_V3 | 609 | #ifdef CONFIG_NFSD_V3 |
610 | /* | 610 | /* |
@@ -903,7 +903,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
903 | loff_t offset, struct kvec *vec, int vlen, unsigned long *count) | 903 | loff_t offset, struct kvec *vec, int vlen, unsigned long *count) |
904 | { | 904 | { |
905 | struct inode *inode; | 905 | struct inode *inode; |
906 | struct raparms *ra; | ||
907 | mm_segment_t oldfs; | 906 | mm_segment_t oldfs; |
908 | __be32 err; | 907 | __be32 err; |
909 | int host_err; | 908 | int host_err; |
@@ -914,12 +913,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
914 | if (svc_msnfs(fhp) && !lock_may_read(inode, offset, *count)) | 913 | if (svc_msnfs(fhp) && !lock_may_read(inode, offset, *count)) |
915 | goto out; | 914 | goto out; |
916 | 915 | ||
917 | /* Get readahead parameters */ | ||
918 | ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino); | ||
919 | |||
920 | if (ra && ra->p_set) | ||
921 | file->f_ra = ra->p_ra; | ||
922 | |||
923 | if (file->f_op->splice_read && rqstp->rq_splice_ok) { | 916 | if (file->f_op->splice_read && rqstp->rq_splice_ok) { |
924 | struct splice_desc sd = { | 917 | struct splice_desc sd = { |
925 | .len = 0, | 918 | .len = 0, |
@@ -937,16 +930,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
937 | set_fs(oldfs); | 930 | set_fs(oldfs); |
938 | } | 931 | } |
939 | 932 | ||
940 | /* Write back readahead params */ | ||
941 | if (ra) { | ||
942 | struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex]; | ||
943 | spin_lock(&rab->pb_lock); | ||
944 | ra->p_ra = file->f_ra; | ||
945 | ra->p_set = 1; | ||
946 | ra->p_count--; | ||
947 | spin_unlock(&rab->pb_lock); | ||
948 | } | ||
949 | |||
950 | if (host_err >= 0) { | 933 | if (host_err >= 0) { |
951 | nfsdstats.io_read += host_err; | 934 | nfsdstats.io_read += host_err; |
952 | *count = host_err; | 935 | *count = host_err; |
@@ -1086,8 +1069,45 @@ out: | |||
1086 | * on entry. On return, *count contains the number of bytes actually read. | 1069 | * on entry. On return, *count contains the number of bytes actually read. |
1087 | * N.B. After this call fhp needs an fh_put | 1070 | * N.B. After this call fhp needs an fh_put |
1088 | */ | 1071 | */ |
1072 | __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, | ||
1073 | loff_t offset, struct kvec *vec, int vlen, unsigned long *count) | ||
1074 | { | ||
1075 | struct file *file; | ||
1076 | struct inode *inode; | ||
1077 | struct raparms *ra; | ||
1078 | __be32 err; | ||
1079 | |||
1080 | err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); | ||
1081 | if (err) | ||
1082 | return err; | ||
1083 | |||
1084 | inode = file->f_path.dentry->d_inode; | ||
1085 | |||
1086 | /* Get readahead parameters */ | ||
1087 | ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino); | ||
1088 | |||
1089 | if (ra && ra->p_set) | ||
1090 | file->f_ra = ra->p_ra; | ||
1091 | |||
1092 | err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count); | ||
1093 | |||
1094 | /* Write back readahead params */ | ||
1095 | if (ra) { | ||
1096 | struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex]; | ||
1097 | spin_lock(&rab->pb_lock); | ||
1098 | ra->p_ra = file->f_ra; | ||
1099 | ra->p_set = 1; | ||
1100 | ra->p_count--; | ||
1101 | spin_unlock(&rab->pb_lock); | ||
1102 | } | ||
1103 | |||
1104 | nfsd_close(file); | ||
1105 | return err; | ||
1106 | } | ||
1107 | |||
1108 | /* As above, but use the provided file descriptor. */ | ||
1089 | __be32 | 1109 | __be32 |
1090 | nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | 1110 | nfsd_read_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, |
1091 | loff_t offset, struct kvec *vec, int vlen, | 1111 | loff_t offset, struct kvec *vec, int vlen, |
1092 | unsigned long *count) | 1112 | unsigned long *count) |
1093 | { | 1113 | { |
@@ -1099,13 +1119,8 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
1099 | if (err) | 1119 | if (err) |
1100 | goto out; | 1120 | goto out; |
1101 | err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count); | 1121 | err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count); |
1102 | } else { | 1122 | } else /* Note file may still be NULL in NFSv4 special stateid case: */ |
1103 | err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); | 1123 | err = nfsd_read(rqstp, fhp, offset, vec, vlen, count); |
1104 | if (err) | ||
1105 | goto out; | ||
1106 | err = nfsd_vfs_read(rqstp, fhp, file, offset, vec, vlen, count); | ||
1107 | nfsd_close(file); | ||
1108 | } | ||
1109 | out: | 1124 | out: |
1110 | return err; | 1125 | return err; |
1111 | } | 1126 | } |
@@ -1631,7 +1646,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
1631 | char *name, int len, struct svc_fh *tfhp) | 1646 | char *name, int len, struct svc_fh *tfhp) |
1632 | { | 1647 | { |
1633 | struct dentry *ddir, *dnew, *dold; | 1648 | struct dentry *ddir, *dnew, *dold; |
1634 | struct inode *dirp, *dest; | 1649 | struct inode *dirp; |
1635 | __be32 err; | 1650 | __be32 err; |
1636 | int host_err; | 1651 | int host_err; |
1637 | 1652 | ||
@@ -1659,7 +1674,6 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
1659 | goto out_nfserr; | 1674 | goto out_nfserr; |
1660 | 1675 | ||
1661 | dold = tfhp->fh_dentry; | 1676 | dold = tfhp->fh_dentry; |
1662 | dest = dold->d_inode; | ||
1663 | 1677 | ||
1664 | host_err = mnt_want_write(tfhp->fh_export->ex_path.mnt); | 1678 | host_err = mnt_want_write(tfhp->fh_export->ex_path.mnt); |
1665 | if (host_err) { | 1679 | if (host_err) { |
@@ -2038,7 +2052,6 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, | |||
2038 | struct dentry *dentry, int acc) | 2052 | struct dentry *dentry, int acc) |
2039 | { | 2053 | { |
2040 | struct inode *inode = dentry->d_inode; | 2054 | struct inode *inode = dentry->d_inode; |
2041 | struct path path; | ||
2042 | int err; | 2055 | int err; |
2043 | 2056 | ||
2044 | if (acc == NFSD_MAY_NOP) | 2057 | if (acc == NFSD_MAY_NOP) |
@@ -2111,15 +2124,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, | |||
2111 | if (err == -EACCES && S_ISREG(inode->i_mode) && | 2124 | if (err == -EACCES && S_ISREG(inode->i_mode) && |
2112 | acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE)) | 2125 | acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE)) |
2113 | err = inode_permission(inode, MAY_EXEC); | 2126 | err = inode_permission(inode, MAY_EXEC); |
2114 | if (err) | ||
2115 | goto nfsd_out; | ||
2116 | 2127 | ||
2117 | /* Do integrity (permission) checking now, but defer incrementing | ||
2118 | * IMA counts to the actual file open. | ||
2119 | */ | ||
2120 | path.mnt = exp->ex_path.mnt; | ||
2121 | path.dentry = dentry; | ||
2122 | nfsd_out: | ||
2123 | return err? nfserrno(err) : 0; | 2128 | return err? nfserrno(err) : 0; |
2124 | } | 2129 | } |
2125 | 2130 | ||
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index 217a62c2a357..9a370a5e36b7 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h | |||
@@ -64,7 +64,9 @@ __be32 nfsd_commit(struct svc_rqst *, struct svc_fh *, | |||
64 | __be32 nfsd_open(struct svc_rqst *, struct svc_fh *, int, | 64 | __be32 nfsd_open(struct svc_rqst *, struct svc_fh *, int, |
65 | int, struct file **); | 65 | int, struct file **); |
66 | void nfsd_close(struct file *); | 66 | void nfsd_close(struct file *); |
67 | __be32 nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *, | 67 | __be32 nfsd_read(struct svc_rqst *, struct svc_fh *, |
68 | loff_t, struct kvec *, int, unsigned long *); | ||
69 | __be32 nfsd_read_file(struct svc_rqst *, struct svc_fh *, struct file *, | ||
68 | loff_t, struct kvec *, int, unsigned long *); | 70 | loff_t, struct kvec *, int, unsigned long *); |
69 | __be32 nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *, | 71 | __be32 nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *, |
70 | loff_t, struct kvec *,int, unsigned long *, int *); | 72 | loff_t, struct kvec *,int, unsigned long *, int *); |