|
@@ -1673,6 +1673,108 @@ static struct inode_operations proc_self_inode_operations = {
|
|
|
.follow_link = proc_self_follow_link,
|
|
|
};
|
|
|
|
|
|
+/*
|
|
|
+ * proc base
|
|
|
+ *
|
|
|
+ * These are the directory entries in the root directory of /proc
|
|
|
+ * that properly belong to the /proc filesystem, as they describe
|
|
|
+ * describe something that is process related.
|
|
|
+ */
|
|
|
+static struct pid_entry proc_base_stuff[] = {
|
|
|
+ NOD(PROC_TGID_INO, "self", S_IFLNK|S_IRWXUGO,
|
|
|
+ &proc_self_inode_operations, NULL, {}),
|
|
|
+ {}
|
|
|
+};
|
|
|
+
|
|
|
+/*
|
|
|
+ * Exceptional case: normally we are not allowed to unhash a busy
|
|
|
+ * directory. In this case, however, we can do it - no aliasing problems
|
|
|
+ * due to the way we treat inodes.
|
|
|
+ */
|
|
|
+static int proc_base_revalidate(struct dentry *dentry, struct nameidata *nd)
|
|
|
+{
|
|
|
+ struct inode *inode = dentry->d_inode;
|
|
|
+ struct task_struct *task = get_proc_task(inode);
|
|
|
+ if (task) {
|
|
|
+ put_task_struct(task);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ d_drop(dentry);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static struct dentry_operations proc_base_dentry_operations =
|
|
|
+{
|
|
|
+ .d_revalidate = proc_base_revalidate,
|
|
|
+ .d_delete = pid_delete_dentry,
|
|
|
+};
|
|
|
+
|
|
|
+static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
|
|
|
+{
|
|
|
+ struct inode *inode;
|
|
|
+ struct dentry *error;
|
|
|
+ struct task_struct *task = get_proc_task(dir);
|
|
|
+ struct pid_entry *p;
|
|
|
+ struct proc_inode *ei;
|
|
|
+
|
|
|
+ error = ERR_PTR(-ENOENT);
|
|
|
+ inode = NULL;
|
|
|
+
|
|
|
+ if (!task)
|
|
|
+ goto out_no_task;
|
|
|
+
|
|
|
+ /* Lookup the directory entry */
|
|
|
+ for (p = proc_base_stuff; p->name; p++) {
|
|
|
+ if (p->len != dentry->d_name.len)
|
|
|
+ continue;
|
|
|
+ if (!memcmp(dentry->d_name.name, p->name, p->len))
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (!p->name)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ /* Allocate the inode */
|
|
|
+ error = ERR_PTR(-ENOMEM);
|
|
|
+ inode = new_inode(dir->i_sb);
|
|
|
+ if (!inode)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ /* Initialize the inode */
|
|
|
+ ei = PROC_I(inode);
|
|
|
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
|
|
|
+ inode->i_ino = fake_ino(0, p->type);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * grab the reference to the task.
|
|
|
+ */
|
|
|
+ ei->pid = get_pid(task_pid(task));
|
|
|
+ if (!ei->pid)
|
|
|
+ goto out_iput;
|
|
|
+
|
|
|
+ inode->i_uid = 0;
|
|
|
+ inode->i_gid = 0;
|
|
|
+ inode->i_mode = p->mode;
|
|
|
+ if (S_ISDIR(inode->i_mode))
|
|
|
+ inode->i_nlink = 2;
|
|
|
+ if (S_ISLNK(inode->i_mode))
|
|
|
+ inode->i_size = 64;
|
|
|
+ if (p->iop)
|
|
|
+ inode->i_op = p->iop;
|
|
|
+ if (p->fop)
|
|
|
+ inode->i_fop = p->fop;
|
|
|
+ ei->op = p->op;
|
|
|
+ dentry->d_op = &proc_base_dentry_operations;
|
|
|
+ d_add(dentry, inode);
|
|
|
+ error = NULL;
|
|
|
+out:
|
|
|
+ put_task_struct(task);
|
|
|
+out_no_task:
|
|
|
+ return error;
|
|
|
+out_iput:
|
|
|
+ iput(inode);
|
|
|
+ goto out;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Thread groups
|
|
|
*/
|
|
@@ -1819,24 +1921,12 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct
|
|
|
struct dentry *result = ERR_PTR(-ENOENT);
|
|
|
struct task_struct *task;
|
|
|
struct inode *inode;
|
|
|
- struct proc_inode *ei;
|
|
|
unsigned tgid;
|
|
|
|
|
|
- if (dentry->d_name.len == 4 && !memcmp(dentry->d_name.name,"self",4)) {
|
|
|
- inode = new_inode(dir->i_sb);
|
|
|
- if (!inode)
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
- ei = PROC_I(inode);
|
|
|
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
|
|
|
- inode->i_ino = fake_ino(0, PROC_TGID_INO);
|
|
|
- ei->pde = NULL;
|
|
|
- inode->i_mode = S_IFLNK|S_IRWXUGO;
|
|
|
- inode->i_uid = inode->i_gid = 0;
|
|
|
- inode->i_size = 64;
|
|
|
- inode->i_op = &proc_self_inode_operations;
|
|
|
- d_add(dentry, inode);
|
|
|
- return NULL;
|
|
|
- }
|
|
|
+ result = proc_base_lookup(dir, dentry);
|
|
|
+ if (!IS_ERR(result) || PTR_ERR(result) != -ENOENT)
|
|
|
+ goto out;
|
|
|
+
|
|
|
tgid = name_to_int(dentry);
|
|
|
if (tgid == ~0U)
|
|
|
goto out;
|
|
@@ -1922,12 +2012,11 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
|
|
|
struct task_struct *task;
|
|
|
int tgid;
|
|
|
|
|
|
- if (!nr) {
|
|
|
- ino_t ino = fake_ino(0,PROC_TGID_INO);
|
|
|
- if (filldir(dirent, "self", 4, filp->f_pos, ino, DT_LNK) < 0)
|
|
|
- return 0;
|
|
|
- filp->f_pos++;
|
|
|
- nr++;
|
|
|
+ for (; nr < (ARRAY_SIZE(proc_base_stuff) - 1); filp->f_pos++, nr++) {
|
|
|
+ struct pid_entry *p = &proc_base_stuff[nr];
|
|
|
+ if (filldir(dirent, p->name, p->len, filp->f_pos,
|
|
|
+ fake_ino(0, p->type), p->mode >> 12) < 0)
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
tgid = filp->f_pos - TGID_OFFSET;
|