2016-08-19 17:25:43

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version-2 00/12] NFSv4.2 inter server to server copy

From: Andy Adamson <[email protected]>


Anna's patches applied first:
The first patch is a bug fix from Anna for the upstream Intra
server to server copy.

The second patch has been submitted upstream, and is being
reviewed by Bruce Fields.

The rest of the patches implement NFSv4.2 Intra-SSC


Andy Adamson (9):
VFS permit cross device vfs_copy_file_range
NFS inter ssc open
NFS add COPY_NOTIFY operation
NFS add ca_source_server<> to COPY
NFSD add ca_source_server<> to COPY
NFSD add COPY_NOTIFY operation
NFSD generalize nfsd4_compound_state flag names
NFSD: allow inter server COPY to have a STALE source server fh
NFSD add nfs4 inter ssc to nfsd4_copy

Anna Schumaker (2):
fs: Don't copy beyond the end of the file
NFSD: Implement the COPY call

Olga Kornievskaia (1):
NFSD: extra stateid checking in read for interserver copy

fs/nfs/internal.h | 10 +
fs/nfs/nfs42.h | 7 +-
fs/nfs/nfs42proc.c | 128 ++++++++++-
fs/nfs/nfs42xdr.c | 205 +++++++++++++++++-
fs/nfs/nfs4_fs.h | 8 +
fs/nfs/nfs4file.c | 135 +++++++++++-
fs/nfs/nfs4proc.c | 6 +-
fs/nfs/nfs4state.c | 2 +-
fs/nfs/nfs4xdr.c | 1 +
fs/nfsd/Kconfig | 10 +
fs/nfsd/nfs4proc.c | 527 ++++++++++++++++++++++++++++++++++++++++++++--
fs/nfsd/nfs4state.c | 47 ++++-
fs/nfsd/nfs4xdr.c | 272 +++++++++++++++++++++++-
fs/nfsd/nfsd.h | 2 +
fs/nfsd/state.h | 8 +
fs/nfsd/vfs.c | 6 +
fs/nfsd/vfs.h | 2 +
fs/nfsd/xdr4.h | 50 ++++-
fs/read_write.c | 8 +-
include/linux/nfs4.h | 43 ++++
include/linux/nfs_fs_sb.h | 1 +
include/linux/nfs_xdr.h | 20 ++
22 files changed, 1443 insertions(+), 55 deletions(-)

--
1.8.3.1



2016-08-19 17:25:45

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version-2 02/12] 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]>
--
v2:
- Don't fsync() after copy
- Tell client that the result is NFS_UNSTABLE
- Fix conflicts with clone

v3:
- Check for copying beyond the end of the file

v4:
- Rename nfsd_copy_range() -> nfsd_copy_file_range()
- Remove size checks handled by VFS
---
fs/nfsd/nfs4proc.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++-------
fs/nfsd/nfs4xdr.c | 63 ++++++++++++++++++++++++++++++++++++--
fs/nfsd/vfs.c | 6 ++++
fs/nfsd/vfs.h | 2 ++
fs/nfsd/xdr4.h | 23 ++++++++++++++
5 files changed, 171 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..58f8219 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -513,6 +513,12 @@ __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)
+{
+ 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;
--
1.8.3.1


2016-08-19 17:25:44

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version-2 01/12] fs: Don't copy beyond the end of the file

From: Anna Schumaker <[email protected]>

Signed-off-by: Anna Schumaker <[email protected]>
---
fs/read_write.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/fs/read_write.c b/fs/read_write.c
index 66215a7..1cbab4e 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -1497,6 +1497,9 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
if (unlikely(ret))
return ret;

+ if (pos_in >= i_size_read(inode_in))
+ return -EINVAL;
+
if (!(file_in->f_mode & FMODE_READ) ||
!(file_out->f_mode & FMODE_WRITE) ||
(file_out->f_flags & O_APPEND))
--
1.8.3.1


2016-08-19 17:25:46

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version-2 03/12] VFS permit cross device vfs_copy_file_range

From: Andy Adamson <[email protected]>

NFSv4.2 inter server to server copy always copies across devices.

Note: both btrfs and nfs have EXDEV checks in their
copy_file_range functions.

Signed-off-by: Andy Adamson <[email protected]>
---
fs/read_write.c | 5 -----
1 file changed, 5 deletions(-)

diff --git a/fs/read_write.c b/fs/read_write.c
index 1cbab4e..a6d3350 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -1483,7 +1483,6 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
size_t len, unsigned int flags)
{
struct inode *inode_in = file_inode(file_in);
- struct inode *inode_out = file_inode(file_out);
ssize_t ret;

if (flags != 0)
@@ -1505,10 +1504,6 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
(file_out->f_flags & O_APPEND))
return -EBADF;

- /* this could be relaxed once a method supports cross-fs copies */
- if (inode_in->i_sb != inode_out->i_sb)
- return -EXDEV;
-
if (len == 0)
return 0;

--
1.8.3.1


2016-08-19 17:25:47

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version-2 04/12] NFS inter ssc open

From: Andy Adamson <[email protected]>

NFSv4.2 inter server to server copy requires the destination server to
READ the data from the source server using the provided stateid and
file handle.

Given an NFSv4 stateid and filehandle from the COPY operaion, provide the
destination server with an NFS client function to create a struct file
suitable for the destiniation server to READ the data to be copied.

Signed-off-by: Andy Adamson <[email protected]>
---
fs/nfs/nfs4_fs.h | 7 ++++
fs/nfs/nfs4file.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++
fs/nfs/nfs4proc.c | 5 ++-
include/linux/nfs4.h | 4 +++
4 files changed, 110 insertions(+), 3 deletions(-)

diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 9bf64ea..e594d9c 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -261,6 +261,13 @@ extern int nfs4_set_rw_stateid(nfs4_stateid *stateid,
const struct nfs_open_context *ctx,
const struct nfs_lock_context *l_ctx,
fmode_t fmode);
+extern int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr,
+ struct nfs4_label *label);
+extern void __update_open_stateid(struct nfs4_state *state,
+ nfs4_stateid *open_stateid,
+ const nfs4_stateid *deleg_stateid,
+ fmode_t fmode);

#if defined(CONFIG_NFS_V4_1)
static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server)
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index d085ad7..4a4eb40 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -7,6 +7,7 @@
#include <linux/file.h>
#include <linux/falloc.h>
#include <linux/nfs_fs.h>
+#include <linux/file.h>
#include <uapi/linux/btrfs.h> /* BTRFS_IOC_CLONE/BTRFS_IOC_CLONE_RANGE */
#include "delegation.h"
#include "internal.h"
@@ -236,6 +237,102 @@ out_unlock:
out:
return ret;
}
+
+static int read_name_gen = 1;
+#define SSC_READ_NAME_BODY "ssc_read_%d"
+
+struct file *
+nfs42_ssc_open(struct nfs42_inter_ssc *ssc, struct nfs_fh *src_fh,
+ nfs4_stateid *stateid)
+{
+ struct nfs_fattr fattr;
+ struct path path = {
+ .dentry = NULL,
+ };
+ struct file *filep, *res;
+ struct nfs_server *server;
+ struct inode *r_ino = NULL;
+ struct nfs_open_context *ctx;
+ struct nfs4_state_owner *sp;
+ char *read_name;
+ int len, status = 0;
+
+ server = NFS_SERVER(ssc->sc_mnt_dentry->d_inode);
+
+ nfs_fattr_init(&fattr);
+
+ status = nfs4_proc_getattr(server, src_fh, &fattr, NULL);
+ if (status < 0) {
+ res = ERR_PTR(status);
+ goto out;
+ }
+
+ res = ERR_PTR(-ENOMEM);
+ len = strlen(SSC_READ_NAME_BODY) + 16;
+ read_name = kzalloc(len, GFP_NOFS);
+ if (read_name == NULL)
+ goto out;
+ snprintf(read_name, len, SSC_READ_NAME_BODY, read_name_gen++);
+ dprintk("%s read_name %s\n", __func__, read_name);
+
+ /* Just put the file under the mount point */
+ path.dentry = d_alloc_name(ssc->sc_mnt_dentry, read_name);
+ kfree(read_name);
+ if (path.dentry == NULL)
+ goto out;
+ path.mnt = ssc->sc_root_mnt;
+ r_ino = nfs_fhget(ssc->sc_mnt_dentry->d_inode->i_sb, src_fh, &fattr,
+ NULL);
+ if (IS_ERR(r_ino)) {
+ res = ERR_CAST(r_ino);
+ goto out_path;
+ }
+
+ d_add(path.dentry, r_ino);
+
+ filep = alloc_file(&path, FMODE_READ, r_ino->i_fop);
+ if (IS_ERR(filep)) {
+ res = ERR_CAST(filep);
+ goto out_path;
+ }
+
+ ctx = alloc_nfs_open_context(filep->f_path.dentry, filep->f_mode);
+ if (IS_ERR(ctx)) {
+ res = ERR_CAST(ctx);
+ goto out_filep;
+ }
+
+ res = ERR_PTR(-EINVAL);
+ sp = nfs4_get_state_owner(server, ctx->cred, GFP_KERNEL);
+ if (sp == NULL)
+ goto out_ctx;
+
+ ctx->state = nfs4_get_open_state(r_ino, sp);
+ if (ctx->state == NULL)
+ goto out_stateowner;
+
+ __update_open_stateid(ctx->state, stateid, NULL, filep->f_mode);
+
+ nfs_file_set_open_context(filep, ctx);
+ put_nfs_open_context(ctx);
+
+ res = filep;
+out:
+ dprintk("<-- %s error %ld filep %p r_ino %p\n",
+ __func__, IS_ERR(res) ? PTR_ERR(res) : 0, res, r_ino);
+
+ return res;
+out_stateowner:
+ nfs4_put_state_owner(sp);
+out_ctx:
+ put_nfs_open_context(ctx);
+out_filep:
+ fput(filep);
+out_path:
+ path_put(&path);
+ goto out;
+}
+EXPORT_SYMBOL_GPL(nfs42_ssc_open);
#endif /* CONFIG_NFS_V4_2 */

const struct file_operations nfs4_file_operations = {
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 1949bbd..d0ae1ca 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -90,7 +90,6 @@ static int _nfs4_proc_open(struct nfs4_opendata *data);
static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr);
-static int nfs4_proc_getattr(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *label);
static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr, struct nfs4_label *label);
static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
struct nfs_fattr *fattr, struct iattr *sattr,
@@ -1405,7 +1404,7 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *
nfs4_stateid_copy(&state->open_stateid, stateid);
}

-static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, const nfs4_stateid *deleg_stateid, fmode_t fmode)
+void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, const nfs4_stateid *deleg_stateid, fmode_t fmode)
{
/*
* Protect the call to nfs4_state_set_mode_locked and
@@ -3416,7 +3415,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
}

-static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
+int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fattr *fattr, struct nfs4_label *label)
{
struct nfs4_exception exception = { };
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index c6564ad..f83b041 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -654,4 +654,8 @@ struct nfs4_op_map {
} u;
};

+struct nfs42_inter_ssc {
+ struct vfsmount *sc_root_mnt;
+ struct dentry *sc_mnt_dentry;
+};
#endif
--
1.8.3.1


2016-08-19 17:25:49

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version-2 06/12] NFS add ca_source_server<> to COPY

From: Andy Adamson <[email protected]>

Support only one source server address: the same address that
the client and source server use.

Signed-off-by: Andy Adamson <[email protected]>
Signed-off-by: Olga Kornievskaia <[email protected]>
---
fs/nfs/nfs42.h | 3 ++-
fs/nfs/nfs42proc.c | 35 +++++++++++++++++++++++++++--------
fs/nfs/nfs42xdr.c | 19 +++++++++++++++++--
fs/nfs/nfs4file.c | 7 ++++++-
include/linux/nfs_xdr.h | 2 ++
5 files changed, 54 insertions(+), 12 deletions(-)

diff --git a/fs/nfs/nfs42.h b/fs/nfs/nfs42.h
index 2f780d2..820fd63 100644
--- a/fs/nfs/nfs42.h
+++ b/fs/nfs/nfs42.h
@@ -14,7 +14,8 @@
/* nfs4.2proc.c */
#if defined(CONFIG_NFS_V4_2)
int nfs42_proc_allocate(struct file *, loff_t, loff_t);
-ssize_t nfs42_proc_copy(struct file *, loff_t, struct file *, loff_t, size_t);
+ssize_t nfs42_proc_copy(struct file *, loff_t, struct file *, loff_t, size_t,
+ struct nl4_servers *, nfs4_stateid *);
int nfs42_proc_deallocate(struct file *, loff_t, loff_t);
loff_t nfs42_proc_llseek(struct file *, loff_t, int);
int nfs42_proc_layoutstats_generic(struct nfs_server *,
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index ace3fae..7a6b3c9 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -171,7 +171,9 @@ static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src,
struct nfs_lock_context *src_lock,
struct file *dst, loff_t pos_dst,
struct nfs_lock_context *dst_lock,
- size_t count)
+ size_t count,
+ struct nl4_servers *nss,
+ nfs4_stateid *cnr_stateid)
{
struct nfs42_copy_args args = {
.src_fh = NFS_FH(file_inode(src)),
@@ -190,10 +192,25 @@ static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src,
struct nfs_server *server = NFS_SERVER(dst_inode);
int status;

- status = nfs4_set_rw_stateid(&args.src_stateid, src_lock->open_context,
- src_lock, FMODE_READ);
- if (status)
- return status;
+ if (nss) {
+ args.cp_src = nss;
+
+ dprintk("--> %s nl4_type %d cp_addr netid %d:%s uaddr %d:%s\n",
+ __func__, args.cp_src->nl_svr->nl4_type,
+ args.cp_src->nl_svr->u.nl4_addr.na_netid_len,
+ args.cp_src->nl_svr->u.nl4_addr.na_netid,
+ args.cp_src->nl_svr->u.nl4_addr.na_uaddr_len,
+ args.cp_src->nl_svr->u.nl4_addr.na_uaddr);
+
+ nfs4_stateid_copy(&args.src_stateid, cnr_stateid);
+ } else {
+
+ status = nfs4_set_rw_stateid(&args.src_stateid,
+ src_lock->open_context,
+ src_lock, FMODE_READ);
+ if (status)
+ return status;
+ }

status = nfs_filemap_write_and_wait_range(file_inode(src)->i_mapping,
pos_src, pos_src + (loff_t)count - 1);
@@ -229,8 +246,9 @@ static ssize_t _nfs42_proc_copy(struct file *src, loff_t pos_src,
}

ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
- struct file *dst, loff_t pos_dst,
- size_t count)
+ struct file *dst, loff_t pos_dst, size_t count,
+ struct nl4_servers *nss,
+ nfs4_stateid *cnr_stateid)
{
struct nfs_server *server = NFS_SERVER(file_inode(dst));
struct nfs_lock_context *src_lock;
@@ -261,7 +279,8 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
do {
inode_lock(file_inode(dst));
err = _nfs42_proc_copy(src, pos_src, src_lock,
- dst, pos_dst, dst_lock, count);
+ dst, pos_dst, dst_lock, count,
+ nss, cnr_stateid);
inode_unlock(file_inode(dst));

if (err == -ENOTSUPP) {
diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c
index 29bfaab..4738c70 100644
--- a/fs/nfs/nfs42xdr.c
+++ b/fs/nfs/nfs42xdr.c
@@ -20,7 +20,10 @@
#define encode_copy_maxsz (op_encode_hdr_maxsz + \
XDR_QUADLEN(NFS4_STATEID_SIZE) + \
XDR_QUADLEN(NFS4_STATEID_SIZE) + \
- 2 + 2 + 2 + 1 + 1 + 1)
+ 2 + 2 + 2 + 1 + 1 + 1 +\
+ 1 + /* One cnr_source_server */\
+ 1 + /* nl4_type */ \
+ 1 + XDR_QUADLEN(NFS4_OPAQUE_LIMIT))
#define decode_copy_maxsz (op_decode_hdr_maxsz + \
NFS42_WRITE_RES_SIZE + \
1 /* cr_consecutive */ + \
@@ -164,6 +167,9 @@ static void encode_copy(struct xdr_stream *xdr,
struct nfs42_copy_args *args,
struct compound_hdr *hdr)
{
+ struct nl4_server *ns;
+ int i;
+
encode_op_hdr(xdr, OP_COPY, decode_copy_maxsz, hdr);
encode_nfs4_stateid(xdr, &args->src_stateid);
encode_nfs4_stateid(xdr, &args->dst_stateid);
@@ -174,7 +180,16 @@ static void encode_copy(struct xdr_stream *xdr,

encode_uint32(xdr, 1); /* consecutive = true */
encode_uint32(xdr, 1); /* synchronous = true */
- encode_uint32(xdr, 0); /* src server list */
+ if (args->cp_src == NULL) { /* intra-ssc */
+ encode_uint32(xdr, 0); /* no src server list */
+ return;
+ }
+ encode_uint32(xdr, args->cp_src->nl_nsvr);
+ ns = args->cp_src->nl_svr;
+ for (i = 0; i < args->cp_src->nl_nsvr; i++) {
+ encode_nl4_server(xdr, args->cp_src->nl_svr);
+ ns++;
+ }
}

static void encode_copy_notify(struct xdr_stream *xdr,
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index cf78bf8..599f1ca 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -135,6 +135,8 @@ static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
size_t count, unsigned int flags)
{
struct nfs42_copy_notify_res *cn_resp = NULL;
+ struct nl4_servers *nss = NULL;
+ nfs4_stateid *cnrs = NULL;
ssize_t ret;

if (file_inode(file_in) == file_inode(file_out))
@@ -160,8 +162,11 @@ static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
ret = nfs42_proc_copy_notify(file_in, file_out, cn_resp);
if (ret)
goto out;
+ nss = &cn_resp->cnr_src;
+ cnrs = &cn_resp->cnr_stateid;
}
- ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
+ ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count, nss,
+ cnrs);

out:
if (cn_resp) {
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index ecd4132..ee3dd09 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1342,6 +1342,8 @@ struct nfs42_copy_args {
u64 dst_pos;

u64 count;
+ /* Support one source server */
+ struct nl4_servers *cp_src;
};

struct nfs42_write_res {
--
1.8.3.1


2016-08-19 17:25:48

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version-2 05/12] NFS add COPY_NOTIFY operation

From: Andy Adamson <[email protected]>

Try using the delegation stateid, then the open stateid.

Only NL4_NETATTR, No support for NL4_NAME and NL4_URL.
Allow only one source server address to be returned for now.

Signed-off-by: Andy Adamson <[email protected]>
---
fs/nfs/internal.h | 10 +++
fs/nfs/nfs42.h | 4 +
fs/nfs/nfs42proc.c | 93 +++++++++++++++++++++++
fs/nfs/nfs42xdr.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++
fs/nfs/nfs4_fs.h | 1 +
fs/nfs/nfs4file.c | 33 +++++++-
fs/nfs/nfs4proc.c | 1 +
fs/nfs/nfs4state.c | 2 +-
fs/nfs/nfs4xdr.c | 1 +
include/linux/nfs4.h | 35 +++++++++
include/linux/nfs_fs_sb.h | 1 +
include/linux/nfs_xdr.h | 18 +++++
12 files changed, 383 insertions(+), 2 deletions(-)

diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 7ce5e02..c8af036 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -7,6 +7,7 @@
#include <linux/security.h>
#include <linux/crc32.h>
#include <linux/nfs_page.h>
+#include <linux/sunrpc/addr.h>

#define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)

@@ -762,3 +763,12 @@ static inline bool nfs_error_is_fatal(int err)
return false;
}
}
+
+static inline bool nfs42_intra_ssc(struct file *in, struct file *out)
+{
+ struct nfs_client *c_in = (NFS_SERVER(file_inode(in)))->nfs_client;
+ struct nfs_client *c_out = (NFS_SERVER(file_inode(out)))->nfs_client;
+
+ return rpc_cmp_addr((struct sockaddr *)&c_in->cl_addr,
+ (struct sockaddr *)&c_out->cl_addr);
+}
diff --git a/fs/nfs/nfs42.h b/fs/nfs/nfs42.h
index b6cd153..2f780d2 100644
--- a/fs/nfs/nfs42.h
+++ b/fs/nfs/nfs42.h
@@ -12,6 +12,7 @@
#define PNFS_LAYOUTSTATS_MAXDEV (4)

/* nfs4.2proc.c */
+#if defined(CONFIG_NFS_V4_2)
int nfs42_proc_allocate(struct file *, loff_t, loff_t);
ssize_t nfs42_proc_copy(struct file *, loff_t, struct file *, loff_t, size_t);
int nfs42_proc_deallocate(struct file *, loff_t, loff_t);
@@ -19,5 +20,8 @@ loff_t nfs42_proc_llseek(struct file *, loff_t, int);
int nfs42_proc_layoutstats_generic(struct nfs_server *,
struct nfs42_layoutstat_data *);
int nfs42_proc_clone(struct file *, struct file *, loff_t, loff_t, loff_t);
+int nfs42_proc_copy_notify(struct file *, struct file *,
+ struct nfs42_copy_notify_res *);
+#endif /* CONFIG_NFS_V4_2 */

#endif /* __LINUX_FS_NFS_NFS4_2_H */
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index 6f47527..ace3fae 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -2,6 +2,7 @@
* Copyright (c) 2014 Anna Schumaker <[email protected]>
*/
#include <linux/fs.h>
+#include <linux/sunrpc/addr.h>
#include <linux/sunrpc/sched.h>
#include <linux/nfs.h>
#include <linux/nfs3.h>
@@ -13,9 +14,47 @@
#include "iostat.h"
#include "pnfs.h"
#include "internal.h"
+#include "delegation.h"

#define NFSDBG_FACILITY NFSDBG_PROC

+static int nfs42_set_open_stateid(nfs4_stateid *dst, struct file *file)
+{
+ struct nfs_open_context *ctx;
+ struct rpc_cred *cred;
+ struct nfs_lockowner lockowner = {
+ .l_owner = current->files,
+ .l_pid = current->tgid,
+ };
+ int ret;
+
+ ctx = get_nfs_open_context(nfs_file_open_context(file));
+ ret = nfs4_select_rw_stateid(ctx->state, FMODE_READ, &lockowner,
+ dst, &cred);
+ dprintk("<-- %s returns %d\n", __func__, ret);
+ return ret;
+}
+
+static void nfs42_set_netaddr(struct file *file_out,
+ struct nfs42_netaddr *naddr)
+{
+ struct nfs_client *clp = (NFS_SERVER(file_inode(file_out)))->nfs_client;
+ unsigned short port = 2049;
+
+ rcu_read_lock();
+ naddr->na_netid_len = scnprintf(naddr->na_netid,
+ sizeof(naddr->na_netid), "%s",
+ rpc_peeraddr2str(clp->cl_rpcclient,
+ RPC_DISPLAY_NETID));
+ naddr->na_uaddr_len = scnprintf(naddr->na_uaddr,
+ sizeof(naddr->na_uaddr),
+ "%s.%u.%u",
+ rpc_peeraddr2str(clp->cl_rpcclient,
+ RPC_DISPLAY_ADDR),
+ port >> 8, port & 255);
+ rcu_read_unlock();
+}
+
static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
struct nfs_lock_context *lock, loff_t offset, loff_t len)
{
@@ -242,6 +281,60 @@ out_put_src_lock:
return err;
}

