This will allow us to move the generic readlink logic into the VFS and get
rid of the readlink method.

Signed-off-by: Miklos Szeredi <[email protected]>
---
 fs/proc/namespaces.c | 56 +++++++++++++++++++++++++++-------------------------
 1 file changed, 29 insertions(+), 27 deletions(-)

diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
index 51b8b0a8ad91..9c9a1683791a 100644
--- a/fs/proc/namespaces.c
+++ b/fs/proc/namespaces.c
@@ -33,6 +33,8 @@ static const struct proc_ns_operations *ns_entries[] = {
 #endif
 };
 
+#define PROC_NS_LINK_MAX 50
+
 static const char *proc_ns_get_link(struct dentry *dentry,
                                    struct inode *inode,
                                    struct delayed_call *done)
@@ -40,47 +42,47 @@ static const char *proc_ns_get_link(struct dentry *dentry,
        const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops;
        struct task_struct *task;
        struct path ns_path;
-       void *error = ERR_PTR(-EACCES);
+       char *res = ERR_PTR(-EACCES);
 
        if (!dentry)
                return ERR_PTR(-ECHILD);
 
        task = get_proc_task(inode);
        if (!task)
-               return error;
-
-       if (ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) {
-               error = ns_get_path(&ns_path, task, ns_ops);
-               if (!error)
-                       nd_jump_link(&ns_path);
-       }
-       put_task_struct(task);
-       return error;
-}
-
-static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int 
buflen)
-{
-       struct inode *inode = d_inode(dentry);
-       const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops;
-       struct task_struct *task;
-       char name[50];
-       int res = -EACCES;
+               goto out;
 
-       task = get_proc_task(inode);
-       if (!task)
-               return res;
+       if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS))
+               goto out_put;
 
-       if (ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) {
-               res = ns_get_name(name, sizeof(name), task, ns_ops);
-               if (res >= 0)
-                       res = readlink_copy(buffer, buflen, name);
+       if (is_following_link()) {
+               res = ns_get_path(&ns_path, task, ns_ops);
+               if (!res)
+                       nd_jump_link(&ns_path);
+       } else {
+               char *name = kmalloc(PROC_NS_LINK_MAX, GFP_KERNEL);
+               int err;
+
+               res = ERR_PTR(-ENOMEM);
+               if (!name)
+                       goto out_put;
+
+               err = ns_get_name(name, PROC_NS_LINK_MAX, task, ns_ops);
+               if (err < 0) {
+                       kfree(name);
+                       res = ERR_PTR(err);
+                       goto out_put;
+               }
+               set_delayed_call(done, kfree_link, name);
+               res = name;
        }
+out_put:
        put_task_struct(task);
+out:
        return res;
 }
 
 static const struct inode_operations proc_ns_link_inode_operations = {
-       .readlink       = proc_ns_readlink,
+       .readlink       = generic_readlink,
        .get_link       = proc_ns_get_link,
        .setattr        = proc_setattr,
 };
-- 
2.5.5

Reply via email to