aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2006-01-18 20:43:53 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-18 22:20:29 -0500
commit5590ff0d5528b60153c0b4e7b771472b5a95e297 (patch)
tree5fdccf2354269702f71beb8e0a2942e4167fd992 /fs/namei.c
parente2f99018eb7b29954747a2dd78e9fc0c36a60f0f (diff)
[PATCH] vfs: *at functions: core
Here is a series of patches which introduce in total 13 new system calls which take a file descriptor/filename pair instead of a single file name. These functions, openat etc, have been discussed on numerous occasions. They are needed to implement race-free filesystem traversal, they are necessary to implement a virtual per-thread current working directory (think multi-threaded backup software), etc. We have in glibc today implementations of the interfaces which use the /proc/self/fd magic. But this code is rather expensive. Here are some results (similar to what Jim Meyering posted before). The test creates a deep directory hierarchy on a tmpfs filesystem. Then rm -fr is used to remove all directories. Without syscall support I get this: real 0m31.921s user 0m0.688s sys 0m31.234s With syscall support the results are much better: real 0m20.699s user 0m0.536s sys 0m20.149s The interfaces are for obvious reasons currently not much used. But they'll be used. coreutils (and Jeff's posixutils) are already using them. Furthermore, code like ftw/fts in libc (maybe even glob) will also start using them. I expect a patch to make follow soon. Every program which is walking the filesystem tree will benefit. Signed-off-by: Ulrich Drepper <drepper@redhat.com> Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Cc: Christoph Hellwig <hch@lst.de> Cc: Al Viro <viro@ftp.linux.org.uk> Acked-by: Ingo Molnar <mingo@elte.hu> Cc: Michael Kerrisk <mtk-manpages@gmx.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c172
1 files changed, 136 insertions, 36 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 33fb5bd34a81..4acdac043b6b 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -30,6 +30,8 @@
30#include <linux/audit.h> 30#include <linux/audit.h>
31#include <linux/capability.h> 31#include <linux/capability.h>
32#include <linux/file.h> 32#include <linux/file.h>
33#include <linux/fcntl.h>
34#include <linux/namei.h>
33#include <asm/namei.h> 35#include <asm/namei.h>
34#include <asm/uaccess.h> 36#include <asm/uaccess.h>
35 37
@@ -1063,7 +1065,8 @@ set_it:
1063} 1065}
1064 1066
1065/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ 1067/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
1066int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata *nd) 1068static int fastcall do_path_lookup(int dfd, const char *name,
1069 unsigned int flags, struct nameidata *nd)
1067{ 1070{
1068 int retval = 0; 1071 int retval = 0;
1069 1072
@@ -1083,9 +1086,38 @@ int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata
1083 } 1086 }
1084 nd->mnt = mntget(current->fs->rootmnt); 1087 nd->mnt = mntget(current->fs->rootmnt);
1085 nd->dentry = dget(current->fs->root); 1088 nd->dentry = dget(current->fs->root);
1086 } else { 1089 } else if (dfd == AT_FDCWD) {
1087 nd->mnt = mntget(current->fs->pwdmnt); 1090 nd->mnt = mntget(current->fs->pwdmnt);
1088 nd->dentry = dget(current->fs->pwd); 1091 nd->dentry = dget(current->fs->pwd);
1092 } else {
1093 struct file *file;
1094 int fput_needed;
1095 struct dentry *dentry;
1096
1097 file = fget_light(dfd, &fput_needed);
1098 if (!file) {
1099 retval = -EBADF;
1100 goto out_fail;
1101 }
1102
1103 dentry = file->f_dentry;
1104
1105 if (!S_ISDIR(dentry->d_inode->i_mode)) {
1106 retval = -ENOTDIR;
1107 fput_light(file, fput_needed);
1108 goto out_fail;
1109 }
1110
1111 retval = file_permission(file, MAY_EXEC);
1112 if (retval) {
1113 fput_light(file, fput_needed);
1114 goto out_fail;
1115 }
1116
1117 nd->mnt = mntget(file->f_vfsmnt);
1118 nd->dentry = dget(dentry);
1119
1120 fput_light(file, fput_needed);
1089 } 1121 }
1090 read_unlock(&current->fs->lock); 1122 read_unlock(&current->fs->lock);
1091 current->total_link_count = 0; 1123 current->total_link_count = 0;
@@ -1094,11 +1126,19 @@ out:
1094 if (unlikely(current->audit_context 1126 if (unlikely(current->audit_context
1095 && nd && nd->dentry && nd->dentry->d_inode)) 1127 && nd && nd->dentry && nd->dentry->d_inode))
1096 audit_inode(name, nd->dentry->d_inode, flags); 1128 audit_inode(name, nd->dentry->d_inode, flags);
1129out_fail:
1097 return retval; 1130 return retval;
1098} 1131}
1099 1132
1100static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags, 1133int fastcall path_lookup(const char *name, unsigned int flags,
1101 struct nameidata *nd, int open_flags, int create_mode) 1134 struct nameidata *nd)
1135{
1136 return do_path_lookup(AT_FDCWD, name, flags, nd);
1137}
1138
1139static int __path_lookup_intent_open(int dfd, const char *name,
1140 unsigned int lookup_flags, struct nameidata *nd,
1141 int open_flags, int create_mode)
1102{ 1142{
1103 struct file *filp = get_empty_filp(); 1143 struct file *filp = get_empty_filp();
1104 int err; 1144 int err;
@@ -1108,7 +1148,7 @@ static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags
1108 nd->intent.open.file = filp; 1148 nd->intent.open.file = filp;
1109 nd->intent.open.flags = open_flags; 1149 nd->intent.open.flags = open_flags;
1110 nd->intent.open.create_mode = create_mode; 1150 nd->intent.open.create_mode = create_mode;
1111 err = path_lookup(name, lookup_flags|LOOKUP_OPEN, nd); 1151 err = do_path_lookup(dfd, name, lookup_flags|LOOKUP_OPEN, nd);
1112 if (IS_ERR(nd->intent.open.file)) { 1152 if (IS_ERR(nd->intent.open.file)) {
1113 if (err == 0) { 1153 if (err == 0) {
1114 err = PTR_ERR(nd->intent.open.file); 1154 err = PTR_ERR(nd->intent.open.file);
@@ -1126,10 +1166,10 @@ static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags
1126 * @nd: pointer to nameidata 1166 * @nd: pointer to nameidata
1127 * @open_flags: open intent flags 1167 * @open_flags: open intent flags
1128 */ 1168 */
1129int path_lookup_open(const char *name, unsigned int lookup_flags, 1169int path_lookup_open(int dfd, const char *name, unsigned int lookup_flags,
1130 struct nameidata *nd, int open_flags) 1170 struct nameidata *nd, int open_flags)
1131{ 1171{
1132 return __path_lookup_intent_open(name, lookup_flags, nd, 1172 return __path_lookup_intent_open(dfd, name, lookup_flags, nd,
1133 open_flags, 0); 1173 open_flags, 0);
1134} 1174}
1135 1175
@@ -1141,12 +1181,12 @@ int path_lookup_open(const char *name, unsigned int lookup_flags,
1141 * @open_flags: open intent flags 1181 * @open_flags: open intent flags
1142 * @create_mode: create intent flags 1182 * @create_mode: create intent flags
1143 */ 1183 */
1144static int path_lookup_create(const char *name, unsigned int lookup_flags, 1184static int path_lookup_create(int dfd, const char *name,
1145 struct nameidata *nd, int open_flags, 1185 unsigned int lookup_flags, struct nameidata *nd,
1146 int create_mode) 1186 int open_flags, int create_mode)
1147{ 1187{
1148 return __path_lookup_intent_open(name, lookup_flags|LOOKUP_CREATE, nd, 1188 return __path_lookup_intent_open(dfd, name, lookup_flags|LOOKUP_CREATE,
1149 open_flags, create_mode); 1189 nd, open_flags, create_mode);
1150} 1190}
1151 1191
1152int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, 1192int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags,
@@ -1156,7 +1196,7 @@ int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags,
1156 int err = PTR_ERR(tmp); 1196 int err = PTR_ERR(tmp);
1157 1197
1158 if (!IS_ERR(tmp)) { 1198 if (!IS_ERR(tmp)) {
1159 err = __path_lookup_intent_open(tmp, lookup_flags, nd, open_flags, 0); 1199 err = __path_lookup_intent_open(AT_FDCWD, tmp, lookup_flags, nd, open_flags, 0);
1160 putname(tmp); 1200 putname(tmp);
1161 } 1201 }
1162 return err; 1202 return err;
@@ -1248,18 +1288,24 @@ access:
1248 * that namei follows links, while lnamei does not. 1288 * that namei follows links, while lnamei does not.
1249 * SMP-safe 1289 * SMP-safe
1250 */ 1290 */
1251int fastcall __user_walk(const char __user *name, unsigned flags, struct nameidata *nd) 1291int fastcall __user_walk_fd(int dfd, const char __user *name, unsigned flags,
1292 struct nameidata *nd)
1252{ 1293{
1253 char *tmp = getname(name); 1294 char *tmp = getname(name);
1254 int err = PTR_ERR(tmp); 1295 int err = PTR_ERR(tmp);
1255 1296
1256 if (!IS_ERR(tmp)) { 1297 if (!IS_ERR(tmp)) {
1257 err = path_lookup(tmp, flags, nd); 1298 err = do_path_lookup(dfd, tmp, flags, nd);
1258 putname(tmp); 1299 putname(tmp);
1259 } 1300 }
1260 return err; 1301 return err;
1261} 1302}
1262 1303
1304int fastcall __user_walk(const char __user *name, unsigned flags, struct nameidata *nd)
1305{
1306 return __user_walk_fd(AT_FDCWD, name, flags, nd);
1307}
1308
1263/* 1309/*
1264 * It's inline, so penalty for filesystems that don't use sticky bit is 1310 * It's inline, so penalty for filesystems that don't use sticky bit is
1265 * minimal. 1311 * minimal.
@@ -1518,7 +1564,8 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
1518 * for symlinks (where the permissions are checked later). 1564 * for symlinks (where the permissions are checked later).
1519 * SMP-safe 1565 * SMP-safe
1520 */ 1566 */
1521int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) 1567int open_namei(int dfd, const char *pathname, int flag,
1568 int mode, struct nameidata *nd)
1522{ 1569{
1523 int acc_mode, error; 1570 int acc_mode, error;
1524 struct path path; 1571 struct path path;
@@ -1540,7 +1587,8 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
1540 * The simplest case - just a plain lookup. 1587 * The simplest case - just a plain lookup.
1541 */ 1588 */
1542 if (!(flag & O_CREAT)) { 1589 if (!(flag & O_CREAT)) {
1543 error = path_lookup_open(pathname, lookup_flags(flag), nd, flag); 1590 error = path_lookup_open(dfd, pathname, lookup_flags(flag),
1591 nd, flag);
1544 if (error) 1592 if (error)
1545 return error; 1593 return error;
1546 goto ok; 1594 goto ok;
@@ -1549,7 +1597,7 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
1549 /* 1597 /*
1550 * Create - we need to know the parent. 1598 * Create - we need to know the parent.
1551 */ 1599 */
1552 error = path_lookup_create(pathname, LOOKUP_PARENT, nd, flag, mode); 1600 error = path_lookup_create(dfd,pathname,LOOKUP_PARENT,nd,flag,mode);
1553 if (error) 1601 if (error)
1554 return error; 1602 return error;
1555 1603
@@ -1744,7 +1792,8 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
1744 return error; 1792 return error;
1745} 1793}
1746 1794
1747asmlinkage long sys_mknod(const char __user * filename, int mode, unsigned dev) 1795asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode,
1796 unsigned dev)
1748{ 1797{
1749 int error = 0; 1798 int error = 0;
1750 char * tmp; 1799 char * tmp;
@@ -1757,7 +1806,7 @@ asmlinkage long sys_mknod(const char __user * filename, int mode, unsigned dev)
1757 if (IS_ERR(tmp)) 1806 if (IS_ERR(tmp))
1758 return PTR_ERR(tmp); 1807 return PTR_ERR(tmp);
1759 1808
1760 error = path_lookup(tmp, LOOKUP_PARENT, &nd); 1809 error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd);
1761 if (error) 1810 if (error)
1762 goto out; 1811 goto out;
1763 dentry = lookup_create(&nd, 0); 1812 dentry = lookup_create(&nd, 0);
@@ -1793,6 +1842,11 @@ out:
1793 return error; 1842 return error;
1794} 1843}
1795 1844
1845asmlinkage long sys_mknod(const char __user *filename, int mode, unsigned dev)
1846{
1847 return sys_mknodat(AT_FDCWD, filename, mode, dev);
1848}
1849
1796int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) 1850int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
1797{ 1851{
1798 int error = may_create(dir, dentry, NULL); 1852 int error = may_create(dir, dentry, NULL);
@@ -1815,7 +1869,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
1815 return error; 1869 return error;
1816} 1870}
1817 1871
1818asmlinkage long sys_mkdir(const char __user * pathname, int mode) 1872asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode)
1819{ 1873{
1820 int error = 0; 1874 int error = 0;
1821 char * tmp; 1875 char * tmp;
@@ -1826,7 +1880,7 @@ asmlinkage long sys_mkdir(const char __user * pathname, int mode)
1826 struct dentry *dentry; 1880 struct dentry *dentry;
1827 struct nameidata nd; 1881 struct nameidata nd;
1828 1882
1829 error = path_lookup(tmp, LOOKUP_PARENT, &nd); 1883 error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd);
1830 if (error) 1884 if (error)
1831 goto out; 1885 goto out;
1832 dentry = lookup_create(&nd, 1); 1886 dentry = lookup_create(&nd, 1);
@@ -1846,6 +1900,11 @@ out:
1846 return error; 1900 return error;
1847} 1901}
1848 1902
1903asmlinkage long sys_mkdir(const char __user *pathname, int mode)
1904{
1905 return sys_mkdirat(AT_FDCWD, pathname, mode);
1906}
1907
1849/* 1908/*
1850 * We try to drop the dentry early: we should have 1909 * We try to drop the dentry early: we should have
1851 * a usage count of 2 if we're the only user of this 1910 * a usage count of 2 if we're the only user of this
@@ -1907,7 +1966,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
1907 return error; 1966 return error;
1908} 1967}
1909 1968
1910asmlinkage long sys_rmdir(const char __user * pathname) 1969static long do_rmdir(int dfd, const char __user *pathname)
1911{ 1970{
1912 int error = 0; 1971 int error = 0;
1913 char * name; 1972 char * name;
@@ -1918,7 +1977,7 @@ asmlinkage long sys_rmdir(const char __user * pathname)
1918 if(IS_ERR(name)) 1977 if(IS_ERR(name))
1919 return PTR_ERR(name); 1978 return PTR_ERR(name);
1920 1979
1921 error = path_lookup(name, LOOKUP_PARENT, &nd); 1980 error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd);
1922 if (error) 1981 if (error)
1923 goto exit; 1982 goto exit;
1924 1983
@@ -1948,6 +2007,11 @@ exit:
1948 return error; 2007 return error;
1949} 2008}
1950 2009
2010asmlinkage long sys_rmdir(const char __user *pathname)
2011{
2012 return do_rmdir(AT_FDCWD, pathname);
2013}
2014
1951int vfs_unlink(struct inode *dir, struct dentry *dentry) 2015int vfs_unlink(struct inode *dir, struct dentry *dentry)
1952{ 2016{
1953 int error = may_delete(dir, dentry, 0); 2017 int error = may_delete(dir, dentry, 0);
@@ -1984,7 +2048,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
1984 * writeout happening, and we don't want to prevent access to the directory 2048 * writeout happening, and we don't want to prevent access to the directory
1985 * while waiting on the I/O. 2049 * while waiting on the I/O.
1986 */ 2050 */
1987asmlinkage long sys_unlink(const char __user * pathname) 2051static long do_unlinkat(int dfd, const char __user *pathname)
1988{ 2052{
1989 int error = 0; 2053 int error = 0;
1990 char * name; 2054 char * name;
@@ -1996,7 +2060,7 @@ asmlinkage long sys_unlink(const char __user * pathname)
1996 if(IS_ERR(name)) 2060 if(IS_ERR(name))
1997 return PTR_ERR(name); 2061 return PTR_ERR(name);
1998 2062
1999 error = path_lookup(name, LOOKUP_PARENT, &nd); 2063 error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd);
2000 if (error) 2064 if (error)
2001 goto exit; 2065 goto exit;
2002 error = -EISDIR; 2066 error = -EISDIR;
@@ -2031,6 +2095,22 @@ slashes:
2031 goto exit2; 2095 goto exit2;
2032} 2096}
2033 2097
2098asmlinkage long sys_unlinkat(int dfd, const char __user *pathname, int flag)
2099{
2100 if ((flag & ~AT_REMOVEDIR) != 0)
2101 return -EINVAL;
2102
2103 if (flag & AT_REMOVEDIR)
2104 return do_rmdir(dfd, pathname);
2105
2106 return do_unlinkat(dfd, pathname);
2107}
2108
2109asmlinkage long sys_unlink(const char __user *pathname)
2110{
2111 return do_unlinkat(AT_FDCWD, pathname);
2112}
2113
2034int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, int mode) 2114int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, int mode)
2035{ 2115{
2036 int error = may_create(dir, dentry, NULL); 2116 int error = may_create(dir, dentry, NULL);
@@ -2052,7 +2132,8 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, i
2052 return error; 2132 return error;
2053} 2133}
2054 2134
2055asmlinkage long sys_symlink(const char __user * oldname, const char __user * newname) 2135asmlinkage long sys_symlinkat(const char __user *oldname,
2136 int newdfd, const char __user *newname)
2056{ 2137{
2057 int error = 0; 2138 int error = 0;
2058 char * from; 2139 char * from;
@@ -2067,7 +2148,7 @@ asmlinkage long sys_symlink(const char __user * oldname, const char __user * new
2067 struct dentry *dentry; 2148 struct dentry *dentry;
2068 struct nameidata nd; 2149 struct nameidata nd;
2069 2150
2070 error = path_lookup(to, LOOKUP_PARENT, &nd); 2151 error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
2071 if (error) 2152 if (error)
2072 goto out; 2153 goto out;
2073 dentry = lookup_create(&nd, 0); 2154 dentry = lookup_create(&nd, 0);
@@ -2085,6 +2166,11 @@ out:
2085 return error; 2166 return error;
2086} 2167}
2087 2168
2169asmlinkage long sys_symlink(const char __user *oldname, const char __user *newname)
2170{
2171 return sys_symlinkat(oldname, AT_FDCWD, newname);
2172}
2173
2088int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) 2174int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
2089{ 2175{
2090 struct inode *inode = old_dentry->d_inode; 2176 struct inode *inode = old_dentry->d_inode;
@@ -2132,7 +2218,8 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
2132 * with linux 2.0, and to avoid hard-linking to directories 2218 * with linux 2.0, and to avoid hard-linking to directories
2133 * and other special files. --ADM 2219 * and other special files. --ADM
2134 */ 2220 */
2135asmlinkage long sys_link(const char __user * oldname, const char __user * newname) 2221asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
2222 int newdfd, const char __user *newname)
2136{ 2223{
2137 struct dentry *new_dentry; 2224 struct dentry *new_dentry;
2138 struct nameidata nd, old_nd; 2225 struct nameidata nd, old_nd;
@@ -2143,10 +2230,10 @@ asmlinkage long sys_link(const char __user * oldname, const char __user * newnam
2143 if (IS_ERR(to)) 2230 if (IS_ERR(to))
2144 return PTR_ERR(to); 2231 return PTR_ERR(to);
2145 2232
2146 error = __user_walk(oldname, 0, &old_nd); 2233 error = __user_walk_fd(olddfd, oldname, 0, &old_nd);
2147 if (error) 2234 if (error)
2148 goto exit; 2235 goto exit;
2149 error = path_lookup(to, LOOKUP_PARENT, &nd); 2236 error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
2150 if (error) 2237 if (error)
2151 goto out; 2238 goto out;
2152 error = -EXDEV; 2239 error = -EXDEV;
@@ -2169,6 +2256,11 @@ exit:
2169 return error; 2256 return error;
2170} 2257}
2171 2258
2259asmlinkage long sys_link(const char __user *oldname, const char __user *newname)
2260{
2261 return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname);
2262}
2263
2172/* 2264/*
2173 * The worst of all namespace operations - renaming directory. "Perverted" 2265 * The worst of all namespace operations - renaming directory. "Perverted"
2174 * doesn't even start to describe it. Somebody in UCB had a heck of a trip... 2266 * doesn't even start to describe it. Somebody in UCB had a heck of a trip...
@@ -2315,7 +2407,8 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
2315 return error; 2407 return error;
2316} 2408}
2317 2409
2318static int do_rename(const char * oldname, const char * newname) 2410static int do_rename(int olddfd, const char *oldname,
2411 int newdfd, const char *newname)
2319{ 2412{
2320 int error = 0; 2413 int error = 0;
2321 struct dentry * old_dir, * new_dir; 2414 struct dentry * old_dir, * new_dir;
@@ -2323,11 +2416,11 @@ static int do_rename(const char * oldname, const char * newname)
2323 struct dentry * trap; 2416 struct dentry * trap;
2324 struct nameidata oldnd, newnd; 2417 struct nameidata oldnd, newnd;
2325 2418
2326 error = path_lookup(oldname, LOOKUP_PARENT, &oldnd); 2419 error = do_path_lookup(olddfd, oldname, LOOKUP_PARENT, &oldnd);
2327 if (error) 2420 if (error)
2328 goto exit; 2421 goto exit;
2329 2422
2330 error = path_lookup(newname, LOOKUP_PARENT, &newnd); 2423 error = do_path_lookup(newdfd, newname, LOOKUP_PARENT, &newnd);
2331 if (error) 2424 if (error)
2332 goto exit1; 2425 goto exit1;
2333 2426
@@ -2391,7 +2484,8 @@ exit:
2391 return error; 2484 return error;
2392} 2485}
2393 2486
2394asmlinkage long sys_rename(const char __user * oldname, const char __user * newname) 2487asmlinkage long sys_renameat(int olddfd, const char __user *oldname,
2488 int newdfd, const char __user *newname)
2395{ 2489{
2396 int error; 2490 int error;
2397 char * from; 2491 char * from;
@@ -2403,13 +2497,18 @@ asmlinkage long sys_rename(const char __user * oldname, const char __user * newn
2403 to = getname(newname); 2497 to = getname(newname);
2404 error = PTR_ERR(to); 2498 error = PTR_ERR(to);
2405 if (!IS_ERR(to)) { 2499 if (!IS_ERR(to)) {
2406 error = do_rename(from,to); 2500 error = do_rename(olddfd, from, newdfd, to);
2407 putname(to); 2501 putname(to);
2408 } 2502 }
2409 putname(from); 2503 putname(from);
2410 return error; 2504 return error;
2411} 2505}
2412 2506
2507asmlinkage long sys_rename(const char __user *oldname, const char __user *newname)
2508{
2509 return sys_renameat(AT_FDCWD, oldname, AT_FDCWD, newname);
2510}
2511
2413int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const char *link) 2512int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const char *link)
2414{ 2513{
2415 int len; 2514 int len;
@@ -2553,6 +2652,7 @@ struct inode_operations page_symlink_inode_operations = {
2553}; 2652};
2554 2653
2555EXPORT_SYMBOL(__user_walk); 2654EXPORT_SYMBOL(__user_walk);
2655EXPORT_SYMBOL(__user_walk_fd);
2556EXPORT_SYMBOL(follow_down); 2656EXPORT_SYMBOL(follow_down);
2557EXPORT_SYMBOL(follow_up); 2657EXPORT_SYMBOL(follow_up);
2558EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ 2658EXPORT_SYMBOL(get_write_access); /* binfmt_aout */