diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2009-12-24 01:26:48 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2010-03-05 09:01:11 -0500 |
commit | 648fa8611de3d4d43bbd64af3226679d2d0eb609 (patch) | |
tree | 96d134de1d935d6d54daac678dc07346bbbda940 /fs | |
parent | 64ba9926759792cf7b95f823402e2781edd1b5d4 (diff) |
beginning to untangle do_filp_open()
That's going to be a long and painful series. The first step:
take the stuff reachable from 'ok' label in do_filp_open() into
a new helper (finish_open()).
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/namei.c | 106 |
1 files changed, 56 insertions, 50 deletions
diff --git a/fs/namei.c b/fs/namei.c index 0741c69b3319..60b74b3946a1 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1590,6 +1590,61 @@ static int open_will_truncate(int flag, struct inode *inode) | |||
1590 | return (flag & O_TRUNC); | 1590 | return (flag & O_TRUNC); |
1591 | } | 1591 | } |
1592 | 1592 | ||
1593 | static struct file *finish_open(struct nameidata *nd, | ||
1594 | int open_flag, int flag, int acc_mode) | ||
1595 | { | ||
1596 | struct file *filp; | ||
1597 | int will_truncate; | ||
1598 | int error; | ||
1599 | |||
1600 | will_truncate = open_will_truncate(flag, nd->path.dentry->d_inode); | ||
1601 | if (will_truncate) { | ||
1602 | error = mnt_want_write(nd->path.mnt); | ||
1603 | if (error) | ||
1604 | goto exit; | ||
1605 | } | ||
1606 | error = may_open(&nd->path, acc_mode, open_flag); | ||
1607 | if (error) { | ||
1608 | if (will_truncate) | ||
1609 | mnt_drop_write(nd->path.mnt); | ||
1610 | goto exit; | ||
1611 | } | ||
1612 | filp = nameidata_to_filp(nd); | ||
1613 | if (!IS_ERR(filp)) { | ||
1614 | error = ima_file_check(filp, acc_mode); | ||
1615 | if (error) { | ||
1616 | fput(filp); | ||
1617 | filp = ERR_PTR(error); | ||
1618 | } | ||
1619 | } | ||
1620 | if (!IS_ERR(filp)) { | ||
1621 | if (acc_mode & MAY_WRITE) | ||
1622 | vfs_dq_init(nd->path.dentry->d_inode); | ||
1623 | |||
1624 | if (will_truncate) { | ||
1625 | error = handle_truncate(&nd->path); | ||
1626 | if (error) { | ||
1627 | fput(filp); | ||
1628 | filp = ERR_PTR(error); | ||
1629 | } | ||
1630 | } | ||
1631 | } | ||
1632 | /* | ||
1633 | * It is now safe to drop the mnt write | ||
1634 | * because the filp has had a write taken | ||
1635 | * on its behalf. | ||
1636 | */ | ||
1637 | if (will_truncate) | ||
1638 | mnt_drop_write(nd->path.mnt); | ||
1639 | return filp; | ||
1640 | |||
1641 | exit: | ||
1642 | if (!IS_ERR(nd->intent.open.file)) | ||
1643 | release_open_intent(nd); | ||
1644 | path_put(&nd->path); | ||
1645 | return ERR_PTR(error); | ||
1646 | } | ||
1647 | |||
1593 | /* | 1648 | /* |
1594 | * Note that the low bits of the passed in "open_flag" | 1649 | * Note that the low bits of the passed in "open_flag" |
1595 | * are not the same as in the local variable "flag". See | 1650 | * are not the same as in the local variable "flag". See |
@@ -1604,7 +1659,6 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
1604 | struct path path; | 1659 | struct path path; |
1605 | struct dentry *dir; | 1660 | struct dentry *dir; |
1606 | int count = 0; | 1661 | int count = 0; |
1607 | int will_truncate; | ||
1608 | int flag = open_to_namei_flags(open_flag); | 1662 | int flag = open_to_namei_flags(open_flag); |
1609 | int force_reval = 0; | 1663 | int force_reval = 0; |
1610 | 1664 | ||
@@ -1769,55 +1823,7 @@ do_last: | |||
1769 | if (S_ISDIR(path.dentry->d_inode->i_mode)) | 1823 | if (S_ISDIR(path.dentry->d_inode->i_mode)) |
1770 | goto exit; | 1824 | goto exit; |
1771 | ok: | 1825 | ok: |
1772 | /* | 1826 | filp = finish_open(&nd, open_flag, flag, acc_mode); |
1773 | * Consider: | ||
1774 | * 1. may_open() truncates a file | ||
1775 | * 2. a rw->ro mount transition occurs | ||
1776 | * 3. nameidata_to_filp() fails due to | ||
1777 | * the ro mount. | ||
1778 | * That would be inconsistent, and should | ||
1779 | * be avoided. Taking this mnt write here | ||
1780 | * ensures that (2) can not occur. | ||
1781 | */ | ||
1782 | will_truncate = open_will_truncate(flag, nd.path.dentry->d_inode); | ||
1783 | if (will_truncate) { | ||
1784 | error = mnt_want_write(nd.path.mnt); | ||
1785 | if (error) | ||
1786 | goto exit; | ||
1787 | } | ||
1788 | error = may_open(&nd.path, acc_mode, open_flag); | ||
1789 | if (error) { | ||
1790 | if (will_truncate) | ||
1791 | mnt_drop_write(nd.path.mnt); | ||
1792 | goto exit; | ||
1793 | } | ||
1794 | filp = nameidata_to_filp(&nd); | ||
1795 | if (!IS_ERR(filp)) { | ||
1796 | error = ima_file_check(filp, acc_mode); | ||
1797 | if (error) { | ||
1798 | fput(filp); | ||
1799 | filp = ERR_PTR(error); | ||
1800 | } | ||
1801 | } | ||
1802 | if (!IS_ERR(filp)) { | ||
1803 | if (acc_mode & MAY_WRITE) | ||
1804 | vfs_dq_init(nd.path.dentry->d_inode); | ||
1805 | |||
1806 | if (will_truncate) { | ||
1807 | error = handle_truncate(&nd.path); | ||
1808 | if (error) { | ||
1809 | fput(filp); | ||
1810 | filp = ERR_PTR(error); | ||
1811 | } | ||
1812 | } | ||
1813 | } | ||
1814 | /* | ||
1815 | * It is now safe to drop the mnt write | ||
1816 | * because the filp has had a write taken | ||
1817 | * on its behalf. | ||
1818 | */ | ||
1819 | if (will_truncate) | ||
1820 | mnt_drop_write(nd.path.mnt); | ||
1821 | if (nd.root.mnt) | 1827 | if (nd.root.mnt) |
1822 | path_put(&nd.root); | 1828 | path_put(&nd.root); |
1823 | return filp; | 1829 | return filp; |