if (!delegation_hashed(dp))
return false;
- if (dp->dl_stid.sc_client->cl_minorversion == 0)
+ if (statusmask == SC_STATUS_REVOKED &&
+ dp->dl_stid.sc_client->cl_minorversion == 0)
statusmask = SC_STATUS_CLOSED;
dp->dl_stid.sc_status |= statusmask;
+ if (statusmask & SC_STATUS_ADMIN_REVOKED)
+ atomic_inc(&dp->dl_stid.sc_client->cl_admin_revoked);
/* Ensure that deleg break won't try to requeue it */
++dp->dl_time;
trace_nfsd_stid_revoke(&dp->dl_stid);
- if (dp->dl_stid.sc_status & SC_STATUS_REVOKED) {
+ if (dp->dl_stid.sc_status &
+ (SC_STATUS_REVOKED | SC_STATUS_ADMIN_REVOKED)) {
spin_lock(&clp->cl_lock);
refcount_inc(&dp->dl_stid.sc_count);
list_add(&dp->dl_recall_lru, &clp->cl_revoked);
unsigned int idhashval;
unsigned int sc_types;
- sc_types = SC_TYPE_OPEN | SC_TYPE_LOCK;
+ sc_types = SC_TYPE_OPEN | SC_TYPE_LOCK | SC_TYPE_DELEG;
spin_lock(&nn->client_lock);
for (idhashval = 0; idhashval < CLIENT_HASH_MASK; idhashval++) {
sc_types);
if (stid) {
struct nfs4_ol_stateid *stp;
+ struct nfs4_delegation *dp;
spin_unlock(&nn->client_lock);
switch (stid->sc_type) {
spin_unlock(&clp->cl_lock);
mutex_unlock(&stp->st_mutex);
break;
+ case SC_TYPE_DELEG:
+ dp = delegstateid(stid);
+ spin_lock(&state_lock);
+ if (!unhash_delegation_locked(
+ dp, SC_STATUS_ADMIN_REVOKED))
+ dp = NULL;
+ spin_unlock(&state_lock);
+ if (dp)
+ revoke_delegation(dp);
+ break;
}
nfs4_put_stid(stid);
spin_lock(&nn->client_lock);
struct nfs4_client *cl = s->sc_client;
LIST_HEAD(reaplist);
struct nfs4_ol_stateid *stp;
+ struct nfs4_delegation *dp;
bool unhashed;
switch (s->sc_type) {
if (unhashed)
nfs4_put_stid(s);
break;
+ case SC_TYPE_DELEG:
+ dp = delegstateid(s);
+ list_del_init(&dp->dl_recall_lru);
+ spin_unlock(&cl->cl_lock);
+ nfs4_put_stid(s);
+ break;
default:
spin_unlock(&cl->cl_lock);
}