Skip to content

Commit a451b12

Browse files
trondmychucklever
authored andcommitted
nfsd: Don't add locks to closed or closing open stateids
In NFSv4, the lock stateids are tied to the lockowner, and the open stateid, so that the action of closing the file also results in either an automatic loss of the locks, or an error of the form NFS4ERR_LOCKS_HELD. In practice this means we must not add new locks to the open stateid after the close process has been invoked. In fact doing so, can result in the following panic: kernel BUG at lib/list_debug.c:51! invalid opcode: 0000 [#1] SMP NOPTI CPU: 2 PID: 1085 Comm: nfsd Not tainted 5.6.0-rc3+ #2 Hardware name: VMware, Inc. VMware7,1/440BX Desktop Reference Platform, BIOS VMW71.00V.14410784.B64.1908150010 08/15/2019 RIP: 0010:__list_del_entry_valid.cold+0x31/0x55 Code: 1a 3d 9b e8 74 10 c2 ff 0f 0b 48 c7 c7 f0 1a 3d 9b e8 66 10 c2 ff 0f 0b 48 89 f2 48 89 fe 48 c7 c7 b0 1a 3d 9b e8 52 10 c2 ff <0f> 0b 48 89 fe 4c 89 c2 48 c7 c7 78 1a 3d 9b e8 3e 10 c2 ff 0f 0b RSP: 0018:ffffb296c1d47d90 EFLAGS: 00010246 RAX: 0000000000000054 RBX: ffff8ba032456ec8 RCX: 0000000000000000 RDX: 0000000000000000 RSI: ffff8ba039e99cc8 RDI: ffff8ba039e99cc8 RBP: ffff8ba032456e60 R08: 0000000000000781 R09: 0000000000000003 R10: 0000000000000000 R11: 0000000000000001 R12: ffff8ba009a4abe0 R13: ffff8ba032456e8c R14: 0000000000000000 R15: ffff8ba00adb01d8 FS: 0000000000000000(0000) GS:ffff8ba039e80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fb213f0b008 CR3: 00000001347de006 CR4: 00000000003606e0 Call Trace: release_lock_stateid+0x2b/0x80 [nfsd] nfsd4_free_stateid+0x1e9/0x210 [nfsd] nfsd4_proc_compound+0x414/0x700 [nfsd] ? nfs4svc_decode_compoundargs+0x407/0x4c0 [nfsd] nfsd_dispatch+0xc1/0x200 [nfsd] svc_process_common+0x476/0x6f0 [sunrpc] ? svc_sock_secure_port+0x12/0x30 [sunrpc] ? svc_recv+0x313/0x9c0 [sunrpc] ? nfsd_svc+0x2d0/0x2d0 [nfsd] svc_process+0xd4/0x110 [sunrpc] nfsd+0xe3/0x140 [nfsd] kthread+0xf9/0x130 ? nfsd_destroy+0x50/0x50 [nfsd] ? kthread_park+0x90/0x90 ret_from_fork+0x1f/0x40 The fix is to ensure that lock creation tests for whether or not the open stateid is unhashed, and to fail if that is the case. Fixes: 659aefb ("nfsd: Ensure we don't recognise lock stateids after freeing them") Signed-off-by: Trond Myklebust <[email protected]> Signed-off-by: Chuck Lever <[email protected]>
1 parent da1661b commit a451b12

File tree

1 file changed

+43
-30
lines changed

1 file changed

+43
-30
lines changed

fs/nfsd/nfs4state.c

Lines changed: 43 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,8 @@ find_any_file(struct nfs4_file *f)
494494
{
495495
struct nfsd_file *ret;
496496

497+
if (!f)
498+
return NULL;
497499
spin_lock(&f->fi_lock);
498500
ret = __nfs4_get_fd(f, O_RDWR);
499501
if (!ret) {
@@ -1309,6 +1311,12 @@ static void nfs4_put_stateowner(struct nfs4_stateowner *sop)
13091311
nfs4_free_stateowner(sop);
13101312
}
13111313

1314+
static bool
1315+
nfs4_ol_stateid_unhashed(const struct nfs4_ol_stateid *stp)
1316+
{
1317+
return list_empty(&stp->st_perfile);
1318+
}
1319+
13121320
static bool unhash_ol_stateid(struct nfs4_ol_stateid *stp)
13131321
{
13141322
struct nfs4_file *fp = stp->st_stid.sc_file;
@@ -1379,9 +1387,11 @@ static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp)
13791387
{
13801388
lockdep_assert_held(&stp->st_stid.sc_client->cl_lock);
13811389

1390+
if (!unhash_ol_stateid(stp))
1391+
return false;
13821392
list_del_init(&stp->st_locks);
13831393
nfs4_unhash_stid(&stp->st_stid);
1384-
return unhash_ol_stateid(stp);
1394+
return true;
13851395
}
13861396

13871397
static void release_lock_stateid(struct nfs4_ol_stateid *stp)
@@ -1446,13 +1456,12 @@ static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp,
14461456
static bool unhash_open_stateid(struct nfs4_ol_stateid *stp,
14471457
struct list_head *reaplist)
14481458
{
1449-
bool unhashed;
1450-
14511459
lockdep_assert_held(&stp->st_stid.sc_client->cl_lock);
14521460

1453-
unhashed = unhash_ol_stateid(stp);
1461+
if (!unhash_ol_stateid(stp))
1462+
return false;
14541463
release_open_stateid_locks(stp, reaplist);
1455-
return unhashed;
1464+
return true;
14561465
}
14571466

14581467
static void release_open_stateid(struct nfs4_ol_stateid *stp)
@@ -6394,21 +6403,21 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp,
63946403
}
63956404

63966405
static struct nfs4_ol_stateid *
6397-
find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp)
6406+
find_lock_stateid(const struct nfs4_lockowner *lo,
6407+
const struct nfs4_ol_stateid *ost)
63986408
{
63996409
struct nfs4_ol_stateid *lst;
6400-
struct nfs4_client *clp = lo->lo_owner.so_client;
64016410

6402-
lockdep_assert_held(&clp->cl_lock);
6411+
lockdep_assert_held(&ost->st_stid.sc_client->cl_lock);
64036412

6404-
list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) {
6405-
if (lst->st_stid.sc_type != NFS4_LOCK_STID)
6406-
continue;
6407-
if (lst->st_stid.sc_file == fp) {
6408-
refcount_inc(&lst->st_stid.sc_count);
6409-
return lst;
6413+
/* If ost is not hashed, ost->st_locks will not be valid */
6414+
if (!nfs4_ol_stateid_unhashed(ost))
6415+
list_for_each_entry(lst, &ost->st_locks, st_locks) {
6416+
if (lst->st_stateowner == &lo->lo_owner) {
6417+
refcount_inc(&lst->st_stid.sc_count);
6418+
return lst;
6419+
}
64106420
}
6411-
}
64126421
return NULL;
64136422
}
64146423

@@ -6424,11 +6433,11 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
64246433
mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX);
64256434
retry:
64266435
spin_lock(&clp->cl_lock);
6427-
spin_lock(&fp->fi_lock);
6428-
retstp = find_lock_stateid(lo, fp);
6436+
if (nfs4_ol_stateid_unhashed(open_stp))
6437+
goto out_close;
6438+
retstp = find_lock_stateid(lo, open_stp);
64296439
if (retstp)
6430-
goto out_unlock;
6431-
6440+
goto out_found;
64326441
refcount_inc(&stp->st_stid.sc_count);
64336442
stp->st_stid.sc_type = NFS4_LOCK_STID;
64346443
stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
@@ -6437,22 +6446,26 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
64376446
stp->st_access_bmap = 0;
64386447
stp->st_deny_bmap = open_stp->st_deny_bmap;
64396448
stp->st_openstp = open_stp;
6449+
spin_lock(&fp->fi_lock);
64406450
list_add(&stp->st_locks, &open_stp->st_locks);
64416451
list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
64426452
list_add(&stp->st_perfile, &fp->fi_stateids);
6443-
out_unlock:
64446453
spin_unlock(&fp->fi_lock);
64456454
spin_unlock(&clp->cl_lock);
6446-
if (retstp) {
6447-
if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) {
6448-
nfs4_put_stid(&retstp->st_stid);
6449-
goto retry;
6450-
}
6451-
/* To keep mutex tracking happy */
6452-
mutex_unlock(&stp->st_mutex);
6453-
stp = retstp;
6454-
}
64556455
return stp;
6456+
out_found:
6457+
spin_unlock(&clp->cl_lock);
6458+
if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) {
6459+
nfs4_put_stid(&retstp->st_stid);
6460+
goto retry;
6461+
}
6462+
/* To keep mutex tracking happy */
6463+
mutex_unlock(&stp->st_mutex);
6464+
return retstp;
6465+
out_close:
6466+
spin_unlock(&clp->cl_lock);
6467+
mutex_unlock(&stp->st_mutex);
6468+
return NULL;
64566469
}
64576470

64586471
static struct nfs4_ol_stateid *
@@ -6467,7 +6480,7 @@ find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi,
64676480

64686481
*new = false;
64696482
spin_lock(&clp->cl_lock);
6470-
lst = find_lock_stateid(lo, fi);
6483+
lst = find_lock_stateid(lo, ost);
64716484
spin_unlock(&clp->cl_lock);
64726485
if (lst != NULL) {
64736486
if (nfsd4_lock_ol_stateid(lst) == nfs_ok)

0 commit comments

Comments
 (0)