Hi Olga, On Mon, 2019-07-08 at 15:24 -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. I'm curious if you've had a look at any of the open-by-filehandle code in fs/fhandle.c? I know none of it is exported right now, but if it can be reused then it would capture whatever filesystem notifications stuff needs to happen at the same time. Anna > > Signed-off-by: Olga Kornievskaia <kolga@xxxxxxxxxx> > Signed-off-by: Andy Adamson <andros@xxxxxxxxxx> > --- > fs/nfs/nfs4_fs.h | 7 ++++ > fs/nfs/nfs4file.c | 94 > +++++++++++++++++++++++++++++++++++++++++++++++ > fs/nfs/nfs4proc.c | 5 +-- > 3 files changed, 103 insertions(+), 3 deletions(-) > > diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h > index d75fea7ecf12..ff1cd600f07f 100644 > --- a/fs/nfs/nfs4_fs.h > +++ b/fs/nfs/nfs4_fs.h > @@ -311,6 +311,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 b9825d02443e..aab4d48764a7 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" > @@ -282,6 +283,99 @@ static loff_t nfs42_remap_file_range(struct file > *src_file, loff_t src_off, > out: > return ret < 0 ? ret : count; > } > + > +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++); > + > + 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: > + 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 9bbd9bad5412..c898ce1bccc6 100644 > --- a/fs/nfs/nfs4proc.c > +++ b/fs/nfs/nfs4proc.c > @@ -91,7 +91,6 @@ struct nfs4_opendata; > 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, const struct cred > *cred, > struct nfs_fattr *fattr, struct iattr > *sattr, > @@ -1674,7 +1673,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) > @@ -3966,7 +3965,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) > {