Hi Olga, On Fri, 2018-10-19 at 11:29 -0400, Olga Kornievskaia wrote: > From: Olga Kornievskaia <kolga@xxxxxxxxxx> > > 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 <andros@xxxxxxxxxx> > Signed-off-by: Olga Kornievskaia <kolga@xxxxxxxxxx> > --- > fs/nfs/nfs4_fs.h | 7 ++++ > fs/nfs/nfs4file.c | 98 > +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > fs/nfs/nfs4proc.c | 5 ++- > 3 files changed, 107 insertions(+), 3 deletions(-) > > diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h > index 8d59c96..f229864 100644 > --- a/fs/nfs/nfs4_fs.h > +++ b/fs/nfs/nfs4_fs.h > @@ -307,6 +307,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, > + struct inode *inode); > +extern int update_open_stateid(struct nfs4_state *state, > + const nfs4_stateid *open_stateid, > + const nfs4_stateid *deleg_stateid, > + fmode_t fmode); > > #if defined(CONFIG_NFS_V4_1) > extern int nfs41_sequence_done(struct rpc_task *, struct nfs4_sequence_res > *); > diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c > index 005862e..7f226f4 100644 > --- a/fs/nfs/nfs4file.c > +++ b/fs/nfs/nfs4file.c > @@ -8,6 +8,7 @@ > #include <linux/file.h> > #include <linux/falloc.h> > #include <linux/nfs_fs.h> > +#include <linux/file.h> > #include "delegation.h" > #include "internal.h" > #include "iostat.h" > @@ -264,6 +265,103 @@ static int nfs42_clone_file_range(struct file *src_file, > loff_t src_off, > out: > return ret; > } > + > +static int read_name_gen = 1; > +#define SSC_READ_NAME_BODY "ssc_read_%d" > + > +struct file * > +nfs42_ssc_open(struct vfsmount *ss_mnt, struct nfs_fh *src_fh, > + nfs4_stateid *stateid) > +{ > + struct nfs_fattr fattr; > + 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(ss_mnt->mnt_root->d_inode); > + > + nfs_fattr_init(&fattr); > + > + status = nfs4_proc_getattr(server, src_fh, &fattr, NULL, 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); Does this dprintk() need to be here? I'm wondering if it would work better as a tracepoint (or if it should just be removed altogether). Thanks, Anna > + > + r_ino = nfs_fhget(ss_mnt->mnt_root->d_inode->i_sb, src_fh, &fattr, > + NULL); > + if (IS_ERR(r_ino)) { > + res = ERR_CAST(r_ino); > + goto out; > + } > + > + filep = alloc_file_pseudo(r_ino, ss_mnt, read_name, FMODE_READ, > + r_ino->i_fop); > + if (IS_ERR(filep)) { > + res = ERR_CAST(filep); > + goto out; > + } > + filep->f_mode |= FMODE_READ; > + > + ctx = alloc_nfs_open_context(filep->f_path.dentry, filep->f_mode, > + filep); > + 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; > + > + set_bit(NFS_OPEN_STATE, &ctx->state->flags); > + memcpy(&ctx->state->open_stateid.other, &stateid->other, > + NFS4_STATEID_OTHER_SIZE); > + update_open_stateid(ctx->state, stateid, NULL, filep->f_mode); > + > + nfs_file_set_open_context(filep, ctx); > + put_nfs_open_context(ctx); > + > + file_ra_state_init(&filep->f_ra, filep->f_mapping->host->i_mapping); > + 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); > + goto out; > +} > +EXPORT_SYMBOL_GPL(nfs42_ssc_open); > +void nfs42_ssc_close(struct file *filep) > +{ > + struct nfs_open_context *ctx = nfs_file_open_context(filep); > + > + ctx->state->flags = 0; > +} > +EXPORT_SYMBOL_GPL(nfs42_ssc_close); > #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 fec6e6b..e5178b2f 100644 > --- a/fs/nfs/nfs4proc.c > +++ b/fs/nfs/nfs4proc.c > @@ -91,7 +91,6 @@ > 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, struct inode *inode); > static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh > *fhandle, struct nfs_fattr *fattr, struct nfs4_label *label, struct inode > *inode); > static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, > struct nfs_fattr *fattr, struct iattr *sattr, > @@ -1653,7 +1652,7 @@ static void nfs_state_clear_delegation(struct nfs4_state > *state) > write_sequnlock(&state->seqlock); > } > > -static int update_open_stateid(struct nfs4_state *state, > +int update_open_stateid(struct nfs4_state *state, > const nfs4_stateid *open_stateid, > const nfs4_stateid *delegation, > fmode_t fmode) > @@ -3936,7 +3935,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 inode *inode) > {