aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-09-15 13:51:07 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-09-15 13:51:07 -0400
commitd6bb3e9075bbcf758d6084bb581f797bb6ea24c6 (patch)
tree74f479798ffd366067f249b3f8bcfe876e3affdb
parent3630056d961593bdf41aaf268c7620d36e635119 (diff)
vfs: simplify and shrink stack frame of link_path_walk()
Commit 9226b5b440f2 ("vfs: avoid non-forwarding large load after small store in path lookup") made link_path_walk() always access the "hash_len" field as a single 64-bit entity, in order to avoid mixed size accesses to the members. However, what I didn't notice was that that effectively means that the whole "struct qstr this" is now basically redundant. We already explicitly track the "const char *name", and if we just use "u64 hash_len" instead of "long len", there is nothing else left of the "struct qstr". We do end up wanting the "struct qstr" if we have a filesystem with a "d_hash()" function, but that's a rare case, and we might as well then just squirrell away the name and hash_len at that point. End result: fewer live variables in the loop, a smaller stack frame, and better code generation. And we don't need to pass in pointers variables to helper functions any more, because the return value contains all the relevant information. So this removes more lines than it adds, and the source code is clearer too. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/namei.c39
1 files changed, 18 insertions, 21 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 215e44254c53..01d03892316c 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1674,14 +1674,13 @@ EXPORT_SYMBOL(full_name_hash);
1674 1674
1675/* 1675/*
1676 * Calculate the length and hash of the path component, and 1676 * Calculate the length and hash of the path component, and
1677 * fill in the qstr. return the "len" as the result. 1677 * return the "hash_len" as the result.
1678 */ 1678 */
1679static inline unsigned long hash_name(const char *name, struct qstr *res) 1679static inline u64 hash_name(const char *name)
1680{ 1680{
1681 unsigned long a, b, adata, bdata, mask, hash, len; 1681 unsigned long a, b, adata, bdata, mask, hash, len;
1682 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;
1683 1683
1684 res->name = name;
1685 hash = a = 0; 1684 hash = a = 0;
1686 len = -sizeof(unsigned long); 1685 len = -sizeof(unsigned long);
1687 do { 1686 do {
@@ -1698,9 +1697,7 @@ static inline unsigned long hash_name(const char *name, struct qstr *res)
1698 1697
1699 hash += a & zero_bytemask(mask); 1698 hash += a & zero_bytemask(mask);
1700 len += find_zero(mask); 1699 len += find_zero(mask);
1701 res->hash_len = hashlen_create(fold_hash(hash), len); 1700 return hashlen_create(fold_hash(hash), len);
1702
1703 return len;
1704} 1701}
1705 1702
1706#else 1703#else
@@ -1718,20 +1715,18 @@ EXPORT_SYMBOL(full_name_hash);
1718 * 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
1719 * one character. 1716 * one character.
1720 */ 1717 */
1721static inline long hash_name(const char *name, struct qstr *res) 1718static inline u64 hash_name(const char *name)
1722{ 1719{
1723 unsigned long hash = init_name_hash(); 1720 unsigned long hash = init_name_hash();
1724 unsigned long len = 0, c; 1721 unsigned long len = 0, c;
1725 1722
1726 res->name = name;
1727 c = (unsigned char)*name; 1723 c = (unsigned char)*name;
1728 do { 1724 do {
1729 len++; 1725 len++;
1730 hash = partial_name_hash(c, hash); 1726 hash = partial_name_hash(c, hash);
1731 c = (unsigned char)name[len]; 1727 c = (unsigned char)name[len];
1732 } while (c && c != '/'); 1728 } while (c && c != '/');
1733 res->hash_len = hashlen_create(end_name_hash(hash), len); 1729 return hashlen_create(end_name_hash(hash), len);
1734 return len;
1735} 1730}
1736 1731
1737#endif 1732#endif
@@ -1756,18 +1751,17 @@ static int link_path_walk(const char *name, struct nameidata *nd)
1756 1751
1757 /* At this point we know we have a real path component. */ 1752 /* At this point we know we have a real path component. */
1758 for(;;) { 1753 for(;;) {
1759 struct qstr this; 1754 u64 hash_len;
1760 long len;
1761 int type; 1755 int type;
1762 1756
1763 err = may_lookup(nd); 1757 err = may_lookup(nd);
1764 if (err) 1758 if (err)
1765 break; 1759 break;
1766 1760
1767 len = hash_name(name, &this); 1761 hash_len = hash_name(name);
1768 1762
1769 type = LAST_NORM; 1763 type = LAST_NORM;
1770 if (name[0] == '.') switch (len) { 1764 if (name[0] == '.') switch (hashlen_len(hash_len)) {
1771 case 2: 1765 case 2:
1772 if (name[1] == '.') { 1766 if (name[1] == '.') {
1773 type = LAST_DOTDOT; 1767 type = LAST_DOTDOT;
@@ -1781,29 +1775,32 @@ static int link_path_walk(const char *name, struct nameidata *nd)
1781 struct dentry *parent = nd->path.dentry; 1775 struct dentry *parent = nd->path.dentry;
1782 nd->flags &= ~LOOKUP_JUMPED; 1776 nd->flags &= ~LOOKUP_JUMPED;
1783 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 };
1784 err = parent->d_op->d_hash(parent, &this); 1779 err = parent->d_op->d_hash(parent, &this);
1785 if (err < 0) 1780 if (err < 0)
1786 break; 1781 break;
1782 hash_len = this.hash_len;
1783 name = this.name;
1787 } 1784 }
1788 } 1785 }
1789 1786
1790 nd->last = this; 1787 nd->last.hash_len = hash_len;
1788 nd->last.name = name;
1791 nd->last_type = type; 1789 nd->last_type = type;
1792 1790
1793 if (!name[len]) 1791 name += hashlen_len(hash_len);
1792 if (!*name)
1794 return 0; 1793 return 0;
1795 /* 1794 /*
1796 * If it wasn't NUL, we know it was '/'. Skip that 1795 * If it wasn't NUL, we know it was '/'. Skip that
1797 * slash, and continue until no more slashes. 1796 * slash, and continue until no more slashes.
1798 */ 1797 */
1799 do { 1798 do {
1800 len++; 1799 name++;
1801 } while (unlikely(name[len] == '/')); 1800 } while (unlikely(*name == '/'));
1802 if (!name[len]) 1801 if (!*name)
1803 return 0; 1802 return 0;
1804 1803
1805 name += len;
1806
1807 err = walk_component(nd, &next, LOOKUP_FOLLOW); 1804 err = walk_component(nd, &next, LOOKUP_FOLLOW);
1808 if (err < 0) 1805 if (err < 0)
1809 return err; 1806 return err;