diff options
Diffstat (limited to 'fs/namei.c')
| -rw-r--r-- | fs/namei.c | 271 |
1 files changed, 186 insertions, 85 deletions
diff --git a/fs/namei.c b/fs/namei.c index 6dbbd42d8b95..4acdac043b6b 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -28,7 +28,10 @@ | |||
| 28 | #include <linux/syscalls.h> | 28 | #include <linux/syscalls.h> |
| 29 | #include <linux/mount.h> | 29 | #include <linux/mount.h> |
| 30 | #include <linux/audit.h> | 30 | #include <linux/audit.h> |
| 31 | #include <linux/capability.h> | ||
| 31 | #include <linux/file.h> | 32 | #include <linux/file.h> |
| 33 | #include <linux/fcntl.h> | ||
| 34 | #include <linux/namei.h> | ||
| 32 | #include <asm/namei.h> | 35 | #include <asm/namei.h> |
| 33 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
| 34 | 37 | ||
| @@ -112,7 +115,7 @@ | |||
| 112 | * POSIX.1 2.4: an empty pathname is invalid (ENOENT). | 115 | * POSIX.1 2.4: an empty pathname is invalid (ENOENT). |
| 113 | * PATH_MAX includes the nul terminator --RR. | 116 | * PATH_MAX includes the nul terminator --RR. |
| 114 | */ | 117 | */ |
| 115 | static inline int do_getname(const char __user *filename, char *page) | 118 | static int do_getname(const char __user *filename, char *page) |
| 116 | { | 119 | { |
| 117 | int retval; | 120 | int retval; |
| 118 | unsigned long len = PATH_MAX; | 121 | unsigned long len = PATH_MAX; |
| @@ -395,7 +398,7 @@ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, | |||
| 395 | * short-cut DAC fails, then call permission() to do more | 398 | * short-cut DAC fails, then call permission() to do more |
| 396 | * complete permission check. | 399 | * complete permission check. |
| 397 | */ | 400 | */ |
| 398 | static inline int exec_permission_lite(struct inode *inode, | 401 | static int exec_permission_lite(struct inode *inode, |
| 399 | struct nameidata *nd) | 402 | struct nameidata *nd) |
| 400 | { | 403 | { |
| 401 | umode_t mode = inode->i_mode; | 404 | umode_t mode = inode->i_mode; |
| @@ -438,7 +441,7 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s | |||
| 438 | struct dentry * result; | 441 | struct dentry * result; |
| 439 | struct inode *dir = parent->d_inode; | 442 | struct inode *dir = parent->d_inode; |
| 440 | 443 | ||
| 441 | down(&dir->i_sem); | 444 | mutex_lock(&dir->i_mutex); |
| 442 | /* | 445 | /* |
| 443 | * First re-do the cached lookup just in case it was created | 446 | * First re-do the cached lookup just in case it was created |
| 444 | * while we waited for the directory semaphore.. | 447 | * while we waited for the directory semaphore.. |
| @@ -464,7 +467,7 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s | |||
| 464 | else | 467 | else |
| 465 | result = dentry; | 468 | result = dentry; |
| 466 | } | 469 | } |
| 467 | up(&dir->i_sem); | 470 | mutex_unlock(&dir->i_mutex); |
| 468 | return result; | 471 | return result; |
| 469 | } | 472 | } |
| 470 | 473 | ||
| @@ -472,7 +475,7 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s | |||
| 472 | * Uhhuh! Nasty case: the cache was re-populated while | 475 | * Uhhuh! Nasty case: the cache was re-populated while |
| 473 | * we waited on the semaphore. Need to revalidate. | 476 | * we waited on the semaphore. Need to revalidate. |
| 474 | */ | 477 | */ |
| 475 | up(&dir->i_sem); | 478 | mutex_unlock(&dir->i_mutex); |
| 476 | if (result->d_op && result->d_op->d_revalidate) { | 479 | if (result->d_op && result->d_op->d_revalidate) { |
| 477 | if (!result->d_op->d_revalidate(result, nd) && !d_invalidate(result)) { | 480 | if (!result->d_op->d_revalidate(result, nd) && !d_invalidate(result)) { |
| 478 | dput(result); | 481 | dput(result); |
| @@ -485,7 +488,7 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s | |||
| 485 | static int __emul_lookup_dentry(const char *, struct nameidata *); | 488 | static int __emul_lookup_dentry(const char *, struct nameidata *); |
| 486 | 489 | ||
| 487 | /* SMP-safe */ | 490 | /* SMP-safe */ |
| 488 | static inline int | 491 | static __always_inline int |
| 489 | walk_init_root(const char *name, struct nameidata *nd) | 492 | walk_init_root(const char *name, struct nameidata *nd) |
| 490 | { | 493 | { |
| 491 | read_lock(¤t->fs->lock); | 494 | read_lock(¤t->fs->lock); |
| @@ -503,7 +506,7 @@ walk_init_root(const char *name, struct nameidata *nd) | |||
| 503 | return 1; | 506 | return 1; |
| 504 | } | 507 | } |
| 505 | 508 | ||
| 506 | static inline int __vfs_follow_link(struct nameidata *nd, const char *link) | 509 | static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link) |
| 507 | { | 510 | { |
| 508 | int res = 0; | 511 | int res = 0; |
| 509 | char *name; | 512 | char *name; |
| @@ -543,7 +546,7 @@ struct path { | |||
| 543 | struct dentry *dentry; | 546 | struct dentry *dentry; |
| 544 | }; | 547 | }; |
| 545 | 548 | ||
| 546 | static inline int __do_follow_link(struct path *path, struct nameidata *nd) | 549 | static __always_inline int __do_follow_link(struct path *path, struct nameidata *nd) |
| 547 | { | 550 | { |
| 548 | int error; | 551 | int error; |
| 549 | void *cookie; | 552 | void *cookie; |
| @@ -689,7 +692,7 @@ int follow_down(struct vfsmount **mnt, struct dentry **dentry) | |||
| 689 | return 0; | 692 | return 0; |
| 690 | } | 693 | } |
| 691 | 694 | ||
| 692 | static inline void follow_dotdot(struct nameidata *nd) | 695 | static __always_inline void follow_dotdot(struct nameidata *nd) |
| 693 | { | 696 | { |
| 694 | while(1) { | 697 | while(1) { |
| 695 | struct vfsmount *parent; | 698 | struct vfsmount *parent; |
| @@ -1062,7 +1065,8 @@ set_it: | |||
| 1062 | } | 1065 | } |
| 1063 | 1066 | ||
| 1064 | /* 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. */ |
| 1065 | int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata *nd) | 1068 | static int fastcall do_path_lookup(int dfd, const char *name, |
| 1069 | unsigned int flags, struct nameidata *nd) | ||
| 1066 | { | 1070 | { |
| 1067 | int retval = 0; | 1071 | int retval = 0; |
| 1068 | 1072 | ||
| @@ -1082,9 +1086,38 @@ int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata | |||
| 1082 | } | 1086 | } |
| 1083 | nd->mnt = mntget(current->fs->rootmnt); | 1087 | nd->mnt = mntget(current->fs->rootmnt); |
| 1084 | nd->dentry = dget(current->fs->root); | 1088 | nd->dentry = dget(current->fs->root); |
| 1085 | } else { | 1089 | } else if (dfd == AT_FDCWD) { |
| 1086 | nd->mnt = mntget(current->fs->pwdmnt); | 1090 | nd->mnt = mntget(current->fs->pwdmnt); |
| 1087 | 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); | ||
| 1088 | } | 1121 | } |
| 1089 | read_unlock(¤t->fs->lock); | 1122 | read_unlock(¤t->fs->lock); |
| 1090 | current->total_link_count = 0; | 1123 | current->total_link_count = 0; |
| @@ -1093,11 +1126,19 @@ out: | |||
| 1093 | if (unlikely(current->audit_context | 1126 | if (unlikely(current->audit_context |
| 1094 | && nd && nd->dentry && nd->dentry->d_inode)) | 1127 | && nd && nd->dentry && nd->dentry->d_inode)) |
| 1095 | audit_inode(name, nd->dentry->d_inode, flags); | 1128 | audit_inode(name, nd->dentry->d_inode, flags); |
| 1129 | out_fail: | ||
| 1096 | return retval; | 1130 | return retval; |
| 1097 | } | 1131 | } |
| 1098 | 1132 | ||
| 1099 | static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags, | 1133 | int fastcall path_lookup(const char *name, unsigned int flags, |
| 1100 | 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 | |||
| 1139 | static 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) | ||
| 1101 | { | 1142 | { |
| 1102 | struct file *filp = get_empty_filp(); | 1143 | struct file *filp = get_empty_filp(); |
| 1103 | int err; | 1144 | int err; |
| @@ -1107,7 +1148,7 @@ static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags | |||
| 1107 | nd->intent.open.file = filp; | 1148 | nd->intent.open.file = filp; |
| 1108 | nd->intent.open.flags = open_flags; | 1149 | nd->intent.open.flags = open_flags; |
| 1109 | nd->intent.open.create_mode = create_mode; | 1150 | nd->intent.open.create_mode = create_mode; |
| 1110 | err = path_lookup(name, lookup_flags|LOOKUP_OPEN, nd); | 1151 | err = do_path_lookup(dfd, name, lookup_flags|LOOKUP_OPEN, nd); |
| 1111 | if (IS_ERR(nd->intent.open.file)) { | 1152 | if (IS_ERR(nd->intent.open.file)) { |
| 1112 | if (err == 0) { | 1153 | if (err == 0) { |
| 1113 | err = PTR_ERR(nd->intent.open.file); | 1154 | err = PTR_ERR(nd->intent.open.file); |
| @@ -1125,10 +1166,10 @@ static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags | |||
| 1125 | * @nd: pointer to nameidata | 1166 | * @nd: pointer to nameidata |
| 1126 | * @open_flags: open intent flags | 1167 | * @open_flags: open intent flags |
| 1127 | */ | 1168 | */ |
| 1128 | int path_lookup_open(const char *name, unsigned int lookup_flags, | 1169 | int path_lookup_open(int dfd, const char *name, unsigned int lookup_flags, |
| 1129 | struct nameidata *nd, int open_flags) | 1170 | struct nameidata *nd, int open_flags) |
| 1130 | { | 1171 | { |
| 1131 | return __path_lookup_intent_open(name, lookup_flags, nd, | 1172 | return __path_lookup_intent_open(dfd, name, lookup_flags, nd, |
| 1132 | open_flags, 0); | 1173 | open_flags, 0); |
| 1133 | } | 1174 | } |
| 1134 | 1175 | ||
| @@ -1140,12 +1181,12 @@ int path_lookup_open(const char *name, unsigned int lookup_flags, | |||
| 1140 | * @open_flags: open intent flags | 1181 | * @open_flags: open intent flags |
| 1141 | * @create_mode: create intent flags | 1182 | * @create_mode: create intent flags |
| 1142 | */ | 1183 | */ |
| 1143 | static int path_lookup_create(const char *name, unsigned int lookup_flags, | 1184 | static int path_lookup_create(int dfd, const char *name, |
| 1144 | struct nameidata *nd, int open_flags, | 1185 | unsigned int lookup_flags, struct nameidata *nd, |
| 1145 | int create_mode) | 1186 | int open_flags, int create_mode) |
| 1146 | { | 1187 | { |
| 1147 | return __path_lookup_intent_open(name, lookup_flags|LOOKUP_CREATE, nd, | 1188 | return __path_lookup_intent_open(dfd, name, lookup_flags|LOOKUP_CREATE, |
| 1148 | open_flags, create_mode); | 1189 | nd, open_flags, create_mode); |
| 1149 | } | 1190 | } |
| 1150 | 1191 | ||
| 1151 | int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, | 1192 | int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, |
| @@ -1155,7 +1196,7 @@ int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, | |||
| 1155 | int err = PTR_ERR(tmp); | 1196 | int err = PTR_ERR(tmp); |
| 1156 | 1197 | ||
| 1157 | if (!IS_ERR(tmp)) { | 1198 | if (!IS_ERR(tmp)) { |
| 1158 | 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); |
| 1159 | putname(tmp); | 1200 | putname(tmp); |
| 1160 | } | 1201 | } |
| 1161 | return err; | 1202 | return err; |
| @@ -1247,18 +1288,24 @@ access: | |||
| 1247 | * that namei follows links, while lnamei does not. | 1288 | * that namei follows links, while lnamei does not. |
| 1248 | * SMP-safe | 1289 | * SMP-safe |
| 1249 | */ | 1290 | */ |
| 1250 | int fastcall __user_walk(const char __user *name, unsigned flags, struct nameidata *nd) | 1291 | int fastcall __user_walk_fd(int dfd, const char __user *name, unsigned flags, |
| 1292 | struct nameidata *nd) | ||
| 1251 | { | 1293 | { |
| 1252 | char *tmp = getname(name); | 1294 | char *tmp = getname(name); |
| 1253 | int err = PTR_ERR(tmp); | 1295 | int err = PTR_ERR(tmp); |
| 1254 | 1296 | ||
| 1255 | if (!IS_ERR(tmp)) { | 1297 | if (!IS_ERR(tmp)) { |
| 1256 | err = path_lookup(tmp, flags, nd); | 1298 | err = do_path_lookup(dfd, tmp, flags, nd); |
| 1257 | putname(tmp); | 1299 | putname(tmp); |
| 1258 | } | 1300 | } |
| 1259 | return err; | 1301 | return err; |
| 1260 | } | 1302 | } |
| 1261 | 1303 | ||
| 1304 | int 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 | |||
| 1262 | /* | 1309 | /* |
| 1263 | * 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 |
| 1264 | * minimal. | 1311 | * minimal. |
| @@ -1293,7 +1340,7 @@ static inline int check_sticky(struct inode *dir, struct inode *inode) | |||
| 1293 | * 10. We don't allow removal of NFS sillyrenamed files; it's handled by | 1340 | * 10. We don't allow removal of NFS sillyrenamed files; it's handled by |
| 1294 | * nfs_async_unlink(). | 1341 | * nfs_async_unlink(). |
| 1295 | */ | 1342 | */ |
| 1296 | static inline int may_delete(struct inode *dir,struct dentry *victim,int isdir) | 1343 | static int may_delete(struct inode *dir,struct dentry *victim,int isdir) |
| 1297 | { | 1344 | { |
| 1298 | int error; | 1345 | int error; |
| 1299 | 1346 | ||
| @@ -1366,7 +1413,7 @@ struct dentry *lock_rename(struct dentry *p1, struct dentry *p2) | |||
| 1366 | struct dentry *p; | 1413 | struct dentry *p; |
| 1367 | 1414 | ||
| 1368 | if (p1 == p2) { | 1415 | if (p1 == p2) { |
| 1369 | down(&p1->d_inode->i_sem); | 1416 | mutex_lock(&p1->d_inode->i_mutex); |
| 1370 | return NULL; | 1417 | return NULL; |
| 1371 | } | 1418 | } |
| 1372 | 1419 | ||
| @@ -1374,30 +1421,30 @@ struct dentry *lock_rename(struct dentry *p1, struct dentry *p2) | |||
| 1374 | 1421 | ||
| 1375 | for (p = p1; p->d_parent != p; p = p->d_parent) { | 1422 | for (p = p1; p->d_parent != p; p = p->d_parent) { |
| 1376 | if (p->d_parent == p2) { | 1423 | if (p->d_parent == p2) { |
| 1377 | down(&p2->d_inode->i_sem); | 1424 | mutex_lock(&p2->d_inode->i_mutex); |
| 1378 | down(&p1->d_inode->i_sem); | 1425 | mutex_lock(&p1->d_inode->i_mutex); |
| 1379 | return p; | 1426 | return p; |
| 1380 | } | 1427 | } |
| 1381 | } | 1428 | } |
| 1382 | 1429 | ||
| 1383 | for (p = p2; p->d_parent != p; p = p->d_parent) { | 1430 | for (p = p2; p->d_parent != p; p = p->d_parent) { |
| 1384 | if (p->d_parent == p1) { | 1431 | if (p->d_parent == p1) { |
| 1385 | down(&p1->d_inode->i_sem); | 1432 | mutex_lock(&p1->d_inode->i_mutex); |
| 1386 | down(&p2->d_inode->i_sem); | 1433 | mutex_lock(&p2->d_inode->i_mutex); |
| 1387 | return p; | 1434 | return p; |
| 1388 | } | 1435 | } |
| 1389 | } | 1436 | } |
| 1390 | 1437 | ||
| 1391 | down(&p1->d_inode->i_sem); | 1438 | mutex_lock(&p1->d_inode->i_mutex); |
| 1392 | down(&p2->d_inode->i_sem); | 1439 | mutex_lock(&p2->d_inode->i_mutex); |
| 1393 | return NULL; | 1440 | return NULL; |
| 1394 | } | 1441 | } |
| 1395 | 1442 | ||
| 1396 | void unlock_rename(struct dentry *p1, struct dentry *p2) | 1443 | void unlock_rename(struct dentry *p1, struct dentry *p2) |
| 1397 | { | 1444 | { |
| 1398 | up(&p1->d_inode->i_sem); | 1445 | mutex_unlock(&p1->d_inode->i_mutex); |
| 1399 | if (p1 != p2) { | 1446 | if (p1 != p2) { |
| 1400 | up(&p2->d_inode->i_sem); | 1447 | mutex_unlock(&p2->d_inode->i_mutex); |
| 1401 | up(&p1->d_inode->i_sb->s_vfs_rename_sem); | 1448 | up(&p1->d_inode->i_sb->s_vfs_rename_sem); |
| 1402 | } | 1449 | } |
| 1403 | } | 1450 | } |
| @@ -1491,7 +1538,7 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) | |||
| 1491 | if (!error) { | 1538 | if (!error) { |
| 1492 | DQUOT_INIT(inode); | 1539 | DQUOT_INIT(inode); |
| 1493 | 1540 | ||
| 1494 | error = do_truncate(dentry, 0, NULL); | 1541 | error = do_truncate(dentry, 0, ATTR_MTIME|ATTR_CTIME, NULL); |
| 1495 | } | 1542 | } |
| 1496 | put_write_access(inode); | 1543 | put_write_access(inode); |
| 1497 | if (error) | 1544 | if (error) |
| @@ -1517,7 +1564,8 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) | |||
| 1517 | * for symlinks (where the permissions are checked later). | 1564 | * for symlinks (where the permissions are checked later). |
| 1518 | * SMP-safe | 1565 | * SMP-safe |
| 1519 | */ | 1566 | */ |
| 1520 | int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | 1567 | int open_namei(int dfd, const char *pathname, int flag, |
| 1568 | int mode, struct nameidata *nd) | ||
| 1521 | { | 1569 | { |
| 1522 | int acc_mode, error; | 1570 | int acc_mode, error; |
| 1523 | struct path path; | 1571 | struct path path; |
| @@ -1539,7 +1587,8 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | |||
| 1539 | * The simplest case - just a plain lookup. | 1587 | * The simplest case - just a plain lookup. |
| 1540 | */ | 1588 | */ |
| 1541 | if (!(flag & O_CREAT)) { | 1589 | if (!(flag & O_CREAT)) { |
| 1542 | error = path_lookup_open(pathname, lookup_flags(flag), nd, flag); | 1590 | error = path_lookup_open(dfd, pathname, lookup_flags(flag), |
| 1591 | nd, flag); | ||
| 1543 | if (error) | 1592 | if (error) |
| 1544 | return error; | 1593 | return error; |
| 1545 | goto ok; | 1594 | goto ok; |
| @@ -1548,7 +1597,7 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | |||
| 1548 | /* | 1597 | /* |
| 1549 | * Create - we need to know the parent. | 1598 | * Create - we need to know the parent. |
| 1550 | */ | 1599 | */ |
| 1551 | error = path_lookup_create(pathname, LOOKUP_PARENT, nd, flag, mode); | 1600 | error = path_lookup_create(dfd,pathname,LOOKUP_PARENT,nd,flag,mode); |
| 1552 | if (error) | 1601 | if (error) |
| 1553 | return error; | 1602 | return error; |
| 1554 | 1603 | ||
| @@ -1563,14 +1612,14 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | |||
| 1563 | 1612 | ||
| 1564 | dir = nd->dentry; | 1613 | dir = nd->dentry; |
| 1565 | nd->flags &= ~LOOKUP_PARENT; | 1614 | nd->flags &= ~LOOKUP_PARENT; |
| 1566 | down(&dir->d_inode->i_sem); | 1615 | mutex_lock(&dir->d_inode->i_mutex); |
| 1567 | path.dentry = lookup_hash(nd); | 1616 | path.dentry = lookup_hash(nd); |
| 1568 | path.mnt = nd->mnt; | 1617 | path.mnt = nd->mnt; |
| 1569 | 1618 | ||
| 1570 | do_last: | 1619 | do_last: |
| 1571 | error = PTR_ERR(path.dentry); | 1620 | error = PTR_ERR(path.dentry); |
| 1572 | if (IS_ERR(path.dentry)) { | 1621 | if (IS_ERR(path.dentry)) { |
| 1573 | up(&dir->d_inode->i_sem); | 1622 | mutex_unlock(&dir->d_inode->i_mutex); |
| 1574 | goto exit; | 1623 | goto exit; |
| 1575 | } | 1624 | } |
| 1576 | 1625 | ||
| @@ -1579,7 +1628,7 @@ do_last: | |||
| 1579 | if (!IS_POSIXACL(dir->d_inode)) | 1628 | if (!IS_POSIXACL(dir->d_inode)) |
| 1580 | mode &= ~current->fs->umask; | 1629 | mode &= ~current->fs->umask; |
| 1581 | error = vfs_create(dir->d_inode, path.dentry, mode, nd); | 1630 | error = vfs_create(dir->d_inode, path.dentry, mode, nd); |
| 1582 | up(&dir->d_inode->i_sem); | 1631 | mutex_unlock(&dir->d_inode->i_mutex); |
| 1583 | dput(nd->dentry); | 1632 | dput(nd->dentry); |
| 1584 | nd->dentry = path.dentry; | 1633 | nd->dentry = path.dentry; |
| 1585 | if (error) | 1634 | if (error) |
| @@ -1593,7 +1642,7 @@ do_last: | |||
| 1593 | /* | 1642 | /* |
| 1594 | * It already exists. | 1643 | * It already exists. |
| 1595 | */ | 1644 | */ |
| 1596 | up(&dir->d_inode->i_sem); | 1645 | mutex_unlock(&dir->d_inode->i_mutex); |
| 1597 | 1646 | ||
| 1598 | error = -EEXIST; | 1647 | error = -EEXIST; |
| 1599 | if (flag & O_EXCL) | 1648 | if (flag & O_EXCL) |
| @@ -1665,7 +1714,7 @@ do_link: | |||
| 1665 | goto exit; | 1714 | goto exit; |
| 1666 | } | 1715 | } |
| 1667 | dir = nd->dentry; | 1716 | dir = nd->dentry; |
| 1668 | down(&dir->d_inode->i_sem); | 1717 | mutex_lock(&dir->d_inode->i_mutex); |
| 1669 | path.dentry = lookup_hash(nd); | 1718 | path.dentry = lookup_hash(nd); |
| 1670 | path.mnt = nd->mnt; | 1719 | path.mnt = nd->mnt; |
| 1671 | __putname(nd->last.name); | 1720 | __putname(nd->last.name); |
| @@ -1680,13 +1729,13 @@ do_link: | |||
| 1680 | * Simple function to lookup and return a dentry and create it | 1729 | * Simple function to lookup and return a dentry and create it |
| 1681 | * if it doesn't exist. Is SMP-safe. | 1730 | * if it doesn't exist. Is SMP-safe. |
| 1682 | * | 1731 | * |
| 1683 | * Returns with nd->dentry->d_inode->i_sem locked. | 1732 | * Returns with nd->dentry->d_inode->i_mutex locked. |
| 1684 | */ | 1733 | */ |
| 1685 | struct dentry *lookup_create(struct nameidata *nd, int is_dir) | 1734 | struct dentry *lookup_create(struct nameidata *nd, int is_dir) |
| 1686 | { | 1735 | { |
| 1687 | struct dentry *dentry = ERR_PTR(-EEXIST); | 1736 | struct dentry *dentry = ERR_PTR(-EEXIST); |
| 1688 | 1737 | ||
| 1689 | down(&nd->dentry->d_inode->i_sem); | 1738 | mutex_lock(&nd->dentry->d_inode->i_mutex); |
| 1690 | /* | 1739 | /* |
| 1691 | * Yucky last component or no last component at all? | 1740 | * Yucky last component or no last component at all? |
| 1692 | * (foo/., foo/.., /////) | 1741 | * (foo/., foo/.., /////) |
| @@ -1743,7 +1792,8 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) | |||
| 1743 | return error; | 1792 | return error; |
| 1744 | } | 1793 | } |
| 1745 | 1794 | ||
| 1746 | asmlinkage long sys_mknod(const char __user * filename, int mode, unsigned dev) | 1795 | asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, |
| 1796 | unsigned dev) | ||
| 1747 | { | 1797 | { |
| 1748 | int error = 0; | 1798 | int error = 0; |
| 1749 | char * tmp; | 1799 | char * tmp; |
| @@ -1756,7 +1806,7 @@ asmlinkage long sys_mknod(const char __user * filename, int mode, unsigned dev) | |||
| 1756 | if (IS_ERR(tmp)) | 1806 | if (IS_ERR(tmp)) |
| 1757 | return PTR_ERR(tmp); | 1807 | return PTR_ERR(tmp); |
| 1758 | 1808 | ||
| 1759 | error = path_lookup(tmp, LOOKUP_PARENT, &nd); | 1809 | error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd); |
| 1760 | if (error) | 1810 | if (error) |
| 1761 | goto out; | 1811 | goto out; |
| 1762 | dentry = lookup_create(&nd, 0); | 1812 | dentry = lookup_create(&nd, 0); |
| @@ -1784,7 +1834,7 @@ asmlinkage long sys_mknod(const char __user * filename, int mode, unsigned dev) | |||
| 1784 | } | 1834 | } |
| 1785 | dput(dentry); | 1835 | dput(dentry); |
| 1786 | } | 1836 | } |
| 1787 | up(&nd.dentry->d_inode->i_sem); | 1837 | mutex_unlock(&nd.dentry->d_inode->i_mutex); |
| 1788 | path_release(&nd); | 1838 | path_release(&nd); |
| 1789 | out: | 1839 | out: |
| 1790 | putname(tmp); | 1840 | putname(tmp); |
| @@ -1792,6 +1842,11 @@ out: | |||
| 1792 | return error; | 1842 | return error; |
| 1793 | } | 1843 | } |
| 1794 | 1844 | ||
| 1845 | asmlinkage long sys_mknod(const char __user *filename, int mode, unsigned dev) | ||
| 1846 | { | ||
| 1847 | return sys_mknodat(AT_FDCWD, filename, mode, dev); | ||
| 1848 | } | ||
| 1849 | |||
| 1795 | int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | 1850 | int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) |
| 1796 | { | 1851 | { |
| 1797 | int error = may_create(dir, dentry, NULL); | 1852 | int error = may_create(dir, dentry, NULL); |
| @@ -1814,7 +1869,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
| 1814 | return error; | 1869 | return error; |
| 1815 | } | 1870 | } |
| 1816 | 1871 | ||
| 1817 | asmlinkage long sys_mkdir(const char __user * pathname, int mode) | 1872 | asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode) |
| 1818 | { | 1873 | { |
| 1819 | int error = 0; | 1874 | int error = 0; |
| 1820 | char * tmp; | 1875 | char * tmp; |
| @@ -1825,7 +1880,7 @@ asmlinkage long sys_mkdir(const char __user * pathname, int mode) | |||
| 1825 | struct dentry *dentry; | 1880 | struct dentry *dentry; |
| 1826 | struct nameidata nd; | 1881 | struct nameidata nd; |
| 1827 | 1882 | ||
| 1828 | error = path_lookup(tmp, LOOKUP_PARENT, &nd); | 1883 | error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd); |
| 1829 | if (error) | 1884 | if (error) |
| 1830 | goto out; | 1885 | goto out; |
| 1831 | dentry = lookup_create(&nd, 1); | 1886 | dentry = lookup_create(&nd, 1); |
| @@ -1836,7 +1891,7 @@ asmlinkage long sys_mkdir(const char __user * pathname, int mode) | |||
| 1836 | error = vfs_mkdir(nd.dentry->d_inode, dentry, mode); | 1891 | error = vfs_mkdir(nd.dentry->d_inode, dentry, mode); |
| 1837 | dput(dentry); | 1892 | dput(dentry); |
| 1838 | } | 1893 | } |
| 1839 | up(&nd.dentry->d_inode->i_sem); | 1894 | mutex_unlock(&nd.dentry->d_inode->i_mutex); |
| 1840 | path_release(&nd); | 1895 | path_release(&nd); |
| 1841 | out: | 1896 | out: |
| 1842 | putname(tmp); | 1897 | putname(tmp); |
| @@ -1845,6 +1900,11 @@ out: | |||
| 1845 | return error; | 1900 | return error; |
| 1846 | } | 1901 | } |
| 1847 | 1902 | ||
| 1903 | asmlinkage long sys_mkdir(const char __user *pathname, int mode) | ||
| 1904 | { | ||
| 1905 | return sys_mkdirat(AT_FDCWD, pathname, mode); | ||
| 1906 | } | ||
| 1907 | |||
| 1848 | /* | 1908 | /* |
| 1849 | * We try to drop the dentry early: we should have | 1909 | * We try to drop the dentry early: we should have |
| 1850 | * 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 |
| @@ -1885,7 +1945,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 1885 | 1945 | ||
| 1886 | DQUOT_INIT(dir); | 1946 | DQUOT_INIT(dir); |
| 1887 | 1947 | ||
| 1888 | down(&dentry->d_inode->i_sem); | 1948 | mutex_lock(&dentry->d_inode->i_mutex); |
| 1889 | dentry_unhash(dentry); | 1949 | dentry_unhash(dentry); |
| 1890 | if (d_mountpoint(dentry)) | 1950 | if (d_mountpoint(dentry)) |
| 1891 | error = -EBUSY; | 1951 | error = -EBUSY; |
| @@ -1897,7 +1957,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 1897 | dentry->d_inode->i_flags |= S_DEAD; | 1957 | dentry->d_inode->i_flags |= S_DEAD; |
| 1898 | } | 1958 | } |
| 1899 | } | 1959 | } |
| 1900 | up(&dentry->d_inode->i_sem); | 1960 | mutex_unlock(&dentry->d_inode->i_mutex); |
| 1901 | if (!error) { | 1961 | if (!error) { |
| 1902 | d_delete(dentry); | 1962 | d_delete(dentry); |
| 1903 | } | 1963 | } |
| @@ -1906,7 +1966,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 1906 | return error; | 1966 | return error; |
| 1907 | } | 1967 | } |
| 1908 | 1968 | ||
| 1909 | asmlinkage long sys_rmdir(const char __user * pathname) | 1969 | static long do_rmdir(int dfd, const char __user *pathname) |
| 1910 | { | 1970 | { |
| 1911 | int error = 0; | 1971 | int error = 0; |
| 1912 | char * name; | 1972 | char * name; |
| @@ -1917,7 +1977,7 @@ asmlinkage long sys_rmdir(const char __user * pathname) | |||
| 1917 | if(IS_ERR(name)) | 1977 | if(IS_ERR(name)) |
| 1918 | return PTR_ERR(name); | 1978 | return PTR_ERR(name); |
| 1919 | 1979 | ||
| 1920 | error = path_lookup(name, LOOKUP_PARENT, &nd); | 1980 | error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd); |
| 1921 | if (error) | 1981 | if (error) |
| 1922 | goto exit; | 1982 | goto exit; |
| 1923 | 1983 | ||
| @@ -1932,14 +1992,14 @@ asmlinkage long sys_rmdir(const char __user * pathname) | |||
| 1932 | error = -EBUSY; | 1992 | error = -EBUSY; |
| 1933 | goto exit1; | 1993 | goto exit1; |
| 1934 | } | 1994 | } |
| 1935 | down(&nd.dentry->d_inode->i_sem); | 1995 | mutex_lock(&nd.dentry->d_inode->i_mutex); |
| 1936 | dentry = lookup_hash(&nd); | 1996 | dentry = lookup_hash(&nd); |
| 1937 | error = PTR_ERR(dentry); | 1997 | error = PTR_ERR(dentry); |
| 1938 | if (!IS_ERR(dentry)) { | 1998 | if (!IS_ERR(dentry)) { |
| 1939 | error = vfs_rmdir(nd.dentry->d_inode, dentry); | 1999 | error = vfs_rmdir(nd.dentry->d_inode, dentry); |
| 1940 | dput(dentry); | 2000 | dput(dentry); |
| 1941 | } | 2001 | } |
| 1942 | up(&nd.dentry->d_inode->i_sem); | 2002 | mutex_unlock(&nd.dentry->d_inode->i_mutex); |
| 1943 | exit1: | 2003 | exit1: |
| 1944 | path_release(&nd); | 2004 | path_release(&nd); |
| 1945 | exit: | 2005 | exit: |
| @@ -1947,6 +2007,11 @@ exit: | |||
| 1947 | return error; | 2007 | return error; |
| 1948 | } | 2008 | } |
| 1949 | 2009 | ||
| 2010 | asmlinkage long sys_rmdir(const char __user *pathname) | ||
| 2011 | { | ||
| 2012 | return do_rmdir(AT_FDCWD, pathname); | ||
| 2013 | } | ||
| 2014 | |||
| 1950 | int vfs_unlink(struct inode *dir, struct dentry *dentry) | 2015 | int vfs_unlink(struct inode *dir, struct dentry *dentry) |
| 1951 | { | 2016 | { |
| 1952 | int error = may_delete(dir, dentry, 0); | 2017 | int error = may_delete(dir, dentry, 0); |
| @@ -1959,7 +2024,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) | |||
| 1959 | 2024 | ||
| 1960 | DQUOT_INIT(dir); | 2025 | DQUOT_INIT(dir); |
| 1961 | 2026 | ||
| 1962 | down(&dentry->d_inode->i_sem); | 2027 | mutex_lock(&dentry->d_inode->i_mutex); |
| 1963 | if (d_mountpoint(dentry)) | 2028 | if (d_mountpoint(dentry)) |
| 1964 | error = -EBUSY; | 2029 | error = -EBUSY; |
| 1965 | else { | 2030 | else { |
| @@ -1967,7 +2032,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) | |||
| 1967 | if (!error) | 2032 | if (!error) |
| 1968 | error = dir->i_op->unlink(dir, dentry); | 2033 | error = dir->i_op->unlink(dir, dentry); |
| 1969 | } | 2034 | } |
| 1970 | up(&dentry->d_inode->i_sem); | 2035 | mutex_unlock(&dentry->d_inode->i_mutex); |
| 1971 | 2036 | ||
| 1972 | /* We don't d_delete() NFS sillyrenamed files--they still exist. */ | 2037 | /* We don't d_delete() NFS sillyrenamed files--they still exist. */ |
| 1973 | if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) { | 2038 | if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) { |
| @@ -1979,11 +2044,11 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) | |||
| 1979 | 2044 | ||
| 1980 | /* | 2045 | /* |
| 1981 | * Make sure that the actual truncation of the file will occur outside its | 2046 | * Make sure that the actual truncation of the file will occur outside its |
| 1982 | * directory's i_sem. Truncate can take a long time if there is a lot of | 2047 | * directory's i_mutex. Truncate can take a long time if there is a lot of |
| 1983 | * 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 |
| 1984 | * while waiting on the I/O. | 2049 | * while waiting on the I/O. |
| 1985 | */ | 2050 | */ |
| 1986 | asmlinkage long sys_unlink(const char __user * pathname) | 2051 | static long do_unlinkat(int dfd, const char __user *pathname) |
| 1987 | { | 2052 | { |
| 1988 | int error = 0; | 2053 | int error = 0; |
| 1989 | char * name; | 2054 | char * name; |
| @@ -1995,13 +2060,13 @@ asmlinkage long sys_unlink(const char __user * pathname) | |||
| 1995 | if(IS_ERR(name)) | 2060 | if(IS_ERR(name)) |
| 1996 | return PTR_ERR(name); | 2061 | return PTR_ERR(name); |
| 1997 | 2062 | ||
| 1998 | error = path_lookup(name, LOOKUP_PARENT, &nd); | 2063 | error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd); |
| 1999 | if (error) | 2064 | if (error) |
| 2000 | goto exit; | 2065 | goto exit; |
| 2001 | error = -EISDIR; | 2066 | error = -EISDIR; |
| 2002 | if (nd.last_type != LAST_NORM) | 2067 | if (nd.last_type != LAST_NORM) |
| 2003 | goto exit1; | 2068 | goto exit1; |
| 2004 | down(&nd.dentry->d_inode->i_sem); | 2069 | mutex_lock(&nd.dentry->d_inode->i_mutex); |
| 2005 | dentry = lookup_hash(&nd); | 2070 | dentry = lookup_hash(&nd); |
| 2006 | error = PTR_ERR(dentry); | 2071 | error = PTR_ERR(dentry); |
| 2007 | if (!IS_ERR(dentry)) { | 2072 | if (!IS_ERR(dentry)) { |
| @@ -2015,7 +2080,7 @@ asmlinkage long sys_unlink(const char __user * pathname) | |||
| 2015 | exit2: | 2080 | exit2: |
| 2016 | dput(dentry); | 2081 | dput(dentry); |
| 2017 | } | 2082 | } |
| 2018 | up(&nd.dentry->d_inode->i_sem); | 2083 | mutex_unlock(&nd.dentry->d_inode->i_mutex); |
| 2019 | if (inode) | 2084 | if (inode) |
| 2020 | iput(inode); /* truncate the inode here */ | 2085 | iput(inode); /* truncate the inode here */ |
| 2021 | exit1: | 2086 | exit1: |
| @@ -2030,6 +2095,22 @@ slashes: | |||
| 2030 | goto exit2; | 2095 | goto exit2; |
| 2031 | } | 2096 | } |
| 2032 | 2097 | ||
| 2098 | asmlinkage 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 | |||
| 2109 | asmlinkage long sys_unlink(const char __user *pathname) | ||
| 2110 | { | ||
| 2111 | return do_unlinkat(AT_FDCWD, pathname); | ||
| 2112 | } | ||
| 2113 | |||
| 2033 | int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, int mode) | 2114 | int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, int mode) |
| 2034 | { | 2115 | { |
| 2035 | int error = may_create(dir, dentry, NULL); | 2116 | int error = may_create(dir, dentry, NULL); |
| @@ -2051,7 +2132,8 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, i | |||
| 2051 | return error; | 2132 | return error; |
| 2052 | } | 2133 | } |
| 2053 | 2134 | ||
| 2054 | asmlinkage long sys_symlink(const char __user * oldname, const char __user * newname) | 2135 | asmlinkage long sys_symlinkat(const char __user *oldname, |
| 2136 | int newdfd, const char __user *newname) | ||
| 2055 | { | 2137 | { |
| 2056 | int error = 0; | 2138 | int error = 0; |
| 2057 | char * from; | 2139 | char * from; |
| @@ -2066,7 +2148,7 @@ asmlinkage long sys_symlink(const char __user * oldname, const char __user * new | |||
| 2066 | struct dentry *dentry; | 2148 | struct dentry *dentry; |
| 2067 | struct nameidata nd; | 2149 | struct nameidata nd; |
| 2068 | 2150 | ||
| 2069 | error = path_lookup(to, LOOKUP_PARENT, &nd); | 2151 | error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd); |
| 2070 | if (error) | 2152 | if (error) |
| 2071 | goto out; | 2153 | goto out; |
| 2072 | dentry = lookup_create(&nd, 0); | 2154 | dentry = lookup_create(&nd, 0); |
| @@ -2075,7 +2157,7 @@ asmlinkage long sys_symlink(const char __user * oldname, const char __user * new | |||
| 2075 | error = vfs_symlink(nd.dentry->d_inode, dentry, from, S_IALLUGO); | 2157 | error = vfs_symlink(nd.dentry->d_inode, dentry, from, S_IALLUGO); |
| 2076 | dput(dentry); | 2158 | dput(dentry); |
| 2077 | } | 2159 | } |
| 2078 | up(&nd.dentry->d_inode->i_sem); | 2160 | mutex_unlock(&nd.dentry->d_inode->i_mutex); |
| 2079 | path_release(&nd); | 2161 | path_release(&nd); |
| 2080 | out: | 2162 | out: |
| 2081 | putname(to); | 2163 | putname(to); |
| @@ -2084,6 +2166,11 @@ out: | |||
| 2084 | return error; | 2166 | return error; |
| 2085 | } | 2167 | } |
| 2086 | 2168 | ||
| 2169 | asmlinkage long sys_symlink(const char __user *oldname, const char __user *newname) | ||
| 2170 | { | ||
| 2171 | return sys_symlinkat(oldname, AT_FDCWD, newname); | ||
| 2172 | } | ||
| 2173 | |||
| 2087 | int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) | 2174 | int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) |
| 2088 | { | 2175 | { |
| 2089 | struct inode *inode = old_dentry->d_inode; | 2176 | struct inode *inode = old_dentry->d_inode; |
| @@ -2113,10 +2200,10 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de | |||
| 2113 | if (error) | 2200 | if (error) |
| 2114 | return error; | 2201 | return error; |
| 2115 | 2202 | ||
| 2116 | down(&old_dentry->d_inode->i_sem); | 2203 | mutex_lock(&old_dentry->d_inode->i_mutex); |
| 2117 | DQUOT_INIT(dir); | 2204 | DQUOT_INIT(dir); |
| 2118 | error = dir->i_op->link(old_dentry, dir, new_dentry); | 2205 | error = dir->i_op->link(old_dentry, dir, new_dentry); |
| 2119 | up(&old_dentry->d_inode->i_sem); | 2206 | mutex_unlock(&old_dentry->d_inode->i_mutex); |
| 2120 | if (!error) | 2207 | if (!error) |
| 2121 | fsnotify_create(dir, new_dentry->d_name.name); | 2208 | fsnotify_create(dir, new_dentry->d_name.name); |
| 2122 | return error; | 2209 | return error; |
| @@ -2131,7 +2218,8 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de | |||
| 2131 | * with linux 2.0, and to avoid hard-linking to directories | 2218 | * with linux 2.0, and to avoid hard-linking to directories |
| 2132 | * and other special files. --ADM | 2219 | * and other special files. --ADM |
| 2133 | */ | 2220 | */ |
| 2134 | asmlinkage long sys_link(const char __user * oldname, const char __user * newname) | 2221 | asmlinkage long sys_linkat(int olddfd, const char __user *oldname, |
| 2222 | int newdfd, const char __user *newname) | ||
| 2135 | { | 2223 | { |
| 2136 | struct dentry *new_dentry; | 2224 | struct dentry *new_dentry; |
| 2137 | struct nameidata nd, old_nd; | 2225 | struct nameidata nd, old_nd; |
| @@ -2142,10 +2230,10 @@ asmlinkage long sys_link(const char __user * oldname, const char __user * newnam | |||
| 2142 | if (IS_ERR(to)) | 2230 | if (IS_ERR(to)) |
| 2143 | return PTR_ERR(to); | 2231 | return PTR_ERR(to); |
| 2144 | 2232 | ||
| 2145 | error = __user_walk(oldname, 0, &old_nd); | 2233 | error = __user_walk_fd(olddfd, oldname, 0, &old_nd); |
| 2146 | if (error) | 2234 | if (error) |
| 2147 | goto exit; | 2235 | goto exit; |
| 2148 | error = path_lookup(to, LOOKUP_PARENT, &nd); | 2236 | error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd); |
| 2149 | if (error) | 2237 | if (error) |
| 2150 | goto out; | 2238 | goto out; |
| 2151 | error = -EXDEV; | 2239 | error = -EXDEV; |
| @@ -2157,7 +2245,7 @@ asmlinkage long sys_link(const char __user * oldname, const char __user * newnam | |||
| 2157 | error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry); | 2245 | error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry); |
| 2158 | dput(new_dentry); | 2246 | dput(new_dentry); |
| 2159 | } | 2247 | } |
| 2160 | up(&nd.dentry->d_inode->i_sem); | 2248 | mutex_unlock(&nd.dentry->d_inode->i_mutex); |
| 2161 | out_release: | 2249 | out_release: |
| 2162 | path_release(&nd); | 2250 | path_release(&nd); |
| 2163 | out: | 2251 | out: |
| @@ -2168,6 +2256,11 @@ exit: | |||
| 2168 | return error; | 2256 | return error; |
| 2169 | } | 2257 | } |
| 2170 | 2258 | ||
| 2259 | asmlinkage long sys_link(const char __user *oldname, const char __user *newname) | ||
| 2260 | { | ||
| 2261 | return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname); | ||
| 2262 | } | ||
| 2263 | |||
| 2171 | /* | 2264 | /* |
| 2172 | * The worst of all namespace operations - renaming directory. "Perverted" | 2265 | * The worst of all namespace operations - renaming directory. "Perverted" |
| 2173 | * 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... |
| @@ -2178,7 +2271,7 @@ exit: | |||
| 2178 | * sb->s_vfs_rename_sem. We might be more accurate, but that's another | 2271 | * sb->s_vfs_rename_sem. We might be more accurate, but that's another |
| 2179 | * story. | 2272 | * story. |
| 2180 | * c) we have to lock _three_ objects - parents and victim (if it exists). | 2273 | * c) we have to lock _three_ objects - parents and victim (if it exists). |
| 2181 | * And that - after we got ->i_sem on parents (until then we don't know | 2274 | * And that - after we got ->i_mutex on parents (until then we don't know |
| 2182 | * whether the target exists). Solution: try to be smart with locking | 2275 | * whether the target exists). Solution: try to be smart with locking |
| 2183 | * order for inodes. We rely on the fact that tree topology may change | 2276 | * order for inodes. We rely on the fact that tree topology may change |
| 2184 | * only under ->s_vfs_rename_sem _and_ that parent of the object we | 2277 | * only under ->s_vfs_rename_sem _and_ that parent of the object we |
| @@ -2195,9 +2288,9 @@ exit: | |||
| 2195 | * stuff into VFS), but the former is not going away. Solution: the same | 2288 | * stuff into VFS), but the former is not going away. Solution: the same |
| 2196 | * trick as in rmdir(). | 2289 | * trick as in rmdir(). |
| 2197 | * e) conversion from fhandle to dentry may come in the wrong moment - when | 2290 | * e) conversion from fhandle to dentry may come in the wrong moment - when |
| 2198 | * we are removing the target. Solution: we will have to grab ->i_sem | 2291 | * we are removing the target. Solution: we will have to grab ->i_mutex |
| 2199 | * in the fhandle_to_dentry code. [FIXME - current nfsfh.c relies on | 2292 | * in the fhandle_to_dentry code. [FIXME - current nfsfh.c relies on |
| 2200 | * ->i_sem on parents, which works but leads to some truely excessive | 2293 | * ->i_mutex on parents, which works but leads to some truely excessive |
| 2201 | * locking]. | 2294 | * locking]. |
| 2202 | */ | 2295 | */ |
| 2203 | static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, | 2296 | static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, |
| @@ -2222,7 +2315,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, | |||
| 2222 | 2315 | ||
| 2223 | target = new_dentry->d_inode; | 2316 | target = new_dentry->d_inode; |
| 2224 | if (target) { | 2317 | if (target) { |
| 2225 | down(&target->i_sem); | 2318 | mutex_lock(&target->i_mutex); |
| 2226 | dentry_unhash(new_dentry); | 2319 | dentry_unhash(new_dentry); |
| 2227 | } | 2320 | } |
| 2228 | if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) | 2321 | if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) |
| @@ -2232,7 +2325,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, | |||
| 2232 | if (target) { | 2325 | if (target) { |
| 2233 | if (!error) | 2326 | if (!error) |
| 2234 | target->i_flags |= S_DEAD; | 2327 | target->i_flags |= S_DEAD; |
| 2235 | up(&target->i_sem); | 2328 | mutex_unlock(&target->i_mutex); |
| 2236 | if (d_unhashed(new_dentry)) | 2329 | if (d_unhashed(new_dentry)) |
| 2237 | d_rehash(new_dentry); | 2330 | d_rehash(new_dentry); |
| 2238 | dput(new_dentry); | 2331 | dput(new_dentry); |
| @@ -2255,7 +2348,7 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, | |||
| 2255 | dget(new_dentry); | 2348 | dget(new_dentry); |
| 2256 | target = new_dentry->d_inode; | 2349 | target = new_dentry->d_inode; |
| 2257 | if (target) | 2350 | if (target) |
| 2258 | down(&target->i_sem); | 2351 | mutex_lock(&target->i_mutex); |
| 2259 | if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) | 2352 | if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) |
| 2260 | error = -EBUSY; | 2353 | error = -EBUSY; |
| 2261 | else | 2354 | else |
| @@ -2266,7 +2359,7 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, | |||
| 2266 | d_move(old_dentry, new_dentry); | 2359 | d_move(old_dentry, new_dentry); |
| 2267 | } | 2360 | } |
| 2268 | if (target) | 2361 | if (target) |
| 2269 | up(&target->i_sem); | 2362 | mutex_unlock(&target->i_mutex); |
| 2270 | dput(new_dentry); | 2363 | dput(new_dentry); |
| 2271 | return error; | 2364 | return error; |
| 2272 | } | 2365 | } |
| @@ -2314,7 +2407,8 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 2314 | return error; | 2407 | return error; |
| 2315 | } | 2408 | } |
| 2316 | 2409 | ||
| 2317 | static inline int do_rename(const char * oldname, const char * newname) | 2410 | static int do_rename(int olddfd, const char *oldname, |
| 2411 | int newdfd, const char *newname) | ||
| 2318 | { | 2412 | { |
| 2319 | int error = 0; | 2413 | int error = 0; |
| 2320 | struct dentry * old_dir, * new_dir; | 2414 | struct dentry * old_dir, * new_dir; |
| @@ -2322,11 +2416,11 @@ static inline int do_rename(const char * oldname, const char * newname) | |||
| 2322 | struct dentry * trap; | 2416 | struct dentry * trap; |
| 2323 | struct nameidata oldnd, newnd; | 2417 | struct nameidata oldnd, newnd; |
| 2324 | 2418 | ||
| 2325 | error = path_lookup(oldname, LOOKUP_PARENT, &oldnd); | 2419 | error = do_path_lookup(olddfd, oldname, LOOKUP_PARENT, &oldnd); |
| 2326 | if (error) | 2420 | if (error) |
| 2327 | goto exit; | 2421 | goto exit; |
| 2328 | 2422 | ||
| 2329 | error = path_lookup(newname, LOOKUP_PARENT, &newnd); | 2423 | error = do_path_lookup(newdfd, newname, LOOKUP_PARENT, &newnd); |
| 2330 | if (error) | 2424 | if (error) |
| 2331 | goto exit1; | 2425 | goto exit1; |
| 2332 | 2426 | ||
| @@ -2390,7 +2484,8 @@ exit: | |||
| 2390 | return error; | 2484 | return error; |
| 2391 | } | 2485 | } |
| 2392 | 2486 | ||
| 2393 | asmlinkage long sys_rename(const char __user * oldname, const char __user * newname) | 2487 | asmlinkage long sys_renameat(int olddfd, const char __user *oldname, |
| 2488 | int newdfd, const char __user *newname) | ||
| 2394 | { | 2489 | { |
| 2395 | int error; | 2490 | int error; |
| 2396 | char * from; | 2491 | char * from; |
| @@ -2402,13 +2497,18 @@ asmlinkage long sys_rename(const char __user * oldname, const char __user * newn | |||
| 2402 | to = getname(newname); | 2497 | to = getname(newname); |
| 2403 | error = PTR_ERR(to); | 2498 | error = PTR_ERR(to); |
| 2404 | if (!IS_ERR(to)) { | 2499 | if (!IS_ERR(to)) { |
| 2405 | error = do_rename(from,to); | 2500 | error = do_rename(olddfd, from, newdfd, to); |
| 2406 | putname(to); | 2501 | putname(to); |
| 2407 | } | 2502 | } |
| 2408 | putname(from); | 2503 | putname(from); |
| 2409 | return error; | 2504 | return error; |
| 2410 | } | 2505 | } |
| 2411 | 2506 | ||
| 2507 | asmlinkage long sys_rename(const char __user *oldname, const char __user *newname) | ||
| 2508 | { | ||
| 2509 | return sys_renameat(AT_FDCWD, oldname, AT_FDCWD, newname); | ||
| 2510 | } | ||
| 2511 | |||
| 2412 | int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const char *link) | 2512 | int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const char *link) |
| 2413 | { | 2513 | { |
| 2414 | int len; | 2514 | int len; |
| @@ -2552,6 +2652,7 @@ struct inode_operations page_symlink_inode_operations = { | |||
| 2552 | }; | 2652 | }; |
| 2553 | 2653 | ||
| 2554 | EXPORT_SYMBOL(__user_walk); | 2654 | EXPORT_SYMBOL(__user_walk); |
| 2655 | EXPORT_SYMBOL(__user_walk_fd); | ||
| 2555 | EXPORT_SYMBOL(follow_down); | 2656 | EXPORT_SYMBOL(follow_down); |
| 2556 | EXPORT_SYMBOL(follow_up); | 2657 | EXPORT_SYMBOL(follow_up); |
| 2557 | EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ | 2658 | EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ |
