162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/cache.h> 362306a36Sopenharmony_ci#include <linux/sched.h> 462306a36Sopenharmony_ci#include <linux/slab.h> 562306a36Sopenharmony_ci#include <linux/pid_namespace.h> 662306a36Sopenharmony_ci#include "internal.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci * /proc/thread_self: 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_cistatic const char *proc_thread_self_get_link(struct dentry *dentry, 1262306a36Sopenharmony_ci struct inode *inode, 1362306a36Sopenharmony_ci struct delayed_call *done) 1462306a36Sopenharmony_ci{ 1562306a36Sopenharmony_ci struct pid_namespace *ns = proc_pid_ns(inode->i_sb); 1662306a36Sopenharmony_ci pid_t tgid = task_tgid_nr_ns(current, ns); 1762306a36Sopenharmony_ci pid_t pid = task_pid_nr_ns(current, ns); 1862306a36Sopenharmony_ci char *name; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci if (!pid) 2162306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 2262306a36Sopenharmony_ci name = kmalloc(10 + 6 + 10 + 1, dentry ? GFP_KERNEL : GFP_ATOMIC); 2362306a36Sopenharmony_ci if (unlikely(!name)) 2462306a36Sopenharmony_ci return dentry ? ERR_PTR(-ENOMEM) : ERR_PTR(-ECHILD); 2562306a36Sopenharmony_ci sprintf(name, "%u/task/%u", tgid, pid); 2662306a36Sopenharmony_ci set_delayed_call(done, kfree_link, name); 2762306a36Sopenharmony_ci return name; 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic const struct inode_operations proc_thread_self_inode_operations = { 3162306a36Sopenharmony_ci .get_link = proc_thread_self_get_link, 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic unsigned thread_self_inum __ro_after_init; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ciint proc_setup_thread_self(struct super_block *s) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci struct inode *root_inode = d_inode(s->s_root); 3962306a36Sopenharmony_ci struct proc_fs_info *fs_info = proc_sb_info(s); 4062306a36Sopenharmony_ci struct dentry *thread_self; 4162306a36Sopenharmony_ci int ret = -ENOMEM; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci inode_lock(root_inode); 4462306a36Sopenharmony_ci thread_self = d_alloc_name(s->s_root, "thread-self"); 4562306a36Sopenharmony_ci if (thread_self) { 4662306a36Sopenharmony_ci struct inode *inode = new_inode(s); 4762306a36Sopenharmony_ci if (inode) { 4862306a36Sopenharmony_ci inode->i_ino = thread_self_inum; 4962306a36Sopenharmony_ci inode->i_mtime = inode->i_atime = inode_set_ctime_current(inode); 5062306a36Sopenharmony_ci inode->i_mode = S_IFLNK | S_IRWXUGO; 5162306a36Sopenharmony_ci inode->i_uid = GLOBAL_ROOT_UID; 5262306a36Sopenharmony_ci inode->i_gid = GLOBAL_ROOT_GID; 5362306a36Sopenharmony_ci inode->i_op = &proc_thread_self_inode_operations; 5462306a36Sopenharmony_ci d_add(thread_self, inode); 5562306a36Sopenharmony_ci ret = 0; 5662306a36Sopenharmony_ci } else { 5762306a36Sopenharmony_ci dput(thread_self); 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci inode_unlock(root_inode); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (ret) 6362306a36Sopenharmony_ci pr_err("proc_fill_super: can't allocate /proc/thread-self\n"); 6462306a36Sopenharmony_ci else 6562306a36Sopenharmony_ci fs_info->proc_thread_self = thread_self; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci return ret; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_civoid __init proc_thread_self_init(void) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci proc_alloc_inum(&thread_self_inum); 7362306a36Sopenharmony_ci} 74