diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 209 |
1 files changed, 117 insertions, 92 deletions
diff --git a/fs/namei.c b/fs/namei.c index 808e4ea2bb94..28d49b301d55 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -518,18 +518,20 @@ static int __emul_lookup_dentry(const char *, struct nameidata *); | |||
518 | static __always_inline int | 518 | static __always_inline int |
519 | walk_init_root(const char *name, struct nameidata *nd) | 519 | walk_init_root(const char *name, struct nameidata *nd) |
520 | { | 520 | { |
521 | read_lock(¤t->fs->lock); | 521 | struct fs_struct *fs = current->fs; |
522 | if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) { | 522 | |
523 | nd->mnt = mntget(current->fs->altrootmnt); | 523 | read_lock(&fs->lock); |
524 | nd->dentry = dget(current->fs->altroot); | 524 | if (fs->altroot && !(nd->flags & LOOKUP_NOALT)) { |
525 | read_unlock(¤t->fs->lock); | 525 | nd->mnt = mntget(fs->altrootmnt); |
526 | nd->dentry = dget(fs->altroot); | ||
527 | read_unlock(&fs->lock); | ||
526 | if (__emul_lookup_dentry(name,nd)) | 528 | if (__emul_lookup_dentry(name,nd)) |
527 | return 0; | 529 | return 0; |
528 | read_lock(¤t->fs->lock); | 530 | read_lock(&fs->lock); |
529 | } | 531 | } |
530 | nd->mnt = mntget(current->fs->rootmnt); | 532 | nd->mnt = mntget(fs->rootmnt); |
531 | nd->dentry = dget(current->fs->root); | 533 | nd->dentry = dget(fs->root); |
532 | read_unlock(¤t->fs->lock); | 534 | read_unlock(&fs->lock); |
533 | return 1; | 535 | return 1; |
534 | } | 536 | } |
535 | 537 | ||
@@ -724,17 +726,19 @@ int follow_down(struct vfsmount **mnt, struct dentry **dentry) | |||
724 | 726 | ||
725 | static __always_inline void follow_dotdot(struct nameidata *nd) | 727 | static __always_inline void follow_dotdot(struct nameidata *nd) |
726 | { | 728 | { |
729 | struct fs_struct *fs = current->fs; | ||
730 | |||
727 | while(1) { | 731 | while(1) { |
728 | struct vfsmount *parent; | 732 | struct vfsmount *parent; |
729 | struct dentry *old = nd->dentry; | 733 | struct dentry *old = nd->dentry; |
730 | 734 | ||
731 | read_lock(¤t->fs->lock); | 735 | read_lock(&fs->lock); |
732 | if (nd->dentry == current->fs->root && | 736 | if (nd->dentry == fs->root && |
733 | nd->mnt == current->fs->rootmnt) { | 737 | nd->mnt == fs->rootmnt) { |
734 | read_unlock(¤t->fs->lock); | 738 | read_unlock(&fs->lock); |
735 | break; | 739 | break; |
736 | } | 740 | } |
737 | read_unlock(¤t->fs->lock); | 741 | read_unlock(&fs->lock); |
738 | spin_lock(&dcache_lock); | 742 | spin_lock(&dcache_lock); |
739 | if (nd->dentry != nd->mnt->mnt_root) { | 743 | if (nd->dentry != nd->mnt->mnt_root) { |
740 | nd->dentry = dget(nd->dentry->d_parent); | 744 | nd->dentry = dget(nd->dentry->d_parent); |
@@ -1042,15 +1046,17 @@ static int __emul_lookup_dentry(const char *name, struct nameidata *nd) | |||
1042 | struct vfsmount *old_mnt = nd->mnt; | 1046 | struct vfsmount *old_mnt = nd->mnt; |
1043 | struct qstr last = nd->last; | 1047 | struct qstr last = nd->last; |
1044 | int last_type = nd->last_type; | 1048 | int last_type = nd->last_type; |
1049 | struct fs_struct *fs = current->fs; | ||
1050 | |||
1045 | /* | 1051 | /* |
1046 | * NAME was not found in alternate root or it's a directory. Try to find | 1052 | * NAME was not found in alternate root or it's a directory. |
1047 | * it in the normal root: | 1053 | * Try to find it in the normal root: |
1048 | */ | 1054 | */ |
1049 | nd->last_type = LAST_ROOT; | 1055 | nd->last_type = LAST_ROOT; |
1050 | read_lock(¤t->fs->lock); | 1056 | read_lock(&fs->lock); |
1051 | nd->mnt = mntget(current->fs->rootmnt); | 1057 | nd->mnt = mntget(fs->rootmnt); |
1052 | nd->dentry = dget(current->fs->root); | 1058 | nd->dentry = dget(fs->root); |
1053 | read_unlock(¤t->fs->lock); | 1059 | read_unlock(&fs->lock); |
1054 | if (path_walk(name, nd) == 0) { | 1060 | if (path_walk(name, nd) == 0) { |
1055 | if (nd->dentry->d_inode) { | 1061 | if (nd->dentry->d_inode) { |
1056 | dput(old_dentry); | 1062 | dput(old_dentry); |
@@ -1074,6 +1080,7 @@ void set_fs_altroot(void) | |||
1074 | struct vfsmount *mnt = NULL, *oldmnt; | 1080 | struct vfsmount *mnt = NULL, *oldmnt; |
1075 | struct dentry *dentry = NULL, *olddentry; | 1081 | struct dentry *dentry = NULL, *olddentry; |
1076 | int err; | 1082 | int err; |
1083 | struct fs_struct *fs = current->fs; | ||
1077 | 1084 | ||
1078 | if (!emul) | 1085 | if (!emul) |
1079 | goto set_it; | 1086 | goto set_it; |
@@ -1083,12 +1090,12 @@ void set_fs_altroot(void) | |||
1083 | dentry = nd.dentry; | 1090 | dentry = nd.dentry; |
1084 | } | 1091 | } |
1085 | set_it: | 1092 | set_it: |
1086 | write_lock(¤t->fs->lock); | 1093 | write_lock(&fs->lock); |
1087 | oldmnt = current->fs->altrootmnt; | 1094 | oldmnt = fs->altrootmnt; |
1088 | olddentry = current->fs->altroot; | 1095 | olddentry = fs->altroot; |
1089 | current->fs->altrootmnt = mnt; | 1096 | fs->altrootmnt = mnt; |
1090 | current->fs->altroot = dentry; | 1097 | fs->altroot = dentry; |
1091 | write_unlock(¤t->fs->lock); | 1098 | write_unlock(&fs->lock); |
1092 | if (olddentry) { | 1099 | if (olddentry) { |
1093 | dput(olddentry); | 1100 | dput(olddentry); |
1094 | mntput(oldmnt); | 1101 | mntput(oldmnt); |
@@ -1102,29 +1109,30 @@ static int fastcall do_path_lookup(int dfd, const char *name, | |||
1102 | int retval = 0; | 1109 | int retval = 0; |
1103 | int fput_needed; | 1110 | int fput_needed; |
1104 | struct file *file; | 1111 | struct file *file; |
1112 | struct fs_struct *fs = current->fs; | ||
1105 | 1113 | ||
1106 | nd->last_type = LAST_ROOT; /* if there are only slashes... */ | 1114 | nd->last_type = LAST_ROOT; /* if there are only slashes... */ |
1107 | nd->flags = flags; | 1115 | nd->flags = flags; |
1108 | nd->depth = 0; | 1116 | nd->depth = 0; |
1109 | 1117 | ||
1110 | if (*name=='/') { | 1118 | if (*name=='/') { |
1111 | read_lock(¤t->fs->lock); | 1119 | read_lock(&fs->lock); |
1112 | if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) { | 1120 | if (fs->altroot && !(nd->flags & LOOKUP_NOALT)) { |
1113 | nd->mnt = mntget(current->fs->altrootmnt); | 1121 | nd->mnt = mntget(fs->altrootmnt); |
1114 | nd->dentry = dget(current->fs->altroot); | 1122 | nd->dentry = dget(fs->altroot); |
1115 | read_unlock(¤t->fs->lock); | 1123 | read_unlock(&fs->lock); |
1116 | if (__emul_lookup_dentry(name,nd)) | 1124 | if (__emul_lookup_dentry(name,nd)) |
1117 | goto out; /* found in altroot */ | 1125 | goto out; /* found in altroot */ |
1118 | read_lock(¤t->fs->lock); | 1126 | read_lock(&fs->lock); |
1119 | } | 1127 | } |
1120 | nd->mnt = mntget(current->fs->rootmnt); | 1128 | nd->mnt = mntget(fs->rootmnt); |
1121 | nd->dentry = dget(current->fs->root); | 1129 | nd->dentry = dget(fs->root); |
1122 | read_unlock(¤t->fs->lock); | 1130 | read_unlock(&fs->lock); |
1123 | } else if (dfd == AT_FDCWD) { | 1131 | } else if (dfd == AT_FDCWD) { |
1124 | read_lock(¤t->fs->lock); | 1132 | read_lock(&fs->lock); |
1125 | nd->mnt = mntget(current->fs->pwdmnt); | 1133 | nd->mnt = mntget(fs->pwdmnt); |
1126 | nd->dentry = dget(current->fs->pwd); | 1134 | nd->dentry = dget(fs->pwd); |
1127 | read_unlock(¤t->fs->lock); | 1135 | read_unlock(&fs->lock); |
1128 | } else { | 1136 | } else { |
1129 | struct dentry *dentry; | 1137 | struct dentry *dentry; |
1130 | 1138 | ||
@@ -1587,6 +1595,24 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) | |||
1587 | return 0; | 1595 | return 0; |
1588 | } | 1596 | } |
1589 | 1597 | ||
1598 | static int open_namei_create(struct nameidata *nd, struct path *path, | ||
1599 | int flag, int mode) | ||
1600 | { | ||
1601 | int error; | ||
1602 | struct dentry *dir = nd->dentry; | ||
1603 | |||
1604 | if (!IS_POSIXACL(dir->d_inode)) | ||
1605 | mode &= ~current->fs->umask; | ||
1606 | error = vfs_create(dir->d_inode, path->dentry, mode, nd); | ||
1607 | mutex_unlock(&dir->d_inode->i_mutex); | ||
1608 | dput(nd->dentry); | ||
1609 | nd->dentry = path->dentry; | ||
1610 | if (error) | ||
1611 | return error; | ||
1612 | /* Don't check for write permission, don't truncate */ | ||
1613 | return may_open(nd, 0, flag & ~O_TRUNC); | ||
1614 | } | ||
1615 | |||
1590 | /* | 1616 | /* |
1591 | * open_namei() | 1617 | * open_namei() |
1592 | * | 1618 | * |
@@ -1668,18 +1694,10 @@ do_last: | |||
1668 | 1694 | ||
1669 | /* Negative dentry, just create the file */ | 1695 | /* Negative dentry, just create the file */ |
1670 | if (!path.dentry->d_inode) { | 1696 | if (!path.dentry->d_inode) { |
1671 | if (!IS_POSIXACL(dir->d_inode)) | 1697 | error = open_namei_create(nd, &path, flag, mode); |
1672 | mode &= ~current->fs->umask; | ||
1673 | error = vfs_create(dir->d_inode, path.dentry, mode, nd); | ||
1674 | mutex_unlock(&dir->d_inode->i_mutex); | ||
1675 | dput(nd->dentry); | ||
1676 | nd->dentry = path.dentry; | ||
1677 | if (error) | 1698 | if (error) |
1678 | goto exit; | 1699 | goto exit; |
1679 | /* Don't check for write permission, don't truncate */ | 1700 | return 0; |
1680 | acc_mode = 0; | ||
1681 | flag &= ~O_TRUNC; | ||
1682 | goto ok; | ||
1683 | } | 1701 | } |
1684 | 1702 | ||
1685 | /* | 1703 | /* |
@@ -1926,30 +1944,32 @@ asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode) | |||
1926 | { | 1944 | { |
1927 | int error = 0; | 1945 | int error = 0; |
1928 | char * tmp; | 1946 | char * tmp; |
1947 | struct dentry *dentry; | ||
1948 | struct nameidata nd; | ||
1929 | 1949 | ||
1930 | tmp = getname(pathname); | 1950 | tmp = getname(pathname); |
1931 | error = PTR_ERR(tmp); | 1951 | error = PTR_ERR(tmp); |
1932 | if (!IS_ERR(tmp)) { | 1952 | if (IS_ERR(tmp)) |
1933 | struct dentry *dentry; | 1953 | goto out_err; |
1934 | struct nameidata nd; | ||
1935 | 1954 | ||
1936 | error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd); | 1955 | error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd); |
1937 | if (error) | 1956 | if (error) |
1938 | goto out; | 1957 | goto out; |
1939 | dentry = lookup_create(&nd, 1); | 1958 | dentry = lookup_create(&nd, 1); |
1940 | error = PTR_ERR(dentry); | 1959 | error = PTR_ERR(dentry); |
1941 | if (!IS_ERR(dentry)) { | 1960 | if (IS_ERR(dentry)) |
1942 | if (!IS_POSIXACL(nd.dentry->d_inode)) | 1961 | goto out_unlock; |
1943 | mode &= ~current->fs->umask; | ||
1944 | error = vfs_mkdir(nd.dentry->d_inode, dentry, mode); | ||
1945 | dput(dentry); | ||
1946 | } | ||
1947 | mutex_unlock(&nd.dentry->d_inode->i_mutex); | ||
1948 | path_release(&nd); | ||
1949 | out: | ||
1950 | putname(tmp); | ||
1951 | } | ||
1952 | 1962 | ||
1963 | if (!IS_POSIXACL(nd.dentry->d_inode)) | ||
1964 | mode &= ~current->fs->umask; | ||
1965 | error = vfs_mkdir(nd.dentry->d_inode, dentry, mode); | ||
1966 | dput(dentry); | ||
1967 | out_unlock: | ||
1968 | mutex_unlock(&nd.dentry->d_inode->i_mutex); | ||
1969 | path_release(&nd); | ||
1970 | out: | ||
1971 | putname(tmp); | ||
1972 | out_err: | ||
1953 | return error; | 1973 | return error; |
1954 | } | 1974 | } |
1955 | 1975 | ||
@@ -2048,10 +2068,11 @@ static long do_rmdir(int dfd, const char __user *pathname) | |||
2048 | mutex_lock_nested(&nd.dentry->d_inode->i_mutex, I_MUTEX_PARENT); | 2068 | mutex_lock_nested(&nd.dentry->d_inode->i_mutex, I_MUTEX_PARENT); |
2049 | dentry = lookup_hash(&nd); | 2069 | dentry = lookup_hash(&nd); |
2050 | error = PTR_ERR(dentry); | 2070 | error = PTR_ERR(dentry); |
2051 | if (!IS_ERR(dentry)) { | 2071 | if (IS_ERR(dentry)) |
2052 | error = vfs_rmdir(nd.dentry->d_inode, dentry); | 2072 | goto exit2; |
2053 | dput(dentry); | 2073 | error = vfs_rmdir(nd.dentry->d_inode, dentry); |
2054 | } | 2074 | dput(dentry); |
2075 | exit2: | ||
2055 | mutex_unlock(&nd.dentry->d_inode->i_mutex); | 2076 | mutex_unlock(&nd.dentry->d_inode->i_mutex); |
2056 | exit1: | 2077 | exit1: |
2057 | path_release(&nd); | 2078 | path_release(&nd); |
@@ -2191,30 +2212,33 @@ asmlinkage long sys_symlinkat(const char __user *oldname, | |||
2191 | int error = 0; | 2212 | int error = 0; |
2192 | char * from; | 2213 | char * from; |
2193 | char * to; | 2214 | char * to; |
2215 | struct dentry *dentry; | ||
2216 | struct nameidata nd; | ||
2194 | 2217 | ||
2195 | from = getname(oldname); | 2218 | from = getname(oldname); |
2196 | if(IS_ERR(from)) | 2219 | if(IS_ERR(from)) |
2197 | return PTR_ERR(from); | 2220 | return PTR_ERR(from); |
2198 | to = getname(newname); | 2221 | to = getname(newname); |
2199 | error = PTR_ERR(to); | 2222 | error = PTR_ERR(to); |
2200 | if (!IS_ERR(to)) { | 2223 | if (IS_ERR(to)) |
2201 | struct dentry *dentry; | 2224 | goto out_putname; |
2202 | struct nameidata nd; | ||
2203 | 2225 | ||
2204 | error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd); | 2226 | error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd); |
2205 | if (error) | 2227 | if (error) |
2206 | goto out; | 2228 | goto out; |
2207 | dentry = lookup_create(&nd, 0); | 2229 | dentry = lookup_create(&nd, 0); |
2208 | error = PTR_ERR(dentry); | 2230 | error = PTR_ERR(dentry); |
2209 | if (!IS_ERR(dentry)) { | 2231 | if (IS_ERR(dentry)) |
2210 | error = vfs_symlink(nd.dentry->d_inode, dentry, from, S_IALLUGO); | 2232 | goto out_unlock; |
2211 | dput(dentry); | 2233 | |
2212 | } | 2234 | error = vfs_symlink(nd.dentry->d_inode, dentry, from, S_IALLUGO); |
2213 | mutex_unlock(&nd.dentry->d_inode->i_mutex); | 2235 | dput(dentry); |
2214 | path_release(&nd); | 2236 | out_unlock: |
2237 | mutex_unlock(&nd.dentry->d_inode->i_mutex); | ||
2238 | path_release(&nd); | ||
2215 | out: | 2239 | out: |
2216 | putname(to); | 2240 | putname(to); |
2217 | } | 2241 | out_putname: |
2218 | putname(from); | 2242 | putname(from); |
2219 | return error; | 2243 | return error; |
2220 | } | 2244 | } |
@@ -2300,10 +2324,11 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname, | |||
2300 | goto out_release; | 2324 | goto out_release; |
2301 | new_dentry = lookup_create(&nd, 0); | 2325 | new_dentry = lookup_create(&nd, 0); |
2302 | error = PTR_ERR(new_dentry); | 2326 | error = PTR_ERR(new_dentry); |
2303 | if (!IS_ERR(new_dentry)) { | 2327 | if (IS_ERR(new_dentry)) |
2304 | error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry); | 2328 | goto out_unlock; |
2305 | dput(new_dentry); | 2329 | error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry); |
2306 | } | 2330 | dput(new_dentry); |
2331 | out_unlock: | ||
2307 | mutex_unlock(&nd.dentry->d_inode->i_mutex); | 2332 | mutex_unlock(&nd.dentry->d_inode->i_mutex); |
2308 | out_release: | 2333 | out_release: |
2309 | path_release(&nd); | 2334 | path_release(&nd); |