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 <dhowe...@redhat.com> --- 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 edaccd07e18e..344c545f934c 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -863,7 +863,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 @@ -878,12 +878,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 dc86177cbc82..7561b9973806 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)