diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-04 14:50:50 (GMT) |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-04 14:50:50 (GMT) |
commit | f4622045455faaac958ca35a0cf313f3d6c14d8b (patch) | |
tree | 96455f6f8a1afca46d939e9937913eb21782214b /fs/dcache.c | |
parent | 0a6ba092d1c8c75ae0c0617ef7f4e6f5043af311 (diff) | |
parent | e419b4cc585680940bc42f8ca8a071d6023fb1bb (diff) | |
download | linux-f4622045455faaac958ca35a0cf313f3d6c14d8b.tar.xz |
Merge branch 'fix-unmapped-word-at-a-time'
Jana Saout confirmed that this fixes the page faults he saw.
His problem was triggered by ocfs2 and autofs symlink lookups, where the
symlink allocation was at the end of a page. But the deeper reason
seems to be the use of Xen-PV, which is what then causes him to have all
these unmapped pages, which is what then makes it a problem when the
unaligned word-at-a-time code fetches data past the end of a page.
* fix-unmapped-word-at-a-time:
vfs: make word-at-a-time accesses handle a non-existing page
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 26 |
1 files changed, 22 insertions, 4 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index b60ddc4..b80531c 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -141,18 +141,29 @@ int proc_nr_dentry(ctl_table *table, int write, void __user *buffer, * Compare 2 name strings, return 0 if they match, otherwise non-zero. * The strings are both count bytes long, and count is non-zero. */ +#ifdef CONFIG_DCACHE_WORD_ACCESS + +#include <asm/word-at-a-time.h> +/* + * NOTE! 'cs' and 'scount' come from a dentry, so it has a + * aligned allocation for this particular component. We don't + * strictly need the load_unaligned_zeropad() safety, but it + * doesn't hurt either. + * + * In contrast, 'ct' and 'tcount' can be from a pathname, and do + * need the careful unaligned handling. + */ static inline int dentry_cmp(const unsigned char *cs, size_t scount, const unsigned char *ct, size_t tcount) { -#ifdef CONFIG_DCACHE_WORD_ACCESS unsigned long a,b,mask; if (unlikely(scount != tcount)) return 1; for (;;) { - a = *(unsigned long *)cs; - b = *(unsigned long *)ct; + a = load_unaligned_zeropad(cs); + b = load_unaligned_zeropad(ct); if (tcount < sizeof(unsigned long)) break; if (unlikely(a != b)) @@ -165,7 +176,13 @@ static inline int dentry_cmp(const unsigned char *cs, size_t scount, } mask = ~(~0ul << tcount*8); return unlikely(!!((a ^ b) & mask)); +} + #else + +static inline int dentry_cmp(const unsigned char *cs, size_t scount, + const unsigned char *ct, size_t tcount) +{ if (scount != tcount) return 1; @@ -177,9 +194,10 @@ static inline int dentry_cmp(const unsigned char *cs, size_t scount, tcount--; } while (tcount); return 0; -#endif } +#endif + static void __d_free(struct rcu_head *head) { struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu); |