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