Skip to content

Commit

Permalink
NFSD check stateids against copy stateids
Browse files Browse the repository at this point in the history
Incoming stateid (used by a READ) could be a saved copy stateid.
Using the provided stateid, look it up in the list of copy_notify
stateids. If found, use the parent's stateid and parent's clid
to look up the parent's stid to do the appropriate checks.

Update the copy notify timestamp (cpntf_time) with current time
this making it 'active' so that laundromat thread will not delete
copy notify state.

Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
  • Loading branch information
Olga Kornievskaia authored and J. Bruce Fields committed Dec 9, 2019
1 parent 624322f commit b734220
Showing 1 changed file with 66 additions and 8 deletions.
74 changes: 66 additions & 8 deletions fs/nfsd/nfs4state.c
Original file line number Diff line number Diff line change
Expand Up @@ -4539,7 +4539,8 @@ static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4

static __be32 lookup_clientid(clientid_t *clid,
struct nfsd4_compound_state *cstate,
struct nfsd_net *nn)
struct nfsd_net *nn,
bool sessions)
{
struct nfs4_client *found;

Expand All @@ -4560,7 +4561,7 @@ static __be32 lookup_clientid(clientid_t *clid,
*/
WARN_ON_ONCE(cstate->session);
spin_lock(&nn->client_lock);
found = find_confirmed_client(clid, false, nn);
found = find_confirmed_client(clid, sessions, nn);
if (!found) {
spin_unlock(&nn->client_lock);
return nfserr_expired;
Expand Down Expand Up @@ -4593,7 +4594,7 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
if (open->op_file == NULL)
return nfserr_jukebox;

status = lookup_clientid(clientid, cstate, nn);
status = lookup_clientid(clientid, cstate, nn, false);
if (status)
return status;
clp = cstate->clp;
Expand Down Expand Up @@ -5182,7 +5183,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,

dprintk("process_renew(%08x/%08x): starting\n",
clid->cl_boot, clid->cl_id);
status = lookup_clientid(clid, cstate, nn);
status = lookup_clientid(clid, cstate, nn, false);
if (status)
goto out;
clp = cstate->clp;
Expand Down Expand Up @@ -5584,7 +5585,8 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) ||
CLOSE_STATEID(stateid))
return nfserr_bad_stateid;
status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn);
status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn,
false);
if (status == nfserr_stale_clientid) {
if (cstate->session)
return nfserr_bad_stateid;
Expand Down Expand Up @@ -5674,6 +5676,59 @@ _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps)
cps->cp_stateid.stid.si_opaque.so_id);
kfree(cps);
}
/*
* A READ from an inter server to server COPY will have a
* copy stateid. Look up the copy notify stateid from the
* idr structure and take a reference on it.
*/
static __be32 _find_cpntf_state(struct nfsd_net *nn, stateid_t *st,
struct nfs4_cpntf_state **cps)
{
copy_stateid_t *cps_t;
struct nfs4_cpntf_state *state = NULL;

if (st->si_opaque.so_clid.cl_id != nn->s2s_cp_cl_id)
return nfserr_bad_stateid;
spin_lock(&nn->s2s_cp_lock);
cps_t = idr_find(&nn->s2s_cp_stateids, st->si_opaque.so_id);
if (cps_t) {
state = container_of(cps_t, struct nfs4_cpntf_state,
cp_stateid);
if (state->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID)
return nfserr_bad_stateid;
refcount_inc(&state->cp_stateid.sc_count);
}
spin_unlock(&nn->s2s_cp_lock);
if (!state)
return nfserr_bad_stateid;
*cps = state;
return 0;
}

static __be32 find_cpntf_state(struct nfsd_net *nn, stateid_t *st,
struct nfs4_stid **stid)
{
__be32 status;
struct nfs4_cpntf_state *cps = NULL;
struct nfsd4_compound_state cstate;

status = _find_cpntf_state(nn, st, &cps);
if (status)
return status;

cps->cpntf_time = get_seconds();
memset(&cstate, 0, sizeof(cstate));
status = lookup_clientid(&cps->cp_p_clid, &cstate, nn, true);
if (status)
goto out;
status = nfsd4_lookup_stateid(&cstate, &cps->cp_p_stateid,
NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID,
stid, nn);
put_client_renew(cstate.clp);
out:
nfs4_put_cpntf_state(nn, cps);
return status;
}

void nfs4_put_cpntf_state(struct nfsd_net *nn, struct nfs4_cpntf_state *cps)
{
Expand Down Expand Up @@ -5711,6 +5766,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 = find_cpntf_state(nn, stateid, &s);
if (status)
return status;
status = nfsd4_stid_check_stateid_generation(stateid, s,
Expand Down Expand Up @@ -6743,7 +6800,8 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
return nfserr_inval;

if (!nfsd4_has_session(cstate)) {
status = lookup_clientid(&lockt->lt_clientid, cstate, nn);
status = lookup_clientid(&lockt->lt_clientid, cstate, nn,
false);
if (status)
goto out;
}
Expand Down Expand Up @@ -6927,7 +6985,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
clid->cl_boot, clid->cl_id);

status = lookup_clientid(clid, cstate, nn);
status = lookup_clientid(clid, cstate, nn, false);
if (status)
return status;

Expand Down Expand Up @@ -7074,7 +7132,7 @@ nfs4_check_open_reclaim(clientid_t *clid,
__be32 status;

/* find clientid in conf_id_hashtbl */
status = lookup_clientid(clid, cstate, nn);
status = lookup_clientid(clid, cstate, nn, false);
if (status)
return nfserr_reclaim_bad;

Expand Down

0 comments on commit b734220

Please sign in to comment.