diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 44 |
1 files changed, 17 insertions, 27 deletions
diff --git a/fs/namei.c b/fs/namei.c index a4855af776a8..0741c69b3319 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -689,33 +689,20 @@ static __always_inline void follow_dotdot(struct nameidata *nd) | |||
689 | set_root(nd); | 689 | set_root(nd); |
690 | 690 | ||
691 | while(1) { | 691 | while(1) { |
692 | struct vfsmount *parent; | ||
693 | struct dentry *old = nd->path.dentry; | 692 | struct dentry *old = nd->path.dentry; |
694 | 693 | ||
695 | if (nd->path.dentry == nd->root.dentry && | 694 | if (nd->path.dentry == nd->root.dentry && |
696 | nd->path.mnt == nd->root.mnt) { | 695 | nd->path.mnt == nd->root.mnt) { |
697 | break; | 696 | break; |
698 | } | 697 | } |
699 | spin_lock(&dcache_lock); | ||
700 | if (nd->path.dentry != nd->path.mnt->mnt_root) { | 698 | if (nd->path.dentry != nd->path.mnt->mnt_root) { |
701 | nd->path.dentry = dget(nd->path.dentry->d_parent); | 699 | /* rare case of legitimate dget_parent()... */ |
702 | spin_unlock(&dcache_lock); | 700 | nd->path.dentry = dget_parent(nd->path.dentry); |
703 | dput(old); | 701 | dput(old); |
704 | break; | 702 | break; |
705 | } | 703 | } |
706 | spin_unlock(&dcache_lock); | 704 | if (!follow_up(&nd->path)) |
707 | spin_lock(&vfsmount_lock); | ||
708 | parent = nd->path.mnt->mnt_parent; | ||
709 | if (parent == nd->path.mnt) { | ||
710 | spin_unlock(&vfsmount_lock); | ||
711 | break; | 705 | break; |
712 | } | ||
713 | mntget(parent); | ||
714 | nd->path.dentry = dget(nd->path.mnt->mnt_mountpoint); | ||
715 | spin_unlock(&vfsmount_lock); | ||
716 | dput(old); | ||
717 | mntput(nd->path.mnt); | ||
718 | nd->path.mnt = parent; | ||
719 | } | 706 | } |
720 | follow_mount(&nd->path); | 707 | follow_mount(&nd->path); |
721 | } | 708 | } |
@@ -1347,7 +1334,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir) | |||
1347 | return -ENOENT; | 1334 | return -ENOENT; |
1348 | 1335 | ||
1349 | BUG_ON(victim->d_parent->d_inode != dir); | 1336 | BUG_ON(victim->d_parent->d_inode != dir); |
1350 | audit_inode_child(victim->d_name.name, victim, dir); | 1337 | audit_inode_child(victim, dir); |
1351 | 1338 | ||
1352 | error = inode_permission(dir, MAY_WRITE | MAY_EXEC); | 1339 | error = inode_permission(dir, MAY_WRITE | MAY_EXEC); |
1353 | if (error) | 1340 | if (error) |
@@ -1503,7 +1490,7 @@ int may_open(struct path *path, int acc_mode, int flag) | |||
1503 | * An append-only file must be opened in append mode for writing. | 1490 | * An append-only file must be opened in append mode for writing. |
1504 | */ | 1491 | */ |
1505 | if (IS_APPEND(inode)) { | 1492 | if (IS_APPEND(inode)) { |
1506 | if ((flag & FMODE_WRITE) && !(flag & O_APPEND)) | 1493 | if ((flag & O_ACCMODE) != O_RDONLY && !(flag & O_APPEND)) |
1507 | return -EPERM; | 1494 | return -EPERM; |
1508 | if (flag & O_TRUNC) | 1495 | if (flag & O_TRUNC) |
1509 | return -EPERM; | 1496 | return -EPERM; |
@@ -1547,7 +1534,7 @@ static int handle_truncate(struct path *path) | |||
1547 | * what get passed to sys_open(). | 1534 | * what get passed to sys_open(). |
1548 | */ | 1535 | */ |
1549 | static int __open_namei_create(struct nameidata *nd, struct path *path, | 1536 | static int __open_namei_create(struct nameidata *nd, struct path *path, |
1550 | int flag, int mode) | 1537 | int open_flag, int mode) |
1551 | { | 1538 | { |
1552 | int error; | 1539 | int error; |
1553 | struct dentry *dir = nd->path.dentry; | 1540 | struct dentry *dir = nd->path.dentry; |
@@ -1565,7 +1552,7 @@ out_unlock: | |||
1565 | if (error) | 1552 | if (error) |
1566 | return error; | 1553 | return error; |
1567 | /* Don't check for write permission, don't truncate */ | 1554 | /* Don't check for write permission, don't truncate */ |
1568 | return may_open(&nd->path, 0, flag & ~O_TRUNC); | 1555 | return may_open(&nd->path, 0, open_flag & ~O_TRUNC); |
1569 | } | 1556 | } |
1570 | 1557 | ||
1571 | /* | 1558 | /* |
@@ -1736,7 +1723,7 @@ do_last: | |||
1736 | error = mnt_want_write(nd.path.mnt); | 1723 | error = mnt_want_write(nd.path.mnt); |
1737 | if (error) | 1724 | if (error) |
1738 | goto exit_mutex_unlock; | 1725 | goto exit_mutex_unlock; |
1739 | error = __open_namei_create(&nd, &path, flag, mode); | 1726 | error = __open_namei_create(&nd, &path, open_flag, mode); |
1740 | if (error) { | 1727 | if (error) { |
1741 | mnt_drop_write(nd.path.mnt); | 1728 | mnt_drop_write(nd.path.mnt); |
1742 | goto exit; | 1729 | goto exit; |
@@ -1798,7 +1785,7 @@ ok: | |||
1798 | if (error) | 1785 | if (error) |
1799 | goto exit; | 1786 | goto exit; |
1800 | } | 1787 | } |
1801 | error = may_open(&nd.path, acc_mode, flag); | 1788 | error = may_open(&nd.path, acc_mode, open_flag); |
1802 | if (error) { | 1789 | if (error) { |
1803 | if (will_truncate) | 1790 | if (will_truncate) |
1804 | mnt_drop_write(nd.path.mnt); | 1791 | mnt_drop_write(nd.path.mnt); |
@@ -2275,8 +2262,11 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) | |||
2275 | error = -EBUSY; | 2262 | error = -EBUSY; |
2276 | else { | 2263 | else { |
2277 | error = security_inode_unlink(dir, dentry); | 2264 | error = security_inode_unlink(dir, dentry); |
2278 | if (!error) | 2265 | if (!error) { |
2279 | error = dir->i_op->unlink(dir, dentry); | 2266 | error = dir->i_op->unlink(dir, dentry); |
2267 | if (!error) | ||
2268 | dentry->d_inode->i_flags |= S_DEAD; | ||
2269 | } | ||
2280 | } | 2270 | } |
2281 | mutex_unlock(&dentry->d_inode->i_mutex); | 2271 | mutex_unlock(&dentry->d_inode->i_mutex); |
2282 | 2272 | ||
@@ -2629,6 +2619,8 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, | |||
2629 | else | 2619 | else |
2630 | 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); |
2631 | if (!error) { | 2621 | if (!error) { |
2622 | if (target) | ||
2623 | target->i_flags |= S_DEAD; | ||
2632 | 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)) |
2633 | d_move(old_dentry, new_dentry); | 2625 | d_move(old_dentry, new_dentry); |
2634 | } | 2626 | } |
@@ -2671,11 +2663,9 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2671 | error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry); | 2663 | error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry); |
2672 | else | 2664 | else |
2673 | error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry); | 2665 | error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry); |
2674 | if (!error) { | 2666 | if (!error) |
2675 | const char *new_name = old_dentry->d_name.name; | 2667 | fsnotify_move(old_dir, new_dir, old_name, is_dir, |
2676 | fsnotify_move(old_dir, new_dir, old_name, new_name, is_dir, | ||
2677 | new_dentry->d_inode, old_dentry); | 2668 | new_dentry->d_inode, old_dentry); |
2678 | } | ||
2679 | fsnotify_oldname_free(old_name); | 2669 | fsnotify_oldname_free(old_name); |
2680 | 2670 | ||
2681 | return error; | 2671 | return error; |