+int _nfs42_proc_copy_notify(struct file *src, struct file *dst,
+struct nfs42_copy_notify_res *res)
+{
+ struct nfs42_copy_notify_args *args;
+ struct nfs_server *src_server = NFS_SERVER(file_inode(src));
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY_NOTIFY],
+ .rpc_resp = res,
+ };
+ int status;
+
+ args = kzalloc(sizeof(struct nfs42_copy_notify_args), GFP_NOFS);
+ if (args == NULL)
+ return -ENOMEM;
+
+ args->cna_src_fh = NFS_FH(file_inode(src)),
+ args->cna_dst.nl4_type = NL4_NETADDR;
+ nfs42_set_netaddr(src, &args->cna_dst.u.nl4_addr);
+ status = nfs42_set_open_stateid(&args->cna_src_stateid, src);
+ if (status)
+ goto out;
+
+ msg.rpc_argp = args;
+ status = nfs4_call_sync(src_server->client, src_server, &msg,
+ &args->cna_seq_args, &res->cnr_seq_res, 0);
+ if (status == -ENOTSUPP)
+ src_server->caps &= ~NFS_CAP_COPY_NOTIFY;
+
+ put_nfs_open_context(nfs_file_open_context(src));
+out:
+ kfree(args);
+ return status;
+}
+
+int nfs42_proc_copy_notify(struct file *src, struct file *dst,
+ struct nfs42_copy_notify_res *res)
+{
+ struct nfs_server *src_server = NFS_SERVER(file_inode(src));
+ struct nfs4_exception exception = { };
+ int status;
+
+ if (!(src_server->caps & NFS_CAP_COPY_NOTIFY))
+ return -ENOTSUPP;
+
+ do {
+ status = _nfs42_proc_copy_notify(src, dst, res);
+ if (status == -ENOTSUPP)
+ return -EOPNOTSUPP;
+ status = nfs4_handle_exception(src_server, status, &exception);
+ } while (exception.retry);
+
+ return status;
+}
+
static loff_t _nfs42_proc_llseek(struct file *filep,
struct nfs_lock_context *lock, loff_t offset, int whence)
{
diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c
index 8b26058..29bfaab 100644
--- a/fs/nfs/nfs42xdr.c
+++ b/fs/nfs/nfs42xdr.c
@@ -25,6 +25,16 @@
NFS42_WRITE_RES_SIZE + \
1 /* cr_consecutive */ + \
1 /* cr_synchronous */)
+#define encode_copy_notify_maxsz (op_encode_hdr_maxsz + \
+ XDR_QUADLEN(NFS4_STATEID_SIZE) + \
+ 1 + /* nl4_type */ \
+ 1 + XDR_QUADLEN(NFS4_OPAQUE_LIMIT))
+#define decode_copy_notify_maxsz (op_decode_hdr_maxsz + \
+ 3 + /* cnr_lease_time */\
+ XDR_QUADLEN(NFS4_STATEID_SIZE) + \
+ 1 + /* Support 1 cnr_source_server */\
+ 1 + /* nl4_type */ \
+ 1 + XDR_QUADLEN(NFS4_OPAQUE_LIMIT))
#define encode_deallocate_maxsz (op_encode_hdr_maxsz + \
encode_fallocate_maxsz)
#define decode_deallocate_maxsz (op_decode_hdr_maxsz)
@@ -72,6 +82,12 @@
decode_savefh_maxsz + \
decode_putfh_maxsz + \
decode_copy_maxsz)
+#define NFS4_enc_copy_notify_sz (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ encode_copy_notify_maxsz)
+#define NFS4_dec_copy_notify_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ decode_copy_notify_maxsz)
#define NFS4_enc_deallocate_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
encode_deallocate_maxsz + \
@@ -125,6 +141,25 @@ static void encode_allocate(struct xdr_stream *xdr,
encode_fallocate(xdr, args);
}

+static void encode_nl4_server(struct xdr_stream *xdr, struct nl4_server *ns)
+{
+ encode_uint32(xdr, ns->nl4_type);
+ switch (ns->nl4_type) {
+ case NL4_NAME:
+ case NL4_URL:
+ encode_string(xdr, ns->u.nl4_str_sz, ns->u.nl4_str);
+ break;
+ case NL4_NETADDR:
+ encode_string(xdr, ns->u.nl4_addr.na_netid_len,
+ ns->u.nl4_addr.na_netid);
+ encode_string(xdr, ns->u.nl4_addr.na_uaddr_len,
+ ns->u.nl4_addr.na_uaddr);
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ }
+}
+
static void encode_copy(struct xdr_stream *xdr,
struct nfs42_copy_args *args,
struct compound_hdr *hdr)
@@ -142,6 +177,15 @@ static void encode_copy(struct xdr_stream *xdr,
encode_uint32(xdr, 0); /* src server list */
}

+static void encode_copy_notify(struct xdr_stream *xdr,
+ struct nfs42_copy_notify_args *args,
+ struct compound_hdr *hdr)
+{
+ encode_op_hdr(xdr, OP_COPY_NOTIFY, decode_copy_notify_maxsz, hdr);
+ encode_nfs4_stateid(xdr, &args->cna_src_stateid);
+ encode_nl4_server(xdr, &args->cna_dst);
+}
+
static void encode_deallocate(struct xdr_stream *xdr,
struct nfs42_falloc_args *args,
struct compound_hdr *hdr)
@@ -242,6 +286,24 @@ static void nfs4_xdr_enc_copy(struct rpc_rqst *req,
}

/*
+ * Encode COPY_NOTIFY request
+ */
+static void nfs4_xdr_enc_copy_notify(struct rpc_rqst *req,
+ struct xdr_stream *xdr,
+ struct nfs42_copy_notify_args *args)
+{
+ struct compound_hdr hdr = {
+ .minorversion = nfs4_xdr_minorversion(&args->cna_seq_args),
+ };
+
+ encode_compound_hdr(xdr, req, &hdr);
+ encode_sequence(xdr, &args->cna_seq_args, &hdr);
+ encode_putfh(xdr, args->cna_src_fh, &hdr);
+ encode_copy_notify(xdr, args, &hdr);
+ encode_nops(&hdr);
+}
+
+/*
* Encode DEALLOCATE request
*/
static void nfs4_xdr_enc_deallocate(struct rpc_rqst *req,
@@ -354,6 +416,58 @@ out_overflow:
return -EIO;
}

+static int decode_nl4_server(struct xdr_stream *xdr, struct nl4_server *ns)
+{
+ struct nfs42_netaddr *naddr;
+ uint32_t dummy;
+ char *dummy_str;
+ __be32 *p;
+ int status;
+
+ /* nl_type */
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ return -EIO;
+ ns->nl4_type = be32_to_cpup(p);
+ switch (ns->nl4_type) {
+ case NL4_NAME:
+ case NL4_URL:
+ status = decode_opaque_inline(xdr, &dummy, &dummy_str);
+ if (unlikely(status))
+ return status;
+ if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
+ return -EIO;
+ memcpy(&ns->u.nl4_str, dummy_str, dummy);
+ ns->u.nl4_str_sz = dummy;
+ break;
+ case NL4_NETADDR:
+ naddr = &ns->u.nl4_addr;
+
+ /* netid string */
+ status = decode_opaque_inline(xdr, &dummy, &dummy_str);
+ if (unlikely(status))
+ return status;
+ if (unlikely(dummy > RPCBIND_MAXNETIDLEN))
+ return -EIO;
+ naddr->na_netid_len = dummy;
+ memcpy(naddr->na_netid, dummy_str, naddr->na_netid_len);
+
+ /* uaddr string */
+ status = decode_opaque_inline(xdr, &dummy, &dummy_str);
+ if (unlikely(status))
+ return status;
+ if (unlikely(dummy > RPCBIND_MAXUADDRLEN))
+ return -EIO;
+ naddr->na_uaddr_len = dummy;
+ memcpy(naddr->na_uaddr, dummy_str, naddr->na_uaddr_len);
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ return -EIO;
+ }
+ return 0;
+}
+
static int decode_copy_requirements(struct xdr_stream *xdr,
struct nfs42_copy_res *res) {
__be32 *p;
@@ -390,6 +504,53 @@ static int decode_copy(struct xdr_stream *xdr, struct nfs42_copy_res *res)
return decode_copy_requirements(xdr, res);
}

+static int decode_copy_notify(struct xdr_stream *xdr,
+ struct nfs42_copy_notify_res *res)
+{
+ __be32 *p;
+ struct nl4_server *ns;
+ int status, i;
+
+ status = decode_op_hdr(xdr, OP_COPY_NOTIFY);
+ if (status)
+ return status;
+ /* cnr_lease_time */
+ p = xdr_inline_decode(xdr, 12);
+ if (unlikely(!p))
+ goto out_overflow;
+ p = xdr_decode_hyper(p, &res->cnr_lease_time.seconds);
+ res->cnr_lease_time.nseconds = be32_to_cpup(p);
+
+ status = decode_opaque_fixed(xdr, &res->cnr_stateid, NFS4_STATEID_SIZE);
+ if (unlikely(status))
+ goto out_overflow;
+
+ /* number of source addresses */
+ p = xdr_inline_decode(xdr, 4);
+ if (unlikely(!p))
+ goto out_overflow;
+
+ res->cnr_src.nl_nsvr = be32_to_cpup(p);
+ if (res->cnr_src.nl_nsvr > NFS42_MAX_SSC_SRC) {
+ pr_warn("NFS: %s: nsvr %d > Supported. Use first %d servers\n",
+ __func__, res->cnr_src.nl_nsvr, NFS42_MAX_SSC_SRC);
+ res->cnr_src.nl_nsvr = NFS42_MAX_SSC_SRC;
+ }
+
+ ns = res->cnr_src.nl_svr;
+ for (i = 0; i < res->cnr_src.nl_nsvr; i++) {
+ status = decode_nl4_server(xdr, ns);
+ if (unlikely(status))
+ goto out_overflow;
+ ns++;
+ }
+ return 0;
+
+out_overflow:
+ print_overflow_msg(__func__, xdr);
+ return -EIO;
+}
+
static int decode_deallocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res)
{
return decode_op_hdr(xdr, OP_DEALLOCATE);
@@ -485,6 +646,31 @@ out:
}

/*
+ * Decode COPY_NOTIFY response
+ */
+static int nfs4_xdr_dec_copy_notify(struct rpc_rqst *rqstp,
+ struct xdr_stream *xdr,
+ struct nfs42_copy_notify_res *res)
+{
+ struct compound_hdr hdr;
+ int status;
+
+ status = decode_compound_hdr(xdr, &hdr);
+ if (status)
+ goto out;
+ status = decode_sequence(xdr, &res->cnr_seq_res, rqstp);
+ if (status)
+ goto out;
+ status = decode_putfh(xdr);
+ if (status)
+ goto out;
+ status = decode_copy_notify(xdr, res);
+
+out:
+ return status;
+}
+
+/*
* Decode DEALLOCATE request
*/
static int nfs4_xdr_dec_deallocate(struct rpc_rqst *rqstp,
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index e594d9c..550f88b 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -454,6 +454,7 @@ extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
extern int nfs4_select_rw_stateid(struct nfs4_state *, fmode_t,
const struct nfs_lockowner *, nfs4_stateid *,
struct rpc_cred **);
+extern void nfs4_copy_open_stateid(nfs4_stateid *, struct nfs4_state *);

extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask);
extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task);
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index 4a4eb40..cf78bf8 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -134,10 +134,41 @@ static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
struct file *file_out, loff_t pos_out,
size_t count, unsigned int flags)
{
+ struct nfs42_copy_notify_res *cn_resp = NULL;
+ ssize_t ret;
+
if (file_inode(file_in) == file_inode(file_out))
return -EINVAL;

- return nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
+ if (nfs42_intra_ssc(file_in, file_out)) { /* Intra-ssc */
+ if (file_in->f_op != file_out->f_op)
+ return -EXDEV;
+ } else { /* Inter-ssc */
+ cn_resp = kzalloc(sizeof(struct nfs42_copy_notify_res),
+ GFP_NOFS);
+ if (unlikely(cn_resp == NULL))
+ return -ENOMEM;
+
+ cn_resp->cnr_src.nl_svr = kzalloc(NFS42_MAX_SSC_SRC *
+ sizeof(struct nl4_server),
+ GFP_NOFS);
+ if (unlikely(cn_resp->cnr_src.nl_svr == NULL)) {
+ kfree(cn_resp);
+ return -ENOMEM;
+ }
+
+ ret = nfs42_proc_copy_notify(file_in, file_out, cn_resp);
+ if (ret)
+ goto out;
+ }
+ ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count);
+
+out:
+ if (cn_resp) {
+ kfree(cn_resp->cnr_src.nl_svr);
+ kfree(cn_resp);
+ }
+ return ret;
}

