18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/cache.h> 38c2ecf20Sopenharmony_ci#include <linux/sched.h> 48c2ecf20Sopenharmony_ci#include <linux/slab.h> 58c2ecf20Sopenharmony_ci#include <linux/pid_namespace.h> 68c2ecf20Sopenharmony_ci#include "internal.h" 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci * /proc/thread_self: 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_cistatic const char *proc_thread_self_get_link(struct dentry *dentry, 128c2ecf20Sopenharmony_ci struct inode *inode, 138c2ecf20Sopenharmony_ci struct delayed_call *done) 148c2ecf20Sopenharmony_ci{ 158c2ecf20Sopenharmony_ci struct pid_namespace *ns = proc_pid_ns(inode->i_sb); 168c2ecf20Sopenharmony_ci pid_t tgid = task_tgid_nr_ns(current, ns); 178c2ecf20Sopenharmony_ci pid_t pid = task_pid_nr_ns(current, ns); 188c2ecf20Sopenharmony_ci char *name; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci if (!pid) 218c2ecf20Sopenharmony_ci return ERR_PTR(-ENOENT); 228c2ecf20Sopenharmony_ci name = kmalloc(10 + 6 + 10 + 1, dentry ? GFP_KERNEL : GFP_ATOMIC); 238c2ecf20Sopenharmony_ci if (unlikely(!name)) 248c2ecf20Sopenharmony_ci return dentry ? ERR_PTR(-ENOMEM) : ERR_PTR(-ECHILD); 258c2ecf20Sopenharmony_ci sprintf(name, "%u/task/%u", tgid, pid); 268c2ecf20Sopenharmony_ci set_delayed_call(done, kfree_link, name); 278c2ecf20Sopenharmony_ci return name; 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic const struct inode_operations proc_thread_self_inode_operations = { 318c2ecf20Sopenharmony_ci .get_link = proc_thread_self_get_link, 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic unsigned thread_self_inum __ro_after_init; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ciint proc_setup_thread_self(struct super_block *s) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct inode *root_inode = d_inode(s->s_root); 398c2ecf20Sopenharmony_ci struct proc_fs_info *fs_info = proc_sb_info(s); 408c2ecf20Sopenharmony_ci struct dentry *thread_self; 418c2ecf20Sopenharmony_ci int ret = -ENOMEM; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci inode_lock(root_inode); 448c2ecf20Sopenharmony_ci thread_self = d_alloc_name(s->s_root, "thread-self"); 458c2ecf20Sopenharmony_ci if (thread_self) { 468c2ecf20Sopenharmony_ci struct inode *inode = new_inode(s); 478c2ecf20Sopenharmony_ci if (inode) { 488c2ecf20Sopenharmony_ci inode->i_ino = thread_self_inum; 498c2ecf20Sopenharmony_ci inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); 508c2ecf20Sopenharmony_ci inode->i_mode = S_IFLNK | S_IRWXUGO; 518c2ecf20Sopenharmony_ci inode->i_uid = GLOBAL_ROOT_UID; 528c2ecf20Sopenharmony_ci inode->i_gid = GLOBAL_ROOT_GID; 538c2ecf20Sopenharmony_ci inode->i_op = &proc_thread_self_inode_operations; 548c2ecf20Sopenharmony_ci d_add(thread_self, inode); 558c2ecf20Sopenharmony_ci ret = 0; 568c2ecf20Sopenharmony_ci } else { 578c2ecf20Sopenharmony_ci dput(thread_self); 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci inode_unlock(root_inode); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (ret) 638c2ecf20Sopenharmony_ci pr_err("proc_fill_super: can't allocate /proc/thread-self\n"); 648c2ecf20Sopenharmony_ci else 658c2ecf20Sopenharmony_ci fs_info->proc_thread_self = thread_self; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci return ret; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_civoid __init proc_thread_self_init(void) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci proc_alloc_inum(&thread_self_inum); 738c2ecf20Sopenharmony_ci} 74