Skip to content

Commit

Permalink
nfsd: add an operation for unhashing a stateowner
Browse files Browse the repository at this point in the history
Allow stateowners to be unhashed and destroyed when the last reference
is put. The unhashing must be idempotent. In a future patch, we'll add
some locking around it, but for now it's only protected by the
client_mutex.

Signed-off-by: Jeff Layton <jlayton@primarydata.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
  • Loading branch information
Jeff Layton authored and J. Bruce Fields committed Jul 31, 2014
1 parent 5db1c03 commit 8f4b54c
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 12 deletions.
49 changes: 37 additions & 12 deletions fs/nfsd/nfs4state.c
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,7 @@ static void nfs4_put_stateowner(struct nfs4_stateowner *sop)
{
if (!atomic_dec_and_test(&sop->so_count))
return;
sop->so_ops->so_unhash(sop);
kfree(sop->so_owner.data);
sop->so_ops->so_free(sop);
}
Expand Down Expand Up @@ -943,10 +944,14 @@ static void __release_lock_stateid(struct nfs4_ol_stateid *stp)
}

static void unhash_lockowner(struct nfs4_lockowner *lo)
{
list_del_init(&lo->lo_owner.so_strhash);
}

static void release_lockowner_stateids(struct nfs4_lockowner *lo)
{
struct nfs4_ol_stateid *stp;

list_del(&lo->lo_owner.so_strhash);
while (!list_empty(&lo->lo_owner.so_stateids)) {
stp = list_first_entry(&lo->lo_owner.so_stateids,
struct nfs4_ol_stateid, st_perstateowner);
Expand All @@ -957,6 +962,7 @@ static void unhash_lockowner(struct nfs4_lockowner *lo)
static void release_lockowner(struct nfs4_lockowner *lo)
{
unhash_lockowner(lo);
release_lockowner_stateids(lo);
nfs4_put_stateowner(&lo->lo_owner);
}

Expand Down Expand Up @@ -1006,15 +1012,8 @@ static void release_open_stateid(struct nfs4_ol_stateid *stp)

static void unhash_openowner(struct nfs4_openowner *oo)
{
struct nfs4_ol_stateid *stp;

list_del(&oo->oo_owner.so_strhash);
list_del(&oo->oo_perclient);
while (!list_empty(&oo->oo_owner.so_stateids)) {
stp = list_first_entry(&oo->oo_owner.so_stateids,
struct nfs4_ol_stateid, st_perstateowner);
release_open_stateid(stp);
}
list_del_init(&oo->oo_owner.so_strhash);
list_del_init(&oo->oo_perclient);
}

static void release_last_closed_stateid(struct nfs4_openowner *oo)
Expand All @@ -1027,9 +1026,21 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo)
}
}

static void release_openowner_stateids(struct nfs4_openowner *oo)
{
struct nfs4_ol_stateid *stp;

while (!list_empty(&oo->oo_owner.so_stateids)) {
stp = list_first_entry(&oo->oo_owner.so_stateids,
struct nfs4_ol_stateid, st_perstateowner);
release_open_stateid(stp);
}
}

static void release_openowner(struct nfs4_openowner *oo)
{
unhash_openowner(oo);
release_openowner_stateids(oo);
list_del(&oo->oo_close_lru);
release_last_closed_stateid(oo);
nfs4_put_stateowner(&oo->oo_owner);
Expand Down Expand Up @@ -2994,6 +3005,13 @@ static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, u
list_add(&oo->oo_perclient, &clp->cl_openowners);
}

static void nfs4_unhash_openowner(struct nfs4_stateowner *so)
{
struct nfs4_openowner *oo = openowner(so);

unhash_openowner(oo);
}

static void nfs4_free_openowner(struct nfs4_stateowner *so)
{
struct nfs4_openowner *oo = openowner(so);
Expand All @@ -3002,7 +3020,8 @@ static void nfs4_free_openowner(struct nfs4_stateowner *so)
}

static const struct nfs4_stateowner_operations openowner_ops = {
.so_free = nfs4_free_openowner,
.so_unhash = nfs4_unhash_openowner,
.so_free = nfs4_free_openowner,
};

static struct nfs4_openowner *
Expand Down Expand Up @@ -4760,6 +4779,11 @@ find_lockowner_str(clientid_t *clid, struct xdr_netobj *owner,
return NULL;
}

static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop)
{
unhash_lockowner(lockowner(sop));
}

static void nfs4_free_lockowner(struct nfs4_stateowner *sop)
{
struct nfs4_lockowner *lo = lockowner(sop);
Expand All @@ -4768,7 +4792,8 @@ static void nfs4_free_lockowner(struct nfs4_stateowner *sop)
}

static const struct nfs4_stateowner_operations lockowner_ops = {
.so_free = nfs4_free_lockowner,
.so_unhash = nfs4_unhash_lockowner,
.so_free = nfs4_free_lockowner,
};

/*
Expand Down
1 change: 1 addition & 0 deletions fs/nfsd/state.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ struct nfs4_replay {
struct nfs4_stateowner;

struct nfs4_stateowner_operations {
void (*so_unhash)(struct nfs4_stateowner *);
void (*so_free)(struct nfs4_stateowner *);
};

Expand Down

0 comments on commit 8f4b54c

Please sign in to comment.