static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index d0ae1ca..4b31e2a 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -8810,6 +8810,7 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
| NFS_CAP_ATOMIC_OPEN_V1
| NFS_CAP_ALLOCATE
| NFS_CAP_COPY
+ | NFS_CAP_COPY_NOTIFY
| NFS_CAP_DEALLOCATE
| NFS_CAP_SEEK
| NFS_CAP_LAYOUTSTATS
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index cada00a..f6d335a 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -967,7 +967,7 @@ out:
return ret;
}

-static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
+void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
{
const nfs4_stateid *src;
int seq;
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 7bd3a5c..9aaf605 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -7545,6 +7545,7 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC(LAYOUTSTATS, enc_layoutstats, dec_layoutstats),
PROC(CLONE, enc_clone, dec_clone),
PROC(COPY, enc_copy, dec_copy),
+ PROC(COPY_NOTIFY, enc_copy_notify, dec_copy_notify),
#endif /* CONFIG_NFS_V4_2 */
};

diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index f83b041..3764885 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -15,6 +15,7 @@
#include <linux/list.h>
#include <linux/uidgid.h>
#include <uapi/linux/nfs4.h>
+#include <linux/sunrpc/msg_prot.h>

enum nfs4_acl_whotype {
NFS4_ACL_WHO_NAMED = 0,
@@ -520,6 +521,7 @@ enum {
NFSPROC4_CLNT_LAYOUTSTATS,
NFSPROC4_CLNT_CLONE,
NFSPROC4_CLNT_COPY,
+ NFSPROC4_CLNT_COPY_NOTIFY,
};

/* nfs41 types */
@@ -658,4 +660,37 @@ struct nfs42_inter_ssc {
struct vfsmount *sc_root_mnt;
struct dentry *sc_mnt_dentry;
};
+
+struct nfs42_netaddr {
+ unsigned int na_netid_len;
+ char na_netid[RPCBIND_MAXNETIDLEN + 1];
+ unsigned int na_uaddr_len;
+ char na_uaddr[RPCBIND_MAXUADDRLEN + 1];
+};
+
+enum netloc_type4 {
+ NL4_NAME = 1,
+ NL4_URL = 2,
+ NL4_NETADDR = 3,
+};
+
+struct nl4_server {
+ enum netloc_type4 nl4_type;
+ union {
+ struct { /* NL4_NAME, NL4_URL */
+ int nl4_str_sz;
+ char nl4_str[NFS4_OPAQUE_LIMIT + 1];
+ };
+ struct nfs42_netaddr nl4_addr; /* NL4_NETADDR */
+ } u;
+};
+
+/* support 1 nl4_server for now */
+#define NFS42_MAX_SSC_SRC 1
+
+struct nl4_servers {
+ int nl_nsvr;
+ struct nl4_server *nl_svr;
+};
+
#endif
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 14a762d..87507dc 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -247,5 +247,6 @@ struct nfs_server {
#define NFS_CAP_LAYOUTSTATS (1U << 22)
#define NFS_CAP_CLONE (1U << 23)
#define NFS_CAP_COPY (1U << 24)
+#define NFS_CAP_COPY_NOTIFY (1U << 25)

#endif
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 7cc0dee..ecd4132 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1356,6 +1356,24 @@ struct nfs42_copy_res {
bool synchronous;
};

+struct nfs42_copy_notify_args {
+ struct nfs4_sequence_args cna_seq_args;
+
+ struct nfs_fh *cna_src_fh;
+ nfs4_stateid cna_src_stateid;
+ /* cna_destiniation_server */
+ struct nl4_server cna_dst;
+};
+
+struct nfs42_copy_notify_res {
+ struct nfs4_sequence_res cnr_seq_res;
+
+ struct nfstime4 cnr_lease_time;
+ nfs4_stateid cnr_stateid;
+ /* cnr_source_server, for now, always 1 */
+ struct nl4_servers cnr_src;
+};
+
struct nfs42_seek_args {
struct nfs4_sequence_args seq_args;

--
1.8.3.1


2016-08-19 17:25:50

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version-2 07/12] NFSD add ca_source_server<> to COPY

From: Andy Adamson <[email protected]>

Note: followed conventiona and have struct nfsd4_compoundargs pointer as a
parameter even though it is unused.

Signed-off-by: Andy Adamson <[email protected]>
---
fs/nfsd/nfs4xdr.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
fs/nfsd/xdr4.h | 4 +++
2 files changed, 77 insertions(+), 2 deletions(-)

diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 5e148d4..f601afb 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -40,6 +40,7 @@
#include <linux/utsname.h>
#include <linux/pagemap.h>
#include <linux/sunrpc/svcauth_gss.h>
+#include <linux/sunrpc/addr.h>

#include "idmap.h"
#include "acl.h"
@@ -1693,11 +1694,58 @@ nfsd4_decode_clone(struct nfsd4_compoundargs *argp, struct nfsd4_clone *clone)
DECODE_TAIL;
}

+static __be32 nfsd4_decode_nl4_server(struct nfsd4_compoundargs *argp,
+ struct nl4_server *ns)
+{
+ DECODE_HEAD;
+ struct nfs42_netaddr *naddr;
+
+ READ_BUF(4);
+ ns->nl4_type = be32_to_cpup(p++);
+
+ /* currently support for 1 inter-server source server */
+ switch (ns->nl4_type) {
+ case NL4_NAME:
+ case NL4_URL:
+ READ_BUF(4);
+ ns->u.nl4_str_sz = be32_to_cpup(p++);
+ if (ns->u.nl4_str_sz > NFS4_OPAQUE_LIMIT)
+ goto xdr_error;
+
+ READ_BUF(ns->u.nl4_str_sz);
+ COPYMEM(ns->u.nl4_str,
+ ns->u.nl4_str_sz);
+ break;
+ case NL4_NETADDR:
+ naddr = &ns->u.nl4_addr;
+
+ READ_BUF(4);
+ naddr->na_netid_len = be32_to_cpup(p++);
+ if (naddr->na_netid_len > RPCBIND_MAXNETIDLEN)
+ goto xdr_error;
+
+ READ_BUF(naddr->na_netid_len + 4); /* 4 for uaddr len */
+ COPYMEM(naddr->na_netid, naddr->na_netid_len);
+
+ naddr->na_uaddr_len = be32_to_cpup(p++);
+ if (naddr->na_uaddr_len > RPCBIND_MAXUADDRLEN)
+ goto xdr_error;
+
+ READ_BUF(naddr->na_uaddr_len);
+ COPYMEM(naddr->na_uaddr, naddr->na_uaddr_len);
+ break;
+ default:
+ goto xdr_error;
+ }
+ DECODE_TAIL;
+}
+
static __be32
nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy)
{
DECODE_HEAD;
- unsigned int tmp;
+ struct nl4_server *ns;
+ int i;

status = nfsd4_decode_stateid(argp, &copy->cp_src_stateid);
if (status)
@@ -1712,8 +1760,29 @@ nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy)
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 */
+ copy->cp_src.nl_nsvr = be32_to_cpup(p++);

+ if (copy->cp_src.nl_nsvr == 0) /* intra-server copy */
+ goto intra;
+
+ /** Support NFSD4_MAX_SSC_SRC number of source servers.
+ * freed in nfsd4_encode_copy
+ */
+ if (copy->cp_src.nl_nsvr > NFSD4_MAX_SSC_SRC)
+ copy->cp_src.nl_nsvr = NFSD4_MAX_SSC_SRC;
+ copy->cp_src.nl_svr = kmalloc(copy->cp_src.nl_nsvr *
+ sizeof(struct nl4_server), GFP_KERNEL);
+ if (copy->cp_src.nl_svr == NULL)
+ return nfserrno(-ENOMEM);
+
+ ns = copy->cp_src.nl_svr;
+ for (i = 0; i < copy->cp_src.nl_nsvr; i++) {
+ status = nfsd4_decode_nl4_server(argp, ns);
+ if (status)
+ return status;
+ ns++;
+ }
+intra:
DECODE_TAIL;
}

@@ -4257,6 +4326,8 @@ nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr,
*p++ = cpu_to_be32(copy->cp_consecutive);
*p++ = cpu_to_be32(copy->cp_synchronous);
}
+ /* allocated in nfsd4_decode_copy */
+ kfree(copy->cp_src.nl_svr);
return nfserr;
}

diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 8fda4ab..6b1a61f 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -509,6 +509,9 @@ struct nfsd42_write_res {
nfs4_verifier wr_verifier;
};

+/* support 1 source server for now */
+#define NFSD4_MAX_SSC_SRC 1
+
struct nfsd4_copy {
/* request */
stateid_t cp_src_stateid;
@@ -516,6 +519,7 @@ struct nfsd4_copy {
u64 cp_src_pos;
u64 cp_dst_pos;
u64 cp_count;
+ struct nl4_servers cp_src;

/* both */
bool cp_consecutive;
--
1.8.3.1


2016-08-19 17:26:26

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version-2 09/12] NFSD generalize nfsd4_compound_state flag names

From: Andy Adamson <[email protected]>

Allow for sid_flag field non-stateid use.

Signed-off-by: Andy Adamson <[email protected]>
---
fs/nfsd/nfs4proc.c | 8 ++++----
fs/nfsd/nfs4state.c | 7 ++++---
fs/nfsd/xdr4.h | 6 +++---
3 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 0a2c23d..244c060 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -536,9 +536,9 @@ nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
return nfserr_restorefh;

fh_dup2(&cstate->current_fh, &cstate->save_fh);
- if (HAS_STATE_ID(cstate, SAVED_STATE_ID_FLAG)) {
+ if (HAS_CSTATE_FLAG(cstate, SAVED_STATE_ID_FLAG)) {
memcpy(&cstate->current_stateid, &cstate->save_stateid, sizeof(stateid_t));
- SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
+ SET_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG);
}
return nfs_ok;
}
@@ -551,9 +551,9 @@ nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
return nfserr_nofilehandle;

fh_dup2(&cstate->save_fh, &cstate->current_fh);
- if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG)) {
+ if (HAS_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG)) {
memcpy(&cstate->save_stateid, &cstate->current_stateid, sizeof(stateid_t));
- SET_STATE_ID(cstate, SAVED_STATE_ID_FLAG);
+ SET_CSTATE_FLAG(cstate, SAVED_STATE_ID_FLAG);
}
return nfs_ok;
}
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index a204d7e..003f624 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -6899,7 +6899,8 @@ nfs4_state_shutdown(void)
static void
get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
{
- if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid))
+ if (HAS_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG) &&
+ CURRENT_STATEID(stateid))
memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t));
}

@@ -6908,14 +6909,14 @@ put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid)
{
if (cstate->minorversion) {
memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t));
- SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
+ SET_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG);
}
}

void
clear_current_stateid(struct nfsd4_compound_state *cstate)
{
- CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG);
+ CLEAR_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG);
}

