OSDN Git Service

NFSD: Refactor the generic write vector fill helper
[uclinux-h8/linux.git] / fs / nfsd / nfs4proc.c
index 5d99e88..b7bc6e1 100644 (file)
@@ -354,6 +354,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        struct svc_fh *resfh = NULL;
        struct net *net = SVC_NET(rqstp);
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+       bool reclaim = false;
 
        dprintk("NFSD: nfsd4_open filename %.*s op_openowner %p\n",
                (int)open->op_fname.len, open->op_fname.data,
@@ -424,6 +425,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                        if (status)
                                goto out;
                        open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
+                       reclaim = true;
                case NFS4_OPEN_CLAIM_FH:
                case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
                        status = do_open_fhandle(rqstp, cstate, open);
@@ -452,6 +454,8 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        WARN(status && open->op_created,
             "nfsd4_process_open2 failed to open newly-created file! status=%u\n",
             be32_to_cpu(status));
+       if (reclaim && !status)
+               nn->somebody_reclaimed = true;
 out:
        if (resfh && resfh != &cstate->current_fh) {
                fh_dup2(&cstate->current_fh, resfh);
@@ -982,24 +986,6 @@ out:
        return status;
 }
 
-static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write)
-{
-        int i = 1;
-        int buflen = write->wr_buflen;
-
-        vec[0].iov_base = write->wr_head.iov_base;
-        vec[0].iov_len = min_t(int, buflen, write->wr_head.iov_len);
-        buflen -= vec[0].iov_len;
-
-        while (buflen) {
-                vec[i].iov_base = page_address(write->wr_pagelist[i - 1]);
-                vec[i].iov_len = min_t(int, PAGE_SIZE, buflen);
-                buflen -= vec[i].iov_len;
-                i++;
-        }
-        return i;
-}
-
 static __be32
 nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
            union nfsd4_op_u *u)
@@ -1027,7 +1013,10 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        write->wr_how_written = write->wr_stable_how;
        gen_boot_verifier(&write->wr_verifier, SVC_NET(rqstp));
 
-       nvecs = fill_in_write_vector(rqstp->rq_vec, write);
+       nvecs = svc_fill_write_vector(rqstp, write->wr_pagelist,
+                                     &write->wr_head, write->wr_buflen);
+       if (!nvecs)
+               return nfserr_io;
        WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec));
 
        status = nfsd_vfs_write(rqstp, &cstate->current_fh, filp,
@@ -1599,7 +1588,7 @@ static const char *nfsd4_op_name(unsigned opnum);
  */
 static __be32 nfs41_check_op_ordering(struct nfsd4_compoundargs *args)
 {
-       struct nfsd4_op *op = &args->ops[0];
+       struct nfsd4_op *first_op = &args->ops[0];
 
        /* These ordering requirements don't apply to NFSv4.0: */
        if (args->minorversion == 0)
@@ -1607,12 +1596,17 @@ static __be32 nfs41_check_op_ordering(struct nfsd4_compoundargs *args)
        /* This is weird, but OK, not our problem: */
        if (args->opcnt == 0)
                return nfs_ok;
-       if (op->status == nfserr_op_illegal)
+       if (first_op->status == nfserr_op_illegal)
                return nfs_ok;
-       if (!(nfsd4_ops[op->opnum].op_flags & ALLOWED_AS_FIRST_OP))
+       if (!(nfsd4_ops[first_op->opnum].op_flags & ALLOWED_AS_FIRST_OP))
                return nfserr_op_not_in_session;
-       if (op->opnum == OP_SEQUENCE)
+       if (first_op->opnum == OP_SEQUENCE)
                return nfs_ok;
+       /*
+        * So first_op is something allowed outside a session, like
+        * EXCHANGE_ID; but then it has to be the only op in the
+        * compound:
+        */
        if (args->opcnt != 1)
                return nfserr_not_only_op;
        return nfs_ok;
@@ -1726,6 +1720,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
        if (status) {
                op = &args->ops[0];
                op->status = status;
+               resp->opcnt = 1;
                goto encode_op;
        }