struct nfsd4_release_lockowner *rlockowner)
{
clientid_t *clid = &rlockowner->rl_clientid;
- struct nfs4_stateowner *sop;
+ struct nfs4_stateowner *sop = NULL, *tmp;
struct nfs4_lockowner *lo;
struct nfs4_ol_stateid *stp;
struct xdr_netobj *owner = &rlockowner->rl_owner;
- struct list_head matches;
unsigned int hashval = ownerstr_hashval(clid->cl_id, owner);
__be32 status;
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
goto out;
status = nfserr_locks_held;
- INIT_LIST_HEAD(&matches);
- list_for_each_entry(sop, &nn->ownerstr_hashtbl[hashval], so_strhash) {
- if (sop->so_is_open_owner)
- continue;
- if (!same_owner_str(sop, owner, clid))
+ /* Find the matching lock stateowner */
+ list_for_each_entry(tmp, &nn->ownerstr_hashtbl[hashval], so_strhash) {
+ if (tmp->so_is_open_owner)
continue;
- list_for_each_entry(stp, &sop->so_stateids,
- st_perstateowner) {
- lo = lockowner(sop);
- if (check_for_locks(stp->st_file, lo))
- goto out;
- list_add(&lo->lo_list, &matches);
+ if (same_owner_str(tmp, owner, clid)) {
+ sop = tmp;
+ break;
}
}
- /* Clients probably won't expect us to return with some (but not all)
- * of the lockowner state released; so don't release any until all
- * have been checked. */
- status = nfs_ok;
- while (!list_empty(&matches)) {
- lo = list_entry(matches.next, struct nfs4_lockowner,
- lo_list);
- /* unhash_stateowner deletes so_perclient only
- * for openowners. */
- list_del(&lo->lo_list);
- release_lockowner(lo);
+
+ /* No matching owner found, maybe a replay? Just declare victory... */
+ if (!sop) {
+ status = nfs_ok;
+ goto out;
+ }
+
+ lo = lockowner(sop);
+ /* see if there are still any locks associated with it */
+ list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) {
+ if (check_for_locks(stp->st_file, lo))
+ goto out;
}
+
+ status = nfs_ok;
+ release_lockowner(lo);
out:
nfs4_unlock_state();
return status;