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 | |
| 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>
| -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; |
