vfs: define struct filename and have getname() return it
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / fs / namei.c
index 9cc0fce7fc91e998f1945df5475e70a14cd9a0a2..ec638d27642f2016cd354dd0972022f46ee92728 100644 (file)
  * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
  * PATH_MAX includes the nul terminator --RR.
  */
-static char *getname_flags(const char __user *filename, int flags, int *empty)
+void final_putname(struct filename *name)
 {
-       char *result = __getname(), *err;
+       __putname(name->name);
+       kfree(name);
+}
+
+static struct filename *
+getname_flags(const char __user *filename, int flags, int *empty)
+{
+       struct filename *result, *err;
+       char *kname;
        int len;
 
+       /* FIXME: create dedicated slabcache? */
+       result = kzalloc(sizeof(*result), GFP_KERNEL);
        if (unlikely(!result))
                return ERR_PTR(-ENOMEM);
 
-       len = strncpy_from_user(result, filename, PATH_MAX);
-       err = ERR_PTR(len);
-       if (unlikely(len < 0))
+       kname = __getname();
+       if (unlikely(!kname)) {
+               err = ERR_PTR(-ENOMEM);
+               goto error_free_name;
+       }
+
+       result->name = kname;
+       result->uptr = filename;
+       len = strncpy_from_user(kname, filename, PATH_MAX);
+       if (unlikely(len < 0)) {
+               err = ERR_PTR(len);
                goto error;
+       }
 
        /* The empty path is special. */
        if (unlikely(!len)) {
@@ -146,22 +165,25 @@ static char *getname_flags(const char __user *filename, int flags, int *empty)
        }
 
 error:
-       __putname(result);
+       __putname(kname);
+error_free_name:
+       kfree(result);
        return err;
 }
 
-char *getname(const char __user * filename)
+struct filename *
+getname(const char __user * filename)
 {
        return getname_flags(filename, 0, NULL);
 }
+EXPORT_SYMBOL(getname);
 
 #ifdef CONFIG_AUDITSYSCALL
-void putname(const char *name)
+void putname(struct filename *name)
 {
        if (unlikely(!audit_dummy_context()))
-               audit_putname(name);
-       else
-               __putname(name);
+               return audit_putname(name);
+       final_putname(name);
 }
 #endif
 
@@ -2093,13 +2115,13 @@ int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
                 struct path *path, int *empty)
 {
        struct nameidata nd;
-       char *tmp = getname_flags(name, flags, empty);
+       struct filename *tmp = getname_flags(name, flags, empty);
        int err = PTR_ERR(tmp);
        if (!IS_ERR(tmp)) {
 
                BUG_ON(flags & LOOKUP_PARENT);
 
-               err = do_path_lookup(dfd, tmp, flags, &nd);
+               err = do_path_lookup(dfd, tmp->name, flags, &nd);
                putname(tmp);
                if (!err)
                        *path = nd.path;
@@ -2113,22 +2135,22 @@ int user_path_at(int dfd, const char __user *name, unsigned flags,
        return user_path_at_empty(dfd, name, flags, path, NULL);
 }
 
-static int user_path_parent(int dfd, const char __user *path,
-                       struct nameidata *nd, char **name)
+static struct filename *
+user_path_parent(int dfd, const char __user *path, struct nameidata *nd)
 {
-       char *s = getname(path);
+       struct filename *s = getname(path);
        int error;
 
        if (IS_ERR(s))
-               return PTR_ERR(s);
+               return s;
 
-       error = do_path_lookup(dfd, s, LOOKUP_PARENT, nd);
-       if (error)
+       error = do_path_lookup(dfd, s->name, LOOKUP_PARENT, nd);
+       if (error) {
                putname(s);
-       else
-               *name = s;
+               return ERR_PTR(error);
+       }
 
-       return error;
+       return s;
 }
 
 /*
@@ -3039,11 +3061,11 @@ EXPORT_SYMBOL(done_path_create);
 
 struct dentry *user_path_create(int dfd, const char __user *pathname, struct path *path, int is_dir)
 {
-       char *tmp = getname(pathname);
+       struct filename *tmp = getname(pathname);
        struct dentry *res;
        if (IS_ERR(tmp))
                return ERR_CAST(tmp);
-       res = kern_path_create(dfd, tmp, path, is_dir);
+       res = kern_path_create(dfd, tmp->name, path, is_dir);
        putname(tmp);
        return res;
 }
@@ -3248,13 +3270,13 @@ out:
 static long do_rmdir(int dfd, const char __user *pathname)
 {
        int error = 0;
-       char * name;
+       struct filename *name;
        struct dentry *dentry;
        struct nameidata nd;
 
-       error = user_path_parent(dfd, pathname, &nd, &name);
-       if (error)
-               return error;
+       name = user_path_parent(dfd, pathname, &nd);
+       if (IS_ERR(name))
+               return PTR_ERR(name);
 
        switch(nd.last_type) {
        case LAST_DOTDOT:
@@ -3343,14 +3365,14 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
 static long do_unlinkat(int dfd, const char __user *pathname)
 {
        int error;
-       char *name;
+       struct filename *name;
        struct dentry *dentry;
        struct nameidata nd;
        struct inode *inode = NULL;
 
-       error = user_path_parent(dfd, pathname, &nd, &name);
-       if (error)
-               return error;
+       name = user_path_parent(dfd, pathname, &nd);
+       if (IS_ERR(name))
+               return PTR_ERR(name);
 
        error = -EISDIR;
        if (nd.last_type != LAST_NORM)
@@ -3434,7 +3456,7 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
                int, newdfd, const char __user *, newname)
 {
        int error;
-       char *from;
+       struct filename *from;
        struct dentry *dentry;
        struct path path;
 
@@ -3447,9 +3469,9 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
        if (IS_ERR(dentry))
                goto out_putname;
 
-       error = security_path_symlink(&path, dentry, from);
+       error = security_path_symlink(&path, dentry, from->name);
        if (!error)
-               error = vfs_symlink(path.dentry->d_inode, dentry, from);
+               error = vfs_symlink(path.dentry->d_inode, dentry, from->name);
        done_path_create(&path, dentry);
 out_putname:
        putname(from);
@@ -3729,17 +3751,21 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
        struct dentry *old_dentry, *new_dentry;
        struct dentry *trap;
        struct nameidata oldnd, newnd;
-       char *from;
-       char *to;
+       struct filename *from;
+       struct filename *to;
        int error;
 
-       error = user_path_parent(olddfd, oldname, &oldnd, &from);
-       if (error)
+       from = user_path_parent(olddfd, oldname, &oldnd);
+       if (IS_ERR(from)) {
+               error = PTR_ERR(from);
                goto exit;
+       }
 
-       error = user_path_parent(newdfd, newname, &newnd, &to);
-       if (error)
+       to = user_path_parent(newdfd, newname, &newnd);
+       if (IS_ERR(to)) {
+               error = PTR_ERR(to);
                goto exit1;
+       }
 
        error = -EXDEV;
        if (oldnd.path.mnt != newnd.path.mnt)