From 24c25de1d34c7141c79d13a4bf59052335f28f0e Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Fri, 21 Nov 2025 17:35:28 -0500 Subject: [PATCH] block_write_{begin,end} take a folio as well as page_mkwrite Adds compat handlers for block_write_begin and block_write_end to take a folio argument instead of page, as this is needed since v6.11-rc1-54-g9f04609f74ec. To avoid having two duplicate page_mkwrite functions there's now a complete page/folio ifdef split here to make it handle either. This is ugly but it's the most straightforward solution here and avoids more obscure macros. Signed-off-by: Auke Kok --- kmod/src/Makefile.kernelcompat | 9 +++++++ kmod/src/data.c | 49 +++++++++++++++++++++++++++++----- kmod/src/kernelcompat.h | 6 +++++ 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/kmod/src/Makefile.kernelcompat b/kmod/src/Makefile.kernelcompat index be8c2c2e..713e3d32 100644 --- a/kmod/src/Makefile.kernelcompat +++ b/kmod/src/Makefile.kernelcompat @@ -334,6 +334,15 @@ ifneq (,$(shell grep 'iterate_shared...struct file.., struct dir_context' includ ccflags-y += -DKC_HAVE_ITERATE_SHARED endif +# +# v6.11-rc1-54-g9f04609f74ec +# +# Last of a series of changes that make block_write_begin/end take a folio instead of +# a struct pagep. +ifneq (,$(shell grep 'int __block_write_begin.struct.folio' include/linux/buffer_head.h)) +ccflags-y += -DKC_BLOCK_WRITE_BEGIN_FOLIO +endif + # # v6.15-13744-g41cb08555c41 # diff --git a/kmod/src/data.c b/kmod/src/data.c index 73c0c44a..f1d9bb66 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -836,7 +836,7 @@ static int scoutfs_write_begin(struct file *file, #ifdef KC_BLOCK_WRITE_BEGIN_AOP_FLAGS unsigned flags, #endif - struct page **pagep, void **fsdata) + KC_PAGE_OR_FOLIO(struct page **pagep, struct folio **folio), void **fsdata) { struct inode *inode = mapping->host; struct scoutfs_inode_info *si = SCOUTFS_I(inode); @@ -881,7 +881,7 @@ retry: #ifdef KC_BLOCK_WRITE_BEGIN_AOP_FLAGS flags, #endif - pagep, scoutfs_get_block_write); + KC_PAGE_OR_FOLIO(pagep, folio), scoutfs_get_block_write); if (ret < 0) { scoutfs_release_trans(sb); scoutfs_inode_index_unlock(sb, &wbd->ind_locks); @@ -929,17 +929,20 @@ void scoutfs_do_write_end(struct inode *inode, struct scoutfs_lock *data_lock, static int scoutfs_write_end(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) + KC_PAGE_OR_FOLIO(struct page *pagep, struct folio *folio), + void *fsdata) { struct inode *inode = mapping->host; struct super_block *sb = inode->i_sb; struct write_begin_data *wbd = fsdata; int ret; - trace_scoutfs_write_end(sb, scoutfs_ino(inode), page->index, (u64)pos, - len, copied); + trace_scoutfs_write_end(sb, scoutfs_ino(inode), + KC_PAGE_OR_FOLIO(pagep->index, folio_index(folio)), + (u64)pos, len, copied); - ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata); + ret = generic_write_end(file, mapping, pos, len, copied, + KC_PAGE_OR_FOLIO(pagep, folio), fsdata); if (ret > 0) scoutfs_do_write_end(inode, wbd->lock, &wbd->ind_locks); @@ -1994,7 +1997,11 @@ int scoutfs_data_waiting(struct super_block *sb, u64 ino, u64 iblock, static vm_fault_t scoutfs_data_page_mkwrite(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; +#ifdef KC_MPAGE_READ_FOLIO + struct folio *folio = page_folio(vmf->page); +#else struct page *page = vmf->page; +#endif struct file *file = vma->vm_file; struct inode *inode = file_inode(file); struct scoutfs_inode_info *si = SCOUTFS_I(inode); @@ -2062,27 +2069,50 @@ static vm_fault_t scoutfs_data_page_mkwrite(struct vm_fault *vmf) down_write(&si->extent_sem); +#ifdef KC_MPAGE_READ_FOLIO + if (!folio_trylock(folio)) { +#else if (!trylock_page(page)) { +#endif ret = VM_FAULT_NOPAGE; goto out_sem; } ret = VM_FAULT_LOCKED; +#ifdef KC_MPAGE_READ_FOLIO + if ((folio->mapping != inode->i_mapping) || + (!folio_test_uptodate(folio)) || + (folio_pos(folio) > size)) { + folio_unlock(folio); +#else if ((page->mapping != inode->i_mapping) || (!PageUptodate(page)) || - (page_offset(page) > size)) { + (page_offset(page) > size)) { unlock_page(page); +#endif ret = VM_FAULT_NOPAGE; goto out_sem; } +#ifdef KC_MPAGE_READ_FOLIO + if (folio_index(folio) == (size - 1) >> PAGE_SHIFT) +#else if (page->index == (size - 1) >> PAGE_SHIFT) +#endif len = ((size - 1) & ~PAGE_MASK) + 1; +#ifdef KC_MPAGE_READ_FOLIO + err = __block_write_begin(KC_PAGE_OR_FOLIO(folio_page(folio, 0), folio), pos, PAGE_SIZE, scoutfs_get_block); +#else err = __block_write_begin(page, pos, PAGE_SIZE, scoutfs_get_block); +#endif if (err) { ret = vmf_error(err); +#ifdef KC_MPAGE_READ_FOLIO + folio_unlock(folio); +#else unlock_page(page); +#endif goto out_sem; } /* end scoutfs_write_begin */ @@ -2092,8 +2122,13 @@ static vm_fault_t scoutfs_data_page_mkwrite(struct vm_fault *vmf) * progress, we are guaranteed that writeback during freezing will * see the dirty page and writeprotect it again. */ +#ifdef KC_MPAGE_READ_FOLIO + folio_mark_dirty(folio); + folio_wait_stable(folio); +#else set_page_dirty(page); wait_for_stable_page(page); +#endif /* scoutfs_write_end */ scoutfs_inode_set_data_seq(inode); diff --git a/kmod/src/kernelcompat.h b/kmod/src/kernelcompat.h index d4b482d8..56cac59d 100644 --- a/kmod/src/kernelcompat.h +++ b/kmod/src/kernelcompat.h @@ -368,6 +368,12 @@ static inline long inode_get_atime_nsec(const struct inode *inode) #define KC_KOBJ_DEFAULT_PICK(group, attrs) (attrs) #endif +#ifdef KC_BLOCK_WRITE_BEGIN_FOLIO +#define KC_PAGE_OR_FOLIO(p, f) f +#else +#define KC_PAGE_OR_FOLIO(p, f) p +#endif + #ifndef KC_TIMER_CONTAINER_OF #define timer_container_of(var, callback_timer, timer_fieldname) \ from_timer(var, callback_timer, timer_fieldname)