diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2009-12-26 07:16:40 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2010-03-05 09:01:36 -0500 |
commit | 806b681cbe588bebe8fe47dd24da62f2d1c55851 (patch) | |
tree | 030d0e479f0c3e462930d18134a15092803d1ad3 /fs/namei.c | |
parent | 10fa8e62f2bc33c452516585911f151d88389e4c (diff) |
Turn do_link spaghetty into a normal loop
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 83 |
1 files changed, 38 insertions, 45 deletions
diff --git a/fs/namei.c b/fs/namei.c index 675a712137f1..08da937b1ee2 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1844,17 +1844,38 @@ reval: | |||
1844 | if (open_flag & O_EXCL) | 1844 | if (open_flag & O_EXCL) |
1845 | nd.flags |= LOOKUP_EXCL; | 1845 | nd.flags |= LOOKUP_EXCL; |
1846 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); | 1846 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); |
1847 | if (!filp) | 1847 | while (unlikely(!filp)) { /* trailing symlink */ |
1848 | goto do_link; | 1848 | error = -ELOOP; |
1849 | goto out; | 1849 | if ((open_flag & O_NOFOLLOW) || count++ == 32) |
1850 | 1850 | goto exit_dput; | |
1851 | exit_dput: | 1851 | /* |
1852 | path_put_conditional(&path, &nd); | 1852 | * This is subtle. Instead of calling do_follow_link() we do |
1853 | if (!IS_ERR(nd.intent.open.file)) | 1853 | * the thing by hands. The reason is that this way we have zero |
1854 | release_open_intent(&nd); | 1854 | * link_count and path_walk() (called from ->follow_link) |
1855 | exit_parent: | 1855 | * honoring LOOKUP_PARENT. After that we have the parent and |
1856 | path_put(&nd.path); | 1856 | * last component, i.e. we are in the same situation as after |
1857 | filp = ERR_PTR(error); | 1857 | * the first path_walk(). Well, almost - if the last component |
1858 | * is normal we get its copy stored in nd->last.name and we will | ||
1859 | * have to putname() it when we are done. Procfs-like symlinks | ||
1860 | * just set LAST_BIND. | ||
1861 | */ | ||
1862 | nd.flags |= LOOKUP_PARENT; | ||
1863 | error = security_inode_follow_link(path.dentry, &nd); | ||
1864 | if (error) | ||
1865 | goto exit_dput; | ||
1866 | error = __do_follow_link(&path, &nd); | ||
1867 | path_put(&path); | ||
1868 | if (error) { | ||
1869 | /* nd.path had been dropped */ | ||
1870 | release_open_intent(&nd); | ||
1871 | filp = ERR_PTR(error); | ||
1872 | goto out; | ||
1873 | } | ||
1874 | nd.flags &= ~LOOKUP_PARENT; | ||
1875 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); | ||
1876 | if (nd.last_type == LAST_NORM) | ||
1877 | __putname(nd.last.name); | ||
1878 | } | ||
1858 | out: | 1879 | out: |
1859 | if (nd.root.mnt) | 1880 | if (nd.root.mnt) |
1860 | path_put(&nd.root); | 1881 | path_put(&nd.root); |
@@ -1864,41 +1885,13 @@ out: | |||
1864 | } | 1885 | } |
1865 | return filp; | 1886 | return filp; |
1866 | 1887 | ||
1867 | do_link: | 1888 | exit_dput: |
1868 | error = -ELOOP; | 1889 | path_put_conditional(&path, &nd); |
1869 | if ((open_flag & O_NOFOLLOW) || count++ == 32) | 1890 | if (!IS_ERR(nd.intent.open.file)) |
1870 | goto exit_dput; | ||
1871 | /* | ||
1872 | * This is subtle. Instead of calling do_follow_link() we do the | ||
1873 | * thing by hands. The reason is that this way we have zero link_count | ||
1874 | * and path_walk() (called from ->follow_link) honoring LOOKUP_PARENT. | ||
1875 | * After that we have the parent and last component, i.e. | ||
1876 | * we are in the same situation as after the first path_walk(). | ||
1877 | * Well, almost - if the last component is normal we get its copy | ||
1878 | * stored in nd->last.name and we will have to putname() it when we | ||
1879 | * are done. Procfs-like symlinks just set LAST_BIND. | ||
1880 | */ | ||
1881 | nd.flags |= LOOKUP_PARENT; | ||
1882 | error = security_inode_follow_link(path.dentry, &nd); | ||
1883 | if (error) | ||
1884 | goto exit_dput; | ||
1885 | error = __do_follow_link(&path, &nd); | ||
1886 | path_put(&path); | ||
1887 | if (error) { | ||
1888 | /* Does someone understand code flow here? Or it is only | ||
1889 | * me so stupid? Anathema to whoever designed this non-sense | ||
1890 | * with "intent.open". | ||
1891 | */ | ||
1892 | release_open_intent(&nd); | 1891 | release_open_intent(&nd); |
1893 | filp = ERR_PTR(error); | 1892 | exit_parent: |
1894 | goto out; | 1893 | path_put(&nd.path); |
1895 | } | 1894 | filp = ERR_PTR(error); |
1896 | nd.flags &= ~LOOKUP_PARENT; | ||
1897 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); | ||
1898 | if (nd.last_type == LAST_NORM) | ||
1899 | __putname(nd.last.name); | ||
1900 | if (!filp) | ||
1901 | goto do_link; | ||
1902 | goto out; | 1895 | goto out; |
1903 | } | 1896 | } |
1904 | 1897 | ||