diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 96 |
1 files changed, 53 insertions, 43 deletions
diff --git a/fs/namei.c b/fs/namei.c index a996bb48dfab..a7b05bf82d31 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/device_cgroup.h> | 34 | #include <linux/device_cgroup.h> |
35 | #include <linux/fs_struct.h> | 35 | #include <linux/fs_struct.h> |
36 | #include <linux/posix_acl.h> | 36 | #include <linux/posix_acl.h> |
37 | #include <linux/hash.h> | ||
37 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
38 | 39 | ||
39 | #include "internal.h" | 40 | #include "internal.h" |
@@ -643,24 +644,22 @@ static int complete_walk(struct nameidata *nd) | |||
643 | 644 | ||
644 | static __always_inline void set_root(struct nameidata *nd) | 645 | static __always_inline void set_root(struct nameidata *nd) |
645 | { | 646 | { |
646 | if (!nd->root.mnt) | 647 | get_fs_root(current->fs, &nd->root); |
647 | get_fs_root(current->fs, &nd->root); | ||
648 | } | 648 | } |
649 | 649 | ||
650 | static int link_path_walk(const char *, struct nameidata *); | 650 | static int link_path_walk(const char *, struct nameidata *); |
651 | 651 | ||
652 | static __always_inline void set_root_rcu(struct nameidata *nd) | 652 | static __always_inline unsigned set_root_rcu(struct nameidata *nd) |
653 | { | 653 | { |
654 | if (!nd->root.mnt) { | 654 | struct fs_struct *fs = current->fs; |
655 | struct fs_struct *fs = current->fs; | 655 | unsigned seq, res; |
656 | unsigned seq; | ||
657 | 656 | ||
658 | do { | 657 | do { |
659 | seq = read_seqcount_begin(&fs->seq); | 658 | seq = read_seqcount_begin(&fs->seq); |
660 | nd->root = fs->root; | 659 | nd->root = fs->root; |
661 | nd->seq = __read_seqcount_begin(&nd->root.dentry->d_seq); | 660 | res = __read_seqcount_begin(&nd->root.dentry->d_seq); |
662 | } while (read_seqcount_retry(&fs->seq, seq)); | 661 | } while (read_seqcount_retry(&fs->seq, seq)); |
663 | } | 662 | return res; |
664 | } | 663 | } |
665 | 664 | ||
666 | static void path_put_conditional(struct path *path, struct nameidata *nd) | 665 | static void path_put_conditional(struct path *path, struct nameidata *nd) |
@@ -860,7 +859,8 @@ follow_link(struct path *link, struct nameidata *nd, void **p) | |||
860 | return PTR_ERR(s); | 859 | return PTR_ERR(s); |
861 | } | 860 | } |
862 | if (*s == '/') { | 861 | if (*s == '/') { |
863 | set_root(nd); | 862 | if (!nd->root.mnt) |
863 | set_root(nd); | ||
864 | path_put(&nd->path); | 864 | path_put(&nd->path); |
865 | nd->path = nd->root; | 865 | nd->path = nd->root; |
866 | path_get(&nd->root); | 866 | path_get(&nd->root); |
@@ -1137,13 +1137,15 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, | |||
1137 | */ | 1137 | */ |
1138 | *inode = path->dentry->d_inode; | 1138 | *inode = path->dentry->d_inode; |
1139 | } | 1139 | } |
1140 | return read_seqretry(&mount_lock, nd->m_seq) && | 1140 | return !read_seqretry(&mount_lock, nd->m_seq) && |
1141 | !(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT); | 1141 | !(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT); |
1142 | } | 1142 | } |
1143 | 1143 | ||
1144 | static int follow_dotdot_rcu(struct nameidata *nd) | 1144 | static int follow_dotdot_rcu(struct nameidata *nd) |
1145 | { | 1145 | { |
1146 | set_root_rcu(nd); | 1146 | struct inode *inode = nd->inode; |
1147 | if (!nd->root.mnt) | ||
1148 | set_root_rcu(nd); | ||
1147 | 1149 | ||
1148 | while (1) { | 1150 | while (1) { |
1149 | if (nd->path.dentry == nd->root.dentry && | 1151 | if (nd->path.dentry == nd->root.dentry && |
@@ -1155,6 +1157,7 @@ static int follow_dotdot_rcu(struct nameidata *nd) | |||
1155 | struct dentry *parent = old->d_parent; | 1157 | struct dentry *parent = old->d_parent; |
1156 | unsigned seq; | 1158 | unsigned seq; |
1157 | 1159 | ||
1160 | inode = parent->d_inode; | ||
1158 | seq = read_seqcount_begin(&parent->d_seq); | 1161 | seq = read_seqcount_begin(&parent->d_seq); |
1159 | if (read_seqcount_retry(&old->d_seq, nd->seq)) | 1162 | if (read_seqcount_retry(&old->d_seq, nd->seq)) |
1160 | goto failed; | 1163 | goto failed; |
@@ -1164,6 +1167,7 @@ static int follow_dotdot_rcu(struct nameidata *nd) | |||
1164 | } | 1167 | } |
1165 | if (!follow_up_rcu(&nd->path)) | 1168 | if (!follow_up_rcu(&nd->path)) |
1166 | break; | 1169 | break; |
1170 | inode = nd->path.dentry->d_inode; | ||
1167 | nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); | 1171 | nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); |
1168 | } | 1172 | } |
1169 | while (d_mountpoint(nd->path.dentry)) { | 1173 | while (d_mountpoint(nd->path.dentry)) { |
@@ -1173,11 +1177,12 @@ static int follow_dotdot_rcu(struct nameidata *nd) | |||
1173 | break; | 1177 | break; |
1174 | nd->path.mnt = &mounted->mnt; | 1178 | nd->path.mnt = &mounted->mnt; |
1175 | nd->path.dentry = mounted->mnt.mnt_root; | 1179 | nd->path.dentry = mounted->mnt.mnt_root; |
1180 | inode = nd->path.dentry->d_inode; | ||
1176 | nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); | 1181 | nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); |
1177 | if (!read_seqretry(&mount_lock, nd->m_seq)) | 1182 | if (read_seqretry(&mount_lock, nd->m_seq)) |
1178 | goto failed; | 1183 | goto failed; |
1179 | } | 1184 | } |
1180 | nd->inode = nd->path.dentry->d_inode; | 1185 | nd->inode = inode; |
1181 | return 0; | 1186 | return 0; |
1182 | 1187 | ||
1183 | failed: | 1188 | failed: |
@@ -1256,7 +1261,8 @@ static void follow_mount(struct path *path) | |||
1256 | 1261 | ||
1257 | static void follow_dotdot(struct nameidata *nd) | 1262 | static void follow_dotdot(struct nameidata *nd) |
1258 | { | 1263 | { |
1259 | set_root(nd); | 1264 | if (!nd->root.mnt) |
1265 | set_root(nd); | ||
1260 | 1266 | ||
1261 | while(1) { | 1267 | while(1) { |
1262 | struct dentry *old = nd->path.dentry; | 1268 | struct dentry *old = nd->path.dentry; |
@@ -1634,8 +1640,7 @@ static inline int nested_symlink(struct path *path, struct nameidata *nd) | |||
1634 | 1640 | ||
1635 | static inline unsigned int fold_hash(unsigned long hash) | 1641 | static inline unsigned int fold_hash(unsigned long hash) |
1636 | { | 1642 | { |
1637 | hash += hash >> (8*sizeof(int)); | 1643 | return hash_64(hash, 32); |
1638 | return hash; | ||
1639 | } | 1644 | } |
1640 | 1645 | ||
1641 | #else /* 32-bit case */ | 1646 | #else /* 32-bit case */ |
@@ -1669,9 +1674,9 @@ EXPORT_SYMBOL(full_name_hash); | |||
1669 | 1674 | ||
1670 | /* | 1675 | /* |
1671 | * Calculate the length and hash of the path component, and | 1676 | * Calculate the length and hash of the path component, and |
1672 | * return the length of the component; | 1677 | * return the "hash_len" as the result. |
1673 | */ | 1678 | */ |
1674 | static inline unsigned long hash_name(const char *name, unsigned int *hashp) | 1679 | static inline u64 hash_name(const char *name) |
1675 | { | 1680 | { |
1676 | unsigned long a, b, adata, bdata, mask, hash, len; | 1681 | unsigned long a, b, adata, bdata, mask, hash, len; |
1677 | const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS; | 1682 | const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS; |
@@ -1691,9 +1696,8 @@ static inline unsigned long hash_name(const char *name, unsigned int *hashp) | |||
1691 | mask = create_zero_mask(adata | bdata); | 1696 | mask = create_zero_mask(adata | bdata); |
1692 | 1697 | ||
1693 | hash += a & zero_bytemask(mask); | 1698 | hash += a & zero_bytemask(mask); |
1694 | *hashp = fold_hash(hash); | 1699 | len += find_zero(mask); |
1695 | 1700 | return hashlen_create(fold_hash(hash), len); | |
1696 | return len + find_zero(mask); | ||
1697 | } | 1701 | } |
1698 | 1702 | ||
1699 | #else | 1703 | #else |
@@ -1711,7 +1715,7 @@ EXPORT_SYMBOL(full_name_hash); | |||
1711 | * We know there's a real path component here of at least | 1715 | * We know there's a real path component here of at least |
1712 | * one character. | 1716 | * one character. |
1713 | */ | 1717 | */ |
1714 | static inline unsigned long hash_name(const char *name, unsigned int *hashp) | 1718 | static inline u64 hash_name(const char *name) |
1715 | { | 1719 | { |
1716 | unsigned long hash = init_name_hash(); | 1720 | unsigned long hash = init_name_hash(); |
1717 | unsigned long len = 0, c; | 1721 | unsigned long len = 0, c; |
@@ -1722,8 +1726,7 @@ static inline unsigned long hash_name(const char *name, unsigned int *hashp) | |||
1722 | hash = partial_name_hash(c, hash); | 1726 | hash = partial_name_hash(c, hash); |
1723 | c = (unsigned char)name[len]; | 1727 | c = (unsigned char)name[len]; |
1724 | } while (c && c != '/'); | 1728 | } while (c && c != '/'); |
1725 | *hashp = end_name_hash(hash); | 1729 | return hashlen_create(end_name_hash(hash), len); |
1726 | return len; | ||
1727 | } | 1730 | } |
1728 | 1731 | ||
1729 | #endif | 1732 | #endif |
@@ -1748,20 +1751,17 @@ static int link_path_walk(const char *name, struct nameidata *nd) | |||
1748 | 1751 | ||
1749 | /* At this point we know we have a real path component. */ | 1752 | /* At this point we know we have a real path component. */ |
1750 | for(;;) { | 1753 | for(;;) { |
1751 | struct qstr this; | 1754 | u64 hash_len; |
1752 | long len; | ||
1753 | int type; | 1755 | int type; |
1754 | 1756 | ||
1755 | err = may_lookup(nd); | 1757 | err = may_lookup(nd); |
1756 | if (err) | 1758 | if (err) |
1757 | break; | 1759 | break; |
1758 | 1760 | ||
1759 | len = hash_name(name, &this.hash); | 1761 | hash_len = hash_name(name); |
1760 | this.name = name; | ||
1761 | this.len = len; | ||
1762 | 1762 | ||
1763 | type = LAST_NORM; | 1763 | type = LAST_NORM; |
1764 | if (name[0] == '.') switch (len) { | 1764 | if (name[0] == '.') switch (hashlen_len(hash_len)) { |
1765 | case 2: | 1765 | case 2: |
1766 | if (name[1] == '.') { | 1766 | if (name[1] == '.') { |
1767 | type = LAST_DOTDOT; | 1767 | type = LAST_DOTDOT; |
@@ -1775,29 +1775,32 @@ static int link_path_walk(const char *name, struct nameidata *nd) | |||
1775 | struct dentry *parent = nd->path.dentry; | 1775 | struct dentry *parent = nd->path.dentry; |
1776 | nd->flags &= ~LOOKUP_JUMPED; | 1776 | nd->flags &= ~LOOKUP_JUMPED; |
1777 | if (unlikely(parent->d_flags & DCACHE_OP_HASH)) { | 1777 | if (unlikely(parent->d_flags & DCACHE_OP_HASH)) { |
1778 | struct qstr this = { { .hash_len = hash_len }, .name = name }; | ||
1778 | err = parent->d_op->d_hash(parent, &this); | 1779 | err = parent->d_op->d_hash(parent, &this); |
1779 | if (err < 0) | 1780 | if (err < 0) |
1780 | break; | 1781 | break; |
1782 | hash_len = this.hash_len; | ||
1783 | name = this.name; | ||
1781 | } | 1784 | } |
1782 | } | 1785 | } |
1783 | 1786 | ||
1784 | nd->last = this; | 1787 | nd->last.hash_len = hash_len; |
1788 | nd->last.name = name; | ||
1785 | nd->last_type = type; | 1789 | nd->last_type = type; |
1786 | 1790 | ||
1787 | if (!name[len]) | 1791 | name += hashlen_len(hash_len); |
1792 | if (!*name) | ||
1788 | return 0; | 1793 | return 0; |
1789 | /* | 1794 | /* |
1790 | * If it wasn't NUL, we know it was '/'. Skip that | 1795 | * If it wasn't NUL, we know it was '/'. Skip that |
1791 | * slash, and continue until no more slashes. | 1796 | * slash, and continue until no more slashes. |
1792 | */ | 1797 | */ |
1793 | do { | 1798 | do { |
1794 | len++; | 1799 | name++; |
1795 | } while (unlikely(name[len] == '/')); | 1800 | } while (unlikely(*name == '/')); |
1796 | if (!name[len]) | 1801 | if (!*name) |
1797 | return 0; | 1802 | return 0; |
1798 | 1803 | ||
1799 | name += len; | ||
1800 | |||
1801 | err = walk_component(nd, &next, LOOKUP_FOLLOW); | 1804 | err = walk_component(nd, &next, LOOKUP_FOLLOW); |
1802 | if (err < 0) | 1805 | if (err < 0) |
1803 | return err; | 1806 | return err; |
@@ -1852,7 +1855,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1852 | if (*name=='/') { | 1855 | if (*name=='/') { |
1853 | if (flags & LOOKUP_RCU) { | 1856 | if (flags & LOOKUP_RCU) { |
1854 | rcu_read_lock(); | 1857 | rcu_read_lock(); |
1855 | set_root_rcu(nd); | 1858 | nd->seq = set_root_rcu(nd); |
1856 | } else { | 1859 | } else { |
1857 | set_root(nd); | 1860 | set_root(nd); |
1858 | path_get(&nd->root); | 1861 | path_get(&nd->root); |
@@ -1903,7 +1906,14 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1903 | } | 1906 | } |
1904 | 1907 | ||
1905 | nd->inode = nd->path.dentry->d_inode; | 1908 | nd->inode = nd->path.dentry->d_inode; |
1906 | return 0; | 1909 | if (!(flags & LOOKUP_RCU)) |
1910 | return 0; | ||
1911 | if (likely(!read_seqcount_retry(&nd->path.dentry->d_seq, nd->seq))) | ||
1912 | return 0; | ||
1913 | if (!(nd->flags & LOOKUP_ROOT)) | ||
1914 | nd->root.mnt = NULL; | ||
1915 | rcu_read_unlock(); | ||
1916 | return -ECHILD; | ||
1907 | } | 1917 | } |
1908 | 1918 | ||
1909 | static inline int lookup_last(struct nameidata *nd, struct path *path) | 1919 | static inline int lookup_last(struct nameidata *nd, struct path *path) |