VFS: Allow the filesystem to return a full file pointer on open intent Signed-off-by: Trond Myklebust --- fs/exec.c | 12 ++++++------ fs/namei.c | 19 ++++++++++++++++--- fs/open.c | 14 +++++++++++++- include/linux/namei.h | 10 ++++++++++ 4 files changed, 45 insertions(+), 10 deletions(-) Index: linux-2.6.12-rc1/fs/namei.c =================================================================== --- linux-2.6.12-rc1.orig/fs/namei.c +++ linux-2.6.12-rc1/fs/namei.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -318,6 +319,19 @@ void path_release_on_umount(struct namei } /* + * Open intents have to release any file pointer that was allocated + * but not used by the VFS. + */ +void path_release_open_intent(struct nameidata *nd) +{ + if ((nd->flags & LOOKUP_OPEN) && nd->intent.open.file != NULL) { + fput(nd->intent.open.file); + nd->intent.open.file = NULL; + } + path_release(nd); +} + +/* * Internal lookup() using the new generic dcache. * SMP-safe */ @@ -1406,8 +1420,7 @@ int open_namei(const char * pathname, in acc_mode |= MAY_APPEND; /* Fill in the open() intent data */ - nd->intent.open.flags = flag; - nd->intent.open.create_mode = mode; + nd_init_open_intent(nd, flag, mode); /* * The simplest case - just a plain lookup. @@ -1498,7 +1511,7 @@ ok: exit_dput: dput(dentry); exit: - path_release(nd); + path_release_open_intent(nd); return error; do_link: Index: linux-2.6.12-rc1/fs/exec.c =================================================================== --- linux-2.6.12-rc1.orig/fs/exec.c +++ linux-2.6.12-rc1/fs/exec.c @@ -123,7 +123,7 @@ asmlinkage long sys_uselib(const char __ struct nameidata nd; int error; - nd.intent.open.flags = FMODE_READ; + nd_init_open_intent(&nd, FMODE_READ, 0); error = __user_walk(library, LOOKUP_FOLLOW|LOOKUP_OPEN, &nd); if (error) goto out; @@ -136,7 +136,7 @@ asmlinkage long sys_uselib(const char __ if (error) goto exit; - file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); + file = nd_open_file(&nd, O_RDONLY); error = PTR_ERR(file); if (IS_ERR(file)) goto out; @@ -164,7 +164,7 @@ asmlinkage long sys_uselib(const char __ out: return error; exit: - path_release(&nd); + path_release_open_intent(&nd); goto out; } @@ -491,7 +491,7 @@ struct file *open_exec(const char *name) int err; struct file *file; - nd.intent.open.flags = FMODE_READ; + nd_init_open_intent(&nd, FMODE_READ, 0); err = path_lookup(name, LOOKUP_FOLLOW|LOOKUP_OPEN, &nd); file = ERR_PTR(err); @@ -505,7 +505,7 @@ struct file *open_exec(const char *name) err = -EACCES; file = ERR_PTR(err); if (!err) { - file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); + file = nd_open_file(&nd, O_RDONLY); if (!IS_ERR(file)) { err = deny_write_access(file); if (err) { @@ -517,7 +517,7 @@ out: return file; } } - path_release(&nd); + path_release_open_intent(&nd); } goto out; } Index: linux-2.6.12-rc1/include/linux/namei.h =================================================================== --- linux-2.6.12-rc1.orig/include/linux/namei.h +++ linux-2.6.12-rc1/include/linux/namei.h @@ -8,6 +8,7 @@ struct vfsmount; struct open_intent { int flags; int create_mode; + struct file *file; }; enum { MAX_NESTED_LINKS = 5 }; @@ -64,6 +65,15 @@ extern int FASTCALL(path_walk(const char extern int FASTCALL(link_path_walk(const char *, struct nameidata *)); extern void path_release(struct nameidata *); extern void path_release_on_umount(struct nameidata *); +extern void path_release_open_intent(struct nameidata *); + +extern struct file *nd_open_file(struct nameidata *nd, int flags); +static inline void nd_init_open_intent(struct nameidata *nd, int flags, int mode) +{ + nd->intent.open.flags = flags; + nd->intent.open.create_mode = mode; + nd->intent.open.file = NULL; +} extern struct dentry * lookup_one_len(const char *, struct dentry *, int); extern struct dentry * lookup_hash(struct qstr *, struct dentry *); Index: linux-2.6.12-rc1/fs/open.c =================================================================== --- linux-2.6.12-rc1.orig/fs/open.c +++ linux-2.6.12-rc1/fs/open.c @@ -763,13 +763,25 @@ struct file *filp_open(const char * file error = open_namei(filename, namei_flags, mode, &nd); if (!error) - return dentry_open(nd.dentry, nd.mnt, flags); + return nd_open_file(&nd, flags); return ERR_PTR(error); } EXPORT_SYMBOL(filp_open); +struct file *nd_open_file(struct nameidata *nd, int flags) +{ + struct file *filp; + + if ((nd->flags & LOOKUP_OPEN) && nd->intent.open.file != NULL) { + filp = nd->intent.open.file; + path_release(nd); + } else + filp = dentry_open(nd->dentry, nd->mnt, flags); + return filp; +} + struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) { struct file * f;