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.

NFS: Fix a spinlock recursion inside nfs_update_inode()

In cases where the server has gone insane, nfs_update_inode() may end
up calling nfs_invalidate_inode(), which again calls stuff that takes
the inode->i_lock that we're already holding.

In addition, given the sort of things we have in NFS these days that
need to be cleaned up on inode release, I'm not sure we should ever
be calling make_bad_inode().

Fix up spinlock recursion, and limit nfs_invalidate_inode() to clearing
the caches, and marking the inode as being stale.

Thanks to Steve Dickson <SteveD@redhat.com> for spotting this.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

+12 -14
+12 -14
fs/nfs/inode.c
··· 643 643 /* 644 644 * Invalidate the local caches 645 645 */ 646 - void 647 - nfs_zap_caches(struct inode *inode) 646 + static void nfs_zap_caches_locked(struct inode *inode) 648 647 { 649 648 struct nfs_inode *nfsi = NFS_I(inode); 650 649 int mode = inode->i_mode; 651 - 652 - spin_lock(&inode->i_lock); 653 650 654 651 NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); 655 652 NFS_ATTRTIMEO_UPDATE(inode) = jiffies; ··· 656 659 nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; 657 660 else 658 661 nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; 662 + } 659 663 664 + void nfs_zap_caches(struct inode *inode) 665 + { 666 + spin_lock(&inode->i_lock); 667 + nfs_zap_caches_locked(inode); 660 668 spin_unlock(&inode->i_lock); 661 669 } 662 670 ··· 678 676 } 679 677 680 678 /* 681 - * Invalidate, but do not unhash, the inode 679 + * Invalidate, but do not unhash, the inode. 680 + * NB: must be called with inode->i_lock held! 682 681 */ 683 - static void 684 - nfs_invalidate_inode(struct inode *inode) 682 + static void nfs_invalidate_inode(struct inode *inode) 685 683 { 686 - umode_t save_mode = inode->i_mode; 687 - 688 - make_bad_inode(inode); 689 - inode->i_mode = save_mode; 690 - nfs_zap_caches(inode); 684 + set_bit(NFS_INO_STALE, &NFS_FLAGS(inode)); 685 + nfs_zap_caches_locked(inode); 691 686 } 692 687 693 688 struct nfs_find_desc { ··· 1527 1528 printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n", 1528 1529 __FUNCTION__, inode->i_ino, inode->i_mode, fattr->mode); 1529 1530 #endif 1531 + out_err: 1530 1532 /* 1531 1533 * No need to worry about unhashing the dentry, as the 1532 1534 * lookup validation will know that the inode is bad. 1533 1535 * (But we fall through to invalidate the caches.) 1534 1536 */ 1535 1537 nfs_invalidate_inode(inode); 1536 - out_err: 1537 - set_bit(NFS_INO_STALE, &NFS_FLAGS(inode)); 1538 1538 return -ESTALE; 1539 1539 } 1540 1540