| #include <linux/proc_fs.h> | 
 | #include <linux/sched.h> | 
 | #include <linux/namei.h> | 
 |  | 
 | /* | 
 |  * /proc/self: | 
 |  */ | 
 | static int proc_self_readlink(struct dentry *dentry, char __user *buffer, | 
 | 			      int buflen) | 
 | { | 
 | 	struct pid_namespace *ns = dentry->d_sb->s_fs_info; | 
 | 	pid_t tgid = task_tgid_nr_ns(current, ns); | 
 | 	char tmp[PROC_NUMBUF]; | 
 | 	if (!tgid) | 
 | 		return -ENOENT; | 
 | 	sprintf(tmp, "%d", tgid); | 
 | 	return vfs_readlink(dentry,buffer,buflen,tmp); | 
 | } | 
 |  | 
 | static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) | 
 | { | 
 | 	struct pid_namespace *ns = dentry->d_sb->s_fs_info; | 
 | 	pid_t tgid = task_tgid_nr_ns(current, ns); | 
 | 	char *name = ERR_PTR(-ENOENT); | 
 | 	if (tgid) { | 
 | 		/* 11 for max length of signed int in decimal + NULL term */ | 
 | 		name = kmalloc(12, GFP_KERNEL); | 
 | 		if (!name) | 
 | 			name = ERR_PTR(-ENOMEM); | 
 | 		else | 
 | 			sprintf(name, "%d", tgid); | 
 | 	} | 
 | 	nd_set_link(nd, name); | 
 | 	return NULL; | 
 | } | 
 |  | 
 | static void proc_self_put_link(struct dentry *dentry, struct nameidata *nd, | 
 | 				void *cookie) | 
 | { | 
 | 	char *s = nd_get_link(nd); | 
 | 	if (!IS_ERR(s)) | 
 | 		kfree(s); | 
 | } | 
 |  | 
 | static const struct inode_operations proc_self_inode_operations = { | 
 | 	.readlink	= proc_self_readlink, | 
 | 	.follow_link	= proc_self_follow_link, | 
 | 	.put_link	= proc_self_put_link, | 
 | }; | 
 |  | 
 | void __init proc_self_init(void) | 
 | { | 
 | 	struct proc_dir_entry *proc_self_symlink; | 
 | 	mode_t mode; | 
 |  | 
 | 	mode = S_IFLNK | S_IRWXUGO; | 
 | 	proc_self_symlink = proc_create("self", mode, NULL, NULL ); | 
 | 	proc_self_symlink->proc_iops = &proc_self_inode_operations; | 
 | } |