/*
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 5db7cd8..38fcb4f 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -46,9 +46,9 @@
#define CURRENT_STATE_ID_FLAG (1<<0)
#define SAVED_STATE_ID_FLAG (1<<1)

-#define SET_STATE_ID(c, f) ((c)->sid_flags |= (f))
-#define HAS_STATE_ID(c, f) ((c)->sid_flags & (f))
-#define CLEAR_STATE_ID(c, f) ((c)->sid_flags &= ~(f))
+#define SET_CSTATE_FLAG(c, f) ((c)->sid_flags |= (f))
+#define HAS_CSTATE_FLAG(c, f) ((c)->sid_flags & (f))
+#define CLEAR_CSTATE_FLAG(c, f) ((c)->sid_flags &= ~(f))

struct nfsd4_compound_state {
struct svc_fh current_fh;
--
1.8.3.1


2016-08-19 17:26:26

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version-2 08/12] NFSD add COPY_NOTIFY operation

From: Andy Adamson <[email protected]>

Signed-off-by: Andy Adamson <[email protected]>
---
fs/nfsd/nfs4proc.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++
fs/nfsd/nfs4xdr.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++-
fs/nfsd/xdr4.h | 13 ++++++
3 files changed, 240 insertions(+), 2 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index abb09b5..0a2c23d 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -35,6 +35,7 @@
#include <linux/file.h>
#include <linux/falloc.h>
#include <linux/slab.h>
+#include <linux/sunrpc/addr.h>

#include "idmap.h"
#include "cache.h"
@@ -1100,6 +1101,101 @@ out:
return status;
}

+static int
+nfsd4_set_src_nl4_netaddr(struct svc_rqst *rqstp, struct nfs42_netaddr *naddr)
+{
+ const struct sockaddr *addr = (struct sockaddr *)&rqstp->rq_daddr;
+ const struct sockaddr_in *sin = (const struct sockaddr_in *)addr;
+ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)addr;
+ int uaddr_len = rqstp->rq_daddrlen + 4 + 1; /* port (4) and '\0' (1) */
+ size_t ret;
+ unsigned short port;
+
+ switch (addr->sa_family) {
+ case AF_INET:
+ port = ntohs(sin->sin_port);
+ ret = rpc_ntop(addr, naddr->na_uaddr, sizeof(naddr->na_uaddr));
+ snprintf(naddr->na_uaddr + ret, uaddr_len, ".%u.%u",
+ port >> 8, port & 255);
+ naddr->na_uaddr_len = strlen(naddr->na_uaddr);
+
+ snprintf(naddr->na_netid, 4, "%s", "tcp");
+ naddr->na_netid_len = 3;
+ break;
+ case AF_INET6:
+ port = ntohs(sin6->sin6_port);
+ ret = rpc_ntop(addr, naddr->na_uaddr, sizeof(naddr->na_uaddr));
+ snprintf(naddr->na_uaddr + ret, uaddr_len, ".%u.%u",
+ port >> 8, port & 255);
+ naddr->na_uaddr_len = strlen(naddr->na_uaddr);
+
+ snprintf(naddr->na_netid, 5, "%s", "tcp6");
+ naddr->na_netid_len = 4;
+ break;
+ default:
+ dprintk("NFSD nfsd4_set_notify_src: unknown address type: %d",
+ addr->sa_family);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static __be32
+nfsd4_copy_notify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_copy_notify *cn)
+{
+ __be32 status;
+ struct file *src = NULL;
+ struct nfs42_netaddr *naddr;
+ struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+ struct nl4_server *ns;
+
+ status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
+ &cn->cpn_src_stateid, RD_STATE, &src,
+ NULL);
+ if (status)
+ return status;
+
+
+ /** XXX Save cpn_src_statid, cpn_src, and any other returned source
+ * server addresses on which the source server is williing to accept
+ * connections from the destination e.g. what is returned in cpn_src,
+ * to verify READ from dest server.
+ */
+
+ /**
+ * For now, only return one server address in cpn_src, the
+ * address used by the client to connect to this server.
+ */
+ cn->cpn_src.nl_nsvr = 1;
+
+ /* freed in nfsd4_encode_copy_notify */
+ cn->cpn_src.nl_svr = kmalloc(cn->cpn_src.nl_nsvr *
+ sizeof(struct nfsd4_copy_notify), GFP_KERNEL);
+ if (cn->cpn_src.nl_svr == NULL)
+ return nfserrno(-ENOMEM);
+
+ ns = cn->cpn_src.nl_svr;
+ ns->nl4_type = NL4_NETADDR;
+ naddr = &ns->u.nl4_addr;
+
+ status = nfsd4_set_src_nl4_netaddr(rqstp, naddr);
+ if (status != 0)
+ goto out;
+
+ cn->cpn_sec = nn->nfsd4_lease;
+ cn->cpn_nsec = 0;
+
+ dprintk("<-- %s cpn_dst %s:%s nl_nsvr %d nl_svr %s:%s\n", __func__,
+ cn->cpn_dst.u.nl4_addr.na_netid,
+ cn->cpn_dst.u.nl4_addr.na_uaddr,
+ cn->cpn_src.nl_nsvr,
+ ns->u.nl4_addr.na_netid,
+ ns->u.nl4_addr.na_uaddr);
+out:
+ return status;
+}
+
static __be32
nfsd4_fallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_fallocate *fallocate, int flags)
@@ -2028,6 +2124,21 @@ static inline u32 nfsd4_copy_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
1 /* cr_synchronous */) * sizeof(__be32);
}

+static inline u32 nfsd4_copy_notify_rsize(struct svc_rqst *rqstp,
+ struct nfsd4_op *op)
+{
+ return (op_encode_hdr_size +
+ 3 /* cnr_lease_time */ +
+ 1 /* We support one cnr_source_server */ +
+ 1 /* cnr_stateid seq */ +
+ op_encode_stateid_maxsz /* cnr_stateid */ +
+ 1 /* num cnr_source_server*/ +
+ 1 /* nl4_type */ +
+ 1 /* nl4 size */ +
+ XDR_QUADLEN(NFS4_OPAQUE_LIMIT) /*nl4_loc + nl4_loc_sz */)
+ * sizeof(__be32);
+}
+
#ifdef CONFIG_NFSD_PNFS
/*
* At this stage we don't really know what layout driver will handle the request,
@@ -2400,6 +2511,12 @@ static struct nfsd4_operation nfsd4_ops[] = {
.op_func = (nfsd4op_func)nfsd4_seek,
.op_name = "OP_SEEK",
},
+ [OP_COPY_NOTIFY] = {
+ .op_func = (nfsd4op_func)nfsd4_copy_notify,
+ .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
+ .op_name = "OP_COPY_NOTIFY",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_copy_notify_rsize,
+ },
};

/**
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index f601afb..f4bb29d 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1787,6 +1787,22 @@ intra:
}

static __be32
+nfsd4_decode_copy_notify(struct nfsd4_compoundargs *argp,
+ struct nfsd4_copy_notify *cn)
+{
+ int status;
+
+ status = nfsd4_decode_stateid(argp, &cn->cpn_src_stateid);
+ if (status)
+ return status;
+ status = nfsd4_decode_nl4_server(argp, &cn->cpn_dst);
+ if (status)
+ return status;
+
+ return status;
+}
+
+static __be32
nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek)
{
DECODE_HEAD;
@@ -1887,7 +1903,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_copy,
- [OP_COPY_NOTIFY] = (nfsd4_dec)nfsd4_decode_notsupp,
+ [OP_COPY_NOTIFY] = (nfsd4_dec)nfsd4_decode_copy_notify,
[OP_DEALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate,
[OP_IO_ADVISE] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_LAYOUTERROR] = (nfsd4_dec)nfsd4_decode_notsupp,
@@ -4312,6 +4328,52 @@ nfsd42_encode_write_res(struct nfsd4_compoundres *resp, struct nfsd42_write_res
}

static __be32
+nfsd42_encode_nl4_server(struct nfsd4_compoundres *resp, struct nl4_server *ns)
+{
+ struct xdr_stream *xdr = &resp->xdr;
+ struct nfs42_netaddr *addr;
+ __be32 *p;
+
+ p = xdr_reserve_space(xdr, 4);
+ *p++ = cpu_to_be32(ns->nl4_type);
+
+ switch (ns->nl4_type) {
+ case NL4_NAME:
+ case NL4_URL:
+ p = xdr_reserve_space(xdr, 4 /* url or name len */ +
+ (XDR_QUADLEN(ns->u.nl4_str_sz) * 4));
+ if (!p)
+ return nfserr_resource;
+ *p++ = cpu_to_be32(ns->u.nl4_str_sz);
+ p = xdr_encode_opaque_fixed(p, ns->u.nl4_str, ns->u.nl4_str_sz);
+ break;
+ case NL4_NETADDR:
+ addr = &ns->u.nl4_addr;
+
+ /** netid_len, netid, uaddr_len, uaddr (port included
+ * in RPCBIND_MAXUADDRLEN)
+ */
+ p = xdr_reserve_space(xdr,
+ 4 /* netid len */ +
+ (XDR_QUADLEN(addr->na_netid_len) * 4) +
+ 4 /* uaddr len */ +
+ (XDR_QUADLEN(addr->na_uaddr_len) * 4));
+ if (!p)
+ return nfserr_resource;
+
+ *p++ = cpu_to_be32(addr->na_netid_len);
+ p = xdr_encode_opaque_fixed(p, addr->na_netid,
+ addr->na_netid_len);
+ *p++ = cpu_to_be32(addr->na_uaddr_len);
+ p = xdr_encode_opaque_fixed(p, addr->na_uaddr,
+ addr->na_uaddr_len);
+ break;
+ }
+
+ return 0;
+}
+
+static __be32
nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_copy *copy)
{
@@ -4332,6 +4394,52 @@ nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr,
}

static __be32
+nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr,
+ struct nfsd4_copy_notify *cn)
+{
+ struct xdr_stream *xdr = &resp->xdr;
+ struct nl4_server *ns;
+ __be32 *p;
+ int i;
+
+ if (nfserr)
+ return nfserr;
+
+ /* 8 sec, 4 nsec */
+ p = xdr_reserve_space(xdr, 12);
+ if (!p)
+ return nfserr_resource;
+
+ /* cnr_lease_time */
+ p = xdr_encode_hyper(p, cn->cpn_sec);
+ *p++ = cpu_to_be32(cn->cpn_nsec);
+
+ /* cnr_stateid */
+ nfserr = nfsd4_encode_stateid(xdr, &cn->cpn_src_stateid);
+ if (nfserr)
+ return nfserr;
+
+ /* cnr_src.nl_nsvr */
+ p = xdr_reserve_space(xdr, 4);
+ if (!p)
+ return nfserr_resource;
+
+ *p++ = cpu_to_be32(cn->cpn_src.nl_nsvr);
+
+ ns = cn->cpn_src.nl_svr;
+ for (i = 0; i < cn->cpn_src.nl_nsvr; i++) {
+ nfserr = nfsd42_encode_nl4_server(resp, ns);
+ if (nfserr)
+ return nfserr;
+ ns++;
+ }
+
+ /* allocated in nfsd4_copy_notify */
+ kfree(cn->cpn_src.nl_svr);
+ return nfserr;
+}
+
+static __be32
nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr,
struct nfsd4_seek *seek)
{
@@ -4431,7 +4539,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
/* NFSv4.2 operations */
[OP_ALLOCATE] = (nfsd4_enc)nfsd4_encode_noop,
[OP_COPY] = (nfsd4_enc)nfsd4_encode_copy,
- [OP_COPY_NOTIFY] = (nfsd4_enc)nfsd4_encode_noop,
+ [OP_COPY_NOTIFY] = (nfsd4_enc)nfsd4_encode_copy_notify,
[OP_DEALLOCATE] = (nfsd4_enc)nfsd4_encode_noop,
[OP_IO_ADVISE] = (nfsd4_enc)nfsd4_encode_noop,
[OP_LAYOUTERROR] = (nfsd4_enc)nfsd4_encode_noop,
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 6b1a61f..5db7cd8 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -540,6 +540,18 @@ struct nfsd4_seek {
loff_t seek_pos;
};

+struct nfsd4_copy_notify {
+ /* request */
+ stateid_t cpn_src_stateid;
+ struct nl4_server cpn_dst;
+
+ /* response */
+ /* Note: cpn_src_stateid is used for cnr_stateid */
+ u64 cpn_sec;
+ u32 cpn_nsec;
+ struct nl4_servers cpn_src;
+};
+
struct nfsd4_op {
int opnum;
__be32 status;
@@ -595,6 +607,7 @@ struct nfsd4_op {
struct nfsd4_fallocate deallocate;
struct nfsd4_clone clone;
struct nfsd4_copy copy;
+ struct nfsd4_copy_notify copy_notify;
struct nfsd4_seek seek;
} u;
struct nfs4_replay * replay;
--
1.8.3.1


2016-08-19 17:26:26

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version-2 10/12] NFSD: allow inter server COPY to have a STALE source server fh

From: Andy Adamson <[email protected]>

The inter server to server COPY source server filehandle
is guaranteed to be stale as the COPY is sent to the destination
server.

Signed-off-by: Andy Adamson <[email protected]>
---
fs/nfsd/nfs4proc.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
fs/nfsd/nfs4xdr.c | 26 +++++++++++++++++++++++++-
fs/nfsd/nfsd.h | 2 ++
fs/nfsd/xdr4.h | 4 ++++
4 files changed, 77 insertions(+), 2 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 244c060..8e9bae6 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -510,11 +510,19 @@ static __be32
nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_putfh *putfh)
{
+ __be32 ret;
+
fh_put(&cstate->current_fh);
cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen;
memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval,
putfh->pf_fhlen);
- return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_BYPASS_GSS);
+ ret = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_BYPASS_GSS);
+ if (ret == nfserr_stale && HAS_CSTATE_FLAG(cstate, NO_VERIFY_FH)) {
+ CLEAR_CSTATE_FLAG(cstate, NO_VERIFY_FH);
+ SET_CSTATE_FLAG(cstate, IS_STALE_FH);
+ ret = 0;
+ }
+ return ret;
}

