Commit b37b03b7 authored by Trond Myklebust's avatar Trond Myklebust

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: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent ff604066
...@@ -643,14 +643,11 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) ...@@ -643,14 +643,11 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
/* /*
* Invalidate the local caches * Invalidate the local caches
*/ */
void static void nfs_zap_caches_locked(struct inode *inode)
nfs_zap_caches(struct inode *inode)
{ {
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
int mode = inode->i_mode; int mode = inode->i_mode;
spin_lock(&inode->i_lock);
NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
NFS_ATTRTIMEO_UPDATE(inode) = jiffies; NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
...@@ -659,7 +656,12 @@ nfs_zap_caches(struct inode *inode) ...@@ -659,7 +656,12 @@ nfs_zap_caches(struct inode *inode)
nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
else else
nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
}
void nfs_zap_caches(struct inode *inode)
{
spin_lock(&inode->i_lock);
nfs_zap_caches_locked(inode);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
...@@ -676,16 +678,13 @@ static void nfs_zap_acl_cache(struct inode *inode) ...@@ -676,16 +678,13 @@ static void nfs_zap_acl_cache(struct inode *inode)
} }
/* /*
* Invalidate, but do not unhash, the inode * Invalidate, but do not unhash, the inode.
* NB: must be called with inode->i_lock held!
*/ */
static void static void nfs_invalidate_inode(struct inode *inode)
nfs_invalidate_inode(struct inode *inode)
{ {
umode_t save_mode = inode->i_mode; set_bit(NFS_INO_STALE, &NFS_FLAGS(inode));
nfs_zap_caches_locked(inode);
make_bad_inode(inode);
inode->i_mode = save_mode;
nfs_zap_caches(inode);
} }
struct nfs_find_desc { struct nfs_find_desc {
...@@ -1528,14 +1527,13 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign ...@@ -1528,14 +1527,13 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n", printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n",
__FUNCTION__, inode->i_ino, inode->i_mode, fattr->mode); __FUNCTION__, inode->i_ino, inode->i_mode, fattr->mode);
#endif #endif
out_err:
/* /*
* No need to worry about unhashing the dentry, as the * No need to worry about unhashing the dentry, as the
* lookup validation will know that the inode is bad. * lookup validation will know that the inode is bad.
* (But we fall through to invalidate the caches.) * (But we fall through to invalidate the caches.)
*/ */
nfs_invalidate_inode(inode); nfs_invalidate_inode(inode);
out_err:
set_bit(NFS_INO_STALE, &NFS_FLAGS(inode));
return -ESTALE; return -ESTALE;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment