Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

NFSv4: Fix nfs_clear_verifier_delegated() for delegated directories

If the client returns a directory delegation, then look up all the child
dentries, and clear their 'verifier delegated' bit, unless subject to a
file delegation.

Similarly, if a file delegation is being returned, check if there is a
directory delegation before clearing a 'verifier delegated' bit.

Reported-by: Christoph Hellwig <hch@lst.de>
Fixes: 156b09482933 ("NFS: Request a directory delegation on ACCESS, CREATE, and UNLINK")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>

+49 -8
+49 -8
fs/nfs/dir.c
··· 1440 1440 1441 1441 if (!dir || !nfs_verify_change_attribute(dir, verf)) 1442 1442 return; 1443 - if (inode && NFS_PROTO(inode)->have_delegation(inode, FMODE_READ, 0)) 1443 + if (NFS_PROTO(dir)->have_delegation(dir, FMODE_READ, 0) || 1444 + (inode && NFS_PROTO(inode)->have_delegation(inode, FMODE_READ, 0))) 1444 1445 nfs_set_verifier_delegated(&verf); 1445 1446 dentry->d_time = verf; 1446 1447 } ··· 1466 1465 EXPORT_SYMBOL_GPL(nfs_set_verifier); 1467 1466 1468 1467 #if IS_ENABLED(CONFIG_NFS_V4) 1468 + static void nfs_clear_verifier_file(struct inode *inode) 1469 + { 1470 + struct dentry *alias; 1471 + struct inode *dir; 1472 + 1473 + hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { 1474 + spin_lock(&alias->d_lock); 1475 + dir = d_inode_rcu(alias->d_parent); 1476 + if (!dir || 1477 + !NFS_PROTO(dir)->have_delegation(dir, FMODE_READ, 0)) 1478 + nfs_unset_verifier_delegated(&alias->d_time); 1479 + spin_unlock(&alias->d_lock); 1480 + } 1481 + } 1482 + 1483 + static void nfs_clear_verifier_directory(struct inode *dir) 1484 + { 1485 + struct dentry *this_parent; 1486 + struct dentry *dentry; 1487 + struct inode *inode; 1488 + 1489 + if (hlist_empty(&dir->i_dentry)) 1490 + return; 1491 + this_parent = 1492 + hlist_entry(dir->i_dentry.first, struct dentry, d_u.d_alias); 1493 + 1494 + spin_lock(&this_parent->d_lock); 1495 + nfs_unset_verifier_delegated(&this_parent->d_time); 1496 + dentry = d_first_child(this_parent); 1497 + hlist_for_each_entry_from(dentry, d_sib) { 1498 + if (unlikely(dentry->d_flags & DCACHE_DENTRY_CURSOR)) 1499 + continue; 1500 + inode = d_inode_rcu(dentry); 1501 + if (inode && 1502 + NFS_PROTO(inode)->have_delegation(inode, FMODE_READ, 0)) 1503 + continue; 1504 + spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); 1505 + nfs_unset_verifier_delegated(&dentry->d_time); 1506 + spin_unlock(&dentry->d_lock); 1507 + } 1508 + spin_unlock(&this_parent->d_lock); 1509 + } 1510 + 1469 1511 /** 1470 1512 * nfs_clear_verifier_delegated - clear the dir verifier delegation tag 1471 1513 * @inode: pointer to inode ··· 1521 1477 */ 1522 1478 void nfs_clear_verifier_delegated(struct inode *inode) 1523 1479 { 1524 - struct dentry *alias; 1525 - 1526 1480 if (!inode) 1527 1481 return; 1528 1482 spin_lock(&inode->i_lock); 1529 - hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { 1530 - spin_lock(&alias->d_lock); 1531 - nfs_unset_verifier_delegated(&alias->d_time); 1532 - spin_unlock(&alias->d_lock); 1533 - } 1483 + if (S_ISREG(inode->i_mode)) 1484 + nfs_clear_verifier_file(inode); 1485 + else if (S_ISDIR(inode->i_mode)) 1486 + nfs_clear_verifier_directory(inode); 1534 1487 spin_unlock(&inode->i_lock); 1535 1488 } 1536 1489 EXPORT_SYMBOL_GPL(nfs_clear_verifier_delegated);