static __be32
@@ -547,6 +555,16 @@ static __be32
nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
void *arg)
{
+ /**
+ * This is either an inter COPY (most likely) or an intra COPY with a
+ * stale file handle. If the latter, nfsd4_copy will reset the PUTFH to
+ * return nfserr_stale. No fh_dentry, just copy the file handle
+ * to use with the inter COPY READ.
+ */
+ if (HAS_CSTATE_FLAG(cstate, IS_STALE_FH)) {
+ cstate->save_fh = cstate->current_fh;
+ return nfs_ok;
+ }
if (!cstate->current_fh.fh_dentry)
return nfserr_nofilehandle;

@@ -1081,6 +1099,13 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (status)
goto out;

+ /* Intra copy source fh is stale. PUTFH will fail with ESTALE */
+ if (HAS_CSTATE_FLAG(cstate, IS_STALE_FH)) {
+ CLEAR_CSTATE_FLAG(cstate, IS_STALE_FH);
+ cstate->status = nfserr_copy_stalefh;
+ goto out_put;
+ }
+
bytes = nfsd_copy_file_range(src, copy->cp_src_pos,
dst, copy->cp_dst_pos, copy->cp_count);

@@ -1095,6 +1120,7 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfs_ok;
}

+out_put:
fput(src);
fput(dst);
out:
@@ -1791,6 +1817,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
struct nfsd4_compound_state *cstate = &resp->cstate;
struct svc_fh *current_fh = &cstate->current_fh;
struct svc_fh *save_fh = &cstate->save_fh;
+ int i;
__be32 status;

svcxdr_init_encode(rqstp, resp);
@@ -1823,6 +1850,12 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
goto encode_op;
}

+ /* NFSv4.2 COPY source file handle may be from a different server */
+ for (i = 0; i < args->opcnt; i++) {
+ op = &args->ops[i];
+ if (op->opnum == OP_COPY)
+ SET_CSTATE_FLAG(cstate, NO_VERIFY_FH);
+ }
while (!status && resp->opcnt < args->opcnt) {
op = &args->ops[resp->opcnt++];

@@ -1842,6 +1875,9 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,

opdesc = OPDESC(op);

+ if (HAS_CSTATE_FLAG(cstate, IS_STALE_FH))
+ goto call_op;
+
if (!current_fh->fh_dentry) {
if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) {
op->status = nfserr_nofilehandle;
@@ -1876,6 +1912,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,

if (opdesc->op_get_currentstateid)
opdesc->op_get_currentstateid(cstate, &op->u);
+call_op:
op->status = opdesc->op_func(rqstp, cstate, &op->u);

if (!op->status) {
@@ -1896,6 +1933,14 @@ encode_op:
status = op->status;
goto out;
}
+ /* Only from intra COPY */
+ if (cstate->status == nfserr_copy_stalefh) {
+ dprintk("%s NFS4.2 intra COPY stale src filehandle\n",
+ __func__);
+ status = nfserr_stale;
+ nfsd4_adjust_encode(resp);
+ goto out;
+ }
if (op->status == nfserr_replay_me) {
op->replay = &cstate->replay_owner->so_replay;
nfsd4_encode_replay(&resp->xdr, op);
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index f4bb29d..30ec499 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -4581,15 +4581,28 @@ __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 respsize)
return nfserr_rep_too_big;
}

+/** Rewind the encoding to return nfserr_stale on the PUTFH
+ * in this failed Intra COPY compound
+ */
+void
+nfsd4_adjust_encode(struct nfsd4_compoundres *resp)
+{
+ __be32 *p;
+
+ p = resp->cstate.putfh_errp;
+ *p++ = nfserr_stale;
+}
+
void
nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
{
struct xdr_stream *xdr = &resp->xdr;
struct nfs4_stateowner *so = resp->cstate.replay_owner;
+ struct nfsd4_compound_state *cstate = &resp->cstate;
struct svc_rqst *rqstp = resp->rqstp;
int post_err_offset;
nfsd4_enc encoder;
- __be32 *p;
+ __be32 *p, *statp;

p = xdr_reserve_space(xdr, 8);
if (!p) {
@@ -4598,9 +4611,20 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
}
*p++ = cpu_to_be32(op->opnum);
post_err_offset = xdr->buf->len;
+ statp = p;

if (op->opnum == OP_ILLEGAL)
goto status;
+
+ /** This is a COPY compound with a stale source server file handle.
+ * If OP_COPY processing determines that this is an intra server to
+ * server COPY, then this PUTFH should return nfserr_ stale so the
+ * putfh_errp will be set to nfserr_stale. If this is an inter server
+ * to server COPY, ignore the nfserr_stale.
+ */
+ if (op->opnum == OP_PUTFH && HAS_CSTATE_FLAG(cstate, IS_STALE_FH))
+ cstate->putfh_errp = statp;
+
BUG_ON(op->opnum < 0 || op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) ||
!nfsd4_enc_ops[op->opnum]);
encoder = nfsd4_enc_ops[op->opnum];
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 9446849..341ff89 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -272,6 +272,8 @@ void nfsd_lockd_shutdown(void);
#define nfserr_replay_me cpu_to_be32(11001)
/* nfs41 replay detected */
#define nfserr_replay_cache cpu_to_be32(11002)
+/* nfs42 intra copy failed with nfserr_stale */
+#define nfserr_copy_stalefh cpu_to_be32(1103)

/* Check for dir entries '.' and '..' */
#define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.'))
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 38fcb4f..aa94295 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -45,6 +45,8 @@

#define CURRENT_STATE_ID_FLAG (1<<0)
#define SAVED_STATE_ID_FLAG (1<<1)
+#define NO_VERIFY_FH (1<<2)
+#define IS_STALE_FH (1<<3)

#define SET_CSTATE_FLAG(c, f) ((c)->sid_flags |= (f))
#define HAS_CSTATE_FLAG(c, f) ((c)->sid_flags & (f))
@@ -63,6 +65,7 @@ struct nfsd4_compound_state {
size_t iovlen;
u32 minorversion;
__be32 status;
+ __be32 *putfh_errp;
stateid_t current_stateid;
stateid_t save_stateid;
/* to indicate current and saved state id presents */
@@ -705,6 +708,7 @@ int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *,
int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *,
struct nfsd4_compoundres *);
__be32 nfsd4_check_resp_size(struct nfsd4_compoundres *, u32);
+void nfsd4_adjust_encode(struct nfsd4_compoundres *);
void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
void nfsd4_encode_replay(struct xdr_stream *xdr, struct nfsd4_op *op);
__be32 nfsd4_encode_fattr_to_buf(__be32 **p, int words,
--
1.8.3.1


2016-08-19 17:26:26

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version-2 11/12] NFSD add nfs4 inter ssc to nfsd4_copy

From: Andy Adamson <[email protected]>

Given a universal address, mount the source server from the destination
server. Use an internal mount. Call the NFS client nfs42_ssc_open to
obtain the NFS struct file suitable for nfsd_copy_range.

Add Kconfig dependencies for inter server to server copy

Signed-off-by: Andy Adamson <[email protected]>
---
fs/nfsd/Kconfig | 10 ++
fs/nfsd/nfs4proc.c | 272 +++++++++++++++++++++++++++++++++++++++++++++++++--
include/linux/nfs4.h | 4 +
3 files changed, 276 insertions(+), 10 deletions(-)

diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
index 47febcf..56c4943 100644
--- a/fs/nfsd/Kconfig
+++ b/fs/nfsd/Kconfig
@@ -130,6 +130,16 @@ config NFSD_FLEXFILELAYOUT

If unsure, say N.

+config NFSD_V4_2_INTER_SSC
+ bool "NFSv4.2 inter server to server COPY"
+ depends on NFSD_V4 && NFS_V4_1 && NFS_V4_2
+ help
+ This option enables support for NFSv4.2 inter server to
+ server copy where the destination server calls the NFSv4.2
+ client to read the data to copy from the source server.
+
+ If unsure, say N.
+
config NFSD_V4_SECURITY_LABEL
bool "Provide Security Label support for NFSv4 server"
depends on NFSD_V4 && SECURITY
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 8e9bae6..220db84 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1086,16 +1086,237 @@ out:
return status;
}

