diff options
| author | Ingo Molnar <mingo@elte.hu> | 2010-08-12 15:38:56 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2010-08-12 15:39:04 -0400 |
| commit | f46a6804135795f77d096ab0128f27531c7d051c (patch) | |
| tree | 7cd33f69e3661327739ae4c96e5a8389e7fc912e /fs/nfsd | |
| parent | b3e84ffa21f916e3354a12a7f19169c9febe96d0 (diff) | |
| parent | ad41a1e0cab07c5125456e8d38e5b1ab148d04aa (diff) | |
Merge branch 'linus' into perf/urgent
Merge reason: Fix upstream breakage introduced by:
de5d9bf: Move list types from <linux/list.h> to <linux/types.h>.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
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 | 9 | ||||
| -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 | 93 | ||||
| -rw-r--r-- | fs/nfsd/vfs.h | 4 |
11 files changed, 480 insertions, 292 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..1a468bbd330f 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
| @@ -1756,6 +1756,10 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
| 1756 | struct nfs4_acl *acl = NULL; | 1756 | struct nfs4_acl *acl = NULL; |
| 1757 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | 1757 | struct nfsd4_compoundres *resp = rqstp->rq_resp; |
| 1758 | u32 minorversion = resp->cstate.minorversion; | 1758 | u32 minorversion = resp->cstate.minorversion; |
| 1759 | struct path path = { | ||
| 1760 | .mnt = exp->ex_path.mnt, | ||
| 1761 | .dentry = dentry, | ||
| 1762 | }; | ||
| 1759 | 1763 | ||
| 1760 | BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1); | 1764 | BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1); |
| 1761 | BUG_ON(bmval0 & ~nfsd_suppattrs0(minorversion)); | 1765 | BUG_ON(bmval0 & ~nfsd_suppattrs0(minorversion)); |
| @@ -1776,7 +1780,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
| 1776 | FATTR4_WORD0_MAXNAME)) || | 1780 | FATTR4_WORD0_MAXNAME)) || |
| 1777 | (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | | 1781 | (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | |
| 1778 | FATTR4_WORD1_SPACE_TOTAL))) { | 1782 | FATTR4_WORD1_SPACE_TOTAL))) { |
| 1779 | err = vfs_statfs(dentry, &statfs); | 1783 | err = vfs_statfs(&path, &statfs); |
| 1780 | if (err) | 1784 | if (err) |
| 1781 | goto out_nfserr; | 1785 | goto out_nfserr; |
| 1782 | } | 1786 | } |
| @@ -2630,7 +2634,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
| 2630 | } | 2634 | } |
| 2631 | read->rd_vlen = v; | 2635 | read->rd_vlen = v; |
| 2632 | 2636 | ||
| 2633 | nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp, read->rd_filp, | 2637 | nfserr = nfsd_read_file(read->rd_rqstp, read->rd_fhp, read->rd_filp, |
| 2634 | read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen, | 2638 | read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen, |
| 2635 | &maxcount); | 2639 | &maxcount); |
| 2636 | 2640 | ||
| @@ -3325,6 +3329,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo | |||
| 3325 | } | 3329 | } |
| 3326 | /* Renew the clientid on success and on replay */ | 3330 | /* Renew the clientid on success and on replay */ |
| 3327 | release_session_client(cs->session); | 3331 | release_session_client(cs->session); |
| 3332 | nfsd4_put_session(cs->session); | ||
| 3328 | } | 3333 | } |
| 3329 | return 1; | 3334 | return 1; |
| 3330 | } | 3335 | } |
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..96360a83cb91 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,21 +930,11 @@ 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; |
| 953 | err = 0; | 936 | err = 0; |
| 954 | fsnotify_access(file->f_path.dentry); | 937 | fsnotify_access(file); |
| 955 | } else | 938 | } else |
| 956 | err = nfserrno(host_err); | 939 | err = nfserrno(host_err); |
| 957 | out: | 940 | out: |
| @@ -1062,7 +1045,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
| 1062 | goto out_nfserr; | 1045 | goto out_nfserr; |
| 1063 | *cnt = host_err; | 1046 | *cnt = host_err; |
| 1064 | nfsdstats.io_write += host_err; | 1047 | nfsdstats.io_write += host_err; |
| 1065 | fsnotify_modify(file->f_path.dentry); | 1048 | fsnotify_modify(file); |
| 1066 | 1049 | ||
| 1067 | /* clear setuid/setgid flag after write */ | 1050 | /* clear setuid/setgid flag after write */ |
| 1068 | if (inode->i_mode & (S_ISUID | S_ISGID)) | 1051 | if (inode->i_mode & (S_ISUID | S_ISGID)) |
| @@ -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) { |
| @@ -2019,8 +2033,14 @@ out: | |||
| 2019 | __be32 | 2033 | __be32 |
| 2020 | nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat, int access) | 2034 | nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat, int access) |
| 2021 | { | 2035 | { |
| 2022 | __be32 err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP | access); | 2036 | struct path path = { |
| 2023 | if (!err && vfs_statfs(fhp->fh_dentry,stat)) | 2037 | .mnt = fhp->fh_export->ex_path.mnt, |
| 2038 | .dentry = fhp->fh_dentry, | ||
| 2039 | }; | ||
| 2040 | __be32 err; | ||
| 2041 | |||
| 2042 | err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP | access); | ||
| 2043 | if (!err && vfs_statfs(&path, stat)) | ||
| 2024 | err = nfserr_io; | 2044 | err = nfserr_io; |
| 2025 | return err; | 2045 | return err; |
| 2026 | } | 2046 | } |
| @@ -2038,7 +2058,6 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, | |||
| 2038 | struct dentry *dentry, int acc) | 2058 | struct dentry *dentry, int acc) |
| 2039 | { | 2059 | { |
| 2040 | struct inode *inode = dentry->d_inode; | 2060 | struct inode *inode = dentry->d_inode; |
| 2041 | struct path path; | ||
| 2042 | int err; | 2061 | int err; |
| 2043 | 2062 | ||
| 2044 | if (acc == NFSD_MAY_NOP) | 2063 | if (acc == NFSD_MAY_NOP) |
| @@ -2111,15 +2130,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, | |||
| 2111 | if (err == -EACCES && S_ISREG(inode->i_mode) && | 2130 | if (err == -EACCES && S_ISREG(inode->i_mode) && |
| 2112 | acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE)) | 2131 | acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE)) |
| 2113 | err = inode_permission(inode, MAY_EXEC); | 2132 | err = inode_permission(inode, MAY_EXEC); |
| 2114 | if (err) | ||
| 2115 | goto nfsd_out; | ||
| 2116 | 2133 | ||
| 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; | 2134 | return err? nfserrno(err) : 0; |
| 2124 | } | 2135 | } |
| 2125 | 2136 | ||
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 *); |
