aboutsummaryrefslogtreecommitdiffstats
path: root/fs/open.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/open.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/open.c')
-rw-r--r--fs/open.c83
1 files changed, 68 insertions, 15 deletions
diff --git a/fs/open.c b/fs/open.c
index 8e20c1f32563..70e0230d8e77 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -20,6 +20,7 @@
20#include <linux/security.h> 20#include <linux/security.h>
21#include <linux/mount.h> 21#include <linux/mount.h>
22#include <linux/vfs.h> 22#include <linux/vfs.h>
23#include <linux/fcntl.h>
23#include <asm/uaccess.h> 24#include <asm/uaccess.h>
24#include <linux/fs.h> 25#include <linux/fs.h>
25#include <linux/personality.h> 26#include <linux/personality.h>
@@ -383,7 +384,7 @@ asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times)
383 384
384 error = get_user(newattrs.ia_atime.tv_sec, &times->actime); 385 error = get_user(newattrs.ia_atime.tv_sec, &times->actime);
385 newattrs.ia_atime.tv_nsec = 0; 386 newattrs.ia_atime.tv_nsec = 0;
386 if (!error) 387 if (!error)
387 error = get_user(newattrs.ia_mtime.tv_sec, &times->modtime); 388 error = get_user(newattrs.ia_mtime.tv_sec, &times->modtime);
388 newattrs.ia_mtime.tv_nsec = 0; 389 newattrs.ia_mtime.tv_nsec = 0;
389 if (error) 390 if (error)
@@ -414,14 +415,14 @@ out:
414 * must be owner or have write permission. 415 * must be owner or have write permission.
415 * Else, update from *times, must be owner or super user. 416 * Else, update from *times, must be owner or super user.
416 */ 417 */
417long do_utimes(char __user * filename, struct timeval * times) 418long do_utimes(int dfd, char __user *filename, struct timeval *times)
418{ 419{
419 int error; 420 int error;
420 struct nameidata nd; 421 struct nameidata nd;
421 struct inode * inode; 422 struct inode * inode;
422 struct iattr newattrs; 423 struct iattr newattrs;
423 424
424 error = user_path_walk(filename, &nd); 425 error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
425 426
426 if (error) 427 if (error)
427 goto out; 428 goto out;
@@ -461,13 +462,18 @@ out:
461 return error; 462 return error;
462} 463}
463 464
464asmlinkage long sys_utimes(char __user * filename, struct timeval __user * utimes) 465asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes)
465{ 466{
466 struct timeval times[2]; 467 struct timeval times[2];
467 468
468 if (utimes && copy_from_user(&times, utimes, sizeof(times))) 469 if (utimes && copy_from_user(&times, utimes, sizeof(times)))
469 return -EFAULT; 470 return -EFAULT;
470 return do_utimes(filename, utimes ? times : NULL); 471 return do_utimes(dfd, filename, utimes ? times : NULL);
472}
473
474asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes)
475{
476 return sys_futimesat(AT_FDCWD, filename, utimes);
471} 477}
472 478
473 479
@@ -476,7 +482,7 @@ asmlinkage long sys_utimes(char __user * filename, struct timeval __user * utime
476 * We do this by temporarily clearing all FS-related capabilities and 482 * We do this by temporarily clearing all FS-related capabilities and
477 * switching the fsuid/fsgid around to the real ones. 483 * switching the fsuid/fsgid around to the real ones.
478 */ 484 */
479asmlinkage long sys_access(const char __user * filename, int mode) 485asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
480{ 486{
481 struct nameidata nd; 487 struct nameidata nd;
482 int old_fsuid, old_fsgid; 488 int old_fsuid, old_fsgid;
@@ -506,7 +512,7 @@ asmlinkage long sys_access(const char __user * filename, int mode)
506 else 512 else
507 current->cap_effective = current->cap_permitted; 513 current->cap_effective = current->cap_permitted;
508 514
509 res = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd); 515 res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
510 if (!res) { 516 if (!res) {
511 res = vfs_permission(&nd, mode); 517 res = vfs_permission(&nd, mode);
512 /* SuS v2 requires we report a read only fs too */ 518 /* SuS v2 requires we report a read only fs too */
@@ -523,6 +529,11 @@ asmlinkage long sys_access(const char __user * filename, int mode)
523 return res; 529 return res;
524} 530}
525 531
532asmlinkage long sys_access(const char __user *filename, int mode)
533{
534 return sys_faccessat(AT_FDCWD, filename, mode);
535}
536
526asmlinkage long sys_chdir(const char __user * filename) 537asmlinkage long sys_chdir(const char __user * filename)
527{ 538{
528 struct nameidata nd; 539 struct nameidata nd;
@@ -635,14 +646,15 @@ out:
635 return err; 646 return err;
636} 647}
637 648
638asmlinkage long sys_chmod(const char __user * filename, mode_t mode) 649asmlinkage long sys_fchmodat(int dfd, const char __user *filename,
650 mode_t mode)
639{ 651{
640 struct nameidata nd; 652 struct nameidata nd;
641 struct inode * inode; 653 struct inode * inode;
642 int error; 654 int error;
643 struct iattr newattrs; 655 struct iattr newattrs;
644 656
645 error = user_path_walk(filename, &nd); 657 error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
646 if (error) 658 if (error)
647 goto out; 659 goto out;
648 inode = nd.dentry->d_inode; 660 inode = nd.dentry->d_inode;
@@ -669,6 +681,11 @@ out:
669 return error; 681 return error;
670} 682}
671 683
684asmlinkage long sys_chmod(const char __user *filename, mode_t mode)
685{
686 return sys_fchmodat(AT_FDCWD, filename, mode);
687}
688
672static int chown_common(struct dentry * dentry, uid_t user, gid_t group) 689static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
673{ 690{
674 struct inode * inode; 691 struct inode * inode;
@@ -717,6 +734,26 @@ asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group)
717 return error; 734 return error;
718} 735}
719 736
737asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user,
738 gid_t group, int flag)
739{
740 struct nameidata nd;
741 int error = -EINVAL;
742 int follow;
743
744 if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
745 goto out;
746
747 follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
748 error = __user_walk_fd(dfd, filename, follow, &nd);
749 if (!error) {
750 error = chown_common(nd.dentry, user, group);
751 path_release(&nd);
752 }
753out:
754 return error;
755}
756
720asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group) 757asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group)
721{ 758{
722 struct nameidata nd; 759 struct nameidata nd;
@@ -820,7 +857,8 @@ cleanup_file:
820 * for the internal routines (ie open_namei()/follow_link() etc). 00 is 857 * for the internal routines (ie open_namei()/follow_link() etc). 00 is
821 * used by symlinks. 858 * used by symlinks.
822 */ 859 */
823struct file *filp_open(const char * filename, int flags, int mode) 860static struct file *do_filp_open(int dfd, const char *filename, int flags,
861 int mode)
824{ 862{
825 int namei_flags, error; 863 int namei_flags, error;
826 struct nameidata nd; 864 struct nameidata nd;
@@ -829,12 +867,17 @@ struct file *filp_open(const char * filename, int flags, int mode)
829 if ((namei_flags+1) & O_ACCMODE) 867 if ((namei_flags+1) & O_ACCMODE)
830 namei_flags++; 868 namei_flags++;
831 869
832 error = open_namei(filename, namei_flags, mode, &nd); 870 error = open_namei(dfd, filename, namei_flags, mode, &nd);
833 if (!error) 871 if (!error)
834 return nameidata_to_filp(&nd, flags); 872 return nameidata_to_filp(&nd, flags);
835 873
836 return ERR_PTR(error); 874 return ERR_PTR(error);
837} 875}
876
877struct file *filp_open(const char *filename, int flags, int mode)
878{
879 return do_filp_open(AT_FDCWD, filename, flags, mode);
880}
838EXPORT_SYMBOL(filp_open); 881EXPORT_SYMBOL(filp_open);
839 882
840/** 883/**
@@ -991,7 +1034,7 @@ void fastcall put_unused_fd(unsigned int fd)
991EXPORT_SYMBOL(put_unused_fd); 1034EXPORT_SYMBOL(put_unused_fd);
992 1035
993/* 1036/*
994 * Install a file pointer in the fd array. 1037 * Install a file pointer in the fd array.
995 * 1038 *
996 * The VFS is full of places where we drop the files lock between 1039 * The VFS is full of places where we drop the files lock between
997 * setting the open_fds bitmap and installing the file in the file 1040 * setting the open_fds bitmap and installing the file in the file
@@ -1016,7 +1059,7 @@ void fastcall fd_install(unsigned int fd, struct file * file)
1016 1059
1017EXPORT_SYMBOL(fd_install); 1060EXPORT_SYMBOL(fd_install);
1018 1061
1019long do_sys_open(const char __user *filename, int flags, int mode) 1062long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
1020{ 1063{
1021 char *tmp = getname(filename); 1064 char *tmp = getname(filename);
1022 int fd = PTR_ERR(tmp); 1065 int fd = PTR_ERR(tmp);
@@ -1024,7 +1067,7 @@ long do_sys_open(const char __user *filename, int flags, int mode)
1024 if (!IS_ERR(tmp)) { 1067 if (!IS_ERR(tmp)) {
1025 fd = get_unused_fd(); 1068 fd = get_unused_fd();
1026 if (fd >= 0) { 1069 if (fd >= 0) {
1027 struct file *f = filp_open(tmp, flags, mode); 1070 struct file *f = do_filp_open(dfd, tmp, flags, mode);
1028 if (IS_ERR(f)) { 1071 if (IS_ERR(f)) {
1029 put_unused_fd(fd); 1072 put_unused_fd(fd);
1030 fd = PTR_ERR(f); 1073 fd = PTR_ERR(f);
@@ -1043,10 +1086,20 @@ asmlinkage long sys_open(const char __user *filename, int flags, int mode)
1043 if (force_o_largefile()) 1086 if (force_o_largefile())
1044 flags |= O_LARGEFILE; 1087 flags |= O_LARGEFILE;
1045 1088
1046 return do_sys_open(filename, flags, mode); 1089 return do_sys_open(AT_FDCWD, filename, flags, mode);
1047} 1090}
1048EXPORT_SYMBOL_GPL(sys_open); 1091EXPORT_SYMBOL_GPL(sys_open);
1049 1092
1093asmlinkage long sys_openat(int dfd, const char __user *filename, int flags,
1094 int mode)
1095{
1096 if (force_o_largefile())
1097 flags |= O_LARGEFILE;
1098
1099 return do_sys_open(dfd, filename, flags, mode);
1100}
1101EXPORT_SYMBOL_GPL(sys_openat);
1102
1050#ifndef __alpha__ 1103#ifndef __alpha__
1051 1104
1052/* 1105/*