+#ifdef CONFIG_NFSD_V4_2_INTER_SSC
+
+#define NFSD42_INTERSSC_RAWDATA "minorversion=1,vers=4,addr=%s,clientaddr=%s"
+
+/**
+ * Support one copy source server for now.
+ */
+static struct nfs42_inter_ssc *
+nfsd4_interssc_connect(struct nl4_servers *nss, struct svc_rqst *rqstp)
+{
+ struct file_system_type *type;
+ struct nfs42_inter_ssc *isp;
+ struct nfs42_netaddr *naddr;
+ struct sockaddr_storage tmp_addr;
+ size_t tmp_addrlen, match_netid_len = 3;
+ char *startsep = "", *endsep = "", *match_netid = "tcp";
+ char *ipaddr, *ipaddr2, *raw_data;
+ int len, raw_len, status = -EINVAL;
+
+ /* Currently support for one NL4_NETADDR source server */
+ if (nss->nl_svr->nl4_type != NL4_NETADDR) {
+ WARN(nss->nl_svr->nl4_type != NL4_NETADDR,
+ "nfsd4_copy src server not NL4_NETADDR\n");
+ goto out_err;
+ }
+
+ naddr = &nss->nl_svr->u.nl4_addr;
+
+ tmp_addrlen = rpc_uaddr2sockaddr(SVC_NET(rqstp), naddr->na_uaddr,
+ naddr->na_uaddr_len,
+ (struct sockaddr *)&tmp_addr,
+ sizeof(tmp_addr));
+ if (tmp_addrlen == 0)
+ goto out_err;
+
+ if (tmp_addr.ss_family == AF_INET6) {
+ startsep = "[";
+ endsep = "]";
+ match_netid = "tcp6";
+ match_netid_len = 4;
+ }
+
+ if (naddr->na_netid_len != match_netid_len ||
+ strncmp(naddr->na_netid, match_netid, naddr->na_netid_len))
+ goto out_err;
+
+ /* Freed in nfsd4_interssc_disconnect */
+ status = -ENOMEM;
+ isp = kzalloc(sizeof(*isp), GFP_KERNEL);
+ if (unlikely(!isp))
+ goto out_err;
+
+ /* Construct the raw data for the vfs_kern_mount call */
+ len = RPC_MAX_ADDRBUFLEN + 1;
+ ipaddr = kzalloc(len, GFP_KERNEL);
+ if (!ipaddr)
+ goto out_free_isp;
+
+ rpc_ntop((struct sockaddr *)&tmp_addr, ipaddr, len);
+
+ /* 2 for ipv6 endsep and startsep. 3 for ":/" and trailing '/0'*/
+ ipaddr2 = kzalloc(len + 5, GFP_KERNEL);
+ if (!ipaddr2)
+ goto out_free_ipaddr;
+
+ rpc_ntop((struct sockaddr *)&rqstp->rq_daddr, ipaddr2, len + 5);
+
+ raw_len = strlen(NFSD42_INTERSSC_RAWDATA) + strlen(ipaddr) +
+ strlen(ipaddr2);
+ raw_data = kzalloc(raw_len, GFP_KERNEL);
+ if (!raw_data)
+ goto out_free_ipaddr2;
+
+ snprintf(raw_data, raw_len, NFSD42_INTERSSC_RAWDATA, ipaddr,
+ ipaddr2);
+
+ status = -ENODEV;
+ type = get_fs_type("nfs");
+ if (!type)
+ goto out_free_rawdata;
+
+ /* Set the server:<export> for the vfs_kerne_mount call */
+ memset(ipaddr2, 0, len + 5);
+ snprintf(ipaddr2, len + 5, "%s%s%s:/", startsep, ipaddr, endsep);
+
+ dprintk("%s Raw mount data: %s server:export %s\n", __func__,
+ raw_data, ipaddr2);
+
+ /* Use an 'internal' mount: MS_KERNMOUNT -> MNT_INTERNAL */
+ isp->sc_root_mnt = vfs_kern_mount(type, MS_KERNMOUNT, ipaddr2,
+ raw_data);
+ if (IS_ERR(isp->sc_root_mnt)) {
+ status = PTR_ERR(isp->sc_root_mnt);
+ goto out_free_rawdata;
+ }
+
+ isp->sc_mnt_dentry = isp->sc_root_mnt->mnt_root;
+
+ kfree(raw_data);
+ kfree(ipaddr2);
+ kfree(ipaddr);
+
+ return isp;
+
+out_free_rawdata:
+ kfree(raw_data);
+out_free_ipaddr2:
+ kfree(ipaddr2);
+out_free_ipaddr:
+ kfree(ipaddr);
+out_free_isp:
+ kfree(isp);
+out_err:
+ dprintk("--> %s ERROR %d\n", __func__, status);
+ return ERR_PTR(status);
+}
+
+static void
+nfsd4_interssc_disconnect(struct nfs42_inter_ssc *ssc)
+{
+ struct super_block *sb = ssc->sc_mnt_dentry->d_inode->i_sb;
+
+ mntput(ssc->sc_root_mnt);
+ deactivate_super(sb);
+
+ /* Allocated in nfsd4_interssc_connect */
+ kfree(ssc);
+}
+
+/**
+ * nfsd4_setup_inter_ssc
+ *
+ * Verify COPY destination stateid.
+ * Connect to the source server with NFSv4.1.
+ * Create the source struct file for nfsd_copy_range.
+ * Called with COPY cstate:
+ * SAVED_FH: source filehandle
+ * CURRENT_FH: destination filehandle
+ *
+ * Returns errno (not nfserrxxx)
+ */
+static struct nfs42_inter_ssc *
+nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
+ struct nfsd4_compound_state *cstate,
+ struct nfsd4_copy *copy, struct file **src,
+ struct file **dst)
+{
+ struct svc_fh *s_fh = NULL;
+ stateid_t *s_stid = &copy->cp_src_stateid;
+ struct nfs_fh fh;
+ nfs4_stateid stateid;
+ struct file *filp;
+ struct nfs42_inter_ssc *sclp;
+ __be32 status;
+
+ /* Verify the destination stateid and set dst struct file*/
+ status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
+ &copy->cp_dst_stateid,
+ WR_STATE, dst, NULL);
+ if (status) {
+ sclp = ERR_PTR(be32_to_cpu(status));
+ goto out;
+ }
+
+ /* Inter copy source fh is always stale */
+ CLEAR_CSTATE_FLAG(cstate, IS_STALE_FH);
+
+ sclp = nfsd4_interssc_connect(&copy->cp_src, rqstp);
+ if (IS_ERR(sclp))
+ goto out;
+
+ s_fh = &cstate->save_fh;
+
+ fh.size = s_fh->fh_handle.fh_size;
+ memcpy(fh.data, &s_fh->fh_handle.fh_base, fh.size);
+ stateid.seqid = s_stid->si_generation;
+ memcpy(stateid.other, (void *)&s_stid->si_opaque,
+ sizeof(stateid_opaque_t));
+
+ filp = nfs42_ssc_open(sclp, &fh, &stateid);
+ if (IS_ERR(filp)) {
+ nfsd4_interssc_disconnect(sclp);
+ return ERR_CAST(filp);
+ }
+ *src = filp;
+out:
+ return sclp;
+}
+
+static void
+nfsd4_cleanup_inter_ssc(struct nfs42_inter_ssc *sclp, struct file *src,
+ struct file *dst)
+{
+ /* "close" the src file. One dput for the READ */
+ dput(src->f_path.dentry);
+ src->f_op->release(src->f_inode, src);
+ fput(dst);
+
+ nfsd4_interssc_disconnect(sclp);
+
+}
+
+#else /* CONFIG_NFSD_V4_2_INTER_SSC */
+
+static struct nfs42_inter_ssc *
+nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
+ struct nfsd4_compound_state *cstate,
+ struct nfsd4_copy *copy, struct file **src,
+ struct file **dst)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+static void
+nfsd4_cleanup_inter_ssc(struct nfs42_inter_ssc *sclp, struct file *src,
+ struct file *dst)
+{
+}
+
+#endif /* CONFIG_NFSD_V4_2_INTER_SSC */
+
static __be32
-nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
- struct nfsd4_copy *copy)
+nfsd4_setup_intra_ssc(struct svc_rqst *rqstp,
+ struct nfsd4_compound_state *cstate,
+ struct nfsd4_copy *copy, struct file **src,
+ struct file **dst)
{
- 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);
+ status = nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid, src,
+ &copy->cp_dst_stateid, dst);
if (status)
goto out;

@@ -1103,7 +1324,37 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (HAS_CSTATE_FLAG(cstate, IS_STALE_FH)) {
CLEAR_CSTATE_FLAG(cstate, IS_STALE_FH);
cstate->status = nfserr_copy_stalefh;
- goto out_put;
+ }
+out:
+ return status;
+}
+
+static void
+nfsd4_cleanup_intra_ssc(struct file *src, struct file *dst)
+{
+ fput(src);
+ fput(dst);
+}
+
+static __be32
+nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_copy *copy)
+{
+ struct nfs42_inter_ssc *sclp = NULL;
+ struct file *src, *dst;
+ __be32 status;
+ ssize_t bytes;
+
+ if (copy->cp_src.nl_nsvr > 0) { /* Inter server SSC */
+ sclp = nfsd4_setup_inter_ssc(rqstp, cstate, copy, &src, &dst);
+ if (IS_ERR(sclp)) {
+ status = nfserrno(PTR_ERR(sclp));
+ goto out;
+ }
+ } else {
+ status = nfsd4_setup_intra_ssc(rqstp, cstate, copy, &src, &dst);
+ if (status)
+ goto out;
}

bytes = nfsd_copy_file_range(src, copy->cp_src_pos,
@@ -1120,9 +1371,10 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfs_ok;
}

-out_put:
- fput(src);
- fput(dst);
+ if (copy->cp_src.nl_nsvr > 0) /* Inter server SSC */
+ nfsd4_cleanup_inter_ssc(sclp, src, dst);
+ else
+ nfsd4_cleanup_intra_ssc(src, dst);
out:
return status;
}
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 3764885..4e61fae 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -15,6 +15,7 @@
#include <linux/list.h>
#include <linux/uidgid.h>
#include <uapi/linux/nfs4.h>
+#include <linux/nfs.h>
#include <linux/sunrpc/msg_prot.h>

enum nfs4_acl_whotype {
@@ -693,4 +694,7 @@ struct nl4_servers {
struct nl4_server *nl_svr;
};

+extern struct file *nfs42_ssc_open(struct nfs42_inter_ssc *ssc,
+ struct nfs_fh *src_fh, nfs4_stateid *stateid);
+
#endif
--
1.8.3.1


2016-08-19 17:26:26

by Andy Adamson

[permalink] [raw]
Subject: [PATCH Version-2 12/12] NFSD: extra stateid checking in read for interserver copy

From: Olga Kornievskaia <[email protected]>

Expand stateid structure to store a mark signifying this stateid is a COPY
stateid and special to pass stateid check on READ operation coming from
a different clientid.

In COPY_NOTIFY, mark the stateid stored under the clientid as 'special' by
setting boolean is_copy field to true.

If we received a READ and check for the stateid fails, we need to look
for the stateid under all other clientid structures and their corresponding
stateid lists. Make sure the stateid was previously marked for use READ
from a COPY operation.

Signed-off-by: Olga Kornievskaia <[email protected]>
---
fs/nfsd/nfs4proc.c | 15 ++++++++++++++-
fs/nfsd/nfs4state.c | 40 +++++++++++++++++++++++++++++++++-------
fs/nfsd/state.h | 8 ++++++++
3 files changed, 55 insertions(+), 8 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 220db84..7c4895e 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -1427,6 +1427,7 @@ nfsd4_copy_notify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfs42_netaddr *naddr;
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
struct nl4_server *ns;
+ struct nfs4_stid *stid = NULL;

status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
&cn->cpn_src_stateid, RD_STATE, &src,
@@ -1440,7 +1441,19 @@ nfsd4_copy_notify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
* connections from the destination e.g. what is returned in cpn_src,
* to verify READ from dest server.
*/
-
+ /* mark the original open stateid special */
+ status = nfserr_bad_stateid;
+ stid = find_stateid_by_type(cstate->session->se_client,
+ &cn->cpn_src_stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|
+ NFS4_LOCK_STID);
+ if (stid) {
+ /* cnp_src_stateid is used for reply cnr_stateid */
+ stid->is_copy = 1;
+ nfs4_put_stid(stid);
+ } else {
+ dprintk("NFSD: %s can't find cpn_src_stateid\n", __func__);
+ goto out;
+ }
/**
* For now, only return one server address in cpn_src, the
* address used by the client to connect to this server.
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 003f624..5469e32 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1890,12 +1890,6 @@ same_verf(nfs4_verifier *v1, nfs4_verifier *v2)
return 0 == memcmp(v1->data, v2->data, sizeof(v1->data));
}

-static int
-same_clid(clientid_t *cl1, clientid_t *cl2)
-{
- return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id);
-}
-
static bool groups_equal(struct group_info *g1, struct group_info *g2)
{
int i;
@@ -2000,7 +1994,7 @@ find_stateid_locked(struct nfs4_client *cl, stateid_t *t)
return ret;
}

-static struct nfs4_stid *
+struct nfs4_stid *
find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask)
{
struct nfs4_stid *s;
@@ -4824,6 +4818,36 @@ nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s,
return 0;
}

+/**
+ * If lookup for the stateid fails, we need to look for the stateid under
+ * all other clientid structures and their corresponding stateid lists.
+ * Make sure the stateid was previously marked for use from a COPY operation.
+ */
+static __be32
+nfs4_find_copy_stateid(stateid_t *stateid, struct nfs4_stid **spp,
+ struct nfsd_net *nn)
+{
+ struct nfs4_client *clp = NULL;
+ struct nfs4_stid *s = NULL;
+ __be32 status = nfserr_bad_stateid;
+
+ spin_lock(&nn->client_lock);
+ list_for_each_entry(clp, &nn->client_lru, cl_lru) {
+ if (same_clid(&clp->cl_clientid, &stateid->si_opaque.so_clid)) {
+ s = find_stateid_by_type(clp, stateid,
+ NFS4_DELEG_STID|NFS4_OPEN_STID|
+ NFS4_LOCK_STID);
+ if (s && s->is_copy)
+ dprintk("%s found COPY stateid\n", __func__);
+ *spp = s;
+ status = nfs_ok;
+ break;
+ }
+ }
+ spin_unlock(&nn->client_lock);
+ return status;
+}
+
/*
* Checks for stateid operations
*/
@@ -4854,6 +4878,8 @@ nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
status = nfsd4_lookup_stateid(cstate, stateid,
NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID,
&s, nn);
+ if (status == nfserr_bad_stateid)
+ status = nfs4_find_copy_stateid(stateid, &s, nn);
if (status)
return status;
status = check_stateid_generation(stateid, &s->sc_stateid,
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index b95adf9..6a97aab 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -94,6 +94,7 @@ struct nfs4_stid {
#define NFS4_REVOKED_DELEG_STID 16
#define NFS4_CLOSED_DELEG_STID 32
#define NFS4_LAYOUT_STID 64
+ bool is_copy;
unsigned char sc_type;
stateid_t sc_stateid;
spinlock_t sc_lock;
@@ -583,6 +584,13 @@ static inline bool nfsd4_stateid_generation_after(stateid_t *a, stateid_t *b)
struct nfsd4_compound_state;
struct nfsd_net;

+static inline int same_clid(clientid_t *cl1, clientid_t *cl2)
+{
+ return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id);
+}
+
+extern struct nfs4_stid *find_stateid_by_type(struct nfs4_client *cl,
+ stateid_t *t, char typemask);
extern __be32 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
struct nfsd4_compound_state *cstate, struct svc_fh *fhp,
stateid_t *stateid, int flags, struct file **filp, bool *tmp_file);
--
1.8.3.1


2016-08-19 21:08:58

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH Version-2 03/12] VFS permit cross device vfs_copy_file_range

I thought I remembered Christoph (cc'd) arguing at the 2015 lsf/mm that
there were some more issues that would need to be taken care of before
we could turn on cross-device copies.

But maybe I misremember. In any case, I don't remember what the issues
were....

--b.

On Fri, Aug 19, 2016 at 01:25:03PM -0400, [email protected] wrote:
> From: Andy Adamson <[email protected]>
>
> NFSv4.2 inter server to server copy always copies across devices.
>
> Note: both btrfs and nfs have EXDEV checks in their
> copy_file_range functions.
>
> Signed-off-by: Andy Adamson <[email protected]>
> ---
> fs/read_write.c | 5 -----
> 1 file changed, 5 deletions(-)
>
> diff --git a/fs/read_write.c b/fs/read_write.c
> index 1cbab4e..a6d3350 100644
> --- a/fs/read_write.c
> +++ b/fs/read_write.c
> @@ -1483,7 +1483,6 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
> size_t len, unsigned int flags)
> {
> struct inode *inode_in = file_inode(file_in);
> - struct inode *inode_out = file_inode(file_out);
> ssize_t ret;
>
> if (flags != 0)
> @@ -1505,10 +1504,6 @@ ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
> (file_out->f_flags & O_APPEND))
> return -EBADF;
>
> - /* this could be relaxed once a method supports cross-fs copies */
> - if (inode_in->i_sb != inode_out->i_sb)
> - return -EXDEV;
> -
> if (len == 0)
> return 0;
>
> --
> 1.8.3.1

2016-08-19 21:11:44

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH Version-2 04/12] NFS inter ssc open

On Fri, Aug 19, 2016 at 01:25:04PM -0400, [email protected] wrote:
> +struct nfs42_inter_ssc {
> + struct vfsmount *sc_root_mnt;
> + struct dentry *sc_mnt_dentry;
> +};

That's just reinventing struct path.

--b.

2016-08-19 21:26:03

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH Version-2 00/12] NFSv4.2 inter server to server copy

I may not be able to review this carefully for a while.

Some general questions:

- how are you testing this?
- have you done any performance testing, and if so do you seem
to be getting expected bandwidth on the server-to-server copy?
- is there wireshark support for the client-to-server and
server-to-server protocol?
- how is the source server authorizing the copy? Is GSSv3 still
needed for this eventually?

--b.

On Fri, Aug 19, 2016 at 01:25:00PM -0400, [email protected] wrote:
> From: Andy Adamson <[email protected]>
>
>
> Anna's patches applied first:
> The first patch is a bug fix from Anna for the upstream Intra
> server to server copy.
>
> The second patch has been submitted upstream, and is being
> reviewed by Bruce Fields.
>
> The rest of the patches implement NFSv4.2 Intra-SSC
>
>
> Andy Adamson (9):
> VFS permit cross device vfs_copy_file_range
> NFS inter ssc open
> NFS add COPY_NOTIFY operation
> NFS add ca_source_server<> to COPY
> NFSD add ca_source_server<> to COPY
> NFSD add COPY_NOTIFY operation
> NFSD generalize nfsd4_compound_state flag names
> NFSD: allow inter server COPY to have a STALE source server fh
> NFSD add nfs4 inter ssc to nfsd4_copy
>
> Anna Schumaker (2):
> fs: Don't copy beyond the end of the file
> NFSD: Implement the COPY call
>
> Olga Kornievskaia (1):
> NFSD: extra stateid checking in read for interserver copy
>
> fs/nfs/internal.h | 10 +
> fs/nfs/nfs42.h | 7 +-
> fs/nfs/nfs42proc.c | 128 ++++++++++-
> fs/nfs/nfs42xdr.c | 205 +++++++++++++++++-
> fs/nfs/nfs4_fs.h | 8 +
> fs/nfs/nfs4file.c | 135 +++++++++++-
> fs/nfs/nfs4proc.c | 6 +-
> fs/nfs/nfs4state.c | 2 +-
> fs/nfs/nfs4xdr.c | 1 +
> fs/nfsd/Kconfig | 10 +
> fs/nfsd/nfs4proc.c | 527 ++++++++++++++++++++++++++++++++++++++++++++--
> fs/nfsd/nfs4state.c | 47 ++++-
> fs/nfsd/nfs4xdr.c | 272 +++++++++++++++++++++++-
> fs/nfsd/nfsd.h | 2 +
> fs/nfsd/state.h | 8 +
> fs/nfsd/vfs.c | 6 +
> fs/nfsd/vfs.h | 2 +
> fs/nfsd/xdr4.h | 50 ++++-
> fs/read_write.c | 8 +-
> include/linux/nfs4.h | 43 ++++
> include/linux/nfs_fs_sb.h | 1 +
> include/linux/nfs_xdr.h | 20 ++
> 22 files changed, 1443 insertions(+), 55 deletions(-)
>
> --
> 1.8.3.1

2016-08-20 06:18:35

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH Version-2 03/12] VFS permit cross device vfs_copy_file_range

On Fri, Aug 19, 2016 at 05:08:44PM -0400, J. Bruce Fields wrote:
> I thought I remembered Christoph (cc'd) arguing at the 2015 lsf/mm that
> there were some more issues that would need to be taken care of before
> we could turn on cross-device copies.

Yes. Noi other VFS operation is supported between mountpoint, so
copy_file_range shouldn't be either.

Also a general NAK to any new copy_file_range work before we have
proper xfstests coverage. And it's not like the coverage is hard,
we already have 100s of tests for clone, which in many way is very
similar and could be partially reused.

2016-08-20 06:19:19

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH Version-2 01/12] fs: Don't copy beyond the end of the file

On Fri, Aug 19, 2016 at 01:25:01PM -0400, [email protected] wrote:
> From: Anna Schumaker <[email protected]>
>
> Signed-off-by: Anna Schumaker <[email protected]>
> ---
> fs/read_write.c | 3 +++

Please also send a regression test for this and add it to xfstests,
thanks.

2016-08-22 19:27:15

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH Version-2 03/12] VFS permit cross device vfs_copy_file_range

On Sat, Aug 20, 2016 at 08:18:33AM +0200, Christoph Hellwig wrote:
> On Fri, Aug 19, 2016 at 05:08:44PM -0400, J. Bruce Fields wrote:
> > I thought I remembered Christoph (cc'd) arguing at the 2015 lsf/mm that
> > there were some more issues that would need to be taken care of before
> > we could turn on cross-device copies.
>
> Yes. Noi other VFS operation is supported between mountpoint, so
> copy_file_range shouldn't be either.

Is there anything specific it would break?

> Also a general NAK to any new copy_file_range work before we have
> proper xfstests coverage. And it's not like the coverage is hard,
> we already have 100s of tests for clone, which in many way is very
> similar and could be partially reused.

Sounds like a reasonable request.

--b.

2016-08-24 18:43:22

by Adamson, Andy

[permalink] [raw]
Subject: Re: [PATCH Version-2 03/12] VFS permit cross device vfs_copy_file_range

DQo+IE9uIEF1ZyAyMCwgMjAxNiwgYXQgMjoxOCBBTSwgQ2hyaXN0b3BoIEhlbGx3aWcgPGhjaEBs
c3QuZGU+IHdyb3RlOg0KPiANCj4gT24gRnJpLCBBdWcgMTksIDIwMTYgYXQgMDU6MDg6NDRQTSAt
MDQwMCwgSi4gQnJ1Y2UgRmllbGRzIHdyb3RlOg0KPj4gSSB0aG91Z2h0IEkgcmVtZW1iZXJlZCBD
aHJpc3RvcGggKGNjJ2QpIGFyZ3VpbmcgYXQgdGhlIDIwMTUgbHNmL21tIHRoYXQNCj4+IHRoZXJl
IHdlcmUgc29tZSBtb3JlIGlzc3VlcyB0aGF0IHdvdWxkIG5lZWQgdG8gYmUgdGFrZW4gY2FyZSBv
ZiBiZWZvcmUNCj4+IHdlIGNvdWxkIHR1cm4gb24gY3Jvc3MtZGV2aWNlIGNvcGllcy4NCj4gDQo+
IFllcy4gIE5vaSBvdGhlciBWRlMgb3BlcmF0aW9uIGlzIHN1cHBvcnRlZCBiZXR3ZWVuIG1vdW50
cG9pbnQsIHNvDQo+IGNvcHlfZmlsZV9yYW5nZSBzaG91bGRuJ3QgYmUgZWl0aGVyLg0KDQpIaSBD
aHJpc3RvcGgNCg0KQXMgeW91IGtub3cgKGJlY2F1c2UgeW91IHJldmlld2VkIHRoZSBwYXRjaCks
IHRoZSBvcmlnaW5hbCBpbnRlbnQgb2YgdnNfY29weV9maWxlX3JhbmdlIGFzIHN0YXRlZCBpbiB0
aGUgc3lzY2FsbCBzdWJtaXNzaW9uIGZyb20gWmFjaCBCcm93biAoY29tbWl0OiA4ODRhMTJhNTk3
MmZjODY3YTkzZjdhZGY3YThhYzJhZGU1ZDM4ZmZmICkgaXMgdG8gYWxsb3cgY29waWVzIGJldHdl
ZW4gZmlsZSBzeXN0ZW1zIOKAnG9uY2Ugd2UgZ2V0IGltcGxlbWVudGF0aW9ucyB3aGljaCBjb3B5
IGJldHdlZW4gdGlsZSBzeXN0ZW1zIHNhZmVseeKAnQ0KDQpORlN2NCBpbnRlciBzZXJ2ZXIgdG8g
c2VydmVyIGNvcHkgd2lsbCBwcm92aWRlIGFuIGltcGxlbWVudGF0aW9uIHdoaWNoIGNhbiBjb3B5
IGJldHdlZW4gdGlsZSBzeXN0ZW1zIHNhZmVseSAtIHNvIEkgZG9u4oCZdCB1bmRlcnN0YW5kIHlv
dXIgb2JqZWN0aW9uIHRvIHRoaXMgZXZlbnR1YWwgdXNlIG9mIHZmc19jb3B5X2ZpbGVfcmFuZ2Uu
DQoNCj4gDQo+IEFsc28gYSBnZW5lcmFsIE5BSyB0byBhbnkgbmV3IGNvcHlfZmlsZV9yYW5nZSB3
b3JrIGJlZm9yZSB3ZSBoYXZlDQo+IHByb3BlciB4ZnN0ZXN0cyBjb3ZlcmFnZS4gIEFuZCBpdCdz
IG5vdCBsaWtlIHRoZSBjb3ZlcmFnZSBpcyBoYXJkLA0KPiB3ZSBhbHJlYWR5IGhhdmUgMTAwcyBv
ZiB0ZXN0cyBmb3IgY2xvbmUsIHdoaWNoIGluIG1hbnkgd2F5IGlzIHZlcnkNCj4gc2ltaWxhciBh
bmQgY291bGQgYmUgcGFydGlhbGx5IHJldXNlZC4NCg0KWWVzIC0gYWdyZWVkLiBBbm5hIGlzIHdv
cmtpbmcgb24gdXBkYXRlZCB4ZnN0ZXN0cyBmb3IgTkZTdjQgaW50cmEgc2VydmVyIHRvIHNlcnZl
ciBjb3B5IGFzIHdlbGwgYXMgZXhwYW5kaW5nIHRoZSB4ZnN0ZXN0cyBmb3Igb3RoZXIgdmZzX2Nv
cHlfZmlsZV9yYW5nZSBmZWF0dXJlcy4gV2UgY2FuIGxvb2sgYXQgZXhwYW5kaW5nIHRoZSB0ZXN0
cyBmb3IgdGhlIGludGVyIHNlcnZlciB0byBzZXJ2ZXIgY2FzZS4gIEpvcmdlIE1vcmEgYXV0aG9y
IG9mIE5GU1Rlc3RzIGlzIGFsc28gd29ya2luZyBvbiBhIHRlc3Qgc3VpdGUgZm9yIGludGVyIHNl
cnZlciB0byBzZXJ2ZXIgY29weS4gDQoNCg==