From: Greg Kroah-Hartman Date: Fri, 31 Jul 2026 06:48:18 +0000 (+0200) Subject: 7.1-stable patches X-Git-Tag: v6.6.148~10 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=198040f5615e5ab608d49225ff95e418592db0dc;p=thirdparty%2Fkernel%2Fstable-queue.git 7.1-stable patches added patches: cifs-consolidate-time_last_write-stamp-into-_cifsfileinfo_put.patch cifs-fix-time_last_write-stamp-placement-in-setattr-truncate-paths.patch s390-ptff-export-ptff_function_mask.patch --- diff --git a/queue-7.1/cifs-consolidate-time_last_write-stamp-into-_cifsfileinfo_put.patch b/queue-7.1/cifs-consolidate-time_last_write-stamp-into-_cifsfileinfo_put.patch new file mode 100644 index 0000000000..174773e683 --- /dev/null +++ b/queue-7.1/cifs-consolidate-time_last_write-stamp-into-_cifsfileinfo_put.patch @@ -0,0 +1,195 @@ +From 0e3ea5445c228048f937ad5a944c27859a78f971 Mon Sep 17 00:00:00 2001 +From: Frank Sorenson +Date: Fri, 24 Jul 2026 11:30:35 -0500 +Subject: cifs: consolidate time_last_write stamp into _cifsFileInfo_put() + +From: Frank Sorenson + +commit 0e3ea5445c228048f937ad5a944c27859a78f971 upstream. + +The time_last_write stamp was scattered across cifs_close(), +smb2_deferred_work_close(), and the three drain functions in misc.c. +This missed the case where background I/O holds the final reference +after userspace close() returns, and required explicit maintenance at +each close-path site. + +Move the smp_store_release() into _cifsFileInfo_put(), immediately +before releasing open_file_lock. This single location covers all +close paths unconditionally: normal close, background I/O dropping the +final reference, deferred close via timer or external drain. The +spinlock's store-release/load-acquire pairing with is_inode_writable() +already provides the ordering guarantee documented in +is_size_safe_to_change(). + +Remove the now-redundant stamps from cifs_close(), +smb2_deferred_work_close(), and all six stamp sites in the misc.c +deferred-close drain functions. + +Fixes: e8a8d54c2d50 ("cifs: prevent readdir from changing file size due to stale directory metadata") +Signed-off-by: Frank Sorenson +Reviewed-by: Paulo Alcantara (Red Hat) +Signed-off-by: Steve French +Cc: Jiri Slaby +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/client/file.c | 37 ++++++++++++++++--------------------- + fs/smb/client/misc.c | 51 ++++++--------------------------------------------- + 2 files changed, 22 insertions(+), 66 deletions(-) + +--- a/fs/smb/client/file.c ++++ b/fs/smb/client/file.c +@@ -915,6 +915,14 @@ void _cifsFileInfo_put(struct cifsFileIn + cifs_set_oplock_level(cifsi, 0); + } + ++ if (OPEN_FMODE(cifs_file->f_flags) & FMODE_WRITE) { ++ /* Stamp while open_file_lock is held; covers all close paths ++ * including background I/O. Pairs with smp_load_acquire() in ++ * is_size_safe_to_change(). ++ */ ++ smp_store_release(&cifsi->time_last_write, jiffies); ++ } ++ + spin_unlock(&cifsi->open_file_lock); + spin_unlock(&tcon->open_file_lock); + +@@ -1429,15 +1437,6 @@ void smb2_deferred_work_close(struct wor + cifs_del_deferred_close(cfile); + cfile->deferred_close_scheduled = false; + spin_unlock(&cinode->deferred_lock); +- /* +- * Refresh time_last_write immediately before the actual server close +- * so the protection window is anchored to the real close time, not +- * the earlier userspace close time stored by cifs_close(). +- */ +- if (OPEN_FMODE(cfile->f_flags) & FMODE_WRITE) { +- /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +- smp_store_release(&cinode->time_last_write, jiffies); +- } + _cifsFileInfo_put(cfile, true, false); + } + +@@ -1467,10 +1466,6 @@ int cifs_close(struct inode *inode, stru + if (file->private_data != NULL) { + cfile = file->private_data; + file->private_data = NULL; +- if (file->f_mode & FMODE_WRITE) { +- /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +- smp_store_release(&cinode->time_last_write, jiffies); +- } + dclose = kmalloc_obj(struct cifs_deferred_close); + if ((cfile->status_file_deleted == false) && + (smb2_can_defer_close(inode, dclose))) { +@@ -3222,13 +3217,13 @@ bool is_size_safe_to_change(struct cifsI + * No writable handles open. Check whether we are within the attribute + * cache validity window of a recent local modification. + * +- * For the close() path: cifs_close() calls smp_store_release() on +- * time_last_write before _cifsFileInfo_put() removes the handle under +- * open_file_lock. That spin_unlock() is a store-release that pairs +- * with the spin_lock() (load-acquire) in is_inode_writable() above, +- * so if is_inode_writable() returned false the smp_load_acquire() +- * below is guaranteed to observe any time_last_write update from a +- * concurrent close(). ++ * For the close() path: _cifsFileInfo_put() stamps time_last_write ++ * (via smp_store_release()) before releasing open_file_lock. That ++ * spin_unlock() is a store-release that pairs with the spin_lock() ++ * (load-acquire) in is_inode_writable() above, so if ++ * is_inode_writable() returned false the smp_load_acquire() below is ++ * guaranteed to observe any time_last_write update from a concurrent ++ * close(), covering all close paths including background I/O. + * + * For the setattr/truncate paths: those callers use smp_store_release() + * directly; the smp_load_acquire() below pairs with that store. There +@@ -3243,7 +3238,7 @@ bool is_size_safe_to_change(struct cifsI + * jiffies is still close to INITIAL_JIFFIES on 32-bit systems. + */ + if (from_readdir) { +- /* Pairs with smp_store_release() at close and truncate sites. */ ++ /* Pairs with smp_store_release() in _cifsFileInfo_put() and setattr. */ + tlw = smp_load_acquire(&cifsInode->time_last_write); + if (tlw && time_before(jiffies, tlw + cifs_sb->ctx->acregmax)) + return false; +--- a/fs/smb/client/misc.c ++++ b/fs/smb/client/misc.c +@@ -521,24 +521,11 @@ cifs_close_deferred_file(struct cifsInod + } + spin_unlock(&cifs_inode->open_file_lock); + +- if (failed_cfile) { +- if (OPEN_FMODE(failed_cfile->f_flags) & FMODE_WRITE) { +- /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +- smp_store_release(&CIFS_I(d_inode(failed_cfile->dentry))->time_last_write, +- jiffies); +- } ++ if (failed_cfile) + _cifsFileInfo_put(failed_cfile, false, false); +- } + + list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) { +- struct cifsFileInfo *cfile = tmp_list->cfile; +- +- if (OPEN_FMODE(cfile->f_flags) & FMODE_WRITE) { +- /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +- smp_store_release(&CIFS_I(d_inode(cfile->dentry))->time_last_write, +- jiffies); +- } +- _cifsFileInfo_put(cfile, false, false); ++ _cifsFileInfo_put(tmp_list->cfile, false, false); + list_del(&tmp_list->list); + kfree(tmp_list); + } +@@ -572,24 +559,11 @@ cifs_close_all_deferred_files(struct cif + } + spin_unlock(&tcon->open_file_lock); + +- if (failed_cfile) { +- if (OPEN_FMODE(failed_cfile->f_flags) & FMODE_WRITE) { +- /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +- smp_store_release(&CIFS_I(d_inode(failed_cfile->dentry))->time_last_write, +- jiffies); +- } ++ if (failed_cfile) + _cifsFileInfo_put(failed_cfile, true, false); +- } + + list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) { +- struct cifsFileInfo *cfile = tmp_list->cfile; +- +- if (OPEN_FMODE(cfile->f_flags) & FMODE_WRITE) { +- /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +- smp_store_release(&CIFS_I(d_inode(cfile->dentry))->time_last_write, +- jiffies); +- } +- _cifsFileInfo_put(cfile, true, false); ++ _cifsFileInfo_put(tmp_list->cfile, true, false); + list_del(&tmp_list->list); + kfree(tmp_list); + } +@@ -659,24 +633,11 @@ void cifs_close_deferred_file_under_dent + } + spin_unlock(&tcon->open_file_lock); + +- if (failed_cfile) { +- if (OPEN_FMODE(failed_cfile->f_flags) & FMODE_WRITE) { +- /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +- smp_store_release(&CIFS_I(d_inode(failed_cfile->dentry))->time_last_write, +- jiffies); +- } ++ if (failed_cfile) + _cifsFileInfo_put(failed_cfile, true, false); +- } + + list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) { +- struct cifsFileInfo *cfile = tmp_list->cfile; +- +- if (OPEN_FMODE(cfile->f_flags) & FMODE_WRITE) { +- /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +- smp_store_release(&CIFS_I(d_inode(cfile->dentry))->time_last_write, +- jiffies); +- } +- _cifsFileInfo_put(cfile, true, false); ++ _cifsFileInfo_put(tmp_list->cfile, true, false); + list_del(&tmp_list->list); + kfree(tmp_list); + } diff --git a/queue-7.1/cifs-fix-time_last_write-stamp-placement-in-setattr-truncate-paths.patch b/queue-7.1/cifs-fix-time_last_write-stamp-placement-in-setattr-truncate-paths.patch new file mode 100644 index 0000000000..e91f81498d --- /dev/null +++ b/queue-7.1/cifs-fix-time_last_write-stamp-placement-in-setattr-truncate-paths.patch @@ -0,0 +1,100 @@ +From ecababf08905958ba8c125979c4e39fc2f1a8a05 Mon Sep 17 00:00:00 2001 +From: Frank Sorenson +Date: Fri, 24 Jul 2026 11:30:36 -0500 +Subject: cifs: fix time_last_write stamp placement in setattr/truncate paths + +From: Frank Sorenson + +commit ecababf08905958ba8c125979c4e39fc2f1a8a05 upstream. + +cifs_file_set_size() calls cifs_setsize() on success, which calls +i_size_write(), updating i_size to the new value. The subsequent +check attrs->ia_size != i_size_read() in both cifs_setattr_unix() +and cifs_setattr_nounix() therefore always evaluates false after a +successful cifs_file_set_size(), making the smp_store_release() of +time_last_write dead code. The truncate path was unprotected against +stale readdir size updates. + +Move the stamp to before the cifs_file_set_size() RPC call, guarded +by attrs->ia_size != i_size_read() to exclude no-op same-size +ftruncate(2) calls from stamping time_last_write unnecessarily. + +On the error path the stamp remains rather than being restored: +restoring a stale snapshot (prev_tlw) could silently erase a +concurrent _cifsFileInfo_put() close stamp if that close arrived +between the READ_ONCE and the smp_store_release. readdir is +suppressed until the stamp expires, which extends beyond one acregmax +if the caller retries failed truncations. stat() is unaffected: the +cifs_revalidate_dentry_attr() path calls cifs_fattr_to_inode() with +from_readdir=false, which bypasses the time_last_write check in +is_size_safe_to_change() entirely and always writes the authoritative +QUERY_INFO result to i_size. + +Remove the now-unreachable stamp from the dead block in both functions. + +Fixes: e8a8d54c2d50 ("cifs: prevent readdir from changing file size due to stale directory metadata") +Signed-off-by: Frank Sorenson +Reviewed-by: Paulo Alcantara (Red Hat) +Signed-off-by: Steve French +Cc: Jiri Slaby +Signed-off-by: Greg Kroah-Hartman +--- + fs/smb/client/inode.c | 26 ++++++++++++++++++++++---- + 1 file changed, 22 insertions(+), 4 deletions(-) + +--- a/fs/smb/client/inode.c ++++ b/fs/smb/client/inode.c +@@ -3182,6 +3182,17 @@ cifs_setattr_unix(struct dentry *direntr + rc = 0; + + if (attrs->ia_valid & ATTR_SIZE) { ++ if (attrs->ia_size != i_size_read(inode)) { ++ /* Stamp before RPC. On failure the stamp remains: restoring a ++ * stale snapshot could silently erase a concurrent ++ * _cifsFileInfo_put() close stamp. readdir is suppressed ++ * until the stamp expires; stat() bypasses this via the ++ * from_readdir=false path in is_size_safe_to_change() and ++ * always returns an authoritative QUERY_INFO result. ++ * Pairs with smp_load_acquire() in is_size_safe_to_change(). ++ */ ++ smp_store_release(&cifsInode->time_last_write, jiffies); ++ } + rc = cifs_file_set_size(xid, direntry, full_path, + open_file, attrs->ia_size); + if (rc != 0) +@@ -3271,8 +3282,6 @@ cifs_setattr_unix(struct dentry *direntr + + if ((attrs->ia_valid & ATTR_SIZE) && + attrs->ia_size != i_size_read(inode)) { +- /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +- smp_store_release(&cifsInode->time_last_write, jiffies); + truncate_setsize(inode, attrs->ia_size); + netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true); + fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size); +@@ -3362,6 +3371,17 @@ cifs_setattr_nounix(struct dentry *diren + } + + if (attrs->ia_valid & ATTR_SIZE) { ++ if (attrs->ia_size != i_size_read(inode)) { ++ /* Stamp before RPC. On failure the stamp remains: restoring a ++ * stale snapshot could silently erase a concurrent ++ * _cifsFileInfo_put() close stamp. readdir is suppressed ++ * until the stamp expires; stat() bypasses this via the ++ * from_readdir=false path in is_size_safe_to_change() and ++ * always returns an authoritative QUERY_INFO result. ++ * Pairs with smp_load_acquire() in is_size_safe_to_change(). ++ */ ++ smp_store_release(&cifsInode->time_last_write, jiffies); ++ } + rc = cifs_file_set_size(xid, direntry, full_path, + cfile, attrs->ia_size); + if (rc != 0) +@@ -3474,8 +3494,6 @@ cifs_setattr_nounix(struct dentry *diren + + if ((attrs->ia_valid & ATTR_SIZE) && + attrs->ia_size != i_size_read(inode)) { +- /* Pairs with smp_load_acquire() in is_size_safe_to_change(). */ +- smp_store_release(&cifsInode->time_last_write, jiffies); + truncate_setsize(inode, attrs->ia_size); + netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true); + fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size); diff --git a/queue-7.1/s390-ptff-export-ptff_function_mask.patch b/queue-7.1/s390-ptff-export-ptff_function_mask.patch new file mode 100644 index 0000000000..2f3090922b --- /dev/null +++ b/queue-7.1/s390-ptff-export-ptff_function_mask.patch @@ -0,0 +1,31 @@ +From 9de445d8296a7f2b011ebb5834fdc94dcda5c778 Mon Sep 17 00:00:00 2001 +From: Sven Schnelle +Date: Tue, 14 Jul 2026 15:03:41 +0200 +Subject: s390/ptff: Export ptff_function_mask[] + +From: Sven Schnelle + +commit 9de445d8296a7f2b011ebb5834fdc94dcda5c778 upstream. + +Export the ptff_function_mask to make ptff_query() usable in modules. + +Signed-off-by: Sven Schnelle +Acked-by: Heiko Carstens +Link: https://patch.msgid.link/20260714130342.1971700-2-svens@linux.ibm.com +Signed-off-by: Jakub Kicinski +Cc: Jiri Slaby +Signed-off-by: Greg Kroah-Hartman +--- + arch/s390/kernel/time.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/s390/kernel/time.c ++++ b/arch/s390/kernel/time.c +@@ -65,6 +65,7 @@ ATOMIC_NOTIFIER_HEAD(s390_epoch_delta_no + EXPORT_SYMBOL(s390_epoch_delta_notifier); + + unsigned char ptff_function_mask[16]; ++EXPORT_SYMBOL(ptff_function_mask); + + static unsigned long lpar_offset; + static unsigned long initial_leap_seconds; diff --git a/queue-7.1/series b/queue-7.1/series index c11342a745..2a87ae2852 100644 --- a/queue-7.1/series +++ b/queue-7.1/series @@ -741,3 +741,6 @@ sched_ext-preserve-rq-tracking-across-local-dsq-dispatch.patch selftests-drv-net-cope-with-slow-env-in-so_txtime.py-test.patch selftests-drv-net-so_txtime-relax-variance-bounds.patch kvm-svm-bump-asid_generation-on-cpu-online-to-avoid-asid-collision-after-hotplug.patch +s390-ptff-export-ptff_function_mask.patch +cifs-fix-time_last_write-stamp-placement-in-setattr-truncate-paths.patch +cifs-consolidate-time_last_write-stamp-into-_cifsfileinfo_put.patch