diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 27 |
1 files changed, 17 insertions, 10 deletions
diff --git a/fs/namei.c b/fs/namei.c index a7dce91a7e4..b86b96fe1dc 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1641,7 +1641,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
1641 | if (nd->last.name[nd->last.len]) { | 1641 | if (nd->last.name[nd->last.len]) { |
1642 | if (open_flag & O_CREAT) | 1642 | if (open_flag & O_CREAT) |
1643 | goto exit; | 1643 | goto exit; |
1644 | nd->flags |= LOOKUP_DIRECTORY; | 1644 | nd->flags |= LOOKUP_DIRECTORY | LOOKUP_FOLLOW; |
1645 | } | 1645 | } |
1646 | 1646 | ||
1647 | /* just plain open? */ | 1647 | /* just plain open? */ |
@@ -1830,6 +1830,8 @@ reval: | |||
1830 | } | 1830 | } |
1831 | if (open_flag & O_DIRECTORY) | 1831 | if (open_flag & O_DIRECTORY) |
1832 | nd.flags |= LOOKUP_DIRECTORY; | 1832 | nd.flags |= LOOKUP_DIRECTORY; |
1833 | if (!(open_flag & O_NOFOLLOW)) | ||
1834 | nd.flags |= LOOKUP_FOLLOW; | ||
1833 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); | 1835 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); |
1834 | while (unlikely(!filp)) { /* trailing symlink */ | 1836 | while (unlikely(!filp)) { /* trailing symlink */ |
1835 | struct path holder; | 1837 | struct path holder; |
@@ -1837,7 +1839,7 @@ reval: | |||
1837 | void *cookie; | 1839 | void *cookie; |
1838 | error = -ELOOP; | 1840 | error = -ELOOP; |
1839 | /* S_ISDIR part is a temporary automount kludge */ | 1841 | /* S_ISDIR part is a temporary automount kludge */ |
1840 | if ((open_flag & O_NOFOLLOW) && !S_ISDIR(inode->i_mode)) | 1842 | if (!(nd.flags & LOOKUP_FOLLOW) && !S_ISDIR(inode->i_mode)) |
1841 | goto exit_dput; | 1843 | goto exit_dput; |
1842 | if (count++ == 32) | 1844 | if (count++ == 32) |
1843 | goto exit_dput; | 1845 | goto exit_dput; |
@@ -2174,8 +2176,10 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
2174 | error = security_inode_rmdir(dir, dentry); | 2176 | error = security_inode_rmdir(dir, dentry); |
2175 | if (!error) { | 2177 | if (!error) { |
2176 | error = dir->i_op->rmdir(dir, dentry); | 2178 | error = dir->i_op->rmdir(dir, dentry); |
2177 | if (!error) | 2179 | if (!error) { |
2178 | dentry->d_inode->i_flags |= S_DEAD; | 2180 | dentry->d_inode->i_flags |= S_DEAD; |
2181 | dont_mount(dentry); | ||
2182 | } | ||
2179 | } | 2183 | } |
2180 | } | 2184 | } |
2181 | mutex_unlock(&dentry->d_inode->i_mutex); | 2185 | mutex_unlock(&dentry->d_inode->i_mutex); |
@@ -2259,7 +2263,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) | |||
2259 | if (!error) { | 2263 | if (!error) { |
2260 | error = dir->i_op->unlink(dir, dentry); | 2264 | error = dir->i_op->unlink(dir, dentry); |
2261 | if (!error) | 2265 | if (!error) |
2262 | dentry->d_inode->i_flags |= S_DEAD; | 2266 | dont_mount(dentry); |
2263 | } | 2267 | } |
2264 | } | 2268 | } |
2265 | mutex_unlock(&dentry->d_inode->i_mutex); | 2269 | mutex_unlock(&dentry->d_inode->i_mutex); |
@@ -2570,17 +2574,20 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, | |||
2570 | return error; | 2574 | return error; |
2571 | 2575 | ||
2572 | target = new_dentry->d_inode; | 2576 | target = new_dentry->d_inode; |
2573 | if (target) { | 2577 | if (target) |
2574 | mutex_lock(&target->i_mutex); | 2578 | mutex_lock(&target->i_mutex); |
2575 | dentry_unhash(new_dentry); | ||
2576 | } | ||
2577 | if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) | 2579 | if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) |
2578 | error = -EBUSY; | 2580 | error = -EBUSY; |
2579 | else | 2581 | else { |
2582 | if (target) | ||
2583 | dentry_unhash(new_dentry); | ||
2580 | error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); | 2584 | error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); |
2585 | } | ||
2581 | if (target) { | 2586 | if (target) { |
2582 | if (!error) | 2587 | if (!error) { |
2583 | target->i_flags |= S_DEAD; | 2588 | target->i_flags |= S_DEAD; |
2589 | dont_mount(new_dentry); | ||
2590 | } | ||
2584 | mutex_unlock(&target->i_mutex); | 2591 | mutex_unlock(&target->i_mutex); |
2585 | if (d_unhashed(new_dentry)) | 2592 | if (d_unhashed(new_dentry)) |
2586 | d_rehash(new_dentry); | 2593 | d_rehash(new_dentry); |
@@ -2612,7 +2619,7 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, | |||
2612 | error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); | 2619 | error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); |
2613 | if (!error) { | 2620 | if (!error) { |
2614 | if (target) | 2621 | if (target) |
2615 | target->i_flags |= S_DEAD; | 2622 | dont_mount(new_dentry); |
2616 | if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE)) | 2623 | if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE)) |
2617 | d_move(old_dentry, new_dentry); | 2624 | d_move(old_dentry, new_dentry); |
2618 | } | 2625 | } |