|
@@ -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, ©->cp_src_stateid, &src,
|
|
|
+ ©->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(©->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",
|