NFSD check stateids against copy stateids
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>
This commit is contained in:
Родитель
624322f1ad
Коммит
b734220425
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче