2016-09-07 19:57:33

by Anna Schumaker

[permalink] [raw]
Subject: [PATCH v5] NFSD: Add support for the COPY operation

This patch adds server support for the NFS v4.2 COPY operation. I did some
performance testing on my own, and found that a 4MB copy cap has performance
pretty close to copying with no cap at all. Here are my results for testing
with various file sizes and copy caps:

|-------|---------|---------|---------|---------|---------|---------|---------|
|NFSv4.1| 512 MB | 1024 MB | 1536 MB | 2048 MB | 2560 MB | 3072 MB | 5120 MB |
|-------|---------|---------|---------|---------|---------|---------|---------|
|user | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s |
|system | 0.28s | 0.48s | 0.72s | 0.94s | 1.17s | 1.42s | 2.37s |
|cpu | 18% | 14% | 14% | 14% | 14% | 13% | 13% |
|total | 1.547s | 3.269s | 5.040s | 6.690s | 8.363s | 10.146s | 16.729s |
|read | 4096 | 8192 | 12288 | 16384 | 20480 | 24576 | 40960 |
|write | 4098 | 8203 | 12302 | 16402 | 20497 | 24668 | 40996 |
|commit | 9 | 18 | 27 | 36 | 46 | 55 | 93 |
|-------|---------|---------|---------|---------|---------|---------|---------|

|-------|---------|---------|---------|---------|---------|---------|---------|
|No Cap | 512 MB | 1024 MB | 1536 MB | 2048 MB | 2560 MB | 3072 MB | 5120 MB |
|-------|---------|---------|---------|---------|---------|---------|---------|
|user | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s |
|system | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s |
|cpu | 0% | 0% | 0% | 0% | 0% | 0% | 0% |
|total | 1.476s | 3.068s | 4.569s | 6.123s | 7.701s | 9.265s | 15.438s |
|copy | 1 | 1 | 1 | 2 | 2 | 2 | 3 |
|commit | 1 | 1 | 1 | 2 | 2 | 2 | 3 |
|-------|---------|---------|---------|---------|---------|---------|---------|

|-------|---------|---------|---------|---------|---------|---------|---------|
|1MB Cap| 512 MB | 1024 MB | 1536 MB | 2048 MB | 2560 MB | 3072 MB | 5120 MB |
|-------|---------|---------|---------|---------|---------|---------|---------|
|user | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s |
|system | 0.01s | 0.02s | 0.03s | 0.04s | 0.05s | 0.07s | 0.10s |
|cpu | 0% | 0% | 0% | 0% | 0% | 0% | 0% |
|total | 1.659s | 3.118s | 4.930s | 6.647s | 8.110s | 9.637s | 16.030s |
|copy | 512 | 1024 | 1536 | 2048 | 2560 | 3072 | 5120 |
|commit | 512 | 1024 | 1536 | 2048 | 2560 | 3072 | 5120 |
|-------|---------|---------|---------|---------|---------|---------|---------|

|-------|---------|---------|---------|---------|---------|---------|---------|
|2MB Cap| 512 MB | 1024 MB | 1536 MB | 2048 MB | 2560 MB | 3072 MB | 5120 MB |
|-------|---------|---------|---------|---------|---------|---------|---------|
|user | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s |
|system | 0.01s | 0.01s | 0.02s | 0.03s | 0.03s | 0.04s | 0.07s |
|cpu | 0% | 0% | 0% | 0% | 0% | 0% | 0% |
|total | 1.757s | 3.351s | 4.791s | 6.522s | 8.090s | 9.594s | 15.977s |
|copy | 256 | 512 | 768 | 1024 | 1280 | 1536 | 2560 |
|commit | 256 | 512 | 768 | 1024 | 1280 | 1536 | 2560 |
|-------|---------|---------|---------|---------|---------|---------|---------|

