@@ -803,8 +803,37 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
&read->rd_stateid, RD_STATE,
&read->rd_filp, &read->rd_tmp_file);
if (status) {
- dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
- goto out;
+ /* if clientid in rd_stateid is different from current,
+ * find corresponding clientid and look for stateid there
+ */
+ struct net *net = SVC_NET(rqstp);
+ struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+ struct nfs4_client *clp = NULL;
+
+ spin_lock(&nn->client_lock);
+ list_for_each_entry(clp, &nn->client_lru, cl_lru) {
+ if (same_clid(&clp->cl_clientid,
+ &read->rd_stateid.si_opaque.so_clid)) {
+ struct nfs4_stid *stid = NULL;
+
+ stid = find_stateid_by_type(clp,
+ &read->rd_stateid,
+ NFS4_DELEG_STID|NFS4_OPEN_STID|
+ NFS4_LOCK_STID);
+ if (stid) {
+ nfs4_put_stid(stid);
+ if (stid->is_copy)
+ status = nfs_ok;
+ break;
+ }
+ }
+ }
+ spin_unlock(&nn->client_lock);
+ if (status != nfs_ok) {
+ dprintk("NFSD: %s: couldn't process stateid!\n",
+ __func__);
+ goto out;
+ }
}
status = nfs_ok;
out:
@@ -1397,6 +1426,7 @@ nfsd4_copy_notify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
__be32 status;
struct file *src = NULL;
struct nfs42_netaddr *naddr;
+ struct nfs4_stid *stid = NULL;
status = nfs4_preprocess_stateid_op(rqstp, cstate,
&cstate->current_fh,
@@ -1412,7 +1442,14 @@ 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 */
+ stid = find_stateid_by_type(cstate->session->se_client,
+ &cp_notify->cpn_src_stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|
+ NFS4_LOCK_STID);
+ if (stid) {
+ stid->is_copy = 1;
+ nfs4_put_stid(stid);
+ }
/**
* For now, only return one source server address, the address used
* by the client in the static cpn_src.
@@ -1809,12 +1809,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;
@@ -1916,7 +1910,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;
@@ -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;
struct nfs4_client *sc_client;
@@ -583,6 +584,13 @@ enum nfsd4_cb_op {
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);