NFSD support for "inter" server-to-server COPY
Subsystems (2)
v4 cover NFSD support for "inter" server-to-server COPY
This depends on the async NFSD series and it depends on the client's inter copy series that provide nfs4_ssc_open/close functions and reboot recovery support for the destination server.
NFSD determines if COPY is intra or inter and if sync or async. For inter, NSFD uses NFSv4.1 protocol and creates an internal mount point (superblock). It will destroy the mount point when copy is done.
On the source server, upon receiving a COPY_NOTIFY, it generate a unique stateid that's kept in the global list. Upon receiving a READ with a stateid, the code checks the normal list of open stateid and now additionally, it'll check the copy state list as well before deciding to either fail with BAD_STATEID or find one that matches. The stored stateid is only valid to be used for the first time with a choosen lease period (90s currently). When the source server received an OFFLOAD_CANCEL, it will remove the stateid from the global list. Otherwise, the copy stateid is removed upon the removal of its "parent" stateid (open/lock/delegation stateid).
v4:
* Don't have the IS_STALE_FH in the compount state structure. Instead mark the filehandle FOREIGN. If the server gets a PUTFH,SAVEFH,PUTFH... COPY compount then it'll allow for the PUTFH to be STALE (foreign) handle. It
* This series has Bruce's proposed "nfsd: remove unnecessary nofilehandle checks" patch as I didn't see it committed yet.
* dropped the support for multiple server netaddrs in the COPY_NOTIFY/ COPY
* made sure to return OFFLOAD_DENIED when mount to the source server fails which triggers the client to fallback on the traditional copy.
Andy Adamson (1):
NFSD generalize nfsd4_compound_state flag names
Olga Kornievskaia (7):
NFSD fill-in netloc4 structure
NFSD add ca_source_server<> to COPY
NFSD add COPY_NOTIFY operation
NFSD check stateids against copy stateids
nfsd: remove unnecessary nofilehandle checks
NFSD: allow inter server COPY to have a STALE source server fh NFSD add nfs4 inter ssc to nfsd4_copy
fs/nfsd/Kconfig | 10 ++ fs/nfsd/nfs4proc.c | 427 ++++++++++++++++++++++++++++++++++++++++++++++----- fs/nfsd/nfs4state.c | 37 ++++- fs/nfsd/nfs4xdr.c | 168 +++++++++++++++++++- fs/nfsd/nfsd.h | 31 +++- fs/nfsd/nfsfh.h | 5 +- fs/nfsd/state.h | 5 +- fs/nfsd/xdr4.h | 25 ++- include/linux/nfs4.h | 1 + 9 files changed, 657 insertions(+), 52 deletions(-)
Signature · 1 line
1.8.3.1
PATCH v4 1/8 NFSD fill-in netloc4 structure
nfs.4 defines nfs42_netaddr structure that represents netloc4.
Populate needed fields from the sockaddr structure.
This will be used by flexfiles and 4.2 inter copy
--- fs/nfsd/nfsd.h | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-)
fs/nfsd/nfsd.h +30 -1
@@ -17,7 +17,7 @@#include <linux/nfs4.h> #include <linux/sunrpc/svc.h> #include <linux/sunrpc/msg_prot.h> - +#include <linux/sunrpc/addr.h> #include <uapi/linux/nfsd/debug.h> #include "stats.h"
@@ -364,6 +364,35 @@ static inline bool nfsd4_spo_must_allow(struct svc_rqst *rqstp)extern const u32 nfsd_suppattrs[3 ][3 ]; +static inline u32 nfsd4_set_netaddr (struct sockaddr *addr,struct nfs42_netaddr *netaddr) +{ +struct sockaddr_in *sin = (struct sockaddr_in *)addr; +struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; +unsigned int port; +size_t ret; + +switch (addr->sa_family) { +case AF_INET : + port =ntohs (sin->sin_port); +sprintf (netaddr->netid,"tcp" ); + netaddr->netid_len =3 ; +break ; +case AF_INET6 : + port =ntohs (sin6->sin6_port); +sprintf (netaddr->netid,"tcp6" ); + netaddr->netid_len =4 ; +break ; +default : +return nfserrno (-EINVAL ); + } + ret =rpc_ntop (addr, netaddr->addr,sizeof (netaddr->addr)); + netaddr->addr_len = ret +snprintf (netaddr->addr + ret, +RPCBIND_MAXUADDRLEN +1 , +".%u.%u" , port >>8 , port &0xff ); + +return 0 ; +} +static inline bool bmval_is_subset (const u32 *bm1,const u32 *bm2) { return !((bm1[0] & ~bm2[0]) ||
Signature · 1 line
1.8.3.1
PATCH v4 2/8 NFSD add ca_source_server<> to COPY
In reply to Olga KornievskaiaNote: followed conventions and have struct nfsd4_compoundargs pointer as a parameter even though it is unused.
--- fs/nfsd/nfs4xdr.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- fs/nfsd/xdr4.h | 1 + 2 files changed, 70 insertions(+), 2 deletions(-)
fs/nfsd/nfs4xdr.c +69 -2
@@ -41,6 +41,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"
@@ -1743,11 +1744,58 @@ static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, strDECODE_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->netid_len =be32_to_cpup (p++); +if (naddr->netid_len >RPCBIND_MAXNETIDLEN ) + goto xdr_error; + +READ_BUF (naddr->netid_len +4 );/* 4 for uaddr len */ +COPYMEM (naddr->netid, naddr->netid_len); + + naddr->addr_len =be32_to_cpup (p++); +if (naddr->addr_len >RPCBIND_MAXUADDRLEN ) + goto xdr_error; + +READ_BUF (naddr->addr_len); +COPYMEM (naddr->addr, naddr->addr_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, count; status =nfsd4_decode_stateid (argp, ©->cp_src_stateid);if (status)
@@ -1762,8 +1810,24 @@ static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, str p =xdr_decode_hyper (p, ©->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 */ + count =be32_to_cpup (p++); + +if (count ==0 )/* intra-server copy */ + goto intra; +/* decode all the supplied server addresses but use first */ + copy->cp_src =kmalloc (count *sizeof (struct nl4_server ),GFP_KERNEL ); +if (copy->cp_src ==NULL ) +return nfserrno (-ENOMEM ); + + ns = copy->cp_src; +for (i =0 ; i < count; i++) { + status =nfsd4_decode_nl4_server (argp, ns); +if (status) +return status; + ns++; + } +intra:DECODE_TAIL ; }
@@ -4232,6 +4296,9 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, p =xdr_reserve_space (&resp->xdr,4 +4 ); *p++ =cpu_to_be32 (copy->cp_consecutive); *p++ =cpu_to_be32 (copy->cp_synchronous); + +/* allocated in nfsd4_decode_copy */ +kfree (copy->cp_src);return 0 ; }
fs/nfsd/xdr4.h +1 -0
@@ -517,6 +517,7 @@ struct nfsd4_copy {u64 cp_src_pos;u64 cp_dst_pos;u64 cp_count; +struct nl4_server *cp_src;/* both */ bool cp_consecutive;
Signature · 1 line
1.8.3.1
PATCH v4 3/8 NFSD add COPY_NOTIFY operation
In reply to Olga KornievskaiaIntroducing the COPY_NOTIFY operation.
Create a new unique stateid that will keep track of the copy state and the upcoming READs that will use that stateid. Keep it in the list associated with parent stateid.
Return single netaddr to advertise to the copy.
--- fs/nfsd/nfs4proc.c | 63 +++++++++++++++++++++++++++++++++- fs/nfsd/nfs4state.c | 3 ++ fs/nfsd/nfs4xdr.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++-- fs/nfsd/state.h | 5 ++- fs/nfsd/xdr4.h | 13 +++++++ 5 files changed, 177 insertions(+), 4 deletions(-)
fs/nfsd/nfs4proc.c +62 -1
@@ -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"
@@ -1263,7 +1264,8 @@ static void nfsd4_do_async_copy(struct work_struct *work) status =nfserrno (-ENOMEM ); goto out; } - copy->cps =nfs4_alloc_init_cp_state (nn, copy->stid); + copy->cps =nfs4_alloc_init_cp_state (nn, nn->nfsd4_lease, + copy->stid);if (!copy->cps) { status =nfserrno (-ENOMEM );kfree (async_copy);
@@ -1306,6 +1308,44 @@ static void nfsd4_do_async_copy(struct work_struct *work) }static __be32 +nfsd4_copy_notify (struct svc_rqst *rqstp,struct nfsd4_compound_state *cstate, +union nfsd4_op_u *u) +{ +struct nfsd4_copy_notify *cn = &u->copy_notify; +__be32 status; +struct nfsd_net *nn =net_generic (SVC_NET (rqstp), nfsd_net_id); +struct nfs4_stid *stid; +struct nfs4_cp_state *cps; + + status =nfs4_preprocess_stateid_op (rqstp, cstate, &cstate->current_fh, + &cn->cpn_src_stateid,RD_STATE ,NULL , +NULL , &stid); +if (status) +return status; + + cn->cpn_sec = nn->nfsd4_lease; + cn->cpn_nsec =0 ; + + status =nfserrno (-ENOMEM ); + cps =nfs4_alloc_init_cp_state (nn, nn->nfsd4_lease, stid); +if (!cps) +return status; +memcpy (&cn->cpn_cnr_stateid, &cps->cp_stateid,sizeof (stateid_t)); + +/** +* For now, only return one server address in cpn_src, the +* address used by the client to connect to this server. +*/ + cn->cpn_src.nl4_type =NL4_NETADDR ; + status =nfsd4_set_netaddr ((struct sockaddr *)&rqstp->rq_daddr, + &cn->cpn_src.u.nl4_addr); +if (status !=0 ) +nfs4_free_cp_state (cps); + +return status; +} + +static __be32 nfsd4_fallocate (struct svc_rqst *rqstp,struct nfsd4_compound_state *cstate,struct nfsd4_fallocate *fallocate,int flags) {
@@ -2251,6 +2291,21 @@ static inline u32 nfsd4_offload_status_rsize(struct svc_rqst *rqstp, 1 /* osr_complete<1> optional 0 for now */) * 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 static inline u32 nfsd4_getdeviceinfo_rsize (struct svc_rqst *rqstp,struct nfsd4_op *op) {
@@ -2674,6 +2729,12 @@ static inline u32 nfsd4_seek_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) .op_name = "OP_OFFLOAD_CANCEL", .op_rsize_bop = nfsd4_only_status_rsize, }, + [OP_COPY_NOTIFY] = { + .op_func = nfsd4_copy_notify, + .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME, + .op_name = "OP_COPY_NOTIFY", + .op_rsize_bop = nfsd4_copy_notify_rsize, + }, };/**
fs/nfsd/nfs4state.c +3 -0
@@ -681,6 +681,7 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *sla* the source file. */ struct nfs4_cp_state *nfs4_alloc_init_cp_state (struct nfsd_net *nn, +u64 cpn_sec,struct nfs4_stid *p_stid) {struct nfs4_cp_state *cps;
@@ -700,6 +701,8 @@ struct nfs4_cp_state *nfs4_alloc_init_cp_state(struct nfsd_net *nn, cps->cp_stateid.si_opaque.so_clid.cl_boot = nn->boot_time; cps->cp_stateid.si_opaque.so_clid.cl_id = nn->s2s_cp_cl_id; cps->cp_p_stid = p_stid; + cps->cp_active = false; + cps->cp_timeout = jiffies + (cpn_sec *HZ );INIT_LIST_HEAD (&cps->cp_list);list_add (&cps->cp_list, &p_stid->sc_cp_list);
fs/nfsd/nfs4xdr.c +95 -2
127 lines not on this page · raw message
fs/nfsd/state.h +4 -1
@@ -114,6 +114,8 @@ struct nfs4_cp_state {bool cp_cancelled;/* copy cancelled */ spinlock_t cp_lock;ssize_t cp_bytes_copied;/* copy progress */ +bool cp_active;/* has the copy started */ +unsigned long cp_timeout;/* copy timeout */ };/*
@@ -623,7 +625,8 @@ __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, struct nfs4_stid **s, struct nfsd_net *nn);struct nfs4_stid *nfs4_alloc_stid (struct nfs4_client *cl,struct kmem_cache *slab,void (*sc_free)(struct nfs4_stid *)); -struct nfs4_cp_state *nfs4_alloc_init_cp_state (struct nfsd_net *nn,struct nfs4_stid *p_stid); +struct nfs4_cp_state *nfs4_alloc_init_cp_state (struct nfsd_net *nn,u64 cpn_sec, +struct nfs4_stid *p_stid);void nfs4_free_cp_state (struct nfs4_cp_state *cps);void nfs4_unhash_stid (struct nfs4_stid *s);void nfs4_put_stid (struct nfs4_stid *s);
fs/nfsd/xdr4.h +13 -0
@@ -561,6 +561,18 @@ struct nfsd4_offload_status {u32 status; }; +struct nfsd4_copy_notify { +/* request */ +stateid_t cpn_src_stateid; +struct nl4_server cpn_dst; + +/* response */ +stateid_t cpn_cnr_stateid; +u64 cpn_sec; +u32 cpn_nsec; +struct nl4_server cpn_src; +}; +struct nfsd4_op {int opnum;const struct nfsd4_operation * opdesc;
@@ -620,6 +632,7 @@ struct nfsd4_op {struct nfsd4_clone clone;struct nfsd4_copy copy;struct nfsd4_offload_status offload_status; +struct nfsd4_copy_notify copy_notify;struct nfsd4_seek seek; } u;struct nfs4_replay * replay;
Signature · 1 line
1.8.3.1
PATCH v4 4/8 NFSD check stateids against copy stateids
In reply to Olga KornievskaiaIncoming stateid (used by a READ) could be a saved copy stateid. On first use make it active and check that the copy has started within the allowable lease time.
--- fs/nfsd/nfs4state.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
fs/nfsd/nfs4state.c +27 -0
@@ -770,6 +770,31 @@ __be32 find_cp_state(struct nfsd_net *nn, stateid_t *st, *cps = state;return 0 ; } +/* +* A READ from an inter server to server COPY will have a +* copy stateid. Return the parent nfs4_stid. +*/ +static __be32 find_cp_state_parent (struct nfsd_net *nn,stateid_t *st, +struct nfs4_stid **stid) +{ +__be32 status; +struct nfs4_cp_state *cps =NULL ; + + status =find_cp_state (nn, st, &cps); +if (status) +return status; + +/* Did the inter server to server copy start in time? */ +if (cps->cp_active == false && !time_after (cps->cp_timeout, jiffies)) +return nfserr_partner_no_auth; +else + cps->cp_active = true; + + *stid = cps->cp_p_stid; +atomic_inc (&cps->cp_p_stid->sc_count); + +return nfs_ok; +}/* * When we recall a delegation, we should be careful not to hand it
@@ -5054,6 +5079,8 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) status =nfsd4_lookup_stateid (cstate, stateid,NFS4_DELEG_STID |NFS4_OPEN_STID |NFS4_LOCK_STID , &s, nn); +if (status == nfserr_bad_stateid) + status =find_cp_state_parent (nn, stateid, &s);if (status)return status; status = check_stateid_generation(stateid, &s->sc_stateid,
Signature · 1 line
1.8.3.1
PATCH v4 5/8 NFSD generalize nfsd4_compound_state flag names
In reply to Olga KornievskaiaFrom: Andy Adamson <[email protected]>
Allow for sid_flag field non-stateid use.
--- fs/nfsd/nfs4proc.c | 8 ++++---- fs/nfsd/nfs4state.c | 7 ++++--- fs/nfsd/xdr4.h | 6 +++--- 3 files changed, 11 insertions(+), 10 deletions(-)
fs/nfsd/nfs4proc.c +4 -4
@@ -546,9 +546,9 @@ static __be32 nfsd4_open_omfg(struct svc_rqst *rqstp, struct nfsd4_compound_statreturn 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; }
@@ -561,9 +561,9 @@ static __be32 nfsd4_open_omfg(struct svc_rqst *rqstp, struct nfsd4_compound_statreturn 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; }
fs/nfsd/nfs4state.c +4 -3
@@ -7226,7 +7226,8 @@ static int nfs4_state_create_net(struct net *net)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)); }
@@ -7235,14 +7236,14 @@ static int nfs4_state_create_net(struct net *net) {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 ); }/*
fs/nfsd/xdr4.h +3 -3
@@ -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;
Signature · 1 line
1.8.3.1
PATCH v4 6/8 nfsd: remove unnecessary nofilehandle checks
In reply to Olga KornievskaiaThese checks should have already be done centrally in nfsd4_proc_compound, the checks in each individual operation are unnecessary.
--- fs/nfsd/nfs4proc.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-)
fs/nfsd/nfs4proc.c +2 -12
@@ -507,9 +507,6 @@ static __be32 nfsd4_open_omfg(struct svc_rqst *rqstp, struct nfsd4_compound_stat nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) { - if (!cstate->current_fh.fh_dentry) - return nfserr_nofilehandle; - u->getfh = &cstate->current_fh;return nfs_ok; }
@@ -557,9 +554,6 @@ static __be32 nfsd4_open_omfg(struct svc_rqst *rqstp, struct nfsd4_compound_stat nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) { - if (!cstate->current_fh.fh_dentry) - return nfserr_nofilehandle; - fh_dup2(&cstate->save_fh, &cstate->current_fh);if (HAS_CSTATE_FLAG (cstate,CURRENT_STATE_ID_FLAG )) {memcpy (&cstate->save_stateid, &cstate->current_stateid,sizeof (stateid_t));
@@ -725,10 +719,8 @@ static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net) union nfsd4_op_u *u) {struct nfsd4_link *link = &u->link; -__be32 status = nfserr_nofilehandle; +__be32 status; -if (!cstate->save_fh.fh_dentry) -return status; status =nfsd_link (rqstp, &cstate->current_fh, link->li_name, link->li_namelen, &cstate->save_fh);if (!status)
@@ -873,10 +865,8 @@ static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh) union nfsd4_op_u *u) {struct nfsd4_rename *rename = &u->rename; -__be32 status = nfserr_nofilehandle; +__be32 status; -if (!cstate->save_fh.fh_dentry) -return status;if (opens_in_grace (SVC_NET (rqstp)) && !(cstate->save_fh.fh_export->ex_flags &NFSEXP_NOSUBTREECHECK ))return nfserr_grace;
Signature · 1 line
1.8.3.1
PATCH v4 7/8 NFSD: allow inter server COPY to have a STALE source server fh
In reply to Olga KornievskaiaThe inter server to server COPY source server filehandle is a foreign filehandle as the COPY is sent to the destination server.
--- fs/nfsd/Kconfig | 10 ++++++++++ fs/nfsd/nfs4proc.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- fs/nfsd/nfsfh.h | 5 ++++- fs/nfsd/xdr4.h | 1 + 4 files changed, 57 insertions(+), 4 deletions(-)
fs/nfsd/Kconfig +10 -0
@@ -131,6 +131,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
fs/nfsd/nfs4proc.c +42 -3
78 lines not on this page · raw message
fs/nfsd/nfsfh.h +4 -1
@@ -33,7 +33,7 @@ static inline ino_t u32_to_ino_t(__u32 uino)bool fh_locked;/* inode locked by us */ bool fh_want_write;/* remount protection taken */ - +int fh_flags;/* FH flags */ #ifdef CONFIG_NFSD_V3 bool fh_post_saved;/* post-op attrs saved */ bool fh_pre_saved;/* pre-op attrs saved */
@@ -54,6 +54,9 @@ static inline ino_t u32_to_ino_t(__u32 uino)#endif /* CONFIG_NFSD_V3 */ } svc_fh; +#define NFSD4_FH_FOREIGN (1<<0) +#define SET_FH_FLAG (c, f) ((c)->fh_flags |= (f)) +#define HAS_FH_FLAG (c, f) ((c)->fh_flags & (f))enum nfsd_fsid {FSID_DEV =0 ,
fs/nfsd/xdr4.h +1 -0
@@ -45,6 +45,7 @@#define CURRENT_STATE_ID_FLAG (1<<0)#define SAVED_STATE_ID_FLAG (1<<1) +#define NO_VERIFY_FH (1<<2)#define SET_CSTATE_FLAG (c, f) ((c)->sid_flags |= (f))#define HAS_CSTATE_FLAG (c, f) ((c)->sid_flags & (f))
Signature · 1 line
1.8.3.1
PATCH v4 8/8 NFSD add nfs4 inter ssc to nfsd4_copy
In reply to Olga KornievskaiaGiven 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.
--- fs/nfsd/nfs4proc.c | 297 +++++++++++++++++++++++++++++++++++++++++++++++---- fs/nfsd/xdr4.h | 4 + include/linux/nfs4.h | 1 + 3 files changed, 283 insertions(+), 19 deletions(-)
fs/nfsd/nfs4proc.c +278 -19
@@ -1110,6 +1110,230 @@ static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write) out:return status; } + +#ifdef CONFIG_NFSD_V4_2_INTER_SSC + +extern struct file *nfs42_ssc_open (struct vfsmount *ss_mnt, +struct nfs_fh *src_fh, +nfs4_stateid *stateid); +extern void nfs42_ssc_close (struct file *filep); + +extern void nfs_sb_deactive (struct super_block *sb); + +#define NFSD42_INTERSSC_MOUNTOPS "minorversion=2,vers=4,addr=%s,clientaddr=%s" + +/** +* Support one copy source server for now. +*/ +static struct vfsmount * +nfsd4_interssc_connect (struct nl4_server *nss,struct svc_rqst *rqstp) +{ +struct file_system_type *type; +struct vfsmount *ss_mnt; +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 only NL4_NETADDR source server */ +if (nss->nl4_type !=NL4_NETADDR ) { +WARN (nss->nl4_type !=NL4_NETADDR , +"nfsd4_copy src server not NL4_NETADDR\n" ); + goto out_err; + } + + naddr = &nss->u.nl4_addr; + + tmp_addrlen =rpc_uaddr2sockaddr (SVC_NET (rqstp), naddr->addr, + naddr->addr_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->netid_len != match_netid_len || +strncmp (naddr->netid, match_netid, naddr->netid_len)) + 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_err; + +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_MOUNTOPS ) +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_MOUNTOPS , 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 */ + ss_mnt =vfs_kern_mount (type,MS_KERNMOUNT , ipaddr2, raw_data); +if (IS_ERR (ss_mnt)) { + status =PTR_ERR (ss_mnt); + goto out_free_rawdata; + } + +kfree (raw_data); +kfree (ipaddr2); +kfree (ipaddr); + +return ss_mnt; + +out_free_rawdata: +kfree (raw_data); +out_free_ipaddr2: +kfree (ipaddr2); +out_free_ipaddr: +kfree (ipaddr); +out_err: +dprintk ("--> %s ERROR %d\n" , __func__, status); +return ERR_PTR (status); +} + +static void +nfsd4_interssc_disconnect (struct vfsmount *ss_mnt) +{ +nfs_sb_deactive (ss_mnt->mnt_sb); +mntput (ss_mnt); +} + +/** +* 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 vfsmount * +nfsd4_setup_inter_ssc (struct svc_rqst *rqstp, +struct nfsd4_compound_state *cstate, +struct nfsd4_copy *copy) +{ +struct svc_fh *s_fh =NULL ; +stateid_t *s_stid = ©->cp_src_stateid; +struct vfsmount *ss_mnt; +__be32 status; + +/* Verify the destination stateid and set dst struct file*/ + status =nfs4_preprocess_stateid_op (rqstp, cstate, &cstate->current_fh, + ©->cp_dst_stateid, +WR_STATE , ©->fh_dst,NULL , + ©->stid); +if (status) { + ss_mnt =ERR_PTR (be32_to_cpu (status)); + goto out; + } + + ss_mnt =nfsd4_interssc_connect (copy->cp_src, rqstp); +if (IS_ERR (ss_mnt)) + goto out; + + s_fh = &cstate->save_fh; + + copy->c_fh.size = s_fh->fh_handle.fh_size; +memcpy (copy->c_fh.data, &s_fh->fh_handle.fh_base, copy->c_fh.size); + copy->stateid.seqid = s_stid->si_generation; +memcpy (copy->stateid.other, (void *)&s_stid->si_opaque, +sizeof (stateid_opaque_t)); + +out: +return ss_mnt; +} + +static void +nfsd4_cleanup_inter_ssc (struct vfsmount *ss_mnt,struct file *src, +struct file *dst) +{ +nfs42_ssc_close (src); +fput (src); +fput (dst); +} + +#else /* CONFIG_NFSD_V4_2_INTER_SSC */ + +static struct vfsmount * +nfsd4_setup_inter_ssc (struct svc_rqst *rqstp, +struct nfsd4_compound_state *cstate, +struct nfsd4_copy *copy) +{ +return ERR_PTR (-EINVAL ); +} + +static void +nfsd4_cleanup_inter_ssc (struct vfsmount *ss_mnt,struct file *src, +struct file *dst) +{ +} + +static void +nfsd4_interssc_disconnect (struct vfsmount *ss_mnt) +{ +} + +static struct file *nfs42_ssc_open (struct vfsmount *ss_mnt, +struct nfs_fh *src_fh, +nfs4_stateid *stateid) +{ +return NULL ; +} +#endif /* CONFIG_NFSD_V4_2_INTER_SSC */ + +static __be32 +nfsd4_setup_intra_ssc (struct svc_rqst *rqstp, +struct nfsd4_compound_state *cstate, +struct nfsd4_copy *copy) +{ +return nfsd4_verify_copy (rqstp, cstate, ©->cp_src_stateid, + ©->fh_src, ©->cp_dst_stateid, + ©->fh_dst, ©->stid); +} + +static void +nfsd4_cleanup_intra_ssc (struct file *src,struct file *dst) +{ +fput (src); +fput (dst); +} +static void nfsd4_cb_offload_release (struct nfsd4_callback *cb) { struct nfsd4_copy *copy = container_of(cb, struct nfsd4_copy, cp_cb);
@@ -1179,12 +1403,16 @@ static int nfsd4_do_copy(struct nfsd4_copy *copy, bool sync)else status =nfsd4_init_copy_res (copy, sync); -fput (copy->fh_src); -fput (copy->fh_dst); +if (copy->cp_src)/* Inter server SSC */ +nfsd4_cleanup_inter_ssc (copy->ss_mnt, copy->fh_src, + copy->fh_dst); +else +nfsd4_cleanup_intra_ssc (copy->fh_src, copy->fh_dst); +return status; } -static void dup_copy_fields (struct nfsd4_copy *src,struct nfsd4_copy *dst) +static int dup_copy_fields (struct nfsd4_copy *src,struct nfsd4_copy *dst) {memcpy (&dst->cp_src_stateid, &src->cp_src_stateid,sizeof (stateid_t));memcpy (&dst->cp_dst_stateid, &src->cp_dst_stateid,sizeof (stateid_t));
@@ -1203,6 +1431,17 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst) dst->net = src->net; dst->stid = src->stid; dst->cps = src->cps; +if (src->cp_src) { + dst->cp_src =kmalloc (sizeof (struct nl4_server ),GFP_KERNEL ); +if (!dst->cp_src) +return -ENOMEM ; +memcpy (dst->cp_src, src->cp_src,sizeof (struct nl4_server )); + } +memcpy (&dst->stateid, &src->stateid,sizeof (src->stateid)); +memcpy (&dst->c_fh, &src->c_fh,sizeof (src->c_fh)); + dst->ss_mnt = src->ss_mnt; + +return 0 ; }static void nfsd4_do_async_copy (struct work_struct *work)
@@ -1214,11 +1453,22 @@ static void nfsd4_do_async_copy(struct work_struct *work)if (test_bit (NFSD4_CLIENT_COPY_KILL , ©->cp_clp->cl_flags)) goto out; +if (copy->cp_src) {/* Inter server SSC */ + copy->fh_src =nfs42_ssc_open (copy->ss_mnt, ©->c_fh, + ©->stateid); +if (IS_ERR (copy->fh_src)) { + copy->nfserr = nfserr_offload_denied; +nfsd4_interssc_disconnect (copy->ss_mnt); + goto do_callback; + } + } + copy->nfserr =nfsd4_do_copy (copy,0 );if (copy->cps->cp_cancelled) goto out; +do_callback: cb_copy =kzalloc (sizeof (struct nfsd4_copy ),GFP_KERNEL );if (!cb_copy) goto out;
@@ -1233,6 +1483,7 @@ static void nfsd4_do_async_copy(struct work_struct *work)list_del (©->cps->cp_list);nfs4_free_cp_state (copy->cps);nfs4_put_stid (copy->stid); +kfree (copy->cp_src);kfree (copy); }
@@ -1242,12 +1493,19 @@ static void nfsd4_do_async_copy(struct work_struct *work) {struct nfsd4_copy *copy = &u->copy;__be32 status; +struct nfsd4_copy *async_copy; - status =nfsd4_verify_copy (rqstp, cstate, ©->cp_src_stateid, - ©->fh_src, ©->cp_dst_stateid, - ©->fh_dst, ©->stid); -if (status) - goto out; +if (copy->cp_src) {/* Inter server SSC */ + copy->ss_mnt =nfsd4_setup_inter_ssc (rqstp, cstate, copy); +if (IS_ERR (copy->ss_mnt)) { + status = nfserr_offload_denied; + goto out; + } + }else { + status =nfsd4_setup_intra_ssc (rqstp, cstate, copy); +if (status) + goto out; + } copy->cp_clp = cstate->clp; memcpy(©->fh, &cstate->current_fh.fh_handle,
@@ -1255,28 +1513,24 @@ static void nfsd4_do_async_copy(struct work_struct *work) copy->net =SVC_NET (rqstp);if (!copy->cp_synchronous) {struct nfsd_net *nn =net_generic (SVC_NET (rqstp), nfsd_net_id); -struct nfsd4_copy *async_copy; status =nfsd4_init_copy_res (copy,0 ); async_copy =kzalloc (sizeof (struct nfsd4_copy ),GFP_KERNEL ); -if (!async_copy) { - status =nfserrno (-ENOMEM ); - goto out; - } +if (!async_copy) + goto out_err; copy->cps =nfs4_alloc_init_cp_state (nn, nn->nfsd4_lease, copy->stid); -if (!copy->cps) { - status =nfserrno (-ENOMEM ); -kfree (async_copy); - goto out; - } +if (!copy->cps) + goto out_err;/* take a reference on the parent stateid so it's not * not freed by the copy compound */ atomic_inc (©->stid->sc_count);memcpy (©->cp_res.cb_stateid, ©->cps->cp_stateid,sizeof (copy->cps->cp_stateid)); -dup_copy_fields (copy, async_copy); + status =dup_copy_fields (copy, async_copy); +if (status) + goto out_err;INIT_WORK (&async_copy->cp_work, nfsd4_do_async_copy);queue_work (copy_wq, &async_copy->cp_work); }else {
@@ -1284,6 +1538,11 @@ static void nfsd4_do_async_copy(struct work_struct *work) } out:return status; +out_err: +kfree (async_copy); + status =nfserrno (-ENOMEM ); +nfsd4_interssc_disconnect (copy->ss_mnt); + goto out; } static __be32
fs/nfsd/xdr4.h +4 -0
@@ -540,6 +540,10 @@ struct nfsd4_copy {struct net *net;struct nfs4_stid *stid;struct nfs4_cp_state *cps; + +struct vfsmount *ss_mnt; +struct nfs_fh c_fh; +nfs4_stateid stateid; };struct nfsd4_seek {
include/linux/nfs4.h +1 -0
@@ -16,6 +16,7 @@#include <linux/uidgid.h> #include <uapi/linux/nfs4.h> #include <linux/sunrpc/msg_prot.h> +#include <linux/nfs.h> enum nfs4_acl_whotype {NFS4_ACL_WHO_NAMED =0 ,
Signature · 1 line
1.8.3.1