|-------|---------|---------|---------|---------|---------|---------|---------|
|4MB Cap| 512 MB | 1024 MB | 1536 MB | 2048 MB | 2560 MB | 3072 MB | 5120 MB |
|-------|---------|---------|---------|---------|---------|---------|---------|
|user | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s |
|system | 0.00s | 0.01s | 0.01s | 0.01s | 0.02s | 0.02s | 0.04s |
|cpu | 0% | 0% | 0% | 0% | 0% | 0% | 0% |
|total | 1.475s | 3.046s | 4.643s | 6.159s | 7.779s | 9.340s | 15.476s |
|copy | 128 | 256 | 384 | 512 | 640 | 768 | 1280 |
|commit | 128 | 256 | 384 | 512 | 640 | 768 | 1280 |
|-------|---------|---------|---------|---------|---------|---------|---------|


Changes in v5:
- Add an arbitrary 4MB copy cap

Anna Schumaker (1):
NFSD: Implement the COPY call

fs/nfsd/nfs4proc.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++-------
fs/nfsd/nfs4xdr.c | 63 ++++++++++++++++++++++++++++++++++++--
fs/nfsd/vfs.c | 8 +++++
fs/nfsd/vfs.h | 2 ++
fs/nfsd/xdr4.h | 23 ++++++++++++++
5 files changed, 173 insertions(+), 13 deletions(-)

--
2.9.3



2016-09-07 19:57:33

by Anna Schumaker

[permalink] [raw]
Subject: [PATCH v5] NFSD: Implement the COPY call

From: Anna Schumaker <[email protected]>

I only implemented the sync version of this call, since it's the
easiest. I can simply call vfs_copy_range() and have the vfs do the
right thing for the filesystem being exported.

Signed-off-by: Anna Schumaker <[email protected]>
--
v5:
- Add arbitrary 4MB copy cap
---
fs/nfsd/nfs4proc.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++-------
fs/nfsd/nfs4xdr.c | 63 ++++++++++++++++++++++++++++++++++++--
fs/nfsd/vfs.c | 8 +++++
fs/nfsd/vfs.h | 2 ++
fs/nfsd/xdr4.h | 23 ++++++++++++++
5 files changed, 173 insertions(+), 13 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 1fb2227..abb09b5 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1010,47 +1010,97 @@ 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",
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 0aa0236..5e148d4 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1694,6 +1694,30 @@ nfsd4_decode_clone(struct nfsd4_compoundargs *argp, struct nfsd4_clone *clone)
}

