diff options
Diffstat (limited to 'fs/nfsd/nfs4proc.c')
-rw-r--r-- | fs/nfsd/nfs4proc.c | 74 |
1 files changed, 61 insertions, 13 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 6c9a4b291dba..9d1c5dba2bbb 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include "xdr4.h" | 40 | #include "xdr4.h" |
41 | #include "vfs.h" | 41 | #include "vfs.h" |
42 | #include "current_stateid.h" | 42 | #include "current_stateid.h" |
43 | #include "netns.h" | ||
43 | 44 | ||
44 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 45 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
45 | 46 | ||
@@ -194,6 +195,7 @@ static __be32 | |||
194 | do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) | 195 | do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) |
195 | { | 196 | { |
196 | struct svc_fh *resfh; | 197 | struct svc_fh *resfh; |
198 | int accmode; | ||
197 | __be32 status; | 199 | __be32 status; |
198 | 200 | ||
199 | resfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL); | 201 | resfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL); |
@@ -253,9 +255,10 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o | |||
253 | /* set reply cache */ | 255 | /* set reply cache */ |
254 | fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh, | 256 | fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh, |
255 | &resfh->fh_handle); | 257 | &resfh->fh_handle); |
256 | if (!open->op_created) | 258 | accmode = NFSD_MAY_NOP; |
257 | status = do_open_permission(rqstp, resfh, open, | 259 | if (open->op_created) |
258 | NFSD_MAY_NOP); | 260 | accmode |= NFSD_MAY_OWNER_OVERRIDE; |
261 | status = do_open_permission(rqstp, resfh, open, accmode); | ||
259 | set_change_info(&open->op_cinfo, current_fh); | 262 | set_change_info(&open->op_cinfo, current_fh); |
260 | fh_dup2(current_fh, resfh); | 263 | fh_dup2(current_fh, resfh); |
261 | out: | 264 | out: |
@@ -304,6 +307,8 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
304 | { | 307 | { |
305 | __be32 status; | 308 | __be32 status; |
306 | struct nfsd4_compoundres *resp; | 309 | struct nfsd4_compoundres *resp; |
310 | struct net *net = SVC_NET(rqstp); | ||
311 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
307 | 312 | ||
308 | dprintk("NFSD: nfsd4_open filename %.*s op_openowner %p\n", | 313 | dprintk("NFSD: nfsd4_open filename %.*s op_openowner %p\n", |
309 | (int)open->op_fname.len, open->op_fname.data, | 314 | (int)open->op_fname.len, open->op_fname.data, |
@@ -331,7 +336,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
331 | 336 | ||
332 | /* check seqid for replay. set nfs4_owner */ | 337 | /* check seqid for replay. set nfs4_owner */ |
333 | resp = rqstp->rq_resp; | 338 | resp = rqstp->rq_resp; |
334 | status = nfsd4_process_open1(&resp->cstate, open); | 339 | status = nfsd4_process_open1(&resp->cstate, open, nn); |
335 | if (status == nfserr_replay_me) { | 340 | if (status == nfserr_replay_me) { |
336 | struct nfs4_replay *rp = &open->op_openowner->oo_owner.so_replay; | 341 | struct nfs4_replay *rp = &open->op_openowner->oo_owner.so_replay; |
337 | fh_put(&cstate->current_fh); | 342 | fh_put(&cstate->current_fh); |
@@ -354,10 +359,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
354 | /* Openowner is now set, so sequence id will get bumped. Now we need | 359 | /* Openowner is now set, so sequence id will get bumped. Now we need |
355 | * these checks before we do any creates: */ | 360 | * these checks before we do any creates: */ |
356 | status = nfserr_grace; | 361 | status = nfserr_grace; |
357 | if (locks_in_grace(SVC_NET(rqstp)) && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) | 362 | if (locks_in_grace(net) && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) |
358 | goto out; | 363 | goto out; |
359 | status = nfserr_no_grace; | 364 | status = nfserr_no_grace; |
360 | if (!locks_in_grace(SVC_NET(rqstp)) && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) | 365 | if (!locks_in_grace(net) && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) |
361 | goto out; | 366 | goto out; |
362 | 367 | ||
363 | switch (open->op_claim_type) { | 368 | switch (open->op_claim_type) { |
@@ -370,7 +375,9 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
370 | break; | 375 | break; |
371 | case NFS4_OPEN_CLAIM_PREVIOUS: | 376 | case NFS4_OPEN_CLAIM_PREVIOUS: |
372 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; | 377 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; |
373 | status = nfs4_check_open_reclaim(&open->op_clientid, cstate->minorversion); | 378 | status = nfs4_check_open_reclaim(&open->op_clientid, |
379 | cstate->minorversion, | ||
380 | nn); | ||
374 | if (status) | 381 | if (status) |
375 | goto out; | 382 | goto out; |
376 | case NFS4_OPEN_CLAIM_FH: | 383 | case NFS4_OPEN_CLAIM_FH: |
@@ -490,12 +497,13 @@ nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
490 | &access->ac_supported); | 497 | &access->ac_supported); |
491 | } | 498 | } |
492 | 499 | ||
493 | static void gen_boot_verifier(nfs4_verifier *verifier) | 500 | static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net) |
494 | { | 501 | { |
495 | __be32 verf[2]; | 502 | __be32 verf[2]; |
503 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
496 | 504 | ||
497 | verf[0] = (__be32)nfssvc_boot.tv_sec; | 505 | verf[0] = (__be32)nn->nfssvc_boot.tv_sec; |
498 | verf[1] = (__be32)nfssvc_boot.tv_usec; | 506 | verf[1] = (__be32)nn->nfssvc_boot.tv_usec; |
499 | memcpy(verifier->data, verf, sizeof(verifier->data)); | 507 | memcpy(verifier->data, verf, sizeof(verifier->data)); |
500 | } | 508 | } |
501 | 509 | ||
@@ -503,7 +511,7 @@ static __be32 | |||
503 | nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 511 | nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
504 | struct nfsd4_commit *commit) | 512 | struct nfsd4_commit *commit) |
505 | { | 513 | { |
506 | gen_boot_verifier(&commit->co_verf); | 514 | gen_boot_verifier(&commit->co_verf, SVC_NET(rqstp)); |
507 | return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset, | 515 | return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset, |
508 | commit->co_count); | 516 | commit->co_count); |
509 | } | 517 | } |
@@ -684,6 +692,17 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
684 | if (read->rd_offset >= OFFSET_MAX) | 692 | if (read->rd_offset >= OFFSET_MAX) |
685 | return nfserr_inval; | 693 | return nfserr_inval; |
686 | 694 | ||
695 | /* | ||
696 | * If we do a zero copy read, then a client will see read data | ||
697 | * that reflects the state of the file *after* performing the | ||
698 | * following compound. | ||
699 | * | ||
700 | * To ensure proper ordering, we therefore turn off zero copy if | ||
701 | * the client wants us to do more in this compound: | ||
702 | */ | ||
703 | if (!nfsd4_last_compound_op(rqstp)) | ||
704 | rqstp->rq_splice_ok = false; | ||
705 | |||
687 | nfs4_lock_state(); | 706 | nfs4_lock_state(); |
688 | /* check stateid */ | 707 | /* check stateid */ |
689 | if ((status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), | 708 | if ((status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), |
@@ -876,6 +895,24 @@ out: | |||
876 | return status; | 895 | return status; |
877 | } | 896 | } |
878 | 897 | ||
898 | static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write) | ||
899 | { | ||
900 | int i = 1; | ||
901 | int buflen = write->wr_buflen; | ||
902 | |||
903 | vec[0].iov_base = write->wr_head.iov_base; | ||
904 | vec[0].iov_len = min_t(int, buflen, write->wr_head.iov_len); | ||
905 | buflen -= vec[0].iov_len; | ||
906 | |||
907 | while (buflen) { | ||
908 | vec[i].iov_base = page_address(write->wr_pagelist[i - 1]); | ||
909 | vec[i].iov_len = min_t(int, PAGE_SIZE, buflen); | ||
910 | buflen -= vec[i].iov_len; | ||
911 | i++; | ||
912 | } | ||
913 | return i; | ||
914 | } | ||
915 | |||
879 | static __be32 | 916 | static __be32 |
880 | nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 917 | nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
881 | struct nfsd4_write *write) | 918 | struct nfsd4_write *write) |
@@ -884,6 +921,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
884 | struct file *filp = NULL; | 921 | struct file *filp = NULL; |
885 | __be32 status = nfs_ok; | 922 | __be32 status = nfs_ok; |
886 | unsigned long cnt; | 923 | unsigned long cnt; |
924 | int nvecs; | ||
887 | 925 | ||
888 | /* no need to check permission - this will be done in nfsd_write() */ | 926 | /* no need to check permission - this will be done in nfsd_write() */ |
889 | 927 | ||
@@ -904,10 +942,13 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
904 | 942 | ||
905 | cnt = write->wr_buflen; | 943 | cnt = write->wr_buflen; |
906 | write->wr_how_written = write->wr_stable_how; | 944 | write->wr_how_written = write->wr_stable_how; |
907 | gen_boot_verifier(&write->wr_verifier); | 945 | gen_boot_verifier(&write->wr_verifier, SVC_NET(rqstp)); |
946 | |||
947 | nvecs = fill_in_write_vector(rqstp->rq_vec, write); | ||
948 | WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec)); | ||
908 | 949 | ||
909 | status = nfsd_write(rqstp, &cstate->current_fh, filp, | 950 | status = nfsd_write(rqstp, &cstate->current_fh, filp, |
910 | write->wr_offset, rqstp->rq_vec, write->wr_vlen, | 951 | write->wr_offset, rqstp->rq_vec, nvecs, |
911 | &cnt, &write->wr_how_written); | 952 | &cnt, &write->wr_how_written); |
912 | if (filp) | 953 | if (filp) |
913 | fput(filp); | 954 | fput(filp); |
@@ -1666,6 +1707,12 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1666 | .op_name = "OP_EXCHANGE_ID", | 1707 | .op_name = "OP_EXCHANGE_ID", |
1667 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_exchange_id_rsize, | 1708 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_exchange_id_rsize, |
1668 | }, | 1709 | }, |
1710 | [OP_BACKCHANNEL_CTL] = { | ||
1711 | .op_func = (nfsd4op_func)nfsd4_backchannel_ctl, | ||
1712 | .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING, | ||
1713 | .op_name = "OP_BACKCHANNEL_CTL", | ||
1714 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | ||
1715 | }, | ||
1669 | [OP_BIND_CONN_TO_SESSION] = { | 1716 | [OP_BIND_CONN_TO_SESSION] = { |
1670 | .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session, | 1717 | .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session, |
1671 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP | 1718 | .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP |
@@ -1719,6 +1766,7 @@ static struct nfsd4_operation nfsd4_ops[] = { | |||
1719 | .op_func = (nfsd4op_func)nfsd4_free_stateid, | 1766 | .op_func = (nfsd4op_func)nfsd4_free_stateid, |
1720 | .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING, | 1767 | .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING, |
1721 | .op_name = "OP_FREE_STATEID", | 1768 | .op_name = "OP_FREE_STATEID", |
1769 | .op_get_currentstateid = (stateid_getter)nfsd4_get_freestateid, | ||
1722 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, | 1770 | .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, |
1723 | }, | 1771 | }, |
1724 | }; | 1772 | }; |