net/mlx4: Fix firmware command timeout during interrupt test
[cascardo/linux.git] / fs / nfsd / nfs4proc.c
index 1fb2227..abb09b5 100644 (file)
@@ -1010,46 +1010,96 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 }
 
 static __be32
-nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
-               struct nfsd4_clone *clone)
+nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+                 stateid_t *src_stateid, struct file **src,
+                 stateid_t *dst_stateid, struct file **dst)
 {
-       struct file *src, *dst;
        __be32 status;
 
        status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->save_fh,
-                                           &clone->cl_src_stateid, RD_STATE,
-                                           &src, NULL);
+                                           src_stateid, RD_STATE, src, NULL);
        if (status) {
                dprintk("NFSD: %s: couldn't process src stateid!\n", __func__);
                goto out;
        }
 
        status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
-                                           &clone->cl_dst_stateid, WR_STATE,
-                                           &dst, NULL);
+                                           dst_stateid, WR_STATE, dst, NULL);
        if (status) {
                dprintk("NFSD: %s: couldn't process dst stateid!\n", __func__);
                goto out_put_src;
        }
 
        /* fix up for NFS-specific error code */
-       if (!S_ISREG(file_inode(src)->i_mode) ||
-           !S_ISREG(file_inode(dst)->i_mode)) {
+       if (!S_ISREG(file_inode(*src)->i_mode) ||
+           !S_ISREG(file_inode(*dst)->i_mode)) {
                status = nfserr_wrong_type;
                goto out_put_dst;
        }
 
+out:
+       return status;
+out_put_dst:
+       fput(*dst);
+out_put_src:
+       fput(*src);
+       goto out;
+}
+
+static __be32
+nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+               struct nfsd4_clone *clone)
+{
+       struct file *src, *dst;
+       __be32 status;
+
+       status = nfsd4_verify_copy(rqstp, cstate, &clone->cl_src_stateid, &src,
+                                  &clone->cl_dst_stateid, &dst);
+       if (status)
+               goto out;
+
        status = nfsd4_clone_file_range(src, clone->cl_src_pos,
                        dst, clone->cl_dst_pos, clone->cl_count);
 
-out_put_dst:
        fput(dst);
-out_put_src:
        fput(src);
 out:
        return status;
 }
 
+static __be32
+nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+               struct nfsd4_copy *copy)
+{
+       struct file *src, *dst;
+       __be32 status;
+       ssize_t bytes;
+
+       status = nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid, &src,
+                                  &copy->cp_dst_stateid, &dst);
+       if (status)
+               goto out;
+
+       bytes = nfsd_copy_file_range(src, copy->cp_src_pos,
+                       dst, copy->cp_dst_pos, copy->cp_count);
+
+       if (bytes < 0)
+               status = nfserrno(bytes);
+       else {
+               copy->cp_res.wr_bytes_written = bytes;
+               copy->cp_res.wr_stable_how = NFS_UNSTABLE;
+               copy->cp_consecutive = 1;
+               copy->cp_synchronous = 1;
+               gen_boot_verifier(&copy->cp_res.wr_verifier, SVC_NET(rqstp));
+               status = nfs_ok;
+       }
+
+       fput(src);
+       fput(dst);
+out:
+       return status;
+}
+
 static __be32
 nfsd4_fallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                struct nfsd4_fallocate *fallocate, int flags)
@@ -1966,6 +2016,18 @@ static inline u32 nfsd4_create_session_rsize(struct svc_rqst *rqstp, struct nfsd
                op_encode_channel_attrs_maxsz) * sizeof(__be32);
 }
 
+static inline u32 nfsd4_copy_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
+{
+       return (op_encode_hdr_size +
+               1 /* wr_callback */ +
+               op_encode_stateid_maxsz /* wr_callback */ +
+               2 /* wr_count */ +
+               1 /* wr_committed */ +
+               op_encode_verifier_maxsz +
+               1 /* cr_consecutive */ +
+               1 /* cr_synchronous */) * sizeof(__be32);
+}
+
 #ifdef CONFIG_NFSD_PNFS
 /*
  * At this stage we don't really know what layout driver will handle the request,
@@ -2328,6 +2390,12 @@ static struct nfsd4_operation nfsd4_ops[] = {
                .op_name = "OP_CLONE",
                .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
        },
+       [OP_COPY] = {
+               .op_func = (nfsd4op_func)nfsd4_copy,
+               .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
+               .op_name = "OP_COPY",
+               .op_rsize_bop = (nfsd4op_rsize)nfsd4_copy_rsize,
+       },
        [OP_SEEK] = {
                .op_func = (nfsd4op_func)nfsd4_seek,
                .op_name = "OP_SEEK",