static __be32
+nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy)
+{
+ DECODE_HEAD;
+ unsigned int tmp;
+
+ status = nfsd4_decode_stateid(argp, &copy->cp_src_stateid);
+ if (status)
+ return status;
+ status = nfsd4_decode_stateid(argp, &copy->cp_dst_stateid);
+ if (status)
+ return status;
+
+ READ_BUF(8 + 8 + 8 + 4 + 4 + 4);
+ p = xdr_decode_hyper(p, &copy->cp_src_pos);
+ p = xdr_decode_hyper(p, &copy->cp_dst_pos);
+ p = xdr_decode_hyper(p, &copy->cp_count);
+ copy->cp_consecutive = be32_to_cpup(p++);
+ copy->cp_synchronous = be32_to_cpup(p++);
+ tmp = be32_to_cpup(p); /* Source server list not supported */
+
+ DECODE_TAIL;
+}
+
+static __be32
nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek)
{
DECODE_HEAD;
@@ -1793,7 +1817,7 @@ static nfsd4_dec nfsd4_dec_ops[] = {

/* new operations for NFSv4.2 */
[OP_ALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate,
- [OP_COPY] = (nfsd4_dec)nfsd4_decode_notsupp,
+ [OP_COPY] = (nfsd4_dec)nfsd4_decode_copy,
[OP_COPY_NOTIFY] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_DEALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate,
[OP_IO_ADVISE] = (nfsd4_dec)nfsd4_decode_notsupp,
@@ -4202,6 +4226,41 @@ nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr,
#endif /* CONFIG_NFSD_PNFS */

static __be32
+nfsd42_encode_write_res(struct nfsd4_compoundres *resp, struct nfsd42_write_res *write)
+{
+ __be32 *p;
+
+ p = xdr_reserve_space(&resp->xdr, 4 + 8 + 4 + NFS4_VERIFIER_SIZE);
+ if (!p)
+ return nfserr_resource;
+
+ *p++ = cpu_to_be32(0);
+ p = xdr_encode_hyper(p, write->wr_bytes_written);
+ *p++ = cpu_to_be32(write->wr_stable_how);
+ p = xdr_encode_opaque_fixed(p, write->wr_verifier.data,
+ NFS4_VERIFIER_SIZE);
+ return nfs_ok;
+}
+
+static __be32
+nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr,
+ struct nfsd4_copy *copy)
+{
+ __be32 *p;
+
+ if (!nfserr) {
+ nfserr = nfsd42_encode_write_res(resp, &copy->cp_res);
+ if (nfserr)
+ return nfserr;
+
+ p = xdr_reserve_space(&resp->xdr, 4 + 4);
+ *p++ = cpu_to_be32(copy->cp_consecutive);
+ *p++ = cpu_to_be32(copy->cp_synchronous);
+ }
+ return nfserr;
+}
+
+static __be32
nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_seek *seek)
{
@@ -4300,7 +4359,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {

/* NFSv4.2 operations */
[OP_ALLOCATE] = (nfsd4_enc)nfsd4_encode_noop,
- [OP_COPY] = (nfsd4_enc)nfsd4_encode_noop,
+ [OP_COPY] = (nfsd4_enc)nfsd4_encode_copy,
[OP_COPY_NOTIFY] = (nfsd4_enc)nfsd4_encode_noop,
[OP_DEALLOCATE] = (nfsd4_enc)nfsd4_encode_noop,
[OP_IO_ADVISE] = (nfsd4_enc)nfsd4_encode_noop,
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index ff476e6..271a23c 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -513,6 +513,14 @@ __be32 nfsd4_clone_file_range(struct file *src, u64 src_pos, struct file *dst,
count));
}

+ssize_t nfsd_copy_file_range(struct file *src, u64 src_pos, struct file *dst,
+ u64 dst_pos, u64 count)
+{
+ /* Arbitrary 4 megabyte copy cap */
+ count = min_t(u64, count, 1 << 22);
+ return vfs_copy_file_range(src, src_pos, dst, dst_pos, count, 0);
+}
+
__be32 nfsd4_vfs_fallocate(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct file *file, loff_t offset, loff_t len,
int flags)
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index 3cbb1b3..0bf9e7b 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -96,6 +96,8 @@ __be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *,
struct svc_fh *res);
__be32 nfsd_link(struct svc_rqst *, struct svc_fh *,
char *, int, struct svc_fh *);
+ssize_t nfsd_copy_file_range(struct file *, u64,
+ struct file *, u64, u64);
__be32 nfsd_rename(struct svc_rqst *,
struct svc_fh *, char *, int,
struct svc_fh *, char *, int);
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index beea0c5..8fda4ab 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -503,6 +503,28 @@ struct nfsd4_clone {
u64 cl_count;
};

+struct nfsd42_write_res {
+ u64 wr_bytes_written;
+ u32 wr_stable_how;
+ nfs4_verifier wr_verifier;
+};
+
+struct nfsd4_copy {
+ /* request */
+ stateid_t cp_src_stateid;
+ stateid_t cp_dst_stateid;
+ u64 cp_src_pos;
+ u64 cp_dst_pos;
+ u64 cp_count;
+
+ /* both */
+ bool cp_consecutive;
+ bool cp_synchronous;
+
+ /* response */
+ struct nfsd42_write_res cp_res;
+};
+
struct nfsd4_seek {
/* request */
stateid_t seek_stateid;
@@ -568,6 +590,7 @@ struct nfsd4_op {
struct nfsd4_fallocate allocate;
struct nfsd4_fallocate deallocate;
struct nfsd4_clone clone;
+ struct nfsd4_copy copy;
struct nfsd4_seek seek;
} u;
struct nfs4_replay * replay;
--
2.9.3


2016-09-09 19:53:38

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH v5] NFSD: Add support for the COPY operation

On Wed, Sep 07, 2016 at 03:57:29PM -0400, Anna Schumaker wrote:
> This patch adds server support for the NFS v4.2 COPY operation. I did some
> performance testing on my own, and found that a 4MB copy cap has performance
> pretty close to copying with no cap at all. Here are my results for testing
> with various file sizes and copy caps:

Thanks, but we expect the tradeoffs here to vary a lot depending on the
latency of the client<->server connection and the server<->server copy
bandwidth. So this isn't really interesting without knowing your
testing setup.

--b.

>
> |-------|---------|---------|---------|---------|---------|---------|---------|
> |NFSv4.1| 512 MB | 1024 MB | 1536 MB | 2048 MB | 2560 MB | 3072 MB | 5120 MB |
> |-------|---------|---------|---------|---------|---------|---------|---------|
> |user | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s |
> |system | 0.28s | 0.48s | 0.72s | 0.94s | 1.17s | 1.42s | 2.37s |
> |cpu | 18% | 14% | 14% | 14% | 14% | 13% | 13% |
> |total | 1.547s | 3.269s | 5.040s | 6.690s | 8.363s | 10.146s | 16.729s |
> |read | 4096 | 8192 | 12288 | 16384 | 20480 | 24576 | 40960 |
> |write | 4098 | 8203 | 12302 | 16402 | 20497 | 24668 | 40996 |
> |commit | 9 | 18 | 27 | 36 | 46 | 55 | 93 |
> |-------|---------|---------|---------|---------|---------|---------|---------|
>
> |-------|---------|---------|---------|---------|---------|---------|---------|
> |No Cap | 512 MB | 1024 MB | 1536 MB | 2048 MB | 2560 MB | 3072 MB | 5120 MB |
> |-------|---------|---------|---------|---------|---------|---------|---------|
> |user | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s |
> |system | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s |
> |cpu | 0% | 0% | 0% | 0% | 0% | 0% | 0% |
> |total | 1.476s | 3.068s | 4.569s | 6.123s | 7.701s | 9.265s | 15.438s |
> |copy | 1 | 1 | 1 | 2 | 2 | 2 | 3 |
> |commit | 1 | 1 | 1 | 2 | 2 | 2 | 3 |
> |-------|---------|---------|---------|---------|---------|---------|---------|
>
> |-------|---------|---------|---------|---------|---------|---------|---------|
> |1MB Cap| 512 MB | 1024 MB | 1536 MB | 2048 MB | 2560 MB | 3072 MB | 5120 MB |
> |-------|---------|---------|---------|---------|---------|---------|---------|
> |user | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s |
> |system | 0.01s | 0.02s | 0.03s | 0.04s | 0.05s | 0.07s | 0.10s |
> |cpu | 0% | 0% | 0% | 0% | 0% | 0% | 0% |
> |total | 1.659s | 3.118s | 4.930s | 6.647s | 8.110s | 9.637s | 16.030s |
> |copy | 512 | 1024 | 1536 | 2048 | 2560 | 3072 | 5120 |
> |commit | 512 | 1024 | 1536 | 2048 | 2560 | 3072 | 5120 |
> |-------|---------|---------|---------|---------|---------|---------|---------|
>
> |-------|---------|---------|---------|---------|---------|---------|---------|
> |2MB Cap| 512 MB | 1024 MB | 1536 MB | 2048 MB | 2560 MB | 3072 MB | 5120 MB |
> |-------|---------|---------|---------|---------|---------|---------|---------|
> |user | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s |
> |system | 0.01s | 0.01s | 0.02s | 0.03s | 0.03s | 0.04s | 0.07s |
> |cpu | 0% | 0% | 0% | 0% | 0% | 0% | 0% |
> |total | 1.757s | 3.351s | 4.791s | 6.522s | 8.090s | 9.594s | 15.977s |
> |copy | 256 | 512 | 768 | 1024 | 1280 | 1536 | 2560 |
> |commit | 256 | 512 | 768 | 1024 | 1280 | 1536 | 2560 |
> |-------|---------|---------|---------|---------|---------|---------|---------|
>
> |-------|---------|---------|---------|---------|---------|---------|---------|
> |4MB Cap| 512 MB | 1024 MB | 1536 MB | 2048 MB | 2560 MB | 3072 MB | 5120 MB |
> |-------|---------|---------|---------|---------|---------|---------|---------|
> |user | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s | 0.00s |
> |system | 0.00s | 0.01s | 0.01s | 0.01s | 0.02s | 0.02s | 0.04s |
> |cpu | 0% | 0% | 0% | 0% | 0% | 0% | 0% |
> |total | 1.475s | 3.046s | 4.643s | 6.159s | 7.779s | 9.340s | 15.476s |
> |copy | 128 | 256 | 384 | 512 | 640 | 768 | 1280 |
> |commit | 128 | 256 | 384 | 512 | 640 | 768 | 1280 |
> |-------|---------|---------|---------|---------|---------|---------|---------|
>
>
> Changes in v5:
> - Add an arbitrary 4MB copy cap
>
> Anna Schumaker (1):
> NFSD: Implement the COPY call
>
> fs/nfsd/nfs4proc.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++-------
> fs/nfsd/nfs4xdr.c | 63 ++++++++++++++++++++++++++++++++++++--
> fs/nfsd/vfs.c | 8 +++++
> fs/nfsd/vfs.h | 2 ++
> fs/nfsd/xdr4.h | 23 ++++++++++++++
> 5 files changed, 173 insertions(+), 13 deletions(-)
>
> --
> 2.9.3

2016-10-07 18:46:41

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH v5] NFSD: Add support for the COPY operation

On Fri, Sep 09, 2016 at 03:53:36PM -0400, J. Bruce Fields wrote:
> On Wed, Sep 07, 2016 at 03:57:29PM -0400, Anna Schumaker wrote:
> > This patch adds server support for the NFS v4.2 COPY operation. I did some
> > performance testing on my own, and found that a 4MB copy cap has performance
> > pretty close to copying with no cap at all. Here are my results for testing
> > with various file sizes and copy caps:
>
> Thanks, but we expect the tradeoffs here to vary a lot depending on the
> latency of the client<->server connection and the server<->server copy
> bandwidth. So this isn't really interesting without knowing your
> testing setup.

... but I guess I'm inclined to try this anyway. It's simple. We can
do something more complicated later if this turns out to be a problem.

Maybe it'd help to leave a little more documentation here.

Applying for 4.8 with that change.

--b.

diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 271a23cf6470..8ca642fe9b21 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -516,7 +516,15 @@ __be32 nfsd4_clone_file_range(struct file *src, u64 src_pos, struct file *dst,
ssize_t nfsd_copy_file_range(struct file *src, u64 src_pos, struct file *dst,
u64 dst_pos, u64 count)
{
- /* Arbitrary 4 megabyte copy cap */
+
+ /*
+ * Limit copy to 4MB to prevent indefinitely blocking an nfsd
+ * thread and client rpc slot. The choice of 4MB is somewhat
+ * arbitrary. We might instead base this on r/wsize, or make it
+ * tunable, or use a time instead of a byte limit, or implement
+ * asynchronous copy. In theory a client could also recognize a
+ * limit like this and pipeline multiple COPY requests.
+ */
count = min_t(u64, count, 1 << 22);
return vfs_copy_file_range(src, src_pos, dst, dst_pos, count, 0);
}