diff options
-rw-r--r-- | fs/proc/base.c | 133 |
1 files changed, 111 insertions, 22 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 6d00ccc48c1c..7832efbd43a6 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -1674,6 +1674,108 @@ static struct inode_operations proc_self_inode_operations = { | |||
1674 | }; | 1674 | }; |
1675 | 1675 | ||
1676 | /* | 1676 | /* |
1677 | * proc base | ||
1678 | * | ||
1679 | * These are the directory entries in the root directory of /proc | ||
1680 | * that properly belong to the /proc filesystem, as they describe | ||
1681 | * describe something that is process related. | ||
1682 | */ | ||
1683 | static struct pid_entry proc_base_stuff[] = { | ||
1684 | NOD(PROC_TGID_INO, "self", S_IFLNK|S_IRWXUGO, | ||
1685 | &proc_self_inode_operations, NULL, {}), | ||
1686 | {} | ||
1687 | }; | ||
1688 | |||
1689 | /* | ||
1690 | * Exceptional case: normally we are not allowed to unhash a busy | ||
1691 | * directory. In this case, however, we can do it - no aliasing problems | ||
1692 | * due to the way we treat inodes. | ||
1693 | */ | ||
1694 | static int proc_base_revalidate(struct dentry *dentry, struct nameidata *nd) | ||
1695 | { | ||
1696 | struct inode *inode = dentry->d_inode; | ||
1697 | struct task_struct *task = get_proc_task(inode); | ||
1698 | if (task) { | ||
1699 | put_task_struct(task); | ||
1700 | return 1; | ||
1701 | } | ||
1702 | d_drop(dentry); | ||
1703 | return 0; | ||
1704 | } | ||
1705 | |||
1706 | static struct dentry_operations proc_base_dentry_operations = | ||
1707 | { | ||
1708 | .d_revalidate = proc_base_revalidate, | ||
1709 | .d_delete = pid_delete_dentry, | ||
1710 | }; | ||
1711 | |||
1712 | static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry) | ||
1713 | { | ||
1714 | struct inode *inode; | ||
1715 | struct dentry *error; | ||
1716 | struct task_struct *task = get_proc_task(dir); | ||
1717 | struct pid_entry *p; | ||
1718 | struct proc_inode *ei; | ||
1719 | |||
1720 | error = ERR_PTR(-ENOENT); | ||
1721 | inode = NULL; | ||
1722 | |||
1723 | if (!task) | ||
1724 | goto out_no_task; | ||
1725 | |||
1726 | /* Lookup the directory entry */ | ||
1727 | for (p = proc_base_stuff; p->name; p++) { | ||
1728 | if (p->len != dentry->d_name.len) | ||
1729 | continue; | ||
1730 | if (!memcmp(dentry->d_name.name, p->name, p->len)) | ||
1731 | break; | ||
1732 | } | ||
1733 | if (!p->name) | ||
1734 | goto out; | ||
1735 | |||
1736 | /* Allocate the inode */ | ||
1737 | error = ERR_PTR(-ENOMEM); | ||
1738 | inode = new_inode(dir->i_sb); | ||
1739 | if (!inode) | ||
1740 | goto out; | ||
1741 | |||
1742 | /* Initialize the inode */ | ||
1743 | ei = PROC_I(inode); | ||
1744 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | ||
1745 | inode->i_ino = fake_ino(0, p->type); | ||
1746 | |||
1747 | /* | ||
1748 | * grab the reference to the task. | ||
1749 | */ | ||
1750 | ei->pid = get_pid(task_pid(task)); | ||
1751 | if (!ei->pid) | ||
1752 | goto out_iput; | ||
1753 | |||
1754 | inode->i_uid = 0; | ||
1755 | inode->i_gid = 0; | ||
1756 | inode->i_mode = p->mode; | ||
1757 | if (S_ISDIR(inode->i_mode)) | ||
1758 | inode->i_nlink = 2; | ||
1759 | if (S_ISLNK(inode->i_mode)) | ||
1760 | inode->i_size = 64; | ||
1761 | if (p->iop) | ||
1762 | inode->i_op = p->iop; | ||
1763 | if (p->fop) | ||
1764 | inode->i_fop = p->fop; | ||
1765 | ei->op = p->op; | ||
1766 | dentry->d_op = &proc_base_dentry_operations; | ||
1767 | d_add(dentry, inode); | ||
1768 | error = NULL; | ||
1769 | out: | ||
1770 | put_task_struct(task); | ||
1771 | out_no_task: | ||
1772 | return error; | ||
1773 | out_iput: | ||
1774 | iput(inode); | ||
1775 | goto out; | ||
1776 | } | ||
1777 | |||
1778 | /* | ||
1677 | * Thread groups | 1779 | * Thread groups |
1678 | */ | 1780 | */ |
1679 | static struct file_operations proc_task_operations; | 1781 | static struct file_operations proc_task_operations; |
@@ -1819,24 +1921,12 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct | |||
1819 | struct dentry *result = ERR_PTR(-ENOENT); | 1921 | struct dentry *result = ERR_PTR(-ENOENT); |
1820 | struct task_struct *task; | 1922 | struct task_struct *task; |
1821 | struct inode *inode; | 1923 | struct inode *inode; |
1822 | struct proc_inode *ei; | ||
1823 | unsigned tgid; | 1924 | unsigned tgid; |
1824 | 1925 | ||
1825 | if (dentry->d_name.len == 4 && !memcmp(dentry->d_name.name,"self",4)) { | 1926 | result = proc_base_lookup(dir, dentry); |
1826 | inode = new_inode(dir->i_sb); | 1927 | if (!IS_ERR(result) || PTR_ERR(result) != -ENOENT) |
1827 | if (!inode) | 1928 | goto out; |
1828 | return ERR_PTR(-ENOMEM); | 1929 | |
1829 | ei = PROC_I(inode); | ||
1830 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | ||
1831 | inode->i_ino = fake_ino(0, PROC_TGID_INO); | ||
1832 | ei->pde = NULL; | ||
1833 | inode->i_mode = S_IFLNK|S_IRWXUGO; | ||
1834 | inode->i_uid = inode->i_gid = 0; | ||
1835 | inode->i_size = 64; | ||
1836 | inode->i_op = &proc_self_inode_operations; | ||
1837 | d_add(dentry, inode); | ||
1838 | return NULL; | ||
1839 | } | ||
1840 | tgid = name_to_int(dentry); | 1930 | tgid = name_to_int(dentry); |
1841 | if (tgid == ~0U) | 1931 | if (tgid == ~0U) |
1842 | goto out; | 1932 | goto out; |
@@ -1922,12 +2012,11 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
1922 | struct task_struct *task; | 2012 | struct task_struct *task; |
1923 | int tgid; | 2013 | int tgid; |
1924 | 2014 | ||
1925 | if (!nr) { | 2015 | for (; nr < (ARRAY_SIZE(proc_base_stuff) - 1); filp->f_pos++, nr++) { |
1926 | ino_t ino = fake_ino(0,PROC_TGID_INO); | 2016 | struct pid_entry *p = &proc_base_stuff[nr]; |
1927 | if (filldir(dirent, "self", 4, filp->f_pos, ino, DT_LNK) < 0) | 2017 | if (filldir(dirent, p->name, p->len, filp->f_pos, |
1928 | return 0; | 2018 | fake_ino(0, p->type), p->mode >> 12) < 0) |
1929 | filp->f_pos++; | 2019 | goto out; |
1930 | nr++; | ||
1931 | } | 2020 | } |
1932 | 2021 | ||
1933 | tgid = filp->f_pos - TGID_OFFSET; | 2022 | tgid = filp->f_pos - TGID_OFFSET; |