aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2005-10-18 17:20:16 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2005-10-18 17:20:16 -0400
commit834f2a4a1554dc5b2598038b3fe8703defcbe467 (patch)
treed27a000a2dd03029e6e2472c6e13801688185b51 /fs
parent039c4d7a82d8268ec71f59679460b41d0dd9b225 (diff)
VFS: Allow the filesystem to return a full file pointer on open intent
This is needed by NFSv4 for atomicity reasons: our open command is in fact a lookup+open, so we need to be able to propagate open context information from lookup() into the resulting struct file's private_data field. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/exec.c12
-rw-r--r--fs/namei.c93
-rw-r--r--fs/open.c79
3 files changed, 157 insertions, 27 deletions
diff --git a/fs/exec.c b/fs/exec.c
index a04a575ad43..d2208f7c87d 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -126,8 +126,7 @@ asmlinkage long sys_uselib(const char __user * library)
126 struct nameidata nd; 126 struct nameidata nd;
127 int error; 127 int error;
128 128
129 nd.intent.open.flags = FMODE_READ; 129 error = __user_path_lookup_open(library, LOOKUP_FOLLOW, &nd, FMODE_READ);
130 error = __user_walk(library, LOOKUP_FOLLOW|LOOKUP_OPEN, &nd);
131 if (error) 130 if (error)
132 goto out; 131 goto out;
133 132
@@ -139,7 +138,7 @@ asmlinkage long sys_uselib(const char __user * library)
139 if (error) 138 if (error)
140 goto exit; 139 goto exit;
141 140
142 file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); 141 file = nameidata_to_filp(&nd, O_RDONLY);
143 error = PTR_ERR(file); 142 error = PTR_ERR(file);
144 if (IS_ERR(file)) 143 if (IS_ERR(file))
145 goto out; 144 goto out;
@@ -167,6 +166,7 @@ asmlinkage long sys_uselib(const char __user * library)
167out: 166out:
168 return error; 167 return error;
169exit: 168exit:
169 release_open_intent(&nd);
170 path_release(&nd); 170 path_release(&nd);
171 goto out; 171 goto out;
172} 172}
@@ -490,8 +490,7 @@ struct file *open_exec(const char *name)
490 int err; 490 int err;
491 struct file *file; 491 struct file *file;
492 492
493 nd.intent.open.flags = FMODE_READ; 493 err = path_lookup_open(name, LOOKUP_FOLLOW, &nd, FMODE_READ);
494 err = path_lookup(name, LOOKUP_FOLLOW|LOOKUP_OPEN, &nd);
495 file = ERR_PTR(err); 494 file = ERR_PTR(err);
496 495
497 if (!err) { 496 if (!err) {
@@ -504,7 +503,7 @@ struct file *open_exec(const char *name)
504 err = -EACCES; 503 err = -EACCES;
505 file = ERR_PTR(err); 504 file = ERR_PTR(err);
506 if (!err) { 505 if (!err) {
507 file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); 506 file = nameidata_to_filp(&nd, O_RDONLY);
508 if (!IS_ERR(file)) { 507 if (!IS_ERR(file)) {
509 err = deny_write_access(file); 508 err = deny_write_access(file);
510 if (err) { 509 if (err) {
@@ -516,6 +515,7 @@ out:
516 return file; 515 return file;
517 } 516 }
518 } 517 }
518 release_open_intent(&nd);
519 path_release(&nd); 519 path_release(&nd);
520 } 520 }
521 goto out; 521 goto out;
diff --git a/fs/namei.c b/fs/namei.c
index aa62dbda93a..0d1dff7d3d9 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -28,6 +28,7 @@
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/file.h>
31#include <asm/namei.h> 32#include <asm/namei.h>
32#include <asm/uaccess.h> 33#include <asm/uaccess.h>
33 34
@@ -317,6 +318,18 @@ void path_release_on_umount(struct nameidata *nd)
317 mntput_no_expire(nd->mnt); 318 mntput_no_expire(nd->mnt);
318} 319}
319 320
321/**
322 * release_open_intent - free up open intent resources
323 * @nd: pointer to nameidata
324 */
325void release_open_intent(struct nameidata *nd)
326{
327 if (nd->intent.open.file->f_dentry == NULL)
328 put_filp(nd->intent.open.file);
329 else
330 fput(nd->intent.open.file);
331}
332
320/* 333/*
321 * Internal lookup() using the new generic dcache. 334 * Internal lookup() using the new generic dcache.
322 * SMP-safe 335 * SMP-safe
@@ -1052,6 +1065,70 @@ out:
1052 return retval; 1065 return retval;
1053} 1066}
1054 1067
1068static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags,
1069 struct nameidata *nd, int open_flags, int create_mode)
1070{
1071 struct file *filp = get_empty_filp();
1072 int err;
1073
1074 if (filp == NULL)
1075 return -ENFILE;
1076 nd->intent.open.file = filp;
1077 nd->intent.open.flags = open_flags;
1078 nd->intent.open.create_mode = create_mode;
1079 err = path_lookup(name, lookup_flags|LOOKUP_OPEN, nd);
1080 if (IS_ERR(nd->intent.open.file)) {
1081 if (err == 0) {
1082 err = PTR_ERR(nd->intent.open.file);
1083 path_release(nd);
1084 }
1085 } else if (err != 0)
1086 release_open_intent(nd);
1087 return err;
1088}
1089
1090/**
1091 * path_lookup_open - lookup a file path with open intent
1092 * @name: pointer to file name
1093 * @lookup_flags: lookup intent flags
1094 * @nd: pointer to nameidata
1095 * @open_flags: open intent flags
1096 */
1097int path_lookup_open(const char *name, unsigned int lookup_flags,
1098 struct nameidata *nd, int open_flags)
1099{
1100 return __path_lookup_intent_open(name, lookup_flags, nd,
1101 open_flags, 0);
1102}
1103
1104/**
1105 * path_lookup_create - lookup a file path with open + create intent
1106 * @name: pointer to file name
1107 * @lookup_flags: lookup intent flags
1108 * @nd: pointer to nameidata
1109 * @open_flags: open intent flags
1110 * @create_mode: create intent flags
1111 */
1112int path_lookup_create(const char *name, unsigned int lookup_flags,
1113 struct nameidata *nd, int open_flags, int create_mode)
1114{
1115 return __path_lookup_intent_open(name, lookup_flags|LOOKUP_CREATE, nd,
1116 open_flags, create_mode);
1117}
1118
1119int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags,
1120 struct nameidata *nd, int open_flags)
1121{
1122 char *tmp = getname(name);
1123 int err = PTR_ERR(tmp);
1124
1125 if (!IS_ERR(tmp)) {
1126 err = __path_lookup_intent_open(tmp, lookup_flags, nd, open_flags, 0);
1127 putname(tmp);
1128 }
1129 return err;
1130}
1131
1055/* 1132/*
1056 * Restricted form of lookup. Doesn't follow links, single-component only, 1133 * Restricted form of lookup. Doesn't follow links, single-component only,
1057 * needs parent already locked. Doesn't follow mounts. 1134 * needs parent already locked. Doesn't follow mounts.
@@ -1416,27 +1493,27 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
1416 */ 1493 */
1417int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) 1494int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
1418{ 1495{
1419 int acc_mode, error = 0; 1496 int acc_mode, error;
1420 struct path path; 1497 struct path path;
1421 struct dentry *dir; 1498 struct dentry *dir;
1422 int count = 0; 1499 int count = 0;
1423 1500
1424 acc_mode = ACC_MODE(flag); 1501 acc_mode = ACC_MODE(flag);
1425 1502
1503 /* O_TRUNC implies we need access checks for write permissions */
1504 if (flag & O_TRUNC)
1505 acc_mode |= MAY_WRITE;
1506
1426 /* Allow the LSM permission hook to distinguish append 1507 /* Allow the LSM permission hook to distinguish append
1427 access from general write access. */ 1508 access from general write access. */
1428 if (flag & O_APPEND) 1509 if (flag & O_APPEND)
1429 acc_mode |= MAY_APPEND; 1510 acc_mode |= MAY_APPEND;
1430 1511
1431 /* Fill in the open() intent data */
1432 nd->intent.open.flags = flag;
1433 nd->intent.open.create_mode = mode;
1434
1435 /* 1512 /*
1436 * The simplest case - just a plain lookup. 1513 * The simplest case - just a plain lookup.
1437 */ 1514 */
1438 if (!(flag & O_CREAT)) { 1515 if (!(flag & O_CREAT)) {
1439 error = path_lookup(pathname, lookup_flags(flag)|LOOKUP_OPEN, nd); 1516 error = path_lookup_open(pathname, lookup_flags(flag), nd, flag);
1440 if (error) 1517 if (error)
1441 return error; 1518 return error;
1442 goto ok; 1519 goto ok;
@@ -1445,7 +1522,7 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
1445 /* 1522 /*
1446 * Create - we need to know the parent. 1523 * Create - we need to know the parent.
1447 */ 1524 */
1448 error = path_lookup(pathname, LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE, nd); 1525 error = path_lookup_create(pathname, LOOKUP_PARENT, nd, flag, mode);
1449 if (error) 1526 if (error)
1450 return error; 1527 return error;
1451 1528
@@ -1520,6 +1597,8 @@ ok:
1520exit_dput: 1597exit_dput:
1521 dput_path(&path, nd); 1598 dput_path(&path, nd);
1522exit: 1599exit:
1600 if (!IS_ERR(nd->intent.open.file))
1601 release_open_intent(nd);
1523 path_release(nd); 1602 path_release(nd);
1524 return error; 1603 return error;
1525 1604
diff --git a/fs/open.c b/fs/open.c
index f0d90cf0495..8d06ec911fd 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -739,7 +739,8 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group)
739} 739}
740 740
741static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, 741static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
742 int flags, struct file *f) 742 int flags, struct file *f,
743 int (*open)(struct inode *, struct file *))
743{ 744{
744 struct inode *inode; 745 struct inode *inode;
745 int error; 746 int error;
@@ -761,11 +762,14 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
761 f->f_op = fops_get(inode->i_fop); 762 f->f_op = fops_get(inode->i_fop);
762 file_move(f, &inode->i_sb->s_files); 763 file_move(f, &inode->i_sb->s_files);
763 764
764 if (f->f_op && f->f_op->open) { 765 if (!open && f->f_op)
765 error = f->f_op->open(inode,f); 766 open = f->f_op->open;
767 if (open) {
768 error = open(inode, f);
766 if (error) 769 if (error)
767 goto cleanup_all; 770 goto cleanup_all;
768 } 771 }
772
769 f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); 773 f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
770 774
771 file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); 775 file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);
@@ -814,28 +818,75 @@ struct file *filp_open(const char * filename, int flags, int mode)
814{ 818{
815 int namei_flags, error; 819 int namei_flags, error;
816 struct nameidata nd; 820 struct nameidata nd;
817 struct file *f;
818 821
819 namei_flags = flags; 822 namei_flags = flags;
820 if ((namei_flags+1) & O_ACCMODE) 823 if ((namei_flags+1) & O_ACCMODE)
821 namei_flags++; 824 namei_flags++;
822 if (namei_flags & O_TRUNC)
823 namei_flags |= 2;
824
825 error = -ENFILE;
826 f = get_empty_filp();
827 if (f == NULL)
828 return ERR_PTR(error);
829 825
830 error = open_namei(filename, namei_flags, mode, &nd); 826 error = open_namei(filename, namei_flags, mode, &nd);
831 if (!error) 827 if (!error)
832 return __dentry_open(nd.dentry, nd.mnt, flags, f); 828 return nameidata_to_filp(&nd, flags);
833 829
834 put_filp(f);
835 return ERR_PTR(error); 830 return ERR_PTR(error);
836} 831}
837EXPORT_SYMBOL(filp_open); 832EXPORT_SYMBOL(filp_open);
838 833
834/**
835 * lookup_instantiate_filp - instantiates the open intent filp
836 * @nd: pointer to nameidata
837 * @dentry: pointer to dentry
838 * @open: open callback
839 *
840 * Helper for filesystems that want to use lookup open intents and pass back
841 * a fully instantiated struct file to the caller.
842 * This function is meant to be called from within a filesystem's
843 * lookup method.
844 * Note that in case of error, nd->intent.open.file is destroyed, but the
845 * path information remains valid.
846 * If the open callback is set to NULL, then the standard f_op->open()
847 * filesystem callback is substituted.
848 */
849struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
850 int (*open)(struct inode *, struct file *))
851{
852 if (IS_ERR(nd->intent.open.file))
853 goto out;
854 if (IS_ERR(dentry))
855 goto out_err;
856 nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->mnt),
857 nd->intent.open.flags - 1,
858 nd->intent.open.file,
859 open);
860out:
861 return nd->intent.open.file;
862out_err:
863 release_open_intent(nd);
864 nd->intent.open.file = (struct file *)dentry;
865 goto out;
866}
867EXPORT_SYMBOL_GPL(lookup_instantiate_filp);
868
869/**
870 * nameidata_to_filp - convert a nameidata to an open filp.
871 * @nd: pointer to nameidata
872 * @flags: open flags
873 *
874 * Note that this function destroys the original nameidata
875 */
876struct file *nameidata_to_filp(struct nameidata *nd, int flags)
877{
878 struct file *filp;
879
880 /* Pick up the filp from the open intent */
881 filp = nd->intent.open.file;
882 /* Has the filesystem initialised the file for us? */
883 if (filp->f_dentry == NULL)
884 filp = __dentry_open(nd->dentry, nd->mnt, flags, filp, NULL);
885 else
886 path_release(nd);
887 return filp;
888}
889
839struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) 890struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
840{ 891{
841 int error; 892 int error;
@@ -846,7 +897,7 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
846 if (f == NULL) 897 if (f == NULL)
847 return ERR_PTR(error); 898 return ERR_PTR(error);
848 899
849 return __dentry_open(dentry, mnt, flags, f); 900 return __dentry_open(dentry, mnt, flags, f, NULL);
850} 901}
851EXPORT_SYMBOL(dentry_open); 902EXPORT_SYMBOL(dentry_open);
852 903