aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfs4proc.c')
-rw-r--r--fs/nfsd/nfs4proc.c74
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
194do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 195do_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);
261out: 264out:
@@ -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
493static void gen_boot_verifier(nfs4_verifier *verifier) 500static 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
503nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 511nfsd4_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
898static 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
879static __be32 916static __be32
880nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 917nfsd4_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};