| From 1945578a43a3b46a3a5683e0143feaae9abd6ce0 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 26 Oct 2020 13:57:44 +0000 |
| Subject: afs: Alter dirty range encoding in page->private |
| |
| From: David Howells <dhowells@redhat.com> |
| |
| [ Upstream commit 65dd2d6072d393a3aa14ded8afa9a12f27d9c8ad ] |
| |
| Currently, page->private on an afs page is used to store the range of |
| dirtied data within the page, where the range includes the lower bound, but |
| excludes the upper bound (e.g. 0-1 is a range covering a single byte). |
| |
| This, however, requires a superfluous bit for the last-byte bound so that |
| on a 4KiB page, it can say 0-4096 to indicate the whole page, the idea |
| being that having both numbers the same would indicate an empty range. |
| This is unnecessary as the PG_private bit is clear if it's an empty range |
| (as is PG_dirty). |
| |
| Alter the way the dirty range is encoded in page->private such that the |
| upper bound is reduced by 1 (e.g. 0-0 is then specified the same single |
| byte range mentioned above). |
| |
| Applying this to both bounds frees up two bits, one of which can be used in |
| a future commit. |
| |
| This allows the afs filesystem to be compiled on ppc32 with 64K pages; |
| without this, the following warnings are seen: |
| |
| ../fs/afs/internal.h: In function 'afs_page_dirty_to': |
| ../fs/afs/internal.h:881:15: warning: right shift count >= width of type [-Wshift-count-overflow] |
| 881 | return (priv >> __AFS_PAGE_PRIV_SHIFT) & __AFS_PAGE_PRIV_MASK; |
| | ^~ |
| ../fs/afs/internal.h: In function 'afs_page_dirty': |
| ../fs/afs/internal.h:886:28: warning: left shift count >= width of type [-Wshift-count-overflow] |
| 886 | return ((unsigned long)to << __AFS_PAGE_PRIV_SHIFT) | from; |
| | ^~ |
| |
| Fixes: 4343d00872e1 ("afs: Get rid of the afs_writeback record") |
| Signed-off-by: David Howells <dhowells@redhat.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| fs/afs/internal.h | 6 +++--- |
| fs/afs/write.c | 2 +- |
| 2 files changed, 4 insertions(+), 4 deletions(-) |
| |
| diff --git a/fs/afs/internal.h b/fs/afs/internal.h |
| index 523bf9698ecdc..fc96c090893f7 100644 |
| --- a/fs/afs/internal.h |
| +++ b/fs/afs/internal.h |
| @@ -862,7 +862,7 @@ struct afs_vnode_cache_aux { |
| * splitting the field into two parts. However, we need to represent a range |
| * 0...PAGE_SIZE inclusive, so we can't support 64K pages on a 32-bit system. |
| */ |
| -#if PAGE_SIZE > 32768 |
| +#ifdef CONFIG_64BIT |
| #define __AFS_PAGE_PRIV_MASK 0xffffffffUL |
| #define __AFS_PAGE_PRIV_SHIFT 32 |
| #else |
| @@ -877,12 +877,12 @@ static inline size_t afs_page_dirty_from(unsigned long priv) |
| |
| static inline size_t afs_page_dirty_to(unsigned long priv) |
| { |
| - return (priv >> __AFS_PAGE_PRIV_SHIFT) & __AFS_PAGE_PRIV_MASK; |
| + return ((priv >> __AFS_PAGE_PRIV_SHIFT) & __AFS_PAGE_PRIV_MASK) + 1; |
| } |
| |
| static inline unsigned long afs_page_dirty(size_t from, size_t to) |
| { |
| - return ((unsigned long)to << __AFS_PAGE_PRIV_SHIFT) | from; |
| + return ((unsigned long)(to - 1) << __AFS_PAGE_PRIV_SHIFT) | from; |
| } |
| |
| #include <trace/events/afs.h> |
| diff --git a/fs/afs/write.c b/fs/afs/write.c |
| index ea1768b3c0b56..1a49f5c89342e 100644 |
| --- a/fs/afs/write.c |
| +++ b/fs/afs/write.c |
| @@ -93,7 +93,7 @@ int afs_write_begin(struct file *file, struct address_space *mapping, |
| /* We want to store information about how much of a page is altered in |
| * page->private. |
| */ |
| - BUILD_BUG_ON(PAGE_SIZE > 32768 && sizeof(page->private) < 8); |
| + BUILD_BUG_ON(PAGE_SIZE - 1 > __AFS_PAGE_PRIV_MASK && sizeof(page->private) < 8); |
| |
| page = grab_cache_page_write_begin(mapping, index, flags); |
| if (!page) |
| -- |
| 2.27.0 |
| |