diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2009-12-03 15:58:56 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2009-12-03 15:58:56 -0500 |
commit | 27226104e60964f21717e0f452cecd45c85a64c6 (patch) | |
tree | fc0bf5aea3d316034a9d51ce00a135e9ddbce5f2 | |
parent | 28f79a1a695e7a5b00af3b6713b449e08581ffbb (diff) |
nfs: dont unhash target if renaming a directory
Move unhashing the target to after the check for existence and being a
non-directory.
If renaming a directory then the VFS already unhashes the target if it
is not busy. If it's busy then acquiring more references during the
rename makes no difference.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/dir.c | 56 |
1 files changed, 29 insertions, 27 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 11d0c4cffffc..76b7f539d76e 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -1579,15 +1579,6 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1579 | struct dentry *dentry = NULL, *rehash = NULL; | 1579 | struct dentry *dentry = NULL, *rehash = NULL; |
1580 | int error = -EBUSY; | 1580 | int error = -EBUSY; |
1581 | 1581 | ||
1582 | /* | ||
1583 | * To prevent any new references to the target during the rename, | ||
1584 | * we unhash the dentry in advance. | ||
1585 | */ | ||
1586 | if (!d_unhashed(new_dentry)) { | ||
1587 | d_drop(new_dentry); | ||
1588 | rehash = new_dentry; | ||
1589 | } | ||
1590 | |||
1591 | dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n", | 1582 | dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n", |
1592 | old_dentry->d_parent->d_name.name, old_dentry->d_name.name, | 1583 | old_dentry->d_parent->d_name.name, old_dentry->d_name.name, |
1593 | new_dentry->d_parent->d_name.name, new_dentry->d_name.name, | 1584 | new_dentry->d_parent->d_name.name, new_dentry->d_name.name, |
@@ -1599,25 +1590,36 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1599 | * silly-rename succeeds, the copied dentry is hashed and becomes | 1590 | * silly-rename succeeds, the copied dentry is hashed and becomes |
1600 | * the new target. | 1591 | * the new target. |
1601 | */ | 1592 | */ |
1602 | if (new_inode && !S_ISDIR(new_inode->i_mode) && | 1593 | if (new_inode && !S_ISDIR(new_inode->i_mode)) { |
1603 | atomic_read(&new_dentry->d_count) > 2) { | 1594 | /* |
1604 | int err; | 1595 | * To prevent any new references to the target during the |
1605 | /* copy the target dentry's name */ | 1596 | * rename, we unhash the dentry in advance. |
1606 | dentry = d_alloc(new_dentry->d_parent, | 1597 | */ |
1607 | &new_dentry->d_name); | 1598 | if (!d_unhashed(new_dentry)) { |
1608 | if (!dentry) | 1599 | d_drop(new_dentry); |
1609 | goto out; | 1600 | rehash = new_dentry; |
1601 | } | ||
1610 | 1602 | ||
1611 | /* silly-rename the existing target ... */ | 1603 | if (atomic_read(&new_dentry->d_count) > 2) { |
1612 | err = nfs_sillyrename(new_dir, new_dentry); | 1604 | int err; |
1613 | if (!err) { | 1605 | |
1614 | new_dentry = rehash = dentry; | 1606 | /* copy the target dentry's name */ |
1615 | new_inode = NULL; | 1607 | dentry = d_alloc(new_dentry->d_parent, |
1616 | /* instantiate the replacement target */ | 1608 | &new_dentry->d_name); |
1617 | d_instantiate(new_dentry, NULL); | 1609 | if (!dentry) |
1618 | } else if (atomic_read(&new_dentry->d_count) > 1) | 1610 | goto out; |
1619 | /* dentry still busy? */ | 1611 | |
1620 | goto out; | 1612 | /* silly-rename the existing target ... */ |
1613 | err = nfs_sillyrename(new_dir, new_dentry); | ||
1614 | if (!err) { | ||
1615 | new_dentry = rehash = dentry; | ||
1616 | new_inode = NULL; | ||
1617 | /* instantiate the replacement target */ | ||
1618 | d_instantiate(new_dentry, NULL); | ||
1619 | } else if (atomic_read(&new_dentry->d_count) > 1) | ||
1620 | /* dentry still busy? */ | ||
1621 | goto out; | ||
1622 | } | ||
1621 | } | 1623 | } |
1622 | 1624 | ||
1623 | /* | 1625 | /* |