if (check_for_locks(stp->st_file, lo))
return nfserr_locks_held;
- /*
- * Currently there's a 1-1 lock stateid<->lockowner
- * correspondance, and we have to delete the lockowner when we
- * delete the lock stateid:
- */
- release_lockowner(lo);
+ release_lockowner_if_empty(lo);
return nfs_ok;
}
return stp;
}
+static struct nfs4_ol_stateid *
+find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp)
+{
+ struct nfs4_ol_stateid *lst;
+
+ list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) {
+ if (lst->st_file == fp)
+ return lst;
+ }
+ return NULL;
+}
+
+
static int
check_lock_length(u64 offset, u64 length)
{
lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid,
&lock->v.new.owner, nn);
- if (lo) {
- if (!cstate->minorversion)
+ if (!lo) {
+ strhashval = ownerstr_hashval(cl->cl_clientid.cl_id,
+ &lock->v.new.owner);
+ lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
+ if (lo == NULL)
+ return nfserr_jukebox;
+ } else {
+ /* with an existing lockowner, seqids must be the same */
+ if (!cstate->minorversion &&
+ lock->lk_new_lock_seqid != lo->lo_owner.so_seqid)
return nfserr_bad_seqid;
- /* XXX: a lockowner always has exactly one stateid: */
- *lst = list_first_entry(&lo->lo_owner.so_stateids,
- struct nfs4_ol_stateid, st_perstateowner);
- return nfs_ok;
}
- strhashval = ownerstr_hashval(cl->cl_clientid.cl_id,
- &lock->v.new.owner);
- lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock);
- if (lo == NULL)
- return nfserr_jukebox;
- *lst = alloc_init_lock_stateid(lo, fi, ost);
+
+ *lst = find_lock_stateid(lo, fi);
if (*lst == NULL) {
- release_lockowner(lo);
- return nfserr_jukebox;
+ *lst = alloc_init_lock_stateid(lo, fi, ost);
+ if (*lst == NULL) {
+ release_lockowner_if_empty(lo);
+ return nfserr_jukebox;
+ }
+ *new = true;
}
- *new = true;
return nfs_ok;
}
}
out:
if (status && new_state)
- release_lockowner(lock_sop);
+ release_lock_stateid(lock_stp);
nfsd4_bump_seqid(cstate, status);
if (!cstate->replay_owner)
nfs4_unlock_state();