diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2009-12-24 01:58:28 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2010-03-05 09:01:13 -0500 |
commit | fb1cc555d533869910e20de4b8d5147570afdfad (patch) | |
tree | 99ee86c8370e28df0991a4ecd03677cb65704f01 /fs/namei.c | |
parent | 648fa8611de3d4d43bbd64af3226679d2d0eb609 (diff) |
gut do_filp_open() a bit more (do_last separation)
Brute-force separation of stuff reachable from do_last: with
the exception of do_link:; just take all that crap to a helper
function as-is and have it tell the caller if it has to go
to do_link.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 171 |
1 files changed, 103 insertions, 68 deletions
diff --git a/fs/namei.c b/fs/namei.c index 60b74b3946a1..3c39fa1608c5 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1645,6 +1645,104 @@ exit: | |||
1645 | return ERR_PTR(error); | 1645 | return ERR_PTR(error); |
1646 | } | 1646 | } |
1647 | 1647 | ||
1648 | static struct file *do_last(struct nameidata *nd, struct path *path, | ||
1649 | int open_flag, int flag, int acc_mode, | ||
1650 | int mode, const char *pathname, | ||
1651 | struct dentry *dir, int *is_link) | ||
1652 | { | ||
1653 | struct file *filp; | ||
1654 | int error; | ||
1655 | |||
1656 | *is_link = 0; | ||
1657 | |||
1658 | error = PTR_ERR(path->dentry); | ||
1659 | if (IS_ERR(path->dentry)) { | ||
1660 | mutex_unlock(&dir->d_inode->i_mutex); | ||
1661 | goto exit; | ||
1662 | } | ||
1663 | |||
1664 | if (IS_ERR(nd->intent.open.file)) { | ||
1665 | error = PTR_ERR(nd->intent.open.file); | ||
1666 | goto exit_mutex_unlock; | ||
1667 | } | ||
1668 | |||
1669 | /* Negative dentry, just create the file */ | ||
1670 | if (!path->dentry->d_inode) { | ||
1671 | /* | ||
1672 | * This write is needed to ensure that a | ||
1673 | * ro->rw transition does not occur between | ||
1674 | * the time when the file is created and when | ||
1675 | * a permanent write count is taken through | ||
1676 | * the 'struct file' in nameidata_to_filp(). | ||
1677 | */ | ||
1678 | error = mnt_want_write(nd->path.mnt); | ||
1679 | if (error) | ||
1680 | goto exit_mutex_unlock; | ||
1681 | error = __open_namei_create(nd, path, open_flag, mode); | ||
1682 | if (error) { | ||
1683 | mnt_drop_write(nd->path.mnt); | ||
1684 | goto exit; | ||
1685 | } | ||
1686 | filp = nameidata_to_filp(nd); | ||
1687 | mnt_drop_write(nd->path.mnt); | ||
1688 | if (nd->root.mnt) | ||
1689 | path_put(&nd->root); | ||
1690 | if (!IS_ERR(filp)) { | ||
1691 | error = ima_file_check(filp, acc_mode); | ||
1692 | if (error) { | ||
1693 | fput(filp); | ||
1694 | filp = ERR_PTR(error); | ||
1695 | } | ||
1696 | } | ||
1697 | return filp; | ||
1698 | } | ||
1699 | |||
1700 | /* | ||
1701 | * It already exists. | ||
1702 | */ | ||
1703 | mutex_unlock(&dir->d_inode->i_mutex); | ||
1704 | audit_inode(pathname, path->dentry); | ||
1705 | |||
1706 | error = -EEXIST; | ||
1707 | if (flag & O_EXCL) | ||
1708 | goto exit_dput; | ||
1709 | |||
1710 | if (__follow_mount(path)) { | ||
1711 | error = -ELOOP; | ||
1712 | if (flag & O_NOFOLLOW) | ||
1713 | goto exit_dput; | ||
1714 | } | ||
1715 | |||
1716 | error = -ENOENT; | ||
1717 | if (!path->dentry->d_inode) | ||
1718 | goto exit_dput; | ||
1719 | if (path->dentry->d_inode->i_op->follow_link) { | ||
1720 | *is_link = 1; | ||
1721 | return NULL; | ||
1722 | } | ||
1723 | |||
1724 | path_to_nameidata(path, nd); | ||
1725 | error = -EISDIR; | ||
1726 | if (S_ISDIR(path->dentry->d_inode->i_mode)) | ||
1727 | goto exit; | ||
1728 | filp = finish_open(nd, open_flag, flag, acc_mode); | ||
1729 | if (nd->root.mnt) | ||
1730 | path_put(&nd->root); | ||
1731 | return filp; | ||
1732 | |||
1733 | exit_mutex_unlock: | ||
1734 | mutex_unlock(&dir->d_inode->i_mutex); | ||
1735 | exit_dput: | ||
1736 | path_put_conditional(path, nd); | ||
1737 | exit: | ||
1738 | if (!IS_ERR(nd->intent.open.file)) | ||
1739 | release_open_intent(nd); | ||
1740 | if (nd->root.mnt) | ||
1741 | path_put(&nd->root); | ||
1742 | path_put(&nd->path); | ||
1743 | return ERR_PTR(error); | ||
1744 | } | ||
1745 | |||
1648 | /* | 1746 | /* |
1649 | * Note that the low bits of the passed in "open_flag" | 1747 | * Note that the low bits of the passed in "open_flag" |
1650 | * are not the same as in the local variable "flag". See | 1748 | * are not the same as in the local variable "flag". See |
@@ -1661,6 +1759,7 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
1661 | int count = 0; | 1759 | int count = 0; |
1662 | int flag = open_to_namei_flags(open_flag); | 1760 | int flag = open_to_namei_flags(open_flag); |
1663 | int force_reval = 0; | 1761 | int force_reval = 0; |
1762 | int is_link; | ||
1664 | 1763 | ||
1665 | /* | 1764 | /* |
1666 | * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only | 1765 | * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only |
@@ -1754,82 +1853,18 @@ reval: | |||
1754 | path.mnt = nd.path.mnt; | 1853 | path.mnt = nd.path.mnt; |
1755 | 1854 | ||
1756 | do_last: | 1855 | do_last: |
1757 | error = PTR_ERR(path.dentry); | 1856 | filp = do_last(&nd, &path, open_flag, flag, acc_mode, mode, |
1758 | if (IS_ERR(path.dentry)) { | 1857 | pathname, dir, &is_link); |
1759 | mutex_unlock(&dir->d_inode->i_mutex); | 1858 | if (is_link) |
1760 | goto exit; | ||
1761 | } | ||
1762 | |||
1763 | if (IS_ERR(nd.intent.open.file)) { | ||
1764 | error = PTR_ERR(nd.intent.open.file); | ||
1765 | goto exit_mutex_unlock; | ||
1766 | } | ||
1767 | |||
1768 | /* Negative dentry, just create the file */ | ||
1769 | if (!path.dentry->d_inode) { | ||
1770 | /* | ||
1771 | * This write is needed to ensure that a | ||
1772 | * ro->rw transition does not occur between | ||
1773 | * the time when the file is created and when | ||
1774 | * a permanent write count is taken through | ||
1775 | * the 'struct file' in nameidata_to_filp(). | ||
1776 | */ | ||
1777 | error = mnt_want_write(nd.path.mnt); | ||
1778 | if (error) | ||
1779 | goto exit_mutex_unlock; | ||
1780 | error = __open_namei_create(&nd, &path, open_flag, mode); | ||
1781 | if (error) { | ||
1782 | mnt_drop_write(nd.path.mnt); | ||
1783 | goto exit; | ||
1784 | } | ||
1785 | filp = nameidata_to_filp(&nd); | ||
1786 | mnt_drop_write(nd.path.mnt); | ||
1787 | if (nd.root.mnt) | ||
1788 | path_put(&nd.root); | ||
1789 | if (!IS_ERR(filp)) { | ||
1790 | error = ima_file_check(filp, acc_mode); | ||
1791 | if (error) { | ||
1792 | fput(filp); | ||
1793 | filp = ERR_PTR(error); | ||
1794 | } | ||
1795 | } | ||
1796 | return filp; | ||
1797 | } | ||
1798 | |||
1799 | /* | ||
1800 | * It already exists. | ||
1801 | */ | ||
1802 | mutex_unlock(&dir->d_inode->i_mutex); | ||
1803 | audit_inode(pathname, path.dentry); | ||
1804 | |||
1805 | error = -EEXIST; | ||
1806 | if (flag & O_EXCL) | ||
1807 | goto exit_dput; | ||
1808 | |||
1809 | if (__follow_mount(&path)) { | ||
1810 | error = -ELOOP; | ||
1811 | if (flag & O_NOFOLLOW) | ||
1812 | goto exit_dput; | ||
1813 | } | ||
1814 | |||
1815 | error = -ENOENT; | ||
1816 | if (!path.dentry->d_inode) | ||
1817 | goto exit_dput; | ||
1818 | if (path.dentry->d_inode->i_op->follow_link) | ||
1819 | goto do_link; | 1859 | goto do_link; |
1860 | return filp; | ||
1820 | 1861 | ||
1821 | path_to_nameidata(&path, &nd); | ||
1822 | error = -EISDIR; | ||
1823 | if (S_ISDIR(path.dentry->d_inode->i_mode)) | ||
1824 | goto exit; | ||
1825 | ok: | 1862 | ok: |
1826 | filp = finish_open(&nd, open_flag, flag, acc_mode); | 1863 | filp = finish_open(&nd, open_flag, flag, acc_mode); |
1827 | if (nd.root.mnt) | 1864 | if (nd.root.mnt) |
1828 | path_put(&nd.root); | 1865 | path_put(&nd.root); |
1829 | return filp; | 1866 | return filp; |
1830 | 1867 | ||
1831 | exit_mutex_unlock: | ||
1832 | mutex_unlock(&dir->d_inode->i_mutex); | ||
1833 | exit_dput: | 1868 | exit_dput: |
1834 | path_put_conditional(&path, &nd); | 1869 | path_put_conditional(&path, &nd); |
1835 | exit: | 1870 | exit: |