]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 6.6
authorSasha Levin <sashal@kernel.org>
Mon, 1 Jan 2024 18:11:03 +0000 (13:11 -0500)
committerSasha Levin <sashal@kernel.org>
Mon, 1 Jan 2024 18:11:03 +0000 (13:11 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
35 files changed:
queue-6.6/block-renumber-queue_flag_hw_wc.patch [new file with mode: 0644]
queue-6.6/client-convert-to-new-timestamp-accessors.patch [new file with mode: 0644]
queue-6.6/fs-cifs-fix-atime-update-check.patch [new file with mode: 0644]
queue-6.6/fs-new-accessor-methods-for-atime-and-mtime.patch [new file with mode: 0644]
queue-6.6/kexec-fix-kexec_file-dependencies.patch [new file with mode: 0644]
queue-6.6/kexec-select-crypto-from-kexec_file-instead-of-depen.patch [new file with mode: 0644]
queue-6.6/ksmbd-add-support-for-surrogate-pair-conversion.patch [new file with mode: 0644]
queue-6.6/ksmbd-avoid-duplicate-opinfo_put-call-on-error-of-sm.patch [new file with mode: 0644]
queue-6.6/ksmbd-don-t-update-op_state-as-oplock_state_none-on-.patch [new file with mode: 0644]
queue-6.6/ksmbd-downgrade-rwh-lease-caching-state-to-rh-for-di.patch [new file with mode: 0644]
queue-6.6/ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_kern_path_.patch [new file with mode: 0644]
queue-6.6/ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_setxattr.patch [new file with mode: 0644]
queue-6.6/ksmbd-fix-missing-rdma-capable-flag-for-ipoib-device.patch [new file with mode: 0644]
queue-6.6/ksmbd-lazy-v2-lease-break-on-smb2_write.patch [new file with mode: 0644]
queue-6.6/ksmbd-move-oplock-handling-after-unlock-parent-dir.patch [new file with mode: 0644]
queue-6.6/ksmbd-move-setting-smb2_flags_async_command-and-asyn.patch [new file with mode: 0644]
queue-6.6/ksmbd-no-need-to-wait-for-binded-connection-terminat.patch [new file with mode: 0644]
queue-6.6/ksmbd-prevent-memory-leak-on-error-return.patch [new file with mode: 0644]
queue-6.6/ksmbd-release-interim-response-after-sending-status-.patch [new file with mode: 0644]
queue-6.6/ksmbd-remove-unused-field-in-ksmbd_user-struct.patch [new file with mode: 0644]
queue-6.6/ksmbd-reorganize-ksmbd_iov_pin_rsp.patch [new file with mode: 0644]
queue-6.6/ksmbd-send-v2-lease-break-notification-for-directory.patch [new file with mode: 0644]
queue-6.6/ksmbd-separately-allocate-ci-per-dentry.patch [new file with mode: 0644]
queue-6.6/ksmbd-set-epoch-in-create-context-v2-lease.patch [new file with mode: 0644]
queue-6.6/ksmbd-set-v2-lease-capability.patch [new file with mode: 0644]
queue-6.6/linux-export-ensure-natural-alignment-of-kcrctab-arr.patch [new file with mode: 0644]
queue-6.6/linux-export-fix-alignment-for-64-bit-ksymtab-entrie.patch [new file with mode: 0644]
queue-6.6/mptcp-fix-inconsistent-state-on-fastopen-race.patch [new file with mode: 0644]
queue-6.6/mptcp-fix-possible-null-pointer-dereference-on-close.patch [new file with mode: 0644]
queue-6.6/mptcp-refactor-sndbuf-auto-tuning.patch [new file with mode: 0644]
queue-6.6/platform-x86-intel-pmc-add-suspend-callback.patch [new file with mode: 0644]
queue-6.6/platform-x86-intel-pmc-allow-reenabling-ltrs.patch [new file with mode: 0644]
queue-6.6/platform-x86-intel-pmc-move-gbe-ltr-ignore-to-suspen.patch [new file with mode: 0644]
queue-6.6/series [new file with mode: 0644]
queue-6.6/virtio_ring-fix-syncs-dma-memory-with-different-dire.patch [new file with mode: 0644]

diff --git a/queue-6.6/block-renumber-queue_flag_hw_wc.patch b/queue-6.6/block-renumber-queue_flag_hw_wc.patch
new file mode 100644 (file)
index 0000000..edadc47
--- /dev/null
@@ -0,0 +1,37 @@
+From fbd24f0e0ca8e3930e380a9ced8deb198c10a149 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 26 Dec 2023 08:15:24 +0000
+Subject: block: renumber QUEUE_FLAG_HW_WC
+
+From: Christoph Hellwig <hch@lst.de>
+
+[ Upstream commit 02d374f3418df577c850f0cd45c3da9245ead547 ]
+
+For the QUEUE_FLAG_HW_WC to actually work, it needs to have a separate
+number from QUEUE_FLAG_FUA, doh.
+
+Fixes: 43c9835b144c ("block: don't allow enabling a cache on devices that don't support it")
+Signed-off-by: Christoph Hellwig <hch@lst.de>
+Link: https://lore.kernel.org/r/20231226081524.180289-1-hch@lst.de
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/blkdev.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
+index eef450f259828..f59fcd5b499a5 100644
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -538,7 +538,7 @@ struct request_queue {
+ #define QUEUE_FLAG_ADD_RANDOM 10      /* Contributes to random pool */
+ #define QUEUE_FLAG_SYNCHRONOUS        11      /* always completes in submit context */
+ #define QUEUE_FLAG_SAME_FORCE 12      /* force complete on same CPU */
+-#define QUEUE_FLAG_HW_WC      18      /* Write back caching supported */
++#define QUEUE_FLAG_HW_WC      13      /* Write back caching supported */
+ #define QUEUE_FLAG_INIT_DONE  14      /* queue is initialized */
+ #define QUEUE_FLAG_STABLE_WRITES 15   /* don't modify blks until WB is done */
+ #define QUEUE_FLAG_POLL               16      /* IO polling enabled if set */
+-- 
+2.43.0
+
diff --git a/queue-6.6/client-convert-to-new-timestamp-accessors.patch b/queue-6.6/client-convert-to-new-timestamp-accessors.patch
new file mode 100644 (file)
index 0000000..9076ded
--- /dev/null
@@ -0,0 +1,185 @@
+From 671945edb68c3d381b1e66740822bf980235d30d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 4 Oct 2023 14:52:53 -0400
+Subject: client: convert to new timestamp accessors
+
+From: Jeff Layton <jlayton@kernel.org>
+
+[ Upstream commit 8f22ce7088835444418f0775efb455d10b825596 ]
+
+Convert to using the new inode timestamp accessor functions.
+
+Signed-off-by: Jeff Layton <jlayton@kernel.org>
+Link: https://lore.kernel.org/r/20231004185347.80880-66-jlayton@kernel.org
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Stable-dep-of: 01fe654f78fd ("fs: cifs: Fix atime update check")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/file.c    | 18 ++++++++++--------
+ fs/smb/client/fscache.h |  6 +++---
+ fs/smb/client/inode.c   | 17 ++++++++---------
+ fs/smb/client/smb2ops.c |  6 ++++--
+ 4 files changed, 25 insertions(+), 22 deletions(-)
+
+diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c
+index 2108b3b40ce92..cf17e3dd703e6 100644
+--- a/fs/smb/client/file.c
++++ b/fs/smb/client/file.c
+@@ -1085,7 +1085,8 @@ int cifs_close(struct inode *inode, struct file *file)
+                   !test_bit(CIFS_INO_CLOSE_ON_LOCK, &cinode->flags) &&
+                   dclose) {
+                       if (test_and_clear_bit(CIFS_INO_MODIFIED_ATTR, &cinode->flags)) {
+-                              inode->i_mtime = inode_set_ctime_current(inode);
++                              inode_set_mtime_to_ts(inode,
++                                                    inode_set_ctime_current(inode));
+                       }
+                       spin_lock(&cinode->deferred_lock);
+                       cifs_add_deferred_close(cfile, dclose);
+@@ -2596,7 +2597,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
+                                          write_data, to - from, &offset);
+               cifsFileInfo_put(open_file);
+               /* Does mm or vfs already set times? */
+-              inode->i_atime = inode->i_mtime = inode_set_ctime_current(inode);
++              simple_inode_init_ts(inode);
+               if ((bytes_written > 0) && (offset))
+                       rc = 0;
+               else if (bytes_written < 0)
+@@ -4647,11 +4648,13 @@ static void cifs_readahead(struct readahead_control *ractl)
+ static int cifs_readpage_worker(struct file *file, struct page *page,
+       loff_t *poffset)
+ {
++      struct inode *inode = file_inode(file);
++      struct timespec64 atime, mtime;
+       char *read_data;
+       int rc;
+       /* Is the page cached? */
+-      rc = cifs_readpage_from_fscache(file_inode(file), page);
++      rc = cifs_readpage_from_fscache(inode, page);
+       if (rc == 0)
+               goto read_complete;
+@@ -4666,11 +4669,10 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
+               cifs_dbg(FYI, "Bytes read %d\n", rc);
+       /* we do not want atime to be less than mtime, it broke some apps */
+-      file_inode(file)->i_atime = current_time(file_inode(file));
+-      if (timespec64_compare(&(file_inode(file)->i_atime), &(file_inode(file)->i_mtime)))
+-              file_inode(file)->i_atime = file_inode(file)->i_mtime;
+-      else
+-              file_inode(file)->i_atime = current_time(file_inode(file));
++      atime = inode_set_atime_to_ts(inode, current_time(inode));
++      mtime = inode_get_mtime(inode);
++      if (timespec64_compare(&atime, &mtime))
++              inode_set_atime_to_ts(inode, inode_get_mtime(inode));
+       if (PAGE_SIZE > rc)
+               memset(read_data + rc, 0, PAGE_SIZE - rc);
+diff --git a/fs/smb/client/fscache.h b/fs/smb/client/fscache.h
+index 84f3b09367d2c..a3d73720914f8 100644
+--- a/fs/smb/client/fscache.h
++++ b/fs/smb/client/fscache.h
+@@ -49,12 +49,12 @@ static inline
+ void cifs_fscache_fill_coherency(struct inode *inode,
+                                struct cifs_fscache_inode_coherency_data *cd)
+ {
+-      struct cifsInodeInfo *cifsi = CIFS_I(inode);
+       struct timespec64 ctime = inode_get_ctime(inode);
++      struct timespec64 mtime = inode_get_mtime(inode);
+       memset(cd, 0, sizeof(*cd));
+-      cd->last_write_time_sec   = cpu_to_le64(cifsi->netfs.inode.i_mtime.tv_sec);
+-      cd->last_write_time_nsec  = cpu_to_le32(cifsi->netfs.inode.i_mtime.tv_nsec);
++      cd->last_write_time_sec   = cpu_to_le64(mtime.tv_sec);
++      cd->last_write_time_nsec  = cpu_to_le32(mtime.tv_nsec);
+       cd->last_change_time_sec  = cpu_to_le64(ctime.tv_sec);
+       cd->last_change_time_nsec = cpu_to_le32(ctime.tv_nsec);
+ }
+diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
+index 6a856945f2b42..09c5c0f5c96e2 100644
+--- a/fs/smb/client/inode.c
++++ b/fs/smb/client/inode.c
+@@ -82,6 +82,7 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
+ {
+       struct cifs_fscache_inode_coherency_data cd;
+       struct cifsInodeInfo *cifs_i = CIFS_I(inode);
++      struct timespec64 mtime;
+       cifs_dbg(FYI, "%s: revalidating inode %llu\n",
+                __func__, cifs_i->uniqueid);
+@@ -101,7 +102,8 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
+        /* revalidate if mtime or size have changed */
+       fattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode);
+-      if (timespec64_equal(&inode->i_mtime, &fattr->cf_mtime) &&
++      mtime = inode_get_mtime(inode);
++      if (timespec64_equal(&mtime, &fattr->cf_mtime) &&
+           cifs_i->server_eof == fattr->cf_eof) {
+               cifs_dbg(FYI, "%s: inode %llu is unchanged\n",
+                        __func__, cifs_i->uniqueid);
+@@ -164,10 +166,10 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
+       fattr->cf_ctime = timestamp_truncate(fattr->cf_ctime, inode);
+       /* we do not want atime to be less than mtime, it broke some apps */
+       if (timespec64_compare(&fattr->cf_atime, &fattr->cf_mtime) < 0)
+-              inode->i_atime = fattr->cf_mtime;
++              inode_set_atime_to_ts(inode, fattr->cf_mtime);
+       else
+-              inode->i_atime = fattr->cf_atime;
+-      inode->i_mtime = fattr->cf_mtime;
++              inode_set_atime_to_ts(inode, fattr->cf_atime);
++      inode_set_mtime_to_ts(inode, fattr->cf_mtime);
+       inode_set_ctime_to_ts(inode, fattr->cf_ctime);
+       inode->i_rdev = fattr->cf_rdev;
+       cifs_nlink_fattr_to_inode(inode, fattr);
+@@ -1868,7 +1870,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
+                                          when needed */
+               inode_set_ctime_current(inode);
+       }
+-      dir->i_mtime = inode_set_ctime_current(dir);
++      inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
+       cifs_inode = CIFS_I(dir);
+       CIFS_I(dir)->time = 0;  /* force revalidate of dir as well */
+ unlink_out:
+@@ -2183,7 +2185,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
+       cifsInode->time = 0;
+       inode_set_ctime_current(d_inode(direntry));
+-      inode->i_mtime = inode_set_ctime_current(inode);
++      inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
+ rmdir_exit:
+       free_dentry_path(page);
+@@ -2389,9 +2391,6 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
+       /* force revalidate to go get info when needed */
+       CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0;
+-      source_dir->i_mtime = target_dir->i_mtime = inode_set_ctime_to_ts(source_dir,
+-                                                                        inode_set_ctime_current(target_dir));
+-
+ cifs_rename_exit:
+       kfree(info_buf_source);
+       free_dentry_path(page2);
+diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
+index 2187921580ac6..e917eeba9c772 100644
+--- a/fs/smb/client/smb2ops.c
++++ b/fs/smb/client/smb2ops.c
+@@ -1409,12 +1409,14 @@ smb2_close_getattr(const unsigned int xid, struct cifs_tcon *tcon,
+       /* Creation time should not need to be updated on close */
+       if (file_inf.LastWriteTime)
+-              inode->i_mtime = cifs_NTtimeToUnix(file_inf.LastWriteTime);
++              inode_set_mtime_to_ts(inode,
++                                    cifs_NTtimeToUnix(file_inf.LastWriteTime));
+       if (file_inf.ChangeTime)
+               inode_set_ctime_to_ts(inode,
+                                     cifs_NTtimeToUnix(file_inf.ChangeTime));
+       if (file_inf.LastAccessTime)
+-              inode->i_atime = cifs_NTtimeToUnix(file_inf.LastAccessTime);
++              inode_set_atime_to_ts(inode,
++                                    cifs_NTtimeToUnix(file_inf.LastAccessTime));
+       /*
+        * i_blocks is not related to (i_size / i_blksize),
+-- 
+2.43.0
+
diff --git a/queue-6.6/fs-cifs-fix-atime-update-check.patch b/queue-6.6/fs-cifs-fix-atime-update-check.patch
new file mode 100644 (file)
index 0000000..224afcd
--- /dev/null
@@ -0,0 +1,44 @@
+From e07f8d4e04e5a8ceaa94203d1204f4c9df6eddda Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 13 Dec 2023 10:23:53 +0800
+Subject: fs: cifs: Fix atime update check
+
+From: Zizhi Wo <wozizhi@huawei.com>
+
+[ Upstream commit 01fe654f78fd1ea4df046ef76b07ba92a35f8dbe ]
+
+Commit 9b9c5bea0b96 ("cifs: do not return atime less than mtime") indicates
+that in cifs, if atime is less than mtime, some apps will break.
+Therefore, it introduce a function to compare this two variables in two
+places where atime is updated. If atime is less than mtime, update it to
+mtime.
+
+However, the patch was handled incorrectly, resulting in atime and mtime
+being exactly equal. A previous commit 69738cfdfa70 ("fs: cifs: Fix atime
+update check vs mtime") fixed one place and forgot to fix another. Fix it.
+
+Fixes: 9b9c5bea0b96 ("cifs: do not return atime less than mtime")
+Cc: stable@vger.kernel.org
+Signed-off-by: Zizhi Wo <wozizhi@huawei.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/client/file.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c
+index cf17e3dd703e6..32a8525415d96 100644
+--- a/fs/smb/client/file.c
++++ b/fs/smb/client/file.c
+@@ -4671,7 +4671,7 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
+       /* we do not want atime to be less than mtime, it broke some apps */
+       atime = inode_set_atime_to_ts(inode, current_time(inode));
+       mtime = inode_get_mtime(inode);
+-      if (timespec64_compare(&atime, &mtime))
++      if (timespec64_compare(&atime, &mtime) < 0)
+               inode_set_atime_to_ts(inode, inode_get_mtime(inode));
+       if (PAGE_SIZE > rc)
+-- 
+2.43.0
+
diff --git a/queue-6.6/fs-new-accessor-methods-for-atime-and-mtime.patch b/queue-6.6/fs-new-accessor-methods-for-atime-and-mtime.patch
new file mode 100644 (file)
index 0000000..e51cb13
--- /dev/null
@@ -0,0 +1,244 @@
+From d8f630c0aff115330cf581a0dad0733aec9bde2e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 4 Oct 2023 14:52:37 -0400
+Subject: fs: new accessor methods for atime and mtime
+
+From: Jeff Layton <jlayton@kernel.org>
+
+[ Upstream commit 077c212f0344ae4198b2b51af128a94b614ccdf4 ]
+
+Recently, we converted the ctime accesses in the kernel to use new
+accessor functions. Linus recently pointed out though that if we add
+accessors for the atime and mtime, then that would allow us to
+seamlessly change how these timestamps are stored in the inode.
+
+Add new accessor functions for the atime and mtime that mirror the
+accessors for the ctime.
+
+Signed-off-by: Jeff Layton <jlayton@kernel.org>
+Link: https://lore.kernel.org/r/20231004185239.80830-1-jlayton@kernel.org
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Stable-dep-of: 01fe654f78fd ("fs: cifs: Fix atime update check")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/libfs.c         | 41 ++++++++++++++++------
+ include/linux/fs.h | 85 +++++++++++++++++++++++++++++++++++++++-------
+ 2 files changed, 102 insertions(+), 24 deletions(-)
+
+diff --git a/fs/libfs.c b/fs/libfs.c
+index 189447cf4acf5..dc0f7519045f1 100644
+--- a/fs/libfs.c
++++ b/fs/libfs.c
+@@ -549,7 +549,8 @@ void simple_recursive_removal(struct dentry *dentry,
+                               dput(victim);           // unpin it
+                       }
+                       if (victim == dentry) {
+-                              inode->i_mtime = inode_set_ctime_current(inode);
++                              inode_set_mtime_to_ts(inode,
++                                                    inode_set_ctime_current(inode));
+                               if (d_is_dir(dentry))
+                                       drop_nlink(inode);
+                               inode_unlock(inode);
+@@ -590,7 +591,7 @@ static int pseudo_fs_fill_super(struct super_block *s, struct fs_context *fc)
+        */
+       root->i_ino = 1;
+       root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
+-      root->i_atime = root->i_mtime = inode_set_ctime_current(root);
++      simple_inode_init_ts(root);
+       s->s_root = d_make_root(root);
+       if (!s->s_root)
+               return -ENOMEM;
+@@ -646,8 +647,8 @@ int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *den
+ {
+       struct inode *inode = d_inode(old_dentry);
+-      dir->i_mtime = inode_set_ctime_to_ts(dir,
+-                                           inode_set_ctime_current(inode));
++      inode_set_mtime_to_ts(dir,
++                            inode_set_ctime_to_ts(dir, inode_set_ctime_current(inode)));
+       inc_nlink(inode);
+       ihold(inode);
+       dget(dentry);
+@@ -681,8 +682,8 @@ int simple_unlink(struct inode *dir, struct dentry *dentry)
+ {
+       struct inode *inode = d_inode(dentry);
+-      dir->i_mtime = inode_set_ctime_to_ts(dir,
+-                                           inode_set_ctime_current(inode));
++      inode_set_mtime_to_ts(dir,
++                            inode_set_ctime_to_ts(dir, inode_set_ctime_current(inode)));
+       drop_nlink(inode);
+       dput(dentry);
+       return 0;
+@@ -717,9 +718,10 @@ void simple_rename_timestamp(struct inode *old_dir, struct dentry *old_dentry,
+ {
+       struct inode *newino = d_inode(new_dentry);
+-      old_dir->i_mtime = inode_set_ctime_current(old_dir);
++      inode_set_mtime_to_ts(old_dir, inode_set_ctime_current(old_dir));
+       if (new_dir != old_dir)
+-              new_dir->i_mtime = inode_set_ctime_current(new_dir);
++              inode_set_mtime_to_ts(new_dir,
++                                    inode_set_ctime_current(new_dir));
+       inode_set_ctime_current(d_inode(old_dentry));
+       if (newino)
+               inode_set_ctime_current(newino);
+@@ -934,7 +936,7 @@ int simple_fill_super(struct super_block *s, unsigned long magic,
+        */
+       inode->i_ino = 1;
+       inode->i_mode = S_IFDIR | 0755;
+-      inode->i_atime = inode->i_mtime = inode_set_ctime_current(inode);
++      simple_inode_init_ts(inode);
+       inode->i_op = &simple_dir_inode_operations;
+       inode->i_fop = &simple_dir_operations;
+       set_nlink(inode, 2);
+@@ -960,7 +962,7 @@ int simple_fill_super(struct super_block *s, unsigned long magic,
+                       goto out;
+               }
+               inode->i_mode = S_IFREG | files->mode;
+-              inode->i_atime = inode->i_mtime = inode_set_ctime_current(inode);
++              simple_inode_init_ts(inode);
+               inode->i_fop = files->ops;
+               inode->i_ino = i;
+               d_add(dentry, inode);
+@@ -1528,7 +1530,7 @@ struct inode *alloc_anon_inode(struct super_block *s)
+       inode->i_uid = current_fsuid();
+       inode->i_gid = current_fsgid();
+       inode->i_flags |= S_PRIVATE;
+-      inode->i_atime = inode->i_mtime = inode_set_ctime_current(inode);
++      simple_inode_init_ts(inode);
+       return inode;
+ }
+ EXPORT_SYMBOL(alloc_anon_inode);
+@@ -1920,3 +1922,20 @@ ssize_t direct_write_fallback(struct kiocb *iocb, struct iov_iter *iter,
+       return direct_written + buffered_written;
+ }
+ EXPORT_SYMBOL_GPL(direct_write_fallback);
++
++/**
++ * simple_inode_init_ts - initialize the timestamps for a new inode
++ * @inode: inode to be initialized
++ *
++ * When a new inode is created, most filesystems set the timestamps to the
++ * current time. Add a helper to do this.
++ */
++struct timespec64 simple_inode_init_ts(struct inode *inode)
++{
++      struct timespec64 ts = inode_set_ctime_current(inode);
++
++      inode_set_atime_to_ts(inode, ts);
++      inode_set_mtime_to_ts(inode, ts);
++      return ts;
++}
++EXPORT_SYMBOL(simple_inode_init_ts);
+diff --git a/include/linux/fs.h b/include/linux/fs.h
+index 4a40823c3c678..d08b97dacd2d9 100644
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -1511,24 +1511,81 @@ static inline bool fsuidgid_has_mapping(struct super_block *sb,
+ struct timespec64 current_time(struct inode *inode);
+ struct timespec64 inode_set_ctime_current(struct inode *inode);
+-/**
+- * inode_get_ctime - fetch the current ctime from the inode
+- * @inode: inode from which to fetch ctime
+- *
+- * Grab the current ctime from the inode and return it.
+- */
++static inline time64_t inode_get_atime_sec(const struct inode *inode)
++{
++      return inode->i_atime.tv_sec;
++}
++
++static inline long inode_get_atime_nsec(const struct inode *inode)
++{
++      return inode->i_atime.tv_nsec;
++}
++
++static inline struct timespec64 inode_get_atime(const struct inode *inode)
++{
++      return inode->i_atime;
++}
++
++static inline struct timespec64 inode_set_atime_to_ts(struct inode *inode,
++                                                    struct timespec64 ts)
++{
++      inode->i_atime = ts;
++      return ts;
++}
++
++static inline struct timespec64 inode_set_atime(struct inode *inode,
++                                              time64_t sec, long nsec)
++{
++      struct timespec64 ts = { .tv_sec  = sec,
++                               .tv_nsec = nsec };
++      return inode_set_atime_to_ts(inode, ts);
++}
++
++static inline time64_t inode_get_mtime_sec(const struct inode *inode)
++{
++      return inode->i_mtime.tv_sec;
++}
++
++static inline long inode_get_mtime_nsec(const struct inode *inode)
++{
++      return inode->i_mtime.tv_nsec;
++}
++
++static inline struct timespec64 inode_get_mtime(const struct inode *inode)
++{
++      return inode->i_mtime;
++}
++
++static inline struct timespec64 inode_set_mtime_to_ts(struct inode *inode,
++                                                    struct timespec64 ts)
++{
++      inode->i_mtime = ts;
++      return ts;
++}
++
++static inline struct timespec64 inode_set_mtime(struct inode *inode,
++                                              time64_t sec, long nsec)
++{
++      struct timespec64 ts = { .tv_sec  = sec,
++                               .tv_nsec = nsec };
++      return inode_set_mtime_to_ts(inode, ts);
++}
++
++static inline time64_t inode_get_ctime_sec(const struct inode *inode)
++{
++      return inode->__i_ctime.tv_sec;
++}
++
++static inline long inode_get_ctime_nsec(const struct inode *inode)
++{
++      return inode->__i_ctime.tv_nsec;
++}
++
+ static inline struct timespec64 inode_get_ctime(const struct inode *inode)
+ {
+       return inode->__i_ctime;
+ }
+-/**
+- * inode_set_ctime_to_ts - set the ctime in the inode
+- * @inode: inode in which to set the ctime
+- * @ts: value to set in the ctime field
+- *
+- * Set the ctime in @inode to @ts
+- */
+ static inline struct timespec64 inode_set_ctime_to_ts(struct inode *inode,
+                                                     struct timespec64 ts)
+ {
+@@ -1553,6 +1610,8 @@ static inline struct timespec64 inode_set_ctime(struct inode *inode,
+       return inode_set_ctime_to_ts(inode, ts);
+ }
++struct timespec64 simple_inode_init_ts(struct inode *inode);
++
+ /*
+  * Snapshotting support.
+  */
+-- 
+2.43.0
+
diff --git a/queue-6.6/kexec-fix-kexec_file-dependencies.patch b/queue-6.6/kexec-fix-kexec_file-dependencies.patch
new file mode 100644 (file)
index 0000000..6d07b1c
--- /dev/null
@@ -0,0 +1,163 @@
+From b55c74642aa82b90e6300d44c4fcf6fe3c5471e2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 23 Oct 2023 13:01:54 +0200
+Subject: kexec: fix KEXEC_FILE dependencies
+
+From: Arnd Bergmann <arnd@arndb.de>
+
+[ Upstream commit c1ad12ee0efc07244be37f69311e6f7c4ac98e62 ]
+
+The cleanup for the CONFIG_KEXEC Kconfig logic accidentally changed the
+'depends on CRYPTO=y' dependency to a plain 'depends on CRYPTO', which
+causes a link failure when all the crypto support is in a loadable module
+and kexec_file support is built-in:
+
+x86_64-linux-ld: vmlinux.o: in function `__x64_sys_kexec_file_load':
+(.text+0x32e30a): undefined reference to `crypto_alloc_shash'
+x86_64-linux-ld: (.text+0x32e58e): undefined reference to `crypto_shash_update'
+x86_64-linux-ld: (.text+0x32e6ee): undefined reference to `crypto_shash_final'
+
+Both s390 and x86 have this problem, while ppc64 and riscv have the
+correct dependency already.  On riscv, the dependency is only used for the
+purgatory, not for the kexec_file code itself, which may be a bit
+surprising as it means that with CONFIG_CRYPTO=m, it is possible to enable
+KEXEC_FILE but then the purgatory code is silently left out.
+
+Move this into the common Kconfig.kexec file in a way that is correct
+everywhere, using the dependency on CRYPTO_SHA256=y only when the
+purgatory code is available.  This requires reversing the dependency
+between ARCH_SUPPORTS_KEXEC_PURGATORY and KEXEC_FILE, but the effect
+remains the same, other than making riscv behave like the other ones.
+
+On s390, there is an additional dependency on CRYPTO_SHA256_S390, which
+should technically not be required but gives better performance.  Remove
+this dependency here, noting that it was not present in the initial
+Kconfig code but was brought in without an explanation in commit
+71406883fd357 ("s390/kexec_file: Add kexec_file_load system call").
+
+[arnd@arndb.de: fix riscv build]
+  Link: https://lkml.kernel.org/r/67ddd260-d424-4229-a815-e3fcfb864a77@app.fastmail.com
+Link: https://lkml.kernel.org/r/20231023110308.1202042-1-arnd@kernel.org
+Fixes: 6af5138083005 ("x86/kexec: refactor for kernel/Kconfig.kexec")
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Reviewed-by: Eric DeVolder <eric_devolder@yahoo.com>
+Tested-by: Eric DeVolder <eric_devolder@yahoo.com>
+Cc: Albert Ou <aou@eecs.berkeley.edu>
+Cc: Alexander Gordeev <agordeev@linux.ibm.com>
+Cc: Ard Biesheuvel <ardb@kernel.org>
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Christian Borntraeger <borntraeger@linux.ibm.com>
+Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
+Cc: Conor Dooley <conor@kernel.org>
+Cc: Dave Hansen <dave.hansen@linux.intel.com>
+Cc: David S. Miller <davem@davemloft.net>
+Cc: Heiko Carstens <hca@linux.ibm.com>
+Cc: Herbert Xu <herbert@gondor.apana.org.au>
+Cc: "H. Peter Anvin" <hpa@zytor.com>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: Nicholas Piggin <npiggin@gmail.com>
+Cc: Palmer Dabbelt <palmer@dabbelt.com>
+Cc: Paul Walmsley <paul.walmsley@sifive.com>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Sven Schnelle <svens@linux.ibm.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/Kconfig | 4 ++--
+ arch/riscv/Kconfig   | 4 +---
+ arch/s390/Kconfig    | 4 ++--
+ arch/x86/Kconfig     | 4 ++--
+ kernel/Kconfig.kexec | 1 +
+ 5 files changed, 8 insertions(+), 9 deletions(-)
+
+diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
+index d5d5388973ac7..4640cee33f123 100644
+--- a/arch/powerpc/Kconfig
++++ b/arch/powerpc/Kconfig
+@@ -607,10 +607,10 @@ config ARCH_SUPPORTS_KEXEC
+       def_bool PPC_BOOK3S || PPC_E500 || (44x && !SMP)
+ config ARCH_SUPPORTS_KEXEC_FILE
+-      def_bool PPC64 && CRYPTO=y && CRYPTO_SHA256=y
++      def_bool PPC64
+ config ARCH_SUPPORTS_KEXEC_PURGATORY
+-      def_bool KEXEC_FILE
++      def_bool y
+ config ARCH_SELECTS_KEXEC_FILE
+       def_bool y
+diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
+index 6688cbbed0b42..9e6d442773eea 100644
+--- a/arch/riscv/Kconfig
++++ b/arch/riscv/Kconfig
+@@ -686,9 +686,7 @@ config ARCH_SELECTS_KEXEC_FILE
+       select KEXEC_ELF
+ config ARCH_SUPPORTS_KEXEC_PURGATORY
+-      def_bool KEXEC_FILE
+-      depends on CRYPTO=y
+-      depends on CRYPTO_SHA256=y
++      def_bool ARCH_SUPPORTS_KEXEC_FILE
+ config ARCH_SUPPORTS_CRASH_DUMP
+       def_bool y
+diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
+index ae29e4392664a..bd4782f23f66d 100644
+--- a/arch/s390/Kconfig
++++ b/arch/s390/Kconfig
+@@ -252,13 +252,13 @@ config ARCH_SUPPORTS_KEXEC
+       def_bool y
+ config ARCH_SUPPORTS_KEXEC_FILE
+-      def_bool CRYPTO && CRYPTO_SHA256 && CRYPTO_SHA256_S390
++      def_bool y
+ config ARCH_SUPPORTS_KEXEC_SIG
+       def_bool MODULE_SIG_FORMAT
+ config ARCH_SUPPORTS_KEXEC_PURGATORY
+-      def_bool KEXEC_FILE
++      def_bool y
+ config ARCH_SUPPORTS_CRASH_DUMP
+       def_bool y
+diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
+index 66bfabae88149..fe3292e310d48 100644
+--- a/arch/x86/Kconfig
++++ b/arch/x86/Kconfig
+@@ -2034,7 +2034,7 @@ config ARCH_SUPPORTS_KEXEC
+       def_bool y
+ config ARCH_SUPPORTS_KEXEC_FILE
+-      def_bool X86_64 && CRYPTO && CRYPTO_SHA256
++      def_bool X86_64
+ config ARCH_SELECTS_KEXEC_FILE
+       def_bool y
+@@ -2042,7 +2042,7 @@ config ARCH_SELECTS_KEXEC_FILE
+       select HAVE_IMA_KEXEC if IMA
+ config ARCH_SUPPORTS_KEXEC_PURGATORY
+-      def_bool KEXEC_FILE
++      def_bool y
+ config ARCH_SUPPORTS_KEXEC_SIG
+       def_bool y
+diff --git a/kernel/Kconfig.kexec b/kernel/Kconfig.kexec
+index f9619ac6b71d9..d3b8a2b1b5732 100644
+--- a/kernel/Kconfig.kexec
++++ b/kernel/Kconfig.kexec
+@@ -36,6 +36,7 @@ config KEXEC
+ config KEXEC_FILE
+       bool "Enable kexec file based system call"
+       depends on ARCH_SUPPORTS_KEXEC_FILE
++      depends on CRYPTO_SHA256=y || !ARCH_SUPPORTS_KEXEC_PURGATORY
+       select KEXEC_CORE
+       help
+         This is new version of kexec system call. This system call is
+-- 
+2.43.0
+
diff --git a/queue-6.6/kexec-select-crypto-from-kexec_file-instead-of-depen.patch b/queue-6.6/kexec-select-crypto-from-kexec_file-instead-of-depen.patch
new file mode 100644 (file)
index 0000000..057d9bc
--- /dev/null
@@ -0,0 +1,73 @@
+From 7b2bff1809afebd3d9c349a92791095fc4b11a5c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 23 Oct 2023 13:01:55 +0200
+Subject: kexec: select CRYPTO from KEXEC_FILE instead of depending on it
+
+From: Arnd Bergmann <arnd@arndb.de>
+
+[ Upstream commit e63bde3d9417f8318d6dd0d0fafa35ebf307aabd ]
+
+All other users of crypto code use 'select' instead of 'depends on', so do
+the same thing with KEXEC_FILE for consistency.
+
+In practice this makes very little difference as kernels with kexec
+support are very likely to also include some other feature that already
+selects both crypto and crypto_sha256, but being consistent here helps for
+usability as well as to avoid potential circular dependencies.
+
+This reverts the dependency back to what it was originally before commit
+74ca317c26a3f ("kexec: create a new config option CONFIG_KEXEC_FILE for
+new syscall"), which changed changed it with the comment "This should be
+safer as "select" is not recursive", but that appears to have been done in
+error, as "select" is indeed recursive, and there are no other
+dependencies that prevent CRYPTO_SHA256 from being selected here.
+
+Link: https://lkml.kernel.org/r/20231023110308.1202042-2-arnd@kernel.org
+Fixes: 74ca317c26a3f ("kexec: create a new config option CONFIG_KEXEC_FILE for new syscall")
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Reviewed-by: Eric DeVolder <eric_devolder@yahoo.com>
+Tested-by: Eric DeVolder <eric_devolder@yahoo.com>
+Acked-by: Baoquan He <bhe@redhat.com>
+Cc: Herbert Xu <herbert@gondor.apana.org.au>
+Cc: "David S. Miller" <davem@davemloft.net>
+Cc: Albert Ou <aou@eecs.berkeley.edu>
+Cc: Alexander Gordeev <agordeev@linux.ibm.com>
+Cc: Ard Biesheuvel <ardb@kernel.org>
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Christian Borntraeger <borntraeger@linux.ibm.com>
+Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
+Cc: Conor Dooley <conor@kernel.org>
+Cc: Dave Hansen <dave.hansen@linux.intel.com>
+Cc: Heiko Carstens <hca@linux.ibm.com>
+Cc: "H. Peter Anvin" <hpa@zytor.com>
+Cc: Ingo Molnar <mingo@redhat.com>
+Cc: Nicholas Piggin <npiggin@gmail.com>
+Cc: Palmer Dabbelt <palmer@dabbelt.com>
+Cc: Paul Walmsley <paul.walmsley@sifive.com>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Sven Schnelle <svens@linux.ibm.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/Kconfig.kexec | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/Kconfig.kexec b/kernel/Kconfig.kexec
+index d3b8a2b1b5732..37e488d5b4fc0 100644
+--- a/kernel/Kconfig.kexec
++++ b/kernel/Kconfig.kexec
+@@ -36,7 +36,8 @@ config KEXEC
+ config KEXEC_FILE
+       bool "Enable kexec file based system call"
+       depends on ARCH_SUPPORTS_KEXEC_FILE
+-      depends on CRYPTO_SHA256=y || !ARCH_SUPPORTS_KEXEC_PURGATORY
++      select CRYPTO
++      select CRYPTO_SHA256
+       select KEXEC_CORE
+       help
+         This is new version of kexec system call. This system call is
+-- 
+2.43.0
+
diff --git a/queue-6.6/ksmbd-add-support-for-surrogate-pair-conversion.patch b/queue-6.6/ksmbd-add-support-for-surrogate-pair-conversion.patch
new file mode 100644 (file)
index 0000000..92195d4
--- /dev/null
@@ -0,0 +1,297 @@
+From fc247894cb76ca52c8598ef3c5a6161cb27e9778 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 Dec 2023 16:19:05 +0900
+Subject: ksmbd: add support for surrogate pair conversion
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 0c180317c654a494fe429adbf7bc9b0793caf9e2 ]
+
+ksmbd is missing supporting to convert filename included surrogate pair
+characters. It triggers a "file or folder does not exist" error in
+Windows client.
+
+[Steps to Reproduce for bug]
+1. Create surrogate pair file
+ touch $(echo -e '\xf0\x9d\x9f\xa3')
+ touch $(echo -e '\xf0\x9d\x9f\xa4')
+
+2. Try to open these files in ksmbd share through Windows client.
+
+This patch update unicode functions not to consider about surrogate pair
+(and IVS).
+
+Reviewed-by: Marios Makassikis <mmakassikis@freebox.fr>
+Tested-by: Marios Makassikis <mmakassikis@freebox.fr>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/unicode.c | 187 +++++++++++++++++++++++++++++-----------
+ 1 file changed, 138 insertions(+), 49 deletions(-)
+
+diff --git a/fs/smb/server/unicode.c b/fs/smb/server/unicode.c
+index 393dd4a7432b6..43ed29ee44ead 100644
+--- a/fs/smb/server/unicode.c
++++ b/fs/smb/server/unicode.c
+@@ -13,46 +13,10 @@
+ #include "unicode.h"
+ #include "smb_common.h"
+-/*
+- * smb_utf16_bytes() - how long will a string be after conversion?
+- * @from:     pointer to input string
+- * @maxbytes: don't go past this many bytes of input string
+- * @codepage: destination codepage
+- *
+- * Walk a utf16le string and return the number of bytes that the string will
+- * be after being converted to the given charset, not including any null
+- * termination required. Don't walk past maxbytes in the source buffer.
+- *
+- * Return:    string length after conversion
+- */
+-static int smb_utf16_bytes(const __le16 *from, int maxbytes,
+-                         const struct nls_table *codepage)
+-{
+-      int i;
+-      int charlen, outlen = 0;
+-      int maxwords = maxbytes / 2;
+-      char tmp[NLS_MAX_CHARSET_SIZE];
+-      __u16 ftmp;
+-
+-      for (i = 0; i < maxwords; i++) {
+-              ftmp = get_unaligned_le16(&from[i]);
+-              if (ftmp == 0)
+-                      break;
+-
+-              charlen = codepage->uni2char(ftmp, tmp, NLS_MAX_CHARSET_SIZE);
+-              if (charlen > 0)
+-                      outlen += charlen;
+-              else
+-                      outlen++;
+-      }
+-
+-      return outlen;
+-}
+-
+ /*
+  * cifs_mapchar() - convert a host-endian char to proper char in codepage
+  * @target:   where converted character should be copied
+- * @src_char: 2 byte host-endian source character
++ * @from:     host-endian source string
+  * @cp:               codepage to which character should be converted
+  * @mapchar:  should character be mapped according to mapchars mount option?
+  *
+@@ -63,10 +27,13 @@ static int smb_utf16_bytes(const __le16 *from, int maxbytes,
+  * Return:    string length after conversion
+  */
+ static int
+-cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
++cifs_mapchar(char *target, const __u16 *from, const struct nls_table *cp,
+            bool mapchar)
+ {
+       int len = 1;
++      __u16 src_char;
++
++      src_char = *from;
+       if (!mapchar)
+               goto cp_convert;
+@@ -104,12 +71,66 @@ cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
+ cp_convert:
+       len = cp->uni2char(src_char, target, NLS_MAX_CHARSET_SIZE);
+-      if (len <= 0) {
+-              *target = '?';
+-              len = 1;
+-      }
++      if (len <= 0)
++              goto surrogate_pair;
+       goto out;
++
++surrogate_pair:
++      /* convert SURROGATE_PAIR and IVS */
++      if (strcmp(cp->charset, "utf8"))
++              goto unknown;
++      len = utf16s_to_utf8s(from, 3, UTF16_LITTLE_ENDIAN, target, 6);
++      if (len <= 0)
++              goto unknown;
++      return len;
++
++unknown:
++      *target = '?';
++      len = 1;
++      goto out;
++}
++
++/*
++ * smb_utf16_bytes() - compute converted string length
++ * @from:     pointer to input string
++ * @maxbytes: input string length
++ * @codepage: destination codepage
++ *
++ * Walk a utf16le string and return the number of bytes that the string will
++ * be after being converted to the given charset, not including any null
++ * termination required. Don't walk past maxbytes in the source buffer.
++ *
++ * Return:    string length after conversion
++ */
++static int smb_utf16_bytes(const __le16 *from, int maxbytes,
++                         const struct nls_table *codepage)
++{
++      int i, j;
++      int charlen, outlen = 0;
++      int maxwords = maxbytes / 2;
++      char tmp[NLS_MAX_CHARSET_SIZE];
++      __u16 ftmp[3];
++
++      for (i = 0; i < maxwords; i++) {
++              ftmp[0] = get_unaligned_le16(&from[i]);
++              if (ftmp[0] == 0)
++                      break;
++              for (j = 1; j <= 2; j++) {
++                      if (i + j < maxwords)
++                              ftmp[j] = get_unaligned_le16(&from[i + j]);
++                      else
++                              ftmp[j] = 0;
++              }
++
++              charlen = cifs_mapchar(tmp, ftmp, codepage, 0);
++              if (charlen > 0)
++                      outlen += charlen;
++              else
++                      outlen++;
++      }
++
++      return outlen;
+ }
+ /*
+@@ -139,12 +160,12 @@ cifs_mapchar(char *target, const __u16 src_char, const struct nls_table *cp,
+ static int smb_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
+                         const struct nls_table *codepage, bool mapchar)
+ {
+-      int i, charlen, safelen;
++      int i, j, charlen, safelen;
+       int outlen = 0;
+       int nullsize = nls_nullsize(codepage);
+       int fromwords = fromlen / 2;
+       char tmp[NLS_MAX_CHARSET_SIZE];
+-      __u16 ftmp;
++      __u16 ftmp[3];  /* ftmp[3] = 3array x 2bytes = 6bytes UTF-16 */
+       /*
+        * because the chars can be of varying widths, we need to take care
+@@ -155,9 +176,15 @@ static int smb_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
+       safelen = tolen - (NLS_MAX_CHARSET_SIZE + nullsize);
+       for (i = 0; i < fromwords; i++) {
+-              ftmp = get_unaligned_le16(&from[i]);
+-              if (ftmp == 0)
++              ftmp[0] = get_unaligned_le16(&from[i]);
++              if (ftmp[0] == 0)
+                       break;
++              for (j = 1; j <= 2; j++) {
++                      if (i + j < fromwords)
++                              ftmp[j] = get_unaligned_le16(&from[i + j]);
++                      else
++                              ftmp[j] = 0;
++              }
+               /*
+                * check to see if converting this character might make the
+@@ -172,6 +199,19 @@ static int smb_from_utf16(char *to, const __le16 *from, int tolen, int fromlen,
+               /* put converted char into 'to' buffer */
+               charlen = cifs_mapchar(&to[outlen], ftmp, codepage, mapchar);
+               outlen += charlen;
++
++              /*
++               * charlen (=bytes of UTF-8 for 1 character)
++               * 4bytes UTF-8(surrogate pair) is charlen=4
++               * (4bytes UTF-16 code)
++               * 7-8bytes UTF-8(IVS) is charlen=3+4 or 4+4
++               * (2 UTF-8 pairs divided to 2 UTF-16 pairs)
++               */
++              if (charlen == 4)
++                      i++;
++              else if (charlen >= 5)
++                      /* 5-6bytes UTF-8 */
++                      i += 2;
+       }
+       /* properly null-terminate string */
+@@ -306,6 +346,9 @@ int smbConvertToUTF16(__le16 *target, const char *source, int srclen,
+       char src_char;
+       __le16 dst_char;
+       wchar_t tmp;
++      wchar_t wchar_to[6];    /* UTF-16 */
++      int ret;
++      unicode_t u;
+       if (!mapchars)
+               return smb_strtoUTF16(target, source, srclen, cp);
+@@ -348,11 +391,57 @@ int smbConvertToUTF16(__le16 *target, const char *source, int srclen,
+                        * if no match, use question mark, which at least in
+                        * some cases serves as wild card
+                        */
+-                      if (charlen < 1) {
+-                              dst_char = cpu_to_le16(0x003f);
+-                              charlen = 1;
++                      if (charlen > 0)
++                              goto ctoUTF16;
++
++                      /* convert SURROGATE_PAIR */
++                      if (strcmp(cp->charset, "utf8"))
++                              goto unknown;
++                      if (*(source + i) & 0x80) {
++                              charlen = utf8_to_utf32(source + i, 6, &u);
++                              if (charlen < 0)
++                                      goto unknown;
++                      } else
++                              goto unknown;
++                      ret  = utf8s_to_utf16s(source + i, charlen,
++                                      UTF16_LITTLE_ENDIAN,
++                                      wchar_to, 6);
++                      if (ret < 0)
++                              goto unknown;
++
++                      i += charlen;
++                      dst_char = cpu_to_le16(*wchar_to);
++                      if (charlen <= 3)
++                              /* 1-3bytes UTF-8 to 2bytes UTF-16 */
++                              put_unaligned(dst_char, &target[j]);
++                      else if (charlen == 4) {
++                              /*
++                               * 4bytes UTF-8(surrogate pair) to 4bytes UTF-16
++                               * 7-8bytes UTF-8(IVS) divided to 2 UTF-16
++                               * (charlen=3+4 or 4+4)
++                               */
++                              put_unaligned(dst_char, &target[j]);
++                              dst_char = cpu_to_le16(*(wchar_to + 1));
++                              j++;
++                              put_unaligned(dst_char, &target[j]);
++                      } else if (charlen >= 5) {
++                              /* 5-6bytes UTF-8 to 6bytes UTF-16 */
++                              put_unaligned(dst_char, &target[j]);
++                              dst_char = cpu_to_le16(*(wchar_to + 1));
++                              j++;
++                              put_unaligned(dst_char, &target[j]);
++                              dst_char = cpu_to_le16(*(wchar_to + 2));
++                              j++;
++                              put_unaligned(dst_char, &target[j]);
+                       }
++                      continue;
++
++unknown:
++                      dst_char = cpu_to_le16(0x003f);
++                      charlen = 1;
+               }
++
++ctoUTF16:
+               /*
+                * character may take more than one byte in the source string,
+                * but will take exactly two bytes in the target string
+-- 
+2.43.0
+
diff --git a/queue-6.6/ksmbd-avoid-duplicate-opinfo_put-call-on-error-of-sm.patch b/queue-6.6/ksmbd-avoid-duplicate-opinfo_put-call-on-error-of-sm.patch
new file mode 100644 (file)
index 0000000..9da4483
--- /dev/null
@@ -0,0 +1,51 @@
+From 863e4d5f3789c5e036e008076264130b5263862a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 Dec 2023 16:19:19 +0900
+Subject: ksmbd: avoid duplicate opinfo_put() call on error of
+ smb21_lease_break_ack()
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 658609d9a618d8881bf549b5893c0ba8fcff4526 ]
+
+opinfo_put() could be called twice on error of smb21_lease_break_ack().
+It will cause UAF issue if opinfo is referenced on other places.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smb2pdu.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
+index cbd5c5572217d..fbd708bb4a5b2 100644
+--- a/fs/smb/server/smb2pdu.c
++++ b/fs/smb/server/smb2pdu.c
+@@ -8219,6 +8219,11 @@ static void smb21_lease_break_ack(struct ksmbd_work *work)
+                           le32_to_cpu(req->LeaseState));
+       }
++      if (ret < 0) {
++              rsp->hdr.Status = err;
++              goto err_out;
++      }
++
+       lease_state = lease->state;
+       opinfo->op_state = OPLOCK_STATE_NONE;
+       wake_up_interruptible_all(&opinfo->oplock_q);
+@@ -8226,11 +8231,6 @@ static void smb21_lease_break_ack(struct ksmbd_work *work)
+       wake_up_interruptible_all(&opinfo->oplock_brk);
+       opinfo_put(opinfo);
+-      if (ret < 0) {
+-              rsp->hdr.Status = err;
+-              goto err_out;
+-      }
+-
+       rsp->StructureSize = cpu_to_le16(36);
+       rsp->Reserved = 0;
+       rsp->Flags = 0;
+-- 
+2.43.0
+
diff --git a/queue-6.6/ksmbd-don-t-update-op_state-as-oplock_state_none-on-.patch b/queue-6.6/ksmbd-don-t-update-op_state-as-oplock_state_none-on-.patch
new file mode 100644 (file)
index 0000000..5ebbfcd
--- /dev/null
@@ -0,0 +1,35 @@
+From 7dc03a40f58d6b1244d68651051496d43a8a09c0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 Dec 2023 16:19:13 +0900
+Subject: ksmbd: don't update ->op_state as OPLOCK_STATE_NONE on error
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit cd80ce7e68f1624ac29cd0a6b057789d1236641e ]
+
+ksmbd set ->op_state as OPLOCK_STATE_NONE on lease break ack error.
+op_state of lease should not be updated because client can send lease
+break ack again. This patch fix smb2.lease.breaking2 test failure.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smb2pdu.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
+index de71532651d97..5bff6746234d4 100644
+--- a/fs/smb/server/smb2pdu.c
++++ b/fs/smb/server/smb2pdu.c
+@@ -8235,7 +8235,6 @@ static void smb21_lease_break_ack(struct ksmbd_work *work)
+               return;
+ err_out:
+-      opinfo->op_state = OPLOCK_STATE_NONE;
+       wake_up_interruptible_all(&opinfo->oplock_q);
+       atomic_dec(&opinfo->breaking_cnt);
+       wake_up_interruptible_all(&opinfo->oplock_brk);
+-- 
+2.43.0
+
diff --git a/queue-6.6/ksmbd-downgrade-rwh-lease-caching-state-to-rh-for-di.patch b/queue-6.6/ksmbd-downgrade-rwh-lease-caching-state-to-rh-for-di.patch
new file mode 100644 (file)
index 0000000..be54402
--- /dev/null
@@ -0,0 +1,94 @@
+From 60c4a1ff2ef4b280c894a0be0e525a4cd29a9e06 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 Dec 2023 16:19:16 +0900
+Subject: ksmbd: downgrade RWH lease caching state to RH for directory
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit eb547407f3572d2110cb1194ecd8865b3371a7a4 ]
+
+RWH(Read + Write + Handle) caching state is not supported for directory.
+ksmbd downgrade it to RH for directory if client send RWH caching lease
+state.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/oplock.c  | 9 +++++++--
+ fs/smb/server/oplock.h  | 2 +-
+ fs/smb/server/smb2pdu.c | 8 ++++----
+ 3 files changed, 12 insertions(+), 7 deletions(-)
+
+diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
+index 5ef6af68d0de6..57950ba7e9257 100644
+--- a/fs/smb/server/oplock.c
++++ b/fs/smb/server/oplock.c
+@@ -1398,10 +1398,11 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
+ /**
+  * parse_lease_state() - parse lease context containted in file open request
+  * @open_req: buffer containing smb2 file open(create) request
++ * @is_dir:   whether leasing file is directory
+  *
+  * Return:  oplock state, -ENOENT if create lease context not found
+  */
+-struct lease_ctx_info *parse_lease_state(void *open_req)
++struct lease_ctx_info *parse_lease_state(void *open_req, bool is_dir)
+ {
+       struct create_context *cc;
+       struct smb2_create_req *req = (struct smb2_create_req *)open_req;
+@@ -1419,7 +1420,11 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
+               struct create_lease_v2 *lc = (struct create_lease_v2 *)cc;
+               memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
+-              lreq->req_state = lc->lcontext.LeaseState;
++              if (is_dir)
++                      lreq->req_state = lc->lcontext.LeaseState &
++                              ~SMB2_LEASE_WRITE_CACHING_LE;
++              else
++                      lreq->req_state = lc->lcontext.LeaseState;
+               lreq->flags = lc->lcontext.LeaseFlags;
+               lreq->epoch = lc->lcontext.Epoch;
+               lreq->duration = lc->lcontext.LeaseDuration;
+diff --git a/fs/smb/server/oplock.h b/fs/smb/server/oplock.h
+index ad31439c61fef..672127318c750 100644
+--- a/fs/smb/server/oplock.h
++++ b/fs/smb/server/oplock.h
+@@ -109,7 +109,7 @@ void opinfo_put(struct oplock_info *opinfo);
+ /* Lease related functions */
+ void create_lease_buf(u8 *rbuf, struct lease *lease);
+-struct lease_ctx_info *parse_lease_state(void *open_req);
++struct lease_ctx_info *parse_lease_state(void *open_req, bool is_dir);
+ __u8 smb2_map_lease_to_oplock(__le32 lease_state);
+ int lease_read_to_write(struct oplock_info *opinfo);
+diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
+index 5bff6746234d4..c4b6adce178a2 100644
+--- a/fs/smb/server/smb2pdu.c
++++ b/fs/smb/server/smb2pdu.c
+@@ -2732,10 +2732,6 @@ int smb2_open(struct ksmbd_work *work)
+               }
+       }
+-      req_op_level = req->RequestedOplockLevel;
+-      if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE)
+-              lc = parse_lease_state(req);
+-
+       if (le32_to_cpu(req->ImpersonationLevel) > le32_to_cpu(IL_DELEGATE)) {
+               pr_err("Invalid impersonationlevel : 0x%x\n",
+                      le32_to_cpu(req->ImpersonationLevel));
+@@ -3215,6 +3211,10 @@ int smb2_open(struct ksmbd_work *work)
+               need_truncate = 1;
+       }
++      req_op_level = req->RequestedOplockLevel;
++      if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE)
++              lc = parse_lease_state(req, S_ISDIR(file_inode(filp)->i_mode));
++
+       share_ret = ksmbd_smb_check_shared_mode(fp->filp, fp);
+       if (!test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_OPLOCKS) ||
+           (req_op_level == SMB2_OPLOCK_LEVEL_LEASE &&
+-- 
+2.43.0
+
diff --git a/queue-6.6/ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_kern_path_.patch b/queue-6.6/ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_kern_path_.patch
new file mode 100644 (file)
index 0000000..be281c3
--- /dev/null
@@ -0,0 +1,44 @@
+From fcc9ac784adc57a05a7310ed135cc8c0c9cdc484 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 Dec 2023 16:19:07 +0900
+Subject: ksmbd: fix kernel-doc comment of ksmbd_vfs_kern_path_locked()
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit f6049712e520287ad695e9d4f1572ab76807fa0c ]
+
+Fix argument list that the kdoc format and script verified in
+ksmbd_vfs_kern_path_locked().
+
+fs/smb/server/vfs.c:1207: warning: Function parameter or member 'parent_path'
+not described in 'ksmbd_vfs_kern_path_locked'
+
+Reported-by: kernel test robot <lkp@intel.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/vfs.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
+index 183e36cda59ec..533257b46fc17 100644
+--- a/fs/smb/server/vfs.c
++++ b/fs/smb/server/vfs.c
+@@ -1186,9 +1186,10 @@ static int ksmbd_vfs_lookup_in_dir(const struct path *dir, char *name,
+ /**
+  * ksmbd_vfs_kern_path_locked() - lookup a file and get path info
+- * @name:     file path that is relative to share
+- * @flags:    lookup flags
+- * @path:     if lookup succeed, return path info
++ * @name:             file path that is relative to share
++ * @flags:            lookup flags
++ * @parent_path:      if lookup succeed, return parent_path info
++ * @path:             if lookup succeed, return path info
+  * @caseless: caseless filename lookup
+  *
+  * Return:    0 on success, otherwise error
+-- 
+2.43.0
+
diff --git a/queue-6.6/ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_setxattr.patch b/queue-6.6/ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_setxattr.patch
new file mode 100644 (file)
index 0000000..ea7b147
--- /dev/null
@@ -0,0 +1,39 @@
+From 8b7cd2ea6b0823abce85a64bb76a8d63cf2f65a5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 Dec 2023 16:19:03 +0900
+Subject: ksmbd: fix kernel-doc comment of ksmbd_vfs_setxattr()
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 3354db668808d5b6d7c5e0cb19ff4c9da4bb5e58 ]
+
+Fix argument list that the kdoc format and script verified in
+ksmbd_vfs_setxattr().
+
+fs/smb/server/vfs.c:929: warning: Function parameter or member 'path'
+not described in 'ksmbd_vfs_setxattr'
+
+Reported-by: kernel test robot <lkp@intel.com>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/vfs.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
+index 5a41c0b4e9335..183e36cda59ec 100644
+--- a/fs/smb/server/vfs.c
++++ b/fs/smb/server/vfs.c
+@@ -906,7 +906,7 @@ ssize_t ksmbd_vfs_getxattr(struct mnt_idmap *idmap,
+ /**
+  * ksmbd_vfs_setxattr() - vfs helper for smb set extended attributes value
+  * @idmap:    idmap of the relevant mount
+- * @dentry:   dentry to set XATTR at
++ * @path:     path of dentry to set XATTR at
+  * @attr_name:        xattr name for setxattr
+  * @attr_value:       xattr value to set
+  * @attr_size:        size of xattr value
+-- 
+2.43.0
+
diff --git a/queue-6.6/ksmbd-fix-missing-rdma-capable-flag-for-ipoib-device.patch b/queue-6.6/ksmbd-fix-missing-rdma-capable-flag-for-ipoib-device.patch
new file mode 100644 (file)
index 0000000..f612c73
--- /dev/null
@@ -0,0 +1,89 @@
+From 7a6e40545d1690575a5500ab0dcadb4793ee3a17 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 Dec 2023 16:19:04 +0900
+Subject: ksmbd: fix missing RDMA-capable flag for IPoIB device in
+ ksmbd_rdma_capable_netdev()
+
+From: Kangjing Huang <huangkangjing@gmail.com>
+
+[ Upstream commit ecce70cf17d91c3dd87a0c4ea00b2d1387729701 ]
+
+Physical ib_device does not have an underlying net_device, thus its
+association with IPoIB net_device cannot be retrieved via
+ops.get_netdev() or ib_device_get_by_netdev(). ksmbd reads physical
+ib_device port GUID from the lower 16 bytes of the hardware addresses on
+IPoIB net_device and match its underlying ib_device using ib_find_gid()
+
+Signed-off-by: Kangjing Huang <huangkangjing@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Reviewed-by: Tom Talpey <tom@talpey.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/transport_rdma.c | 40 +++++++++++++++++++++++++---------
+ 1 file changed, 30 insertions(+), 10 deletions(-)
+
+diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c
+index 3b269e1f523a1..c5629a68c8b73 100644
+--- a/fs/smb/server/transport_rdma.c
++++ b/fs/smb/server/transport_rdma.c
+@@ -2140,8 +2140,7 @@ static int smb_direct_ib_client_add(struct ib_device *ib_dev)
+       if (ib_dev->node_type != RDMA_NODE_IB_CA)
+               smb_direct_port = SMB_DIRECT_PORT_IWARP;
+-      if (!ib_dev->ops.get_netdev ||
+-          !rdma_frwr_is_supported(&ib_dev->attrs))
++      if (!rdma_frwr_is_supported(&ib_dev->attrs))
+               return 0;
+       smb_dev = kzalloc(sizeof(*smb_dev), GFP_KERNEL);
+@@ -2241,17 +2240,38 @@ bool ksmbd_rdma_capable_netdev(struct net_device *netdev)
+               for (i = 0; i < smb_dev->ib_dev->phys_port_cnt; i++) {
+                       struct net_device *ndev;
+-                      ndev = smb_dev->ib_dev->ops.get_netdev(smb_dev->ib_dev,
+-                                                             i + 1);
+-                      if (!ndev)
+-                              continue;
++                      if (smb_dev->ib_dev->ops.get_netdev) {
++                              ndev = smb_dev->ib_dev->ops.get_netdev(
++                                      smb_dev->ib_dev, i + 1);
++                              if (!ndev)
++                                      continue;
+-                      if (ndev == netdev) {
++                              if (ndev == netdev) {
++                                      dev_put(ndev);
++                                      rdma_capable = true;
++                                      goto out;
++                              }
+                               dev_put(ndev);
+-                              rdma_capable = true;
+-                              goto out;
++                      /* if ib_dev does not implement ops.get_netdev
++                       * check for matching infiniband GUID in hw_addr
++                       */
++                      } else if (netdev->type == ARPHRD_INFINIBAND) {
++                              struct netdev_hw_addr *ha;
++                              union ib_gid gid;
++                              u32 port_num;
++                              int ret;
++
++                              netdev_hw_addr_list_for_each(
++                                      ha, &netdev->dev_addrs) {
++                                      memcpy(&gid, ha->addr + 4, sizeof(gid));
++                                      ret = ib_find_gid(smb_dev->ib_dev, &gid,
++                                                        &port_num, NULL);
++                                      if (!ret) {
++                                              rdma_capable = true;
++                                              goto out;
++                                      }
++                              }
+                       }
+-                      dev_put(ndev);
+               }
+       }
+ out:
+-- 
+2.43.0
+
diff --git a/queue-6.6/ksmbd-lazy-v2-lease-break-on-smb2_write.patch b/queue-6.6/ksmbd-lazy-v2-lease-break-on-smb2_write.patch
new file mode 100644 (file)
index 0000000..0acd5cc
--- /dev/null
@@ -0,0 +1,124 @@
+From 0291d341c42d2be8e72ec6ac68730aa09e05ccbf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 Dec 2023 16:19:18 +0900
+Subject: ksmbd: lazy v2 lease break on smb2_write()
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit c2a721eead71202a0d8ddd9b56ec8dce652c71d1 ]
+
+Don't immediately send directory lease break notification on smb2_write().
+Instead, It postpones it until smb2_close().
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/oplock.c    | 45 +++++++++++++++++++++++++++++++++++++--
+ fs/smb/server/oplock.h    |  1 +
+ fs/smb/server/vfs.c       |  3 +++
+ fs/smb/server/vfs_cache.h |  1 +
+ 4 files changed, 48 insertions(+), 2 deletions(-)
+
+diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
+index 147d98427ce89..562b180459a1a 100644
+--- a/fs/smb/server/oplock.c
++++ b/fs/smb/server/oplock.c
+@@ -396,8 +396,8 @@ void close_id_del_oplock(struct ksmbd_file *fp)
+ {
+       struct oplock_info *opinfo;
+-      if (S_ISDIR(file_inode(fp->filp)->i_mode))
+-              return;
++      if (fp->reserve_lease_break)
++              smb_lazy_parent_lease_break_close(fp);
+       opinfo = opinfo_get(fp);
+       if (!opinfo)
+@@ -1127,6 +1127,47 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
+       ksmbd_inode_put(p_ci);
+ }
++void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp)
++{
++      struct oplock_info *opinfo;
++      struct ksmbd_inode *p_ci = NULL;
++
++      rcu_read_lock();
++      opinfo = rcu_dereference(fp->f_opinfo);
++      rcu_read_unlock();
++
++      if (!opinfo->is_lease || opinfo->o_lease->version != 2)
++              return;
++
++      p_ci = ksmbd_inode_lookup_lock(fp->filp->f_path.dentry->d_parent);
++      if (!p_ci)
++              return;
++
++      read_lock(&p_ci->m_lock);
++      list_for_each_entry(opinfo, &p_ci->m_op_list, op_entry) {
++              if (!opinfo->is_lease)
++                      continue;
++
++              if (opinfo->o_lease->state != SMB2_OPLOCK_LEVEL_NONE) {
++                      if (!atomic_inc_not_zero(&opinfo->refcount))
++                              continue;
++
++                      atomic_inc(&opinfo->conn->r_count);
++                      if (ksmbd_conn_releasing(opinfo->conn)) {
++                              atomic_dec(&opinfo->conn->r_count);
++                              continue;
++                      }
++                      read_unlock(&p_ci->m_lock);
++                      oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE);
++                      opinfo_conn_put(opinfo);
++                      read_lock(&p_ci->m_lock);
++              }
++      }
++      read_unlock(&p_ci->m_lock);
++
++      ksmbd_inode_put(p_ci);
++}
++
+ /**
+  * smb_grant_oplock() - handle oplock/lease request on file open
+  * @work:             smb work
+diff --git a/fs/smb/server/oplock.h b/fs/smb/server/oplock.h
+index b64d1536882a1..5b93ea9196c01 100644
+--- a/fs/smb/server/oplock.h
++++ b/fs/smb/server/oplock.h
+@@ -129,4 +129,5 @@ int find_same_lease_key(struct ksmbd_session *sess, struct ksmbd_inode *ci,
+ void destroy_lease_table(struct ksmbd_conn *conn);
+ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
+                                     struct lease_ctx_info *lctx);
++void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp);
+ #endif /* __KSMBD_OPLOCK_H */
+diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
+index 9091dcd7a3102..4277750a6da1b 100644
+--- a/fs/smb/server/vfs.c
++++ b/fs/smb/server/vfs.c
+@@ -517,6 +517,9 @@ int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp,
+               }
+       }
++      /* Reserve lease break for parent dir at closing time */
++      fp->reserve_lease_break = true;
++
+       /* Do we need to break any of a levelII oplock? */
+       smb_break_all_levII_oplock(work, fp, 1);
+diff --git a/fs/smb/server/vfs_cache.h b/fs/smb/server/vfs_cache.h
+index 4d4938d6029b6..a528f0cc775ae 100644
+--- a/fs/smb/server/vfs_cache.h
++++ b/fs/smb/server/vfs_cache.h
+@@ -105,6 +105,7 @@ struct ksmbd_file {
+       struct ksmbd_readdir_data       readdir_data;
+       int                             dot_dotdot[2];
+       unsigned int                    f_state;
++      bool                            reserve_lease_break;
+ };
+ static inline void set_ctx_actor(struct dir_context *ctx,
+-- 
+2.43.0
+
diff --git a/queue-6.6/ksmbd-move-oplock-handling-after-unlock-parent-dir.patch b/queue-6.6/ksmbd-move-oplock-handling-after-unlock-parent-dir.patch
new file mode 100644 (file)
index 0000000..9455825
--- /dev/null
@@ -0,0 +1,363 @@
+From 8cbb70617659725ea092ed031b7ad2ea57f10bbd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 Dec 2023 16:19:10 +0900
+Subject: ksmbd: move oplock handling after unlock parent dir
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 2e450920d58b4991a436c8cecf3484bcacd8e535 ]
+
+ksmbd should process secound parallel smb2 create request during waiting
+oplock break ack. parent lock range that is too large in smb2_open() causes
+smb2_open() to be serialized. Move the oplock handling to the bottom of
+smb2_open() and make it called after parent unlock. This fixes the failure
+of smb2.lease.breaking1 testcase.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smb2pdu.c | 121 +++++++++++++++++++++-------------------
+ 1 file changed, 65 insertions(+), 56 deletions(-)
+
+diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
+index 28b61dad27498..e58504d0e9c1e 100644
+--- a/fs/smb/server/smb2pdu.c
++++ b/fs/smb/server/smb2pdu.c
+@@ -2691,7 +2691,7 @@ int smb2_open(struct ksmbd_work *work)
+                   *(char *)req->Buffer == '\\') {
+                       pr_err("not allow directory name included leading slash\n");
+                       rc = -EINVAL;
+-                      goto err_out1;
++                      goto err_out2;
+               }
+               name = smb2_get_name(req->Buffer,
+@@ -2702,7 +2702,7 @@ int smb2_open(struct ksmbd_work *work)
+                       if (rc != -ENOMEM)
+                               rc = -ENOENT;
+                       name = NULL;
+-                      goto err_out1;
++                      goto err_out2;
+               }
+               ksmbd_debug(SMB, "converted name = %s\n", name);
+@@ -2710,28 +2710,28 @@ int smb2_open(struct ksmbd_work *work)
+                       if (!test_share_config_flag(work->tcon->share_conf,
+                                                   KSMBD_SHARE_FLAG_STREAMS)) {
+                               rc = -EBADF;
+-                              goto err_out1;
++                              goto err_out2;
+                       }
+                       rc = parse_stream_name(name, &stream_name, &s_type);
+                       if (rc < 0)
+-                              goto err_out1;
++                              goto err_out2;
+               }
+               rc = ksmbd_validate_filename(name);
+               if (rc < 0)
+-                      goto err_out1;
++                      goto err_out2;
+               if (ksmbd_share_veto_filename(share, name)) {
+                       rc = -ENOENT;
+                       ksmbd_debug(SMB, "Reject open(), vetoed file: %s\n",
+                                   name);
+-                      goto err_out1;
++                      goto err_out2;
+               }
+       } else {
+               name = kstrdup("", GFP_KERNEL);
+               if (!name) {
+                       rc = -ENOMEM;
+-                      goto err_out1;
++                      goto err_out2;
+               }
+       }
+@@ -2744,14 +2744,14 @@ int smb2_open(struct ksmbd_work *work)
+                      le32_to_cpu(req->ImpersonationLevel));
+               rc = -EIO;
+               rsp->hdr.Status = STATUS_BAD_IMPERSONATION_LEVEL;
+-              goto err_out1;
++              goto err_out2;
+       }
+       if (req->CreateOptions && !(req->CreateOptions & CREATE_OPTIONS_MASK_LE)) {
+               pr_err("Invalid create options : 0x%x\n",
+                      le32_to_cpu(req->CreateOptions));
+               rc = -EINVAL;
+-              goto err_out1;
++              goto err_out2;
+       } else {
+               if (req->CreateOptions & FILE_SEQUENTIAL_ONLY_LE &&
+                   req->CreateOptions & FILE_RANDOM_ACCESS_LE)
+@@ -2761,13 +2761,13 @@ int smb2_open(struct ksmbd_work *work)
+                   (FILE_OPEN_BY_FILE_ID_LE | CREATE_TREE_CONNECTION |
+                    FILE_RESERVE_OPFILTER_LE)) {
+                       rc = -EOPNOTSUPP;
+-                      goto err_out1;
++                      goto err_out2;
+               }
+               if (req->CreateOptions & FILE_DIRECTORY_FILE_LE) {
+                       if (req->CreateOptions & FILE_NON_DIRECTORY_FILE_LE) {
+                               rc = -EINVAL;
+-                              goto err_out1;
++                              goto err_out2;
+                       } else if (req->CreateOptions & FILE_NO_COMPRESSION_LE) {
+                               req->CreateOptions = ~(FILE_NO_COMPRESSION_LE);
+                       }
+@@ -2779,21 +2779,21 @@ int smb2_open(struct ksmbd_work *work)
+               pr_err("Invalid create disposition : 0x%x\n",
+                      le32_to_cpu(req->CreateDisposition));
+               rc = -EINVAL;
+-              goto err_out1;
++              goto err_out2;
+       }
+       if (!(req->DesiredAccess & DESIRED_ACCESS_MASK)) {
+               pr_err("Invalid desired access : 0x%x\n",
+                      le32_to_cpu(req->DesiredAccess));
+               rc = -EACCES;
+-              goto err_out1;
++              goto err_out2;
+       }
+       if (req->FileAttributes && !(req->FileAttributes & FILE_ATTRIBUTE_MASK_LE)) {
+               pr_err("Invalid file attribute : 0x%x\n",
+                      le32_to_cpu(req->FileAttributes));
+               rc = -EINVAL;
+-              goto err_out1;
++              goto err_out2;
+       }
+       if (req->CreateContextsOffset) {
+@@ -2801,19 +2801,19 @@ int smb2_open(struct ksmbd_work *work)
+               context = smb2_find_context_vals(req, SMB2_CREATE_EA_BUFFER, 4);
+               if (IS_ERR(context)) {
+                       rc = PTR_ERR(context);
+-                      goto err_out1;
++                      goto err_out2;
+               } else if (context) {
+                       ea_buf = (struct create_ea_buf_req *)context;
+                       if (le16_to_cpu(context->DataOffset) +
+                           le32_to_cpu(context->DataLength) <
+                           sizeof(struct create_ea_buf_req)) {
+                               rc = -EINVAL;
+-                              goto err_out1;
++                              goto err_out2;
+                       }
+                       if (req->CreateOptions & FILE_NO_EA_KNOWLEDGE_LE) {
+                               rsp->hdr.Status = STATUS_ACCESS_DENIED;
+                               rc = -EACCES;
+-                              goto err_out1;
++                              goto err_out2;
+                       }
+               }
+@@ -2821,7 +2821,7 @@ int smb2_open(struct ksmbd_work *work)
+                                                SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST, 4);
+               if (IS_ERR(context)) {
+                       rc = PTR_ERR(context);
+-                      goto err_out1;
++                      goto err_out2;
+               } else if (context) {
+                       ksmbd_debug(SMB,
+                                   "get query maximal access context\n");
+@@ -2832,11 +2832,11 @@ int smb2_open(struct ksmbd_work *work)
+                                                SMB2_CREATE_TIMEWARP_REQUEST, 4);
+               if (IS_ERR(context)) {
+                       rc = PTR_ERR(context);
+-                      goto err_out1;
++                      goto err_out2;
+               } else if (context) {
+                       ksmbd_debug(SMB, "get timewarp context\n");
+                       rc = -EBADF;
+-                      goto err_out1;
++                      goto err_out2;
+               }
+               if (tcon->posix_extensions) {
+@@ -2844,7 +2844,7 @@ int smb2_open(struct ksmbd_work *work)
+                                                        SMB2_CREATE_TAG_POSIX, 16);
+                       if (IS_ERR(context)) {
+                               rc = PTR_ERR(context);
+-                              goto err_out1;
++                              goto err_out2;
+                       } else if (context) {
+                               struct create_posix *posix =
+                                       (struct create_posix *)context;
+@@ -2852,7 +2852,7 @@ int smb2_open(struct ksmbd_work *work)
+                                   le32_to_cpu(context->DataLength) <
+                                   sizeof(struct create_posix) - 4) {
+                                       rc = -EINVAL;
+-                                      goto err_out1;
++                                      goto err_out2;
+                               }
+                               ksmbd_debug(SMB, "get posix context\n");
+@@ -2864,7 +2864,7 @@ int smb2_open(struct ksmbd_work *work)
+       if (ksmbd_override_fsids(work)) {
+               rc = -ENOMEM;
+-              goto err_out1;
++              goto err_out2;
+       }
+       rc = ksmbd_vfs_kern_path_locked(work, name, LOOKUP_NO_SYMLINKS,
+@@ -3177,11 +3177,6 @@ int smb2_open(struct ksmbd_work *work)
+       fp->attrib_only = !(req->DesiredAccess & ~(FILE_READ_ATTRIBUTES_LE |
+                       FILE_WRITE_ATTRIBUTES_LE | FILE_SYNCHRONIZE_LE));
+-      if (!S_ISDIR(file_inode(filp)->i_mode) && open_flags & O_TRUNC &&
+-          !fp->attrib_only && !stream_name) {
+-              smb_break_all_oplock(work, fp);
+-              need_truncate = 1;
+-      }
+       /* fp should be searchable through ksmbd_inode.m_fp_list
+        * after daccess, saccess, attrib_only, and stream are
+@@ -3197,13 +3192,39 @@ int smb2_open(struct ksmbd_work *work)
+               goto err_out;
+       }
++      rc = ksmbd_vfs_getattr(&path, &stat);
++      if (rc)
++              goto err_out;
++
++      if (stat.result_mask & STATX_BTIME)
++              fp->create_time = ksmbd_UnixTimeToNT(stat.btime);
++      else
++              fp->create_time = ksmbd_UnixTimeToNT(stat.ctime);
++      if (req->FileAttributes || fp->f_ci->m_fattr == 0)
++              fp->f_ci->m_fattr =
++                      cpu_to_le32(smb2_get_dos_mode(&stat, le32_to_cpu(req->FileAttributes)));
++
++      if (!created)
++              smb2_update_xattrs(tcon, &path, fp);
++      else
++              smb2_new_xattrs(tcon, &path, fp);
++
++      if (file_present || created)
++              ksmbd_vfs_kern_path_unlock(&parent_path, &path);
++
++      if (!S_ISDIR(file_inode(filp)->i_mode) && open_flags & O_TRUNC &&
++          !fp->attrib_only && !stream_name) {
++              smb_break_all_oplock(work, fp);
++              need_truncate = 1;
++      }
++
+       share_ret = ksmbd_smb_check_shared_mode(fp->filp, fp);
+       if (!test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_OPLOCKS) ||
+           (req_op_level == SMB2_OPLOCK_LEVEL_LEASE &&
+            !(conn->vals->capabilities & SMB2_GLOBAL_CAP_LEASING))) {
+               if (share_ret < 0 && !S_ISDIR(file_inode(fp->filp)->i_mode)) {
+                       rc = share_ret;
+-                      goto err_out;
++                      goto err_out1;
+               }
+       } else {
+               if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) {
+@@ -3213,7 +3234,7 @@ int smb2_open(struct ksmbd_work *work)
+                                   name, req_op_level, lc->req_state);
+                       rc = find_same_lease_key(sess, fp->f_ci, lc);
+                       if (rc)
+-                              goto err_out;
++                              goto err_out1;
+               } else if (open_flags == O_RDONLY &&
+                          (req_op_level == SMB2_OPLOCK_LEVEL_BATCH ||
+                           req_op_level == SMB2_OPLOCK_LEVEL_EXCLUSIVE))
+@@ -3224,12 +3245,18 @@ int smb2_open(struct ksmbd_work *work)
+                                     le32_to_cpu(req->hdr.Id.SyncId.TreeId),
+                                     lc, share_ret);
+               if (rc < 0)
+-                      goto err_out;
++                      goto err_out1;
+       }
+       if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)
+               ksmbd_fd_set_delete_on_close(fp, file_info);
++      if (need_truncate) {
++              rc = smb2_create_truncate(&fp->filp->f_path);
++              if (rc)
++                      goto err_out1;
++      }
++
+       if (req->CreateContextsOffset) {
+               struct create_alloc_size_req *az_req;
+@@ -3237,7 +3264,7 @@ int smb2_open(struct ksmbd_work *work)
+                                       SMB2_CREATE_ALLOCATION_SIZE, 4);
+               if (IS_ERR(az_req)) {
+                       rc = PTR_ERR(az_req);
+-                      goto err_out;
++                      goto err_out1;
+               } else if (az_req) {
+                       loff_t alloc_size;
+                       int err;
+@@ -3246,7 +3273,7 @@ int smb2_open(struct ksmbd_work *work)
+                           le32_to_cpu(az_req->ccontext.DataLength) <
+                           sizeof(struct create_alloc_size_req)) {
+                               rc = -EINVAL;
+-                              goto err_out;
++                              goto err_out1;
+                       }
+                       alloc_size = le64_to_cpu(az_req->AllocationSize);
+                       ksmbd_debug(SMB,
+@@ -3264,30 +3291,13 @@ int smb2_open(struct ksmbd_work *work)
+               context = smb2_find_context_vals(req, SMB2_CREATE_QUERY_ON_DISK_ID, 4);
+               if (IS_ERR(context)) {
+                       rc = PTR_ERR(context);
+-                      goto err_out;
++                      goto err_out1;
+               } else if (context) {
+                       ksmbd_debug(SMB, "get query on disk id context\n");
+                       query_disk_id = 1;
+               }
+       }
+-      rc = ksmbd_vfs_getattr(&path, &stat);
+-      if (rc)
+-              goto err_out;
+-
+-      if (stat.result_mask & STATX_BTIME)
+-              fp->create_time = ksmbd_UnixTimeToNT(stat.btime);
+-      else
+-              fp->create_time = ksmbd_UnixTimeToNT(stat.ctime);
+-      if (req->FileAttributes || fp->f_ci->m_fattr == 0)
+-              fp->f_ci->m_fattr =
+-                      cpu_to_le32(smb2_get_dos_mode(&stat, le32_to_cpu(req->FileAttributes)));
+-
+-      if (!created)
+-              smb2_update_xattrs(tcon, &path, fp);
+-      else
+-              smb2_new_xattrs(tcon, &path, fp);
+-
+       memcpy(fp->client_guid, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);
+       rsp->StructureSize = cpu_to_le16(89);
+@@ -3394,14 +3404,13 @@ int smb2_open(struct ksmbd_work *work)
+       }
+ err_out:
+-      if (file_present || created)
++      if (rc && (file_present || created))
+               ksmbd_vfs_kern_path_unlock(&parent_path, &path);
+-      if (fp && need_truncate)
+-              rc = smb2_create_truncate(&fp->filp->f_path);
+-
+-      ksmbd_revert_fsids(work);
+ err_out1:
++      ksmbd_revert_fsids(work);
++
++err_out2:
+       if (!rc) {
+               ksmbd_update_fstate(&work->sess->file_table, fp, FP_INITED);
+               rc = ksmbd_iov_pin_rsp(work, (void *)rsp, iov_len);
+-- 
+2.43.0
+
diff --git a/queue-6.6/ksmbd-move-setting-smb2_flags_async_command-and-asyn.patch b/queue-6.6/ksmbd-move-setting-smb2_flags_async_command-and-asyn.patch
new file mode 100644 (file)
index 0000000..fe357f3
--- /dev/null
@@ -0,0 +1,57 @@
+From 7c32b1c166d3279f9cf01c8409f4aa9cf08bd291 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 Dec 2023 16:19:12 +0900
+Subject: ksmbd: move setting SMB2_FLAGS_ASYNC_COMMAND and AsyncId
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 9ac45ac7cf65b0623ceeab9b28b307a08efa22dc ]
+
+Directly set SMB2_FLAGS_ASYNC_COMMAND flags and AsyncId in smb2 header of
+interim response instead of current response header.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smb2pdu.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
+index e58504d0e9c1e..de71532651d97 100644
+--- a/fs/smb/server/smb2pdu.c
++++ b/fs/smb/server/smb2pdu.c
+@@ -657,13 +657,9 @@ smb2_get_name(const char *src, const int maxlen, struct nls_table *local_nls)
+ int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg)
+ {
+-      struct smb2_hdr *rsp_hdr;
+       struct ksmbd_conn *conn = work->conn;
+       int id;
+-      rsp_hdr = ksmbd_resp_buf_next(work);
+-      rsp_hdr->Flags |= SMB2_FLAGS_ASYNC_COMMAND;
+-
+       id = ksmbd_acquire_async_msg_id(&conn->async_ida);
+       if (id < 0) {
+               pr_err("Failed to alloc async message id\n");
+@@ -671,7 +667,6 @@ int setup_async_work(struct ksmbd_work *work, void (*fn)(void **), void **arg)
+       }
+       work->asynchronous = true;
+       work->async_id = id;
+-      rsp_hdr->Id.AsyncId = cpu_to_le64(id);
+       ksmbd_debug(SMB,
+                   "Send interim Response to inform async request id : %d\n",
+@@ -723,6 +718,8 @@ void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status)
+              __SMB2_HEADER_STRUCTURE_SIZE);
+       rsp_hdr = smb2_get_msg(in_work->response_buf);
++      rsp_hdr->Flags |= SMB2_FLAGS_ASYNC_COMMAND;
++      rsp_hdr->Id.AsyncId = cpu_to_le64(work->async_id);
+       smb2_set_err_rsp(in_work);
+       rsp_hdr->Status = status;
+-- 
+2.43.0
+
diff --git a/queue-6.6/ksmbd-no-need-to-wait-for-binded-connection-terminat.patch b/queue-6.6/ksmbd-no-need-to-wait-for-binded-connection-terminat.patch
new file mode 100644 (file)
index 0000000..be996d9
--- /dev/null
@@ -0,0 +1,51 @@
+From ea08891fcdc4be6df14a3d6d80df248307d5c443 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 Dec 2023 16:19:06 +0900
+Subject: ksmbd: no need to wait for binded connection termination at logoff
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 67797da8a4b82446d42c52b6ee1419a3100d78ff ]
+
+The connection could be binded to the existing session for Multichannel.
+session will be destroyed when binded connections are released.
+So no need to wait for that's connection at logoff.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/connection.c | 16 ----------------
+ 1 file changed, 16 deletions(-)
+
+diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c
+index 4b38c3a285f60..b6fa1e285c401 100644
+--- a/fs/smb/server/connection.c
++++ b/fs/smb/server/connection.c
+@@ -167,23 +167,7 @@ void ksmbd_all_conn_set_status(u64 sess_id, u32 status)
+ void ksmbd_conn_wait_idle(struct ksmbd_conn *conn, u64 sess_id)
+ {
+-      struct ksmbd_conn *bind_conn;
+-
+       wait_event(conn->req_running_q, atomic_read(&conn->req_running) < 2);
+-
+-      down_read(&conn_list_lock);
+-      list_for_each_entry(bind_conn, &conn_list, conns_list) {
+-              if (bind_conn == conn)
+-                      continue;
+-
+-              if ((bind_conn->binding || xa_load(&bind_conn->sessions, sess_id)) &&
+-                  !ksmbd_conn_releasing(bind_conn) &&
+-                  atomic_read(&bind_conn->req_running)) {
+-                      wait_event(bind_conn->req_running_q,
+-                              atomic_read(&bind_conn->req_running) == 0);
+-              }
+-      }
+-      up_read(&conn_list_lock);
+ }
+ int ksmbd_conn_write(struct ksmbd_work *work)
+-- 
+2.43.0
+
diff --git a/queue-6.6/ksmbd-prevent-memory-leak-on-error-return.patch b/queue-6.6/ksmbd-prevent-memory-leak-on-error-return.patch
new file mode 100644 (file)
index 0000000..5bc1d48
--- /dev/null
@@ -0,0 +1,53 @@
+From e75aebb6c928acc8f25124afd53b26f394eaa659 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 Dec 2023 16:19:08 +0900
+Subject: ksmbd: prevent memory leak on error return
+
+From: Zongmin Zhou <zhouzongmin@kylinos.cn>
+
+[ Upstream commit 90044481e7cca6cb3125b3906544954a25f1309f ]
+
+When allocated memory for 'new' failed,just return
+will cause memory leak of 'ar'.
+
+Fixes: 1819a9042999 ("ksmbd: reorganize ksmbd_iov_pin_rsp()")
+Reported-by: kernel test robot <lkp@intel.com>
+Reported-by: Dan Carpenter <error27@gmail.com>
+Closes: https://lore.kernel.org/r/202311031837.H3yo7JVl-lkp@intel.com/
+Signed-off-by: Zongmin Zhou<zhouzongmin@kylinos.cn>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/ksmbd_work.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/fs/smb/server/ksmbd_work.c b/fs/smb/server/ksmbd_work.c
+index a2ed441e837ae..2510b9f3c8c14 100644
+--- a/fs/smb/server/ksmbd_work.c
++++ b/fs/smb/server/ksmbd_work.c
+@@ -106,7 +106,7 @@ static inline void __ksmbd_iov_pin(struct ksmbd_work *work, void *ib,
+ static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len,
+                              void *aux_buf, unsigned int aux_size)
+ {
+-      struct aux_read *ar;
++      struct aux_read *ar = NULL;
+       int need_iov_cnt = 1;
+       if (aux_size) {
+@@ -123,8 +123,11 @@ static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len,
+               new = krealloc(work->iov,
+                              sizeof(struct kvec) * work->iov_alloc_cnt,
+                              GFP_KERNEL | __GFP_ZERO);
+-              if (!new)
++              if (!new) {
++                      kfree(ar);
++                      work->iov_alloc_cnt -= 4;
+                       return -ENOMEM;
++              }
+               work->iov = new;
+       }
+-- 
+2.43.0
+
diff --git a/queue-6.6/ksmbd-release-interim-response-after-sending-status-.patch b/queue-6.6/ksmbd-release-interim-response-after-sending-status-.patch
new file mode 100644 (file)
index 0000000..5dece04
--- /dev/null
@@ -0,0 +1,51 @@
+From 7b205000c9ef02b1c2020d70e1366eb8d4254ebe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 Dec 2023 16:19:11 +0900
+Subject: ksmbd: release interim response after sending status pending response
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 2a3f7857ec742e212d6cee7fbbf7b0e2ae7f5161 ]
+
+Add missing release async id and delete interim response entry after
+sending status pending response. This only cause when smb2 lease is enable.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/ksmbd_work.c | 3 +++
+ fs/smb/server/oplock.c     | 3 ++-
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/fs/smb/server/ksmbd_work.c b/fs/smb/server/ksmbd_work.c
+index 2510b9f3c8c14..d7c676c151e20 100644
+--- a/fs/smb/server/ksmbd_work.c
++++ b/fs/smb/server/ksmbd_work.c
+@@ -56,6 +56,9 @@ void ksmbd_free_work_struct(struct ksmbd_work *work)
+       kfree(work->tr_buf);
+       kvfree(work->request_buf);
+       kfree(work->iov);
++      if (!list_empty(&work->interim_entry))
++              list_del(&work->interim_entry);
++
+       if (work->async_id)
+               ksmbd_release_id(&work->conn->async_ida, work->async_id);
+       kmem_cache_free(work_cache, work);
+diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
+index 9bc0103720f57..50c68beb71d6c 100644
+--- a/fs/smb/server/oplock.c
++++ b/fs/smb/server/oplock.c
+@@ -833,7 +833,8 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo)
+                                            interim_entry);
+                       setup_async_work(in_work, NULL, NULL);
+                       smb2_send_interim_resp(in_work, STATUS_PENDING);
+-                      list_del(&in_work->interim_entry);
++                      list_del_init(&in_work->interim_entry);
++                      release_async_work(in_work);
+               }
+               INIT_WORK(&work->work, __smb2_lease_break_noti);
+               ksmbd_queue_work(work);
+-- 
+2.43.0
+
diff --git a/queue-6.6/ksmbd-remove-unused-field-in-ksmbd_user-struct.patch b/queue-6.6/ksmbd-remove-unused-field-in-ksmbd_user-struct.patch
new file mode 100644 (file)
index 0000000..5665375
--- /dev/null
@@ -0,0 +1,34 @@
+From ca9d4237b8763667328cb86ff0a5364c972c76fb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 Dec 2023 16:19:01 +0900
+Subject: ksmbd: Remove unused field in ksmbd_user struct
+
+From: Cheng-Han Wu <hank20010209@gmail.com>
+
+[ Upstream commit eacc655e18d1dec9b50660d16a1ddeeb4d6c48f2 ]
+
+fs/smb/server/mgmt/user_config.h:21: Remove the unused field 'failed_login_count' from the ksmbd_user struct.
+
+Signed-off-by: Cheng-Han Wu <hank20010209@gmail.com>
+Acked-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/mgmt/user_config.h | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/fs/smb/server/mgmt/user_config.h b/fs/smb/server/mgmt/user_config.h
+index 6a44109617f14..e068a19fd9049 100644
+--- a/fs/smb/server/mgmt/user_config.h
++++ b/fs/smb/server/mgmt/user_config.h
+@@ -18,7 +18,6 @@ struct ksmbd_user {
+       size_t                  passkey_sz;
+       char                    *passkey;
+-      unsigned int            failed_login_count;
+ };
+ static inline bool user_guest(struct ksmbd_user *user)
+-- 
+2.43.0
+
diff --git a/queue-6.6/ksmbd-reorganize-ksmbd_iov_pin_rsp.patch b/queue-6.6/ksmbd-reorganize-ksmbd_iov_pin_rsp.patch
new file mode 100644 (file)
index 0000000..442e4e8
--- /dev/null
@@ -0,0 +1,99 @@
+From 2cdb97e320d71b96acdcbca1d0ece7761429637c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 Dec 2023 16:19:02 +0900
+Subject: ksmbd: reorganize ksmbd_iov_pin_rsp()
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 1819a904299942b309f687cc0f08b123500aa178 ]
+
+If ksmbd_iov_pin_rsp fail, io vertor should be rollback.
+This patch moves memory allocations to before setting the io vector
+to avoid rollbacks.
+
+Fixes: e2b76ab8b5c9 ("ksmbd: add support for read compound")
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/ksmbd_work.c | 43 +++++++++++++++++++-------------------
+ 1 file changed, 22 insertions(+), 21 deletions(-)
+
+diff --git a/fs/smb/server/ksmbd_work.c b/fs/smb/server/ksmbd_work.c
+index 51def3ca74c01..a2ed441e837ae 100644
+--- a/fs/smb/server/ksmbd_work.c
++++ b/fs/smb/server/ksmbd_work.c
+@@ -95,11 +95,28 @@ bool ksmbd_queue_work(struct ksmbd_work *work)
+       return queue_work(ksmbd_wq, &work->work);
+ }
+-static int ksmbd_realloc_iov_pin(struct ksmbd_work *work, void *ib,
+-                               unsigned int ib_len)
++static inline void __ksmbd_iov_pin(struct ksmbd_work *work, void *ib,
++                                 unsigned int ib_len)
+ {
++      work->iov[++work->iov_idx].iov_base = ib;
++      work->iov[work->iov_idx].iov_len = ib_len;
++      work->iov_cnt++;
++}
++
++static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len,
++                             void *aux_buf, unsigned int aux_size)
++{
++      struct aux_read *ar;
++      int need_iov_cnt = 1;
+-      if (work->iov_alloc_cnt <= work->iov_cnt) {
++      if (aux_size) {
++              need_iov_cnt++;
++              ar = kmalloc(sizeof(struct aux_read), GFP_KERNEL);
++              if (!ar)
++                      return -ENOMEM;
++      }
++
++      if (work->iov_alloc_cnt < work->iov_cnt + need_iov_cnt) {
+               struct kvec *new;
+               work->iov_alloc_cnt += 4;
+@@ -111,16 +128,6 @@ static int ksmbd_realloc_iov_pin(struct ksmbd_work *work, void *ib,
+               work->iov = new;
+       }
+-      work->iov[++work->iov_idx].iov_base = ib;
+-      work->iov[work->iov_idx].iov_len = ib_len;
+-      work->iov_cnt++;
+-
+-      return 0;
+-}
+-
+-static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len,
+-                             void *aux_buf, unsigned int aux_size)
+-{
+       /* Plus rfc_length size on first iov */
+       if (!work->iov_idx) {
+               work->iov[work->iov_idx].iov_base = work->response_buf;
+@@ -129,19 +136,13 @@ static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len,
+               work->iov_cnt++;
+       }
+-      ksmbd_realloc_iov_pin(work, ib, len);
++      __ksmbd_iov_pin(work, ib, len);
+       inc_rfc1001_len(work->iov[0].iov_base, len);
+       if (aux_size) {
+-              struct aux_read *ar;
+-
+-              ksmbd_realloc_iov_pin(work, aux_buf, aux_size);
++              __ksmbd_iov_pin(work, aux_buf, aux_size);
+               inc_rfc1001_len(work->iov[0].iov_base, aux_size);
+-              ar = kmalloc(sizeof(struct aux_read), GFP_KERNEL);
+-              if (!ar)
+-                      return -ENOMEM;
+-
+               ar->buf = aux_buf;
+               list_add(&ar->entry, &work->aux_read_list);
+       }
+-- 
+2.43.0
+
diff --git a/queue-6.6/ksmbd-send-v2-lease-break-notification-for-directory.patch b/queue-6.6/ksmbd-send-v2-lease-break-notification-for-directory.patch
new file mode 100644 (file)
index 0000000..0f4cf4c
--- /dev/null
@@ -0,0 +1,230 @@
+From 6f97c5d91588a4e085325e121593d11e2f582608 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 Dec 2023 16:19:17 +0900
+Subject: ksmbd: send v2 lease break notification for directory
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit d47d9886aeef79feba7adac701a510d65f3682b5 ]
+
+If client send different parent key, different client guid, or there is
+no parent lease key flags in create context v2 lease, ksmbd send lease
+break to client.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/common/smb2pdu.h   |  1 +
+ fs/smb/server/oplock.c    | 56 +++++++++++++++++++++++++++++++++++----
+ fs/smb/server/oplock.h    |  4 +++
+ fs/smb/server/smb2pdu.c   |  7 +++++
+ fs/smb/server/vfs_cache.c | 13 ++++++++-
+ fs/smb/server/vfs_cache.h |  2 ++
+ 6 files changed, 77 insertions(+), 6 deletions(-)
+
+diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h
+index ec20c83cc8366..d58550c1c9378 100644
+--- a/fs/smb/common/smb2pdu.h
++++ b/fs/smb/common/smb2pdu.h
+@@ -1228,6 +1228,7 @@ struct create_mxac_rsp {
+ #define SMB2_LEASE_WRITE_CACHING_LE           cpu_to_le32(0x04)
+ #define SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE  cpu_to_le32(0x02)
++#define SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE       cpu_to_le32(0x04)
+ #define SMB2_LEASE_KEY_SIZE                   16
+diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
+index 57950ba7e9257..147d98427ce89 100644
+--- a/fs/smb/server/oplock.c
++++ b/fs/smb/server/oplock.c
+@@ -102,6 +102,7 @@ static int alloc_lease(struct oplock_info *opinfo, struct lease_ctx_info *lctx)
+       lease->new_state = 0;
+       lease->flags = lctx->flags;
+       lease->duration = lctx->duration;
++      lease->is_dir = lctx->is_dir;
+       memcpy(lease->parent_lease_key, lctx->parent_lease_key, SMB2_LEASE_KEY_SIZE);
+       lease->version = lctx->version;
+       lease->epoch = le16_to_cpu(lctx->epoch);
+@@ -543,12 +544,13 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci,
+                       /* upgrading lease */
+                       if ((atomic_read(&ci->op_count) +
+                            atomic_read(&ci->sop_count)) == 1) {
+-                              if (lease->state ==
+-                                  (lctx->req_state & lease->state)) {
++                              if (lease->state != SMB2_LEASE_NONE_LE &&
++                                  lease->state == (lctx->req_state & lease->state)) {
+                                       lease->state |= lctx->req_state;
+                                       if (lctx->req_state &
+                                               SMB2_LEASE_WRITE_CACHING_LE)
+                                               lease_read_to_write(opinfo);
++
+                               }
+                       } else if ((atomic_read(&ci->op_count) +
+                                   atomic_read(&ci->sop_count)) > 1) {
+@@ -900,7 +902,8 @@ static int oplock_break(struct oplock_info *brk_opinfo, int req_op_level)
+                                       lease->new_state =
+                                               SMB2_LEASE_READ_CACHING_LE;
+                       } else {
+-                              if (lease->state & SMB2_LEASE_HANDLE_CACHING_LE)
++                              if (lease->state & SMB2_LEASE_HANDLE_CACHING_LE &&
++                                              !lease->is_dir)
+                                       lease->new_state =
+                                               SMB2_LEASE_READ_CACHING_LE;
+                               else
+@@ -1082,6 +1085,48 @@ static void set_oplock_level(struct oplock_info *opinfo, int level,
+       }
+ }
++void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
++                                    struct lease_ctx_info *lctx)
++{
++      struct oplock_info *opinfo;
++      struct ksmbd_inode *p_ci = NULL;
++
++      if (lctx->version != 2)
++              return;
++
++      p_ci = ksmbd_inode_lookup_lock(fp->filp->f_path.dentry->d_parent);
++      if (!p_ci)
++              return;
++
++      read_lock(&p_ci->m_lock);
++      list_for_each_entry(opinfo, &p_ci->m_op_list, op_entry) {
++              if (!opinfo->is_lease)
++                      continue;
++
++              if (opinfo->o_lease->state != SMB2_OPLOCK_LEVEL_NONE &&
++                  (!(lctx->flags & SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE) ||
++                   !compare_guid_key(opinfo, fp->conn->ClientGUID,
++                                    lctx->parent_lease_key))) {
++                      if (!atomic_inc_not_zero(&opinfo->refcount))
++                              continue;
++
++                      atomic_inc(&opinfo->conn->r_count);
++                      if (ksmbd_conn_releasing(opinfo->conn)) {
++                              atomic_dec(&opinfo->conn->r_count);
++                              continue;
++                      }
++
++                      read_unlock(&p_ci->m_lock);
++                      oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE);
++                      opinfo_conn_put(opinfo);
++                      read_lock(&p_ci->m_lock);
++              }
++      }
++      read_unlock(&p_ci->m_lock);
++
++      ksmbd_inode_put(p_ci);
++}
++
+ /**
+  * smb_grant_oplock() - handle oplock/lease request on file open
+  * @work:             smb work
+@@ -1420,10 +1465,11 @@ struct lease_ctx_info *parse_lease_state(void *open_req, bool is_dir)
+               struct create_lease_v2 *lc = (struct create_lease_v2 *)cc;
+               memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
+-              if (is_dir)
++              if (is_dir) {
+                       lreq->req_state = lc->lcontext.LeaseState &
+                               ~SMB2_LEASE_WRITE_CACHING_LE;
+-              else
++                      lreq->is_dir = true;
++              } else
+                       lreq->req_state = lc->lcontext.LeaseState;
+               lreq->flags = lc->lcontext.LeaseFlags;
+               lreq->epoch = lc->lcontext.Epoch;
+diff --git a/fs/smb/server/oplock.h b/fs/smb/server/oplock.h
+index 672127318c750..b64d1536882a1 100644
+--- a/fs/smb/server/oplock.h
++++ b/fs/smb/server/oplock.h
+@@ -36,6 +36,7 @@ struct lease_ctx_info {
+       __u8                    parent_lease_key[SMB2_LEASE_KEY_SIZE];
+       __le16                  epoch;
+       int                     version;
++      bool                    is_dir;
+ };
+ struct lease_table {
+@@ -54,6 +55,7 @@ struct lease {
+       __u8                    parent_lease_key[SMB2_LEASE_KEY_SIZE];
+       int                     version;
+       unsigned short          epoch;
++      bool                    is_dir;
+       struct lease_table      *l_lb;
+ };
+@@ -125,4 +127,6 @@ struct oplock_info *lookup_lease_in_table(struct ksmbd_conn *conn,
+ int find_same_lease_key(struct ksmbd_session *sess, struct ksmbd_inode *ci,
+                       struct lease_ctx_info *lctx);
+ void destroy_lease_table(struct ksmbd_conn *conn);
++void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
++                                    struct lease_ctx_info *lctx);
+ #endif /* __KSMBD_OPLOCK_H */
+diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
+index c4b6adce178a2..cbd5c5572217d 100644
+--- a/fs/smb/server/smb2pdu.c
++++ b/fs/smb/server/smb2pdu.c
+@@ -3225,6 +3225,13 @@ int smb2_open(struct ksmbd_work *work)
+               }
+       } else {
+               if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) {
++                      /*
++                       * Compare parent lease using parent key. If there is no
++                       * a lease that has same parent key, Send lease break
++                       * notification.
++                       */
++                      smb_send_parent_lease_break_noti(fp, lc);
++
+                       req_op_level = smb2_map_lease_to_oplock(lc->req_state);
+                       ksmbd_debug(SMB,
+                                   "lease req for(%s) req oplock state 0x%x, lease state 0x%x\n",
+diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c
+index ddf233994ddbb..4e82ff627d122 100644
+--- a/fs/smb/server/vfs_cache.c
++++ b/fs/smb/server/vfs_cache.c
+@@ -87,6 +87,17 @@ static struct ksmbd_inode *ksmbd_inode_lookup(struct ksmbd_file *fp)
+       return __ksmbd_inode_lookup(fp->filp->f_path.dentry);
+ }
++struct ksmbd_inode *ksmbd_inode_lookup_lock(struct dentry *d)
++{
++      struct ksmbd_inode *ci;
++
++      read_lock(&inode_hash_lock);
++      ci = __ksmbd_inode_lookup(d);
++      read_unlock(&inode_hash_lock);
++
++      return ci;
++}
++
+ int ksmbd_query_inode_status(struct dentry *dentry)
+ {
+       struct ksmbd_inode *ci;
+@@ -199,7 +210,7 @@ static void ksmbd_inode_free(struct ksmbd_inode *ci)
+       kfree(ci);
+ }
+-static void ksmbd_inode_put(struct ksmbd_inode *ci)
++void ksmbd_inode_put(struct ksmbd_inode *ci)
+ {
+       if (atomic_dec_and_test(&ci->m_count))
+               ksmbd_inode_free(ci);
+diff --git a/fs/smb/server/vfs_cache.h b/fs/smb/server/vfs_cache.h
+index 8325cf4527c46..4d4938d6029b6 100644
+--- a/fs/smb/server/vfs_cache.h
++++ b/fs/smb/server/vfs_cache.h
+@@ -138,6 +138,8 @@ struct ksmbd_file *ksmbd_lookup_foreign_fd(struct ksmbd_work *work, u64 id);
+ struct ksmbd_file *ksmbd_lookup_fd_slow(struct ksmbd_work *work, u64 id,
+                                       u64 pid);
+ void ksmbd_fd_put(struct ksmbd_work *work, struct ksmbd_file *fp);
++struct ksmbd_inode *ksmbd_inode_lookup_lock(struct dentry *d);
++void ksmbd_inode_put(struct ksmbd_inode *ci);
+ struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id);
+ struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid);
+ struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry);
+-- 
+2.43.0
+
diff --git a/queue-6.6/ksmbd-separately-allocate-ci-per-dentry.patch b/queue-6.6/ksmbd-separately-allocate-ci-per-dentry.patch
new file mode 100644 (file)
index 0000000..99ad5e5
--- /dev/null
@@ -0,0 +1,181 @@
+From 640162d3794d3503e8aa018f14dd655a7f4e9549 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 Dec 2023 16:19:09 +0900
+Subject: ksmbd: separately allocate ci per dentry
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 4274a9dc6aeb9fea66bffba15697a35ae8983b6a ]
+
+xfstests generic/002 test fail when enabling smb2 leases feature.
+This test create hard link file, but removeal failed.
+ci has a file open count to count file open through the smb client,
+but in the case of hard link files, The allocation of ci per inode
+cause incorrectly open count for file deletion. This patch allocate
+ci per dentry to counts open counts for hard link.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/smb2pdu.c   |  2 +-
+ fs/smb/server/vfs.c       |  2 +-
+ fs/smb/server/vfs_cache.c | 33 +++++++++++++--------------------
+ fs/smb/server/vfs_cache.h |  6 +++---
+ 4 files changed, 18 insertions(+), 25 deletions(-)
+
+diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
+index 2b248d45d40ae..28b61dad27498 100644
+--- a/fs/smb/server/smb2pdu.c
++++ b/fs/smb/server/smb2pdu.c
+@@ -3039,7 +3039,7 @@ int smb2_open(struct ksmbd_work *work)
+               }
+       }
+-      rc = ksmbd_query_inode_status(d_inode(path.dentry->d_parent));
++      rc = ksmbd_query_inode_status(path.dentry->d_parent);
+       if (rc == KSMBD_INODE_STATUS_PENDING_DELETE) {
+               rc = -EBUSY;
+               goto err_out;
+diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
+index 533257b46fc17..9091dcd7a3102 100644
+--- a/fs/smb/server/vfs.c
++++ b/fs/smb/server/vfs.c
+@@ -719,7 +719,7 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
+               goto out3;
+       }
+-      parent_fp = ksmbd_lookup_fd_inode(d_inode(old_child->d_parent));
++      parent_fp = ksmbd_lookup_fd_inode(old_child->d_parent);
+       if (parent_fp) {
+               if (parent_fp->daccess & FILE_DELETE_LE) {
+                       pr_err("parent dir is opened with delete access\n");
+diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c
+index c91eac6514dd9..ddf233994ddbb 100644
+--- a/fs/smb/server/vfs_cache.c
++++ b/fs/smb/server/vfs_cache.c
+@@ -66,14 +66,14 @@ static unsigned long inode_hash(struct super_block *sb, unsigned long hashval)
+       return tmp & inode_hash_mask;
+ }
+-static struct ksmbd_inode *__ksmbd_inode_lookup(struct inode *inode)
++static struct ksmbd_inode *__ksmbd_inode_lookup(struct dentry *de)
+ {
+       struct hlist_head *head = inode_hashtable +
+-              inode_hash(inode->i_sb, inode->i_ino);
++              inode_hash(d_inode(de)->i_sb, (unsigned long)de);
+       struct ksmbd_inode *ci = NULL, *ret_ci = NULL;
+       hlist_for_each_entry(ci, head, m_hash) {
+-              if (ci->m_inode == inode) {
++              if (ci->m_de == de) {
+                       if (atomic_inc_not_zero(&ci->m_count))
+                               ret_ci = ci;
+                       break;
+@@ -84,26 +84,16 @@ static struct ksmbd_inode *__ksmbd_inode_lookup(struct inode *inode)
+ static struct ksmbd_inode *ksmbd_inode_lookup(struct ksmbd_file *fp)
+ {
+-      return __ksmbd_inode_lookup(file_inode(fp->filp));
++      return __ksmbd_inode_lookup(fp->filp->f_path.dentry);
+ }
+-static struct ksmbd_inode *ksmbd_inode_lookup_by_vfsinode(struct inode *inode)
+-{
+-      struct ksmbd_inode *ci;
+-
+-      read_lock(&inode_hash_lock);
+-      ci = __ksmbd_inode_lookup(inode);
+-      read_unlock(&inode_hash_lock);
+-      return ci;
+-}
+-
+-int ksmbd_query_inode_status(struct inode *inode)
++int ksmbd_query_inode_status(struct dentry *dentry)
+ {
+       struct ksmbd_inode *ci;
+       int ret = KSMBD_INODE_STATUS_UNKNOWN;
+       read_lock(&inode_hash_lock);
+-      ci = __ksmbd_inode_lookup(inode);
++      ci = __ksmbd_inode_lookup(dentry);
+       if (ci) {
+               ret = KSMBD_INODE_STATUS_OK;
+               if (ci->m_flags & (S_DEL_PENDING | S_DEL_ON_CLS))
+@@ -143,7 +133,7 @@ void ksmbd_fd_set_delete_on_close(struct ksmbd_file *fp,
+ static void ksmbd_inode_hash(struct ksmbd_inode *ci)
+ {
+       struct hlist_head *b = inode_hashtable +
+-              inode_hash(ci->m_inode->i_sb, ci->m_inode->i_ino);
++              inode_hash(d_inode(ci->m_de)->i_sb, (unsigned long)ci->m_de);
+       hlist_add_head(&ci->m_hash, b);
+ }
+@@ -157,7 +147,6 @@ static void ksmbd_inode_unhash(struct ksmbd_inode *ci)
+ static int ksmbd_inode_init(struct ksmbd_inode *ci, struct ksmbd_file *fp)
+ {
+-      ci->m_inode = file_inode(fp->filp);
+       atomic_set(&ci->m_count, 1);
+       atomic_set(&ci->op_count, 0);
+       atomic_set(&ci->sop_count, 0);
+@@ -166,6 +155,7 @@ static int ksmbd_inode_init(struct ksmbd_inode *ci, struct ksmbd_file *fp)
+       INIT_LIST_HEAD(&ci->m_fp_list);
+       INIT_LIST_HEAD(&ci->m_op_list);
+       rwlock_init(&ci->m_lock);
++      ci->m_de = fp->filp->f_path.dentry;
+       return 0;
+ }
+@@ -488,12 +478,15 @@ struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid)
+       return fp;
+ }
+-struct ksmbd_file *ksmbd_lookup_fd_inode(struct inode *inode)
++struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry)
+ {
+       struct ksmbd_file       *lfp;
+       struct ksmbd_inode      *ci;
++      struct inode            *inode = d_inode(dentry);
+-      ci = ksmbd_inode_lookup_by_vfsinode(inode);
++      read_lock(&inode_hash_lock);
++      ci = __ksmbd_inode_lookup(dentry);
++      read_unlock(&inode_hash_lock);
+       if (!ci)
+               return NULL;
+diff --git a/fs/smb/server/vfs_cache.h b/fs/smb/server/vfs_cache.h
+index 03d0bf941216f..8325cf4527c46 100644
+--- a/fs/smb/server/vfs_cache.h
++++ b/fs/smb/server/vfs_cache.h
+@@ -51,7 +51,7 @@ struct ksmbd_inode {
+       atomic_t                        op_count;
+       /* opinfo count for streams */
+       atomic_t                        sop_count;
+-      struct inode                    *m_inode;
++      struct dentry                   *m_de;
+       unsigned int                    m_flags;
+       struct hlist_node               m_hash;
+       struct list_head                m_fp_list;
+@@ -140,7 +140,7 @@ struct ksmbd_file *ksmbd_lookup_fd_slow(struct ksmbd_work *work, u64 id,
+ void ksmbd_fd_put(struct ksmbd_work *work, struct ksmbd_file *fp);
+ struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id);
+ struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid);
+-struct ksmbd_file *ksmbd_lookup_fd_inode(struct inode *inode);
++struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry);
+ unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp);
+ struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp);
+ void ksmbd_close_tree_conn_fds(struct ksmbd_work *work);
+@@ -164,7 +164,7 @@ enum KSMBD_INODE_STATUS {
+       KSMBD_INODE_STATUS_PENDING_DELETE,
+ };
+-int ksmbd_query_inode_status(struct inode *inode);
++int ksmbd_query_inode_status(struct dentry *dentry);
+ bool ksmbd_inode_pending_delete(struct ksmbd_file *fp);
+ void ksmbd_set_inode_pending_delete(struct ksmbd_file *fp);
+ void ksmbd_clear_inode_pending_delete(struct ksmbd_file *fp);
+-- 
+2.43.0
+
diff --git a/queue-6.6/ksmbd-set-epoch-in-create-context-v2-lease.patch b/queue-6.6/ksmbd-set-epoch-in-create-context-v2-lease.patch
new file mode 100644 (file)
index 0000000..1bffca9
--- /dev/null
@@ -0,0 +1,72 @@
+From f95b24e87a8aafa1b5956fa94ac851d495eae69f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 Dec 2023 16:19:14 +0900
+Subject: ksmbd: set epoch in create context v2 lease
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit d045850b628aaf931fc776c90feaf824dca5a1cf ]
+
+To support v2 lease(directory lease), ksmbd set epoch in create context
+v2 lease response.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/oplock.c | 5 ++++-
+ fs/smb/server/oplock.h | 1 +
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
+index 50c68beb71d6c..ff5c83b1fb85c 100644
+--- a/fs/smb/server/oplock.c
++++ b/fs/smb/server/oplock.c
+@@ -104,7 +104,7 @@ static int alloc_lease(struct oplock_info *opinfo, struct lease_ctx_info *lctx)
+       lease->duration = lctx->duration;
+       memcpy(lease->parent_lease_key, lctx->parent_lease_key, SMB2_LEASE_KEY_SIZE);
+       lease->version = lctx->version;
+-      lease->epoch = 0;
++      lease->epoch = le16_to_cpu(lctx->epoch);
+       INIT_LIST_HEAD(&opinfo->lease_entry);
+       opinfo->o_lease = lease;
+@@ -1032,6 +1032,7 @@ static void copy_lease(struct oplock_info *op1, struct oplock_info *op2)
+              SMB2_LEASE_KEY_SIZE);
+       lease2->duration = lease1->duration;
+       lease2->flags = lease1->flags;
++      lease2->epoch = lease1->epoch++;
+ }
+ static int add_lease_global_list(struct oplock_info *opinfo)
+@@ -1364,6 +1365,7 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
+               memcpy(buf->lcontext.LeaseKey, lease->lease_key,
+                      SMB2_LEASE_KEY_SIZE);
+               buf->lcontext.LeaseFlags = lease->flags;
++              buf->lcontext.Epoch = cpu_to_le16(++lease->epoch);
+               buf->lcontext.LeaseState = lease->state;
+               memcpy(buf->lcontext.ParentLeaseKey, lease->parent_lease_key,
+                      SMB2_LEASE_KEY_SIZE);
+@@ -1423,6 +1425,7 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
+               memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
+               lreq->req_state = lc->lcontext.LeaseState;
+               lreq->flags = lc->lcontext.LeaseFlags;
++              lreq->epoch = lc->lcontext.Epoch;
+               lreq->duration = lc->lcontext.LeaseDuration;
+               memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey,
+                               SMB2_LEASE_KEY_SIZE);
+diff --git a/fs/smb/server/oplock.h b/fs/smb/server/oplock.h
+index 4b0fe6da76940..ad31439c61fef 100644
+--- a/fs/smb/server/oplock.h
++++ b/fs/smb/server/oplock.h
+@@ -34,6 +34,7 @@ struct lease_ctx_info {
+       __le32                  flags;
+       __le64                  duration;
+       __u8                    parent_lease_key[SMB2_LEASE_KEY_SIZE];
++      __le16                  epoch;
+       int                     version;
+ };
+-- 
+2.43.0
+
diff --git a/queue-6.6/ksmbd-set-v2-lease-capability.patch b/queue-6.6/ksmbd-set-v2-lease-capability.patch
new file mode 100644 (file)
index 0000000..f91fc31
--- /dev/null
@@ -0,0 +1,72 @@
+From 411d996a9f134b8df9dc5d925cd19343bb044c81 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 31 Dec 2023 16:19:15 +0900
+Subject: ksmbd: set v2 lease capability
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 18dd1c367c31d0a060f737d48345747662369b64 ]
+
+Set SMB2_GLOBAL_CAP_DIRECTORY_LEASING to ->capabilities to inform server
+support directory lease to client.
+
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/oplock.c  | 4 ----
+ fs/smb/server/smb2ops.c | 9 ++++++---
+ 2 files changed, 6 insertions(+), 7 deletions(-)
+
+diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
+index ff5c83b1fb85c..5ef6af68d0de6 100644
+--- a/fs/smb/server/oplock.c
++++ b/fs/smb/server/oplock.c
+@@ -1105,10 +1105,6 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
+       bool prev_op_has_lease;
+       __le32 prev_op_state = 0;
+-      /* not support directory lease */
+-      if (S_ISDIR(file_inode(fp->filp)->i_mode))
+-              return 0;
+-
+       opinfo = alloc_opinfo(work, pid, tid);
+       if (!opinfo)
+               return -ENOMEM;
+diff --git a/fs/smb/server/smb2ops.c b/fs/smb/server/smb2ops.c
+index aed7704a06728..27a9dce3e03ab 100644
+--- a/fs/smb/server/smb2ops.c
++++ b/fs/smb/server/smb2ops.c
+@@ -221,7 +221,8 @@ void init_smb3_0_server(struct ksmbd_conn *conn)
+       conn->signing_algorithm = SIGNING_ALG_AES_CMAC_LE;
+       if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES)
+-              conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING;
++              conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING |
++                      SMB2_GLOBAL_CAP_DIRECTORY_LEASING;
+       if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION &&
+           conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION)
+@@ -245,7 +246,8 @@ void init_smb3_02_server(struct ksmbd_conn *conn)
+       conn->signing_algorithm = SIGNING_ALG_AES_CMAC_LE;
+       if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES)
+-              conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING;
++              conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING |
++                      SMB2_GLOBAL_CAP_DIRECTORY_LEASING;
+       if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION ||
+           (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF) &&
+@@ -270,7 +272,8 @@ int init_smb3_11_server(struct ksmbd_conn *conn)
+       conn->signing_algorithm = SIGNING_ALG_AES_CMAC_LE;
+       if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES)
+-              conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING;
++              conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING |
++                      SMB2_GLOBAL_CAP_DIRECTORY_LEASING;
+       if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION ||
+           (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF) &&
+-- 
+2.43.0
+
diff --git a/queue-6.6/linux-export-ensure-natural-alignment-of-kcrctab-arr.patch b/queue-6.6/linux-export-ensure-natural-alignment-of-kcrctab-arr.patch
new file mode 100644 (file)
index 0000000..47945b1
--- /dev/null
@@ -0,0 +1,35 @@
+From 42baf792ef97846cb809cdba0d5bd374d850815f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 28 Dec 2023 11:36:03 +0100
+Subject: linux/export: Ensure natural alignment of kcrctab array
+
+From: Helge Deller <deller@gmx.de>
+
+[ Upstream commit 753547de0daecbdbd1af3618987ddade325d9aaa ]
+
+The ___kcrctab section holds an array of 32-bit CRC values.
+Add a .balign 4 to tell the linker the correct memory alignment.
+
+Fixes: f3304ecd7f06 ("linux/export: use inline assembler to populate symbol CRCs")
+Signed-off-by: Helge Deller <deller@gmx.de>
+Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/export-internal.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/include/linux/export-internal.h b/include/linux/export-internal.h
+index b842aeecef791..5280194777340 100644
+--- a/include/linux/export-internal.h
++++ b/include/linux/export-internal.h
+@@ -66,6 +66,7 @@
+ #define SYMBOL_CRC(sym, crc, sec)   \
+       asm(".section \"___kcrctab" sec "+" #sym "\",\"a\""     "\n" \
++          ".balign 4"                                         "\n" \
+           "__crc_" #sym ":"                                   "\n" \
+           ".long " #crc                                       "\n" \
+           ".previous"                                         "\n")
+-- 
+2.43.0
+
diff --git a/queue-6.6/linux-export-fix-alignment-for-64-bit-ksymtab-entrie.patch b/queue-6.6/linux-export-fix-alignment-for-64-bit-ksymtab-entrie.patch
new file mode 100644 (file)
index 0000000..64bc4f5
--- /dev/null
@@ -0,0 +1,51 @@
+From 616d3a9f442244f63e12fd5a992261153b46a38f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 22 Nov 2023 23:18:11 +0100
+Subject: linux/export: Fix alignment for 64-bit ksymtab entries
+
+From: Helge Deller <deller@gmx.de>
+
+[ Upstream commit f6847807c22f6944c71c981b630b9fff30801e73 ]
+
+An alignment of 4 bytes is wrong for 64-bit platforms which don't define
+CONFIG_HAVE_ARCH_PREL32_RELOCATIONS (which then store 64-bit pointers).
+Fix their alignment to 8 bytes.
+
+Fixes: ddb5cdbafaaa ("kbuild: generate KSYMTAB entries by modpost")
+Signed-off-by: Helge Deller <deller@gmx.de>
+Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/export-internal.h | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/include/linux/export-internal.h b/include/linux/export-internal.h
+index 45fca09b23194..b842aeecef791 100644
+--- a/include/linux/export-internal.h
++++ b/include/linux/export-internal.h
+@@ -16,10 +16,13 @@
+  * and eliminates the need for absolute relocations that require runtime
+  * processing on relocatable kernels.
+  */
++#define __KSYM_ALIGN          ".balign 4"
+ #define __KSYM_REF(sym)               ".long " #sym "- ."
+ #elif defined(CONFIG_64BIT)
++#define __KSYM_ALIGN          ".balign 8"
+ #define __KSYM_REF(sym)               ".quad " #sym
+ #else
++#define __KSYM_ALIGN          ".balign 4"
+ #define __KSYM_REF(sym)               ".long " #sym
+ #endif
+@@ -42,7 +45,7 @@
+           "   .asciz \"" ns "\""                                      "\n"    \
+           "   .previous"                                              "\n"    \
+           "   .section \"___ksymtab" sec "+" #name "\", \"a\""        "\n"    \
+-          "   .balign 4"                                              "\n"    \
++              __KSYM_ALIGN                                            "\n"    \
+           "__ksymtab_" #name ":"                                      "\n"    \
+               __KSYM_REF(sym)                                         "\n"    \
+               __KSYM_REF(__kstrtab_ ##name)                           "\n"    \
+-- 
+2.43.0
+
diff --git a/queue-6.6/mptcp-fix-inconsistent-state-on-fastopen-race.patch b/queue-6.6/mptcp-fix-inconsistent-state-on-fastopen-race.patch
new file mode 100644 (file)
index 0000000..2f6d6ca
--- /dev/null
@@ -0,0 +1,237 @@
+From 2b1d92ea197fb279ca67e48645295e9aa1c51a7c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 15 Dec 2023 17:04:25 +0100
+Subject: mptcp: fix inconsistent state on fastopen race
+
+From: Paolo Abeni <pabeni@redhat.com>
+
+[ Upstream commit 4fd19a30701659af5839b7bd19d1f05f05933ebe ]
+
+The netlink PM can race with fastopen self-connect attempts, shutting
+down the first subflow via:
+
+MPTCP_PM_CMD_DEL_ADDR -> mptcp_nl_remove_id_zero_address ->
+  mptcp_pm_nl_rm_subflow_received -> mptcp_close_ssk
+
+and transitioning such subflow to FIN_WAIT1 status before the syn-ack
+packet is processed. The MPTCP code does not react to such state change,
+leaving the connection in not-fallback status and the subflow handshake
+uncompleted, triggering the following splat:
+
+  WARNING: CPU: 0 PID: 10630 at net/mptcp/subflow.c:1405 subflow_data_ready+0x39f/0x690 net/mptcp/subflow.c:1405
+  Modules linked in:
+  CPU: 0 PID: 10630 Comm: kworker/u4:11 Not tainted 6.6.0-syzkaller-14500-g1c41041124bd #0
+  Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/09/2023
+  Workqueue: bat_events batadv_nc_worker
+  RIP: 0010:subflow_data_ready+0x39f/0x690 net/mptcp/subflow.c:1405
+  Code: 18 89 ee e8 e3 d2 21 f7 40 84 ed 75 1f e8 a9 d7 21 f7 44 89 fe bf 07 00 00 00 e8 0c d3 21 f7 41 83 ff 07 74 07 e8 91 d7 21 f7 <0f> 0b e8 8a d7 21 f7 48 89 df e8 d2 b2 ff ff 31 ff 89 c5 89 c6 e8
+  RSP: 0018:ffffc90000007448 EFLAGS: 00010246
+  RAX: 0000000000000000 RBX: ffff888031efc700 RCX: ffffffff8a65baf4
+  RDX: ffff888043222140 RSI: ffffffff8a65baff RDI: 0000000000000005
+  RBP: 0000000000000000 R08: 0000000000000005 R09: 0000000000000007
+  R10: 000000000000000b R11: 0000000000000000 R12: 1ffff92000000e89
+  R13: ffff88807a534d80 R14: ffff888021c11a00 R15: 000000000000000b
+  FS:  0000000000000000(0000) GS:ffff8880b9800000(0000) knlGS:0000000000000000
+  CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+  CR2: 00007fa19a0ffc81 CR3: 000000007a2db000 CR4: 00000000003506f0
+  DR0: 000000000000d8dd DR1: 0000000000000000 DR2: 0000000000000000
+  DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
+  Call Trace:
+   <IRQ>
+   tcp_data_ready+0x14c/0x5b0 net/ipv4/tcp_input.c:5128
+   tcp_data_queue+0x19c3/0x5190 net/ipv4/tcp_input.c:5208
+   tcp_rcv_state_process+0x11ef/0x4e10 net/ipv4/tcp_input.c:6844
+   tcp_v4_do_rcv+0x369/0xa10 net/ipv4/tcp_ipv4.c:1929
+   tcp_v4_rcv+0x3888/0x3b30 net/ipv4/tcp_ipv4.c:2329
+   ip_protocol_deliver_rcu+0x9f/0x480 net/ipv4/ip_input.c:205
+   ip_local_deliver_finish+0x2e4/0x510 net/ipv4/ip_input.c:233
+   NF_HOOK include/linux/netfilter.h:314 [inline]
+   NF_HOOK include/linux/netfilter.h:308 [inline]
+   ip_local_deliver+0x1b6/0x550 net/ipv4/ip_input.c:254
+   dst_input include/net/dst.h:461 [inline]
+   ip_rcv_finish+0x1c4/0x2e0 net/ipv4/ip_input.c:449
+   NF_HOOK include/linux/netfilter.h:314 [inline]
+   NF_HOOK include/linux/netfilter.h:308 [inline]
+   ip_rcv+0xce/0x440 net/ipv4/ip_input.c:569
+   __netif_receive_skb_one_core+0x115/0x180 net/core/dev.c:5527
+   __netif_receive_skb+0x1f/0x1b0 net/core/dev.c:5641
+   process_backlog+0x101/0x6b0 net/core/dev.c:5969
+   __napi_poll.constprop.0+0xb4/0x540 net/core/dev.c:6531
+   napi_poll net/core/dev.c:6600 [inline]
+   net_rx_action+0x956/0xe90 net/core/dev.c:6733
+   __do_softirq+0x21a/0x968 kernel/softirq.c:553
+   do_softirq kernel/softirq.c:454 [inline]
+   do_softirq+0xaa/0xe0 kernel/softirq.c:441
+   </IRQ>
+   <TASK>
+   __local_bh_enable_ip+0xf8/0x120 kernel/softirq.c:381
+   spin_unlock_bh include/linux/spinlock.h:396 [inline]
+   batadv_nc_purge_paths+0x1ce/0x3c0 net/batman-adv/network-coding.c:471
+   batadv_nc_worker+0x9b1/0x10e0 net/batman-adv/network-coding.c:722
+   process_one_work+0x884/0x15c0 kernel/workqueue.c:2630
+   process_scheduled_works kernel/workqueue.c:2703 [inline]
+   worker_thread+0x8b9/0x1290 kernel/workqueue.c:2784
+   kthread+0x33c/0x440 kernel/kthread.c:388
+   ret_from_fork+0x45/0x80 arch/x86/kernel/process.c:147
+   ret_from_fork_asm+0x11/0x20 arch/x86/entry/entry_64.S:242
+   </TASK>
+
+To address the issue, catch the racing subflow state change and
+use it to cause the MPTCP fallback. Such fallback is also used to
+cause the first subflow state propagation to the msk socket via
+mptcp_set_connected(). After this change, the first subflow can
+additionally propagate the TCP_FIN_WAIT1 state, so rename the
+helper accordingly.
+
+Finally, if the state propagation is delayed to the msk release
+callback, the first subflow can change to a different state in between.
+Cache the relevant target state in a new msk-level field and use
+such value to update the msk state at release time.
+
+Fixes: 1e777f39b4d7 ("mptcp: add MSG_FASTOPEN sendmsg flag support")
+Cc: stable@vger.kernel.org
+Reported-by: <syzbot+c53d4d3ddb327e80bc51@syzkaller.appspotmail.com>
+Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/458
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Signed-off-by: Matthieu Baerts <matttbe@kernel.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mptcp/protocol.c |  6 +++---
+ net/mptcp/protocol.h |  9 ++++++---
+ net/mptcp/subflow.c  | 28 +++++++++++++++++-----------
+ 3 files changed, 26 insertions(+), 17 deletions(-)
+
+diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
+index dc030551cac13..5c003a0f0fe5b 100644
+--- a/net/mptcp/protocol.c
++++ b/net/mptcp/protocol.c
+@@ -3397,12 +3397,12 @@ static void mptcp_release_cb(struct sock *sk)
+       if (__test_and_clear_bit(MPTCP_CLEAN_UNA, &msk->cb_flags))
+               __mptcp_clean_una_wakeup(sk);
+       if (unlikely(msk->cb_flags)) {
+-              /* be sure to set the current sk state before taking actions
++              /* be sure to sync the msk state before taking actions
+                * depending on sk_state (MPTCP_ERROR_REPORT)
+                * On sk release avoid actions depending on the first subflow
+                */
+-              if (__test_and_clear_bit(MPTCP_CONNECTED, &msk->cb_flags) && msk->first)
+-                      __mptcp_set_connected(sk);
++              if (__test_and_clear_bit(MPTCP_SYNC_STATE, &msk->cb_flags) && msk->first)
++                      __mptcp_sync_state(sk, msk->pending_state);
+               if (__test_and_clear_bit(MPTCP_ERROR_REPORT, &msk->cb_flags))
+                       __mptcp_error_report(sk);
+               if (__test_and_clear_bit(MPTCP_SYNC_SNDBUF, &msk->cb_flags))
+diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
+index 40866acd91ad5..07c5ac37d092b 100644
+--- a/net/mptcp/protocol.h
++++ b/net/mptcp/protocol.h
+@@ -122,7 +122,7 @@
+ #define MPTCP_ERROR_REPORT    3
+ #define MPTCP_RETRANSMIT      4
+ #define MPTCP_FLUSH_JOIN_LIST 5
+-#define MPTCP_CONNECTED               6
++#define MPTCP_SYNC_STATE      6
+ #define MPTCP_SYNC_SNDBUF     7
+ struct mptcp_skb_cb {
+@@ -293,6 +293,9 @@ struct mptcp_sock {
+       bool            use_64bit_ack; /* Set when we received a 64-bit DSN */
+       bool            csum_enabled;
+       bool            allow_infinite_fallback;
++      u8              pending_state; /* A subflow asked to set this sk_state,
++                                      * protected by the msk data lock
++                                      */
+       u8              mpc_endpoint_id;
+       u8              recvmsg_inq:1,
+                       cork:1,
+@@ -711,7 +714,7 @@ void mptcp_get_options(const struct sk_buff *skb,
+                      struct mptcp_options_received *mp_opt);
+ void mptcp_finish_connect(struct sock *sk);
+-void __mptcp_set_connected(struct sock *sk);
++void __mptcp_sync_state(struct sock *sk, int state);
+ void mptcp_reset_tout_timer(struct mptcp_sock *msk, unsigned long fail_tout);
+ static inline void mptcp_stop_tout_timer(struct sock *sk)
+@@ -1101,7 +1104,7 @@ static inline bool subflow_simultaneous_connect(struct sock *sk)
+ {
+       struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
+-      return sk->sk_state == TCP_ESTABLISHED &&
++      return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_FIN_WAIT1) &&
+              is_active_ssk(subflow) &&
+              !subflow->conn_finished;
+ }
+diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
+index d8827427ffc84..f3a1e4aa0e5eb 100644
+--- a/net/mptcp/subflow.c
++++ b/net/mptcp/subflow.c
+@@ -419,22 +419,28 @@ static bool subflow_use_different_dport(struct mptcp_sock *msk, const struct soc
+       return inet_sk(sk)->inet_dport != inet_sk((struct sock *)msk)->inet_dport;
+ }
+-void __mptcp_set_connected(struct sock *sk)
++void __mptcp_sync_state(struct sock *sk, int state)
+ {
+-      __mptcp_propagate_sndbuf(sk, mptcp_sk(sk)->first);
++      struct mptcp_sock *msk = mptcp_sk(sk);
++
++      __mptcp_propagate_sndbuf(sk, msk->first);
+       if (sk->sk_state == TCP_SYN_SENT) {
+-              inet_sk_state_store(sk, TCP_ESTABLISHED);
++              inet_sk_state_store(sk, state);
+               sk->sk_state_change(sk);
+       }
+ }
+-static void mptcp_set_connected(struct sock *sk)
++static void mptcp_propagate_state(struct sock *sk, struct sock *ssk)
+ {
++      struct mptcp_sock *msk = mptcp_sk(sk);
++
+       mptcp_data_lock(sk);
+-      if (!sock_owned_by_user(sk))
+-              __mptcp_set_connected(sk);
+-      else
+-              __set_bit(MPTCP_CONNECTED, &mptcp_sk(sk)->cb_flags);
++      if (!sock_owned_by_user(sk)) {
++              __mptcp_sync_state(sk, ssk->sk_state);
++      } else {
++              msk->pending_state = ssk->sk_state;
++              __set_bit(MPTCP_SYNC_STATE, &msk->cb_flags);
++      }
+       mptcp_data_unlock(sk);
+ }
+@@ -496,7 +502,7 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
+               subflow_set_remote_key(msk, subflow, &mp_opt);
+               MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPCAPABLEACTIVEACK);
+               mptcp_finish_connect(sk);
+-              mptcp_set_connected(parent);
++              mptcp_propagate_state(parent, sk);
+       } else if (subflow->request_join) {
+               u8 hmac[SHA256_DIGEST_SIZE];
+@@ -540,7 +546,7 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
+       } else if (mptcp_check_fallback(sk)) {
+ fallback:
+               mptcp_rcv_space_init(msk, sk);
+-              mptcp_set_connected(parent);
++              mptcp_propagate_state(parent, sk);
+       }
+       return;
+@@ -1732,7 +1738,7 @@ static void subflow_state_change(struct sock *sk)
+               mptcp_rcv_space_init(msk, sk);
+               pr_fallback(msk);
+               subflow->conn_finished = 1;
+-              mptcp_set_connected(parent);
++              mptcp_propagate_state(parent, sk);
+       }
+       /* as recvmsg() does not acquire the subflow socket for ssk selection
+-- 
+2.43.0
+
diff --git a/queue-6.6/mptcp-fix-possible-null-pointer-dereference-on-close.patch b/queue-6.6/mptcp-fix-possible-null-pointer-dereference-on-close.patch
new file mode 100644 (file)
index 0000000..27a2dc7
--- /dev/null
@@ -0,0 +1,110 @@
+From 4af5540db7fecce388dcf27be65e4d510fc7aafb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 14 Nov 2023 00:16:14 +0100
+Subject: mptcp: fix possible NULL pointer dereference on close
+
+From: Paolo Abeni <pabeni@redhat.com>
+
+[ Upstream commit d109a7767273d1706b541c22b83a0323823dfde4 ]
+
+After the blamed commit below, the MPTCP release callback can
+dereference the first subflow pointer via __mptcp_set_connected()
+and send buffer auto-tuning. Such pointer is always expected to be
+valid, except at socket destruction time, when the first subflow is
+deleted and the pointer zeroed.
+
+If the connect event is handled by the release callback while the
+msk socket is finally released, MPTCP hits the following splat:
+
+  general protection fault, probably for non-canonical address 0xdffffc00000000f2: 0000 [#1] PREEMPT SMP KASAN
+  KASAN: null-ptr-deref in range [0x0000000000000790-0x0000000000000797]
+  CPU: 1 PID: 26719 Comm: syz-executor.2 Not tainted 6.6.0-syzkaller-10102-gff269e2cd5ad #0
+  Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/09/2023
+  RIP: 0010:mptcp_subflow_ctx net/mptcp/protocol.h:542 [inline]
+  RIP: 0010:__mptcp_propagate_sndbuf net/mptcp/protocol.h:813 [inline]
+  RIP: 0010:__mptcp_set_connected+0x57/0x3e0 net/mptcp/subflow.c:424
+  RAX: dffffc0000000000 RBX: 0000000000000000 RCX: ffffffff8a62323c
+  RDX: 00000000000000f2 RSI: ffffffff8a630116 RDI: 0000000000000790
+  RBP: ffff88803334b100 R08: 0000000000000001 R09: 0000000000000000
+  R10: 0000000000000001 R11: 0000000000000034 R12: ffff88803334b198
+  R13: ffff888054f0b018 R14: 0000000000000000 R15: ffff88803334b100
+  FS:  0000000000000000(0000) GS:ffff8880b9900000(0000) knlGS:0000000000000000
+  CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+  CR2: 00007fbcb4f75198 CR3: 000000006afb5000 CR4: 00000000003506f0
+  DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+  DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+  Call Trace:
+   <TASK>
+   mptcp_release_cb+0xa2c/0xc40 net/mptcp/protocol.c:3405
+   release_sock+0xba/0x1f0 net/core/sock.c:3537
+   mptcp_close+0x32/0xf0 net/mptcp/protocol.c:3084
+   inet_release+0x132/0x270 net/ipv4/af_inet.c:433
+   inet6_release+0x4f/0x70 net/ipv6/af_inet6.c:485
+   __sock_release+0xae/0x260 net/socket.c:659
+   sock_close+0x1c/0x20 net/socket.c:1419
+   __fput+0x270/0xbb0 fs/file_table.c:394
+   task_work_run+0x14d/0x240 kernel/task_work.c:180
+   exit_task_work include/linux/task_work.h:38 [inline]
+   do_exit+0xa92/0x2a20 kernel/exit.c:876
+   do_group_exit+0xd4/0x2a0 kernel/exit.c:1026
+   get_signal+0x23ba/0x2790 kernel/signal.c:2900
+   arch_do_signal_or_restart+0x90/0x7f0 arch/x86/kernel/signal.c:309
+   exit_to_user_mode_loop kernel/entry/common.c:168 [inline]
+   exit_to_user_mode_prepare+0x11f/0x240 kernel/entry/common.c:204
+   __syscall_exit_to_user_mode_work kernel/entry/common.c:285 [inline]
+   syscall_exit_to_user_mode+0x1d/0x60 kernel/entry/common.c:296
+   do_syscall_64+0x4b/0x110 arch/x86/entry/common.c:88
+   entry_SYSCALL_64_after_hwframe+0x63/0x6b
+  RIP: 0033:0x7fb515e7cae9
+  Code: Unable to access opcode bytes at 0x7fb515e7cabf.
+  RSP: 002b:00007fb516c560c8 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
+  RAX: 000000000000003c RBX: 00007fb515f9c120 RCX: 00007fb515e7cae9
+  RDX: 0000000000000000 RSI: 0000000020000140 RDI: 0000000000000006
+  RBP: 00007fb515ec847a R08: 0000000000000000 R09: 0000000000000000
+  R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
+  R13: 000000000000006e R14: 00007fb515f9c120 R15: 00007ffc631eb968
+   </TASK>
+
+To avoid sparkling unneeded conditionals, address the issue explicitly
+checking msk->first only in the critical place.
+
+Fixes: 8005184fd1ca ("mptcp: refactor sndbuf auto-tuning")
+Cc: stable@vger.kernel.org
+Reported-by: <syzbot+9dfbaedb6e6baca57a32@syzkaller.appspotmail.com>
+Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/454
+Reported-by: Eric Dumazet <edumazet@google.com>
+Closes: https://lore.kernel.org/netdev/CANn89iLZUA6S2a=K8GObnS62KK6Jt4B7PsAs7meMFooM8xaTgw@mail.gmail.com/
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Signed-off-by: Matthieu Baerts <matttbe@kernel.org>
+Link: https://lore.kernel.org/r/20231114-upstream-net-20231113-mptcp-misc-fixes-6-7-rc2-v1-2-7b9cd6a7b7f4@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 4fd19a307016 ("mptcp: fix inconsistent state on fastopen race")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mptcp/protocol.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
+index 44499e49d76e6..dc030551cac13 100644
+--- a/net/mptcp/protocol.c
++++ b/net/mptcp/protocol.c
+@@ -3397,10 +3397,11 @@ static void mptcp_release_cb(struct sock *sk)
+       if (__test_and_clear_bit(MPTCP_CLEAN_UNA, &msk->cb_flags))
+               __mptcp_clean_una_wakeup(sk);
+       if (unlikely(msk->cb_flags)) {
+-              /* be sure to set the current sk state before tacking actions
+-               * depending on sk_state, that is processing MPTCP_ERROR_REPORT
++              /* be sure to set the current sk state before taking actions
++               * depending on sk_state (MPTCP_ERROR_REPORT)
++               * On sk release avoid actions depending on the first subflow
+                */
+-              if (__test_and_clear_bit(MPTCP_CONNECTED, &msk->cb_flags))
++              if (__test_and_clear_bit(MPTCP_CONNECTED, &msk->cb_flags) && msk->first)
+                       __mptcp_set_connected(sk);
+               if (__test_and_clear_bit(MPTCP_ERROR_REPORT, &msk->cb_flags))
+                       __mptcp_error_report(sk);
+-- 
+2.43.0
+
diff --git a/queue-6.6/mptcp-refactor-sndbuf-auto-tuning.patch b/queue-6.6/mptcp-refactor-sndbuf-auto-tuning.patch
new file mode 100644 (file)
index 0000000..18cd632
--- /dev/null
@@ -0,0 +1,257 @@
+From ce42391e5377ff68cfc85036666147da9f2521ae Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 23 Oct 2023 13:44:42 -0700
+Subject: mptcp: refactor sndbuf auto-tuning
+
+From: Paolo Abeni <pabeni@redhat.com>
+
+[ Upstream commit 8005184fd1ca6aeb3fea36f4eb9463fc1b90c114 ]
+
+The MPTCP protocol account for the data enqueued on all the subflows
+to the main socket send buffer, while the send buffer auto-tuning
+algorithm set the main socket send buffer size as the max size among
+the subflows.
+
+That causes bad performances when at least one subflow is sndbuf
+limited, e.g. due to very high latency, as the MPTCP scheduler can't
+even fill such buffer.
+
+Change the send-buffer auto-tuning algorithm to compute the main socket
+send buffer size as the sum of all the subflows buffer size.
+
+Reviewed-by: Mat Martineau <martineau@kernel.org>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Mat Martineau <martineau@kernel.org>
+Link: https://lore.kernel.org/r/20231023-send-net-next-20231023-2-v1-9-9dc60939d371@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 4fd19a307016 ("mptcp: fix inconsistent state on fastopen race")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mptcp/protocol.c | 18 +++++++++++++--
+ net/mptcp/protocol.h | 54 ++++++++++++++++++++++++++++++++++++++++----
+ net/mptcp/sockopt.c  |  5 +++-
+ net/mptcp/subflow.c  |  3 +--
+ 4 files changed, 70 insertions(+), 10 deletions(-)
+
+diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
+index c1527f520dce3..44499e49d76e6 100644
+--- a/net/mptcp/protocol.c
++++ b/net/mptcp/protocol.c
+@@ -893,6 +893,7 @@ static bool __mptcp_finish_join(struct mptcp_sock *msk, struct sock *ssk)
+       mptcp_sockopt_sync_locked(msk, ssk);
+       mptcp_subflow_joined(msk, ssk);
+       mptcp_stop_tout_timer(sk);
++      __mptcp_propagate_sndbuf(sk, ssk);
+       return true;
+ }
+@@ -1079,15 +1080,16 @@ static void mptcp_enter_memory_pressure(struct sock *sk)
+       struct mptcp_sock *msk = mptcp_sk(sk);
+       bool first = true;
+-      sk_stream_moderate_sndbuf(sk);
+       mptcp_for_each_subflow(msk, subflow) {
+               struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
+               if (first)
+                       tcp_enter_memory_pressure(ssk);
+               sk_stream_moderate_sndbuf(ssk);
++
+               first = false;
+       }
++      __mptcp_sync_sndbuf(sk);
+ }
+ /* ensure we get enough memory for the frag hdr, beyond some minimal amount of
+@@ -2452,6 +2454,7 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
+               WRITE_ONCE(msk->first, NULL);
+ out:
++      __mptcp_sync_sndbuf(sk);
+       if (need_push)
+               __mptcp_push_pending(sk, 0);
+@@ -3223,7 +3226,7 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
+        * uses the correct data
+        */
+       mptcp_copy_inaddrs(nsk, ssk);
+-      mptcp_propagate_sndbuf(nsk, ssk);
++      __mptcp_propagate_sndbuf(nsk, ssk);
+       mptcp_rcv_space_init(msk, ssk);
+       bh_unlock_sock(nsk);
+@@ -3401,6 +3404,8 @@ static void mptcp_release_cb(struct sock *sk)
+                       __mptcp_set_connected(sk);
+               if (__test_and_clear_bit(MPTCP_ERROR_REPORT, &msk->cb_flags))
+                       __mptcp_error_report(sk);
++              if (__test_and_clear_bit(MPTCP_SYNC_SNDBUF, &msk->cb_flags))
++                      __mptcp_sync_sndbuf(sk);
+       }
+       __mptcp_update_rmem(sk);
+@@ -3445,6 +3450,14 @@ void mptcp_subflow_process_delegated(struct sock *ssk, long status)
+                       __set_bit(MPTCP_PUSH_PENDING, &mptcp_sk(sk)->cb_flags);
+               mptcp_data_unlock(sk);
+       }
++      if (status & BIT(MPTCP_DELEGATE_SNDBUF)) {
++              mptcp_data_lock(sk);
++              if (!sock_owned_by_user(sk))
++                      __mptcp_sync_sndbuf(sk);
++              else
++                      __set_bit(MPTCP_SYNC_SNDBUF, &mptcp_sk(sk)->cb_flags);
++              mptcp_data_unlock(sk);
++      }
+       if (status & BIT(MPTCP_DELEGATE_ACK))
+               schedule_3rdack_retransmission(ssk);
+ }
+@@ -3529,6 +3542,7 @@ bool mptcp_finish_join(struct sock *ssk)
+       /* active subflow, already present inside the conn_list */
+       if (!list_empty(&subflow->node)) {
+               mptcp_subflow_joined(msk, ssk);
++              mptcp_propagate_sndbuf(parent, ssk);
+               return true;
+       }
+diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
+index 3612545fa62e0..40866acd91ad5 100644
+--- a/net/mptcp/protocol.h
++++ b/net/mptcp/protocol.h
+@@ -123,6 +123,7 @@
+ #define MPTCP_RETRANSMIT      4
+ #define MPTCP_FLUSH_JOIN_LIST 5
+ #define MPTCP_CONNECTED               6
++#define MPTCP_SYNC_SNDBUF     7
+ struct mptcp_skb_cb {
+       u64 map_seq;
+@@ -447,6 +448,7 @@ DECLARE_PER_CPU(struct mptcp_delegated_action, mptcp_delegated_actions);
+ #define MPTCP_DELEGATE_SCHEDULED      0
+ #define MPTCP_DELEGATE_SEND           1
+ #define MPTCP_DELEGATE_ACK            2
++#define MPTCP_DELEGATE_SNDBUF         3
+ #define MPTCP_DELEGATE_ACTIONS_MASK   (~BIT(MPTCP_DELEGATE_SCHEDULED))
+ /* MPTCP subflow context */
+@@ -520,6 +522,9 @@ struct mptcp_subflow_context {
+       u32     setsockopt_seq;
+       u32     stale_rcv_tstamp;
++      int     cached_sndbuf;      /* sndbuf size when last synced with the msk sndbuf,
++                                   * protected by the msk socket lock
++                                   */
+       struct  sock *tcp_sock;     /* tcp sk backpointer */
+       struct  sock *conn;         /* parent mptcp_sock */
+@@ -762,13 +767,52 @@ static inline bool mptcp_data_fin_enabled(const struct mptcp_sock *msk)
+              READ_ONCE(msk->write_seq) == READ_ONCE(msk->snd_nxt);
+ }
+-static inline bool mptcp_propagate_sndbuf(struct sock *sk, struct sock *ssk)
++static inline void __mptcp_sync_sndbuf(struct sock *sk)
+ {
+-      if ((sk->sk_userlocks & SOCK_SNDBUF_LOCK) || ssk->sk_sndbuf <= READ_ONCE(sk->sk_sndbuf))
+-              return false;
++      struct mptcp_subflow_context *subflow;
++      int ssk_sndbuf, new_sndbuf;
++
++      if (sk->sk_userlocks & SOCK_SNDBUF_LOCK)
++              return;
++
++      new_sndbuf = sock_net(sk)->ipv4.sysctl_tcp_wmem[0];
++      mptcp_for_each_subflow(mptcp_sk(sk), subflow) {
++              ssk_sndbuf =  READ_ONCE(mptcp_subflow_tcp_sock(subflow)->sk_sndbuf);
++
++              subflow->cached_sndbuf = ssk_sndbuf;
++              new_sndbuf += ssk_sndbuf;
++      }
++
++      /* the msk max wmem limit is <nr_subflows> * tcp wmem[2] */
++      WRITE_ONCE(sk->sk_sndbuf, new_sndbuf);
++}
++
++/* The called held both the msk socket and the subflow socket locks,
++ * possibly under BH
++ */
++static inline void __mptcp_propagate_sndbuf(struct sock *sk, struct sock *ssk)
++{
++      struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
++
++      if (READ_ONCE(ssk->sk_sndbuf) != subflow->cached_sndbuf)
++              __mptcp_sync_sndbuf(sk);
++}
++
++/* the caller held only the subflow socket lock, either in process or
++ * BH context. Additionally this can be called under the msk data lock,
++ * so we can't acquire such lock here: let the delegate action acquires
++ * the needed locks in suitable order.
++ */
++static inline void mptcp_propagate_sndbuf(struct sock *sk, struct sock *ssk)
++{
++      struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
++
++      if (likely(READ_ONCE(ssk->sk_sndbuf) == subflow->cached_sndbuf))
++              return;
+-      WRITE_ONCE(sk->sk_sndbuf, ssk->sk_sndbuf);
+-      return true;
++      local_bh_disable();
++      mptcp_subflow_delegate(subflow, MPTCP_DELEGATE_SNDBUF);
++      local_bh_enable();
+ }
+ static inline void mptcp_write_space(struct sock *sk)
+diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
+index 7539b9c8c2fb4..116e3008231bd 100644
+--- a/net/mptcp/sockopt.c
++++ b/net/mptcp/sockopt.c
+@@ -95,6 +95,7 @@ static void mptcp_sol_socket_sync_intval(struct mptcp_sock *msk, int optname, in
+               case SO_SNDBUFFORCE:
+                       ssk->sk_userlocks |= SOCK_SNDBUF_LOCK;
+                       WRITE_ONCE(ssk->sk_sndbuf, sk->sk_sndbuf);
++                      mptcp_subflow_ctx(ssk)->cached_sndbuf = sk->sk_sndbuf;
+                       break;
+               case SO_RCVBUF:
+               case SO_RCVBUFFORCE:
+@@ -1418,8 +1419,10 @@ static void sync_socket_options(struct mptcp_sock *msk, struct sock *ssk)
+       if (sk->sk_userlocks & tx_rx_locks) {
+               ssk->sk_userlocks |= sk->sk_userlocks & tx_rx_locks;
+-              if (sk->sk_userlocks & SOCK_SNDBUF_LOCK)
++              if (sk->sk_userlocks & SOCK_SNDBUF_LOCK) {
+                       WRITE_ONCE(ssk->sk_sndbuf, sk->sk_sndbuf);
++                      mptcp_subflow_ctx(ssk)->cached_sndbuf = sk->sk_sndbuf;
++              }
+               if (sk->sk_userlocks & SOCK_RCVBUF_LOCK)
+                       WRITE_ONCE(ssk->sk_rcvbuf, sk->sk_rcvbuf);
+       }
+diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
+index 9c1f8d1d63d24..d8827427ffc84 100644
+--- a/net/mptcp/subflow.c
++++ b/net/mptcp/subflow.c
+@@ -421,6 +421,7 @@ static bool subflow_use_different_dport(struct mptcp_sock *msk, const struct soc
+ void __mptcp_set_connected(struct sock *sk)
+ {
++      __mptcp_propagate_sndbuf(sk, mptcp_sk(sk)->first);
+       if (sk->sk_state == TCP_SYN_SENT) {
+               inet_sk_state_store(sk, TCP_ESTABLISHED);
+               sk->sk_state_change(sk);
+@@ -472,7 +473,6 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
+               return;
+       msk = mptcp_sk(parent);
+-      mptcp_propagate_sndbuf(parent, sk);
+       subflow->rel_write_seq = 1;
+       subflow->conn_finished = 1;
+       subflow->ssn_offset = TCP_SKB_CB(skb)->seq;
+@@ -1728,7 +1728,6 @@ static void subflow_state_change(struct sock *sk)
+       msk = mptcp_sk(parent);
+       if (subflow_simultaneous_connect(sk)) {
+-              mptcp_propagate_sndbuf(parent, sk);
+               mptcp_do_fallback(sk);
+               mptcp_rcv_space_init(msk, sk);
+               pr_fallback(msk);
+-- 
+2.43.0
+
diff --git a/queue-6.6/platform-x86-intel-pmc-add-suspend-callback.patch b/queue-6.6/platform-x86-intel-pmc-add-suspend-callback.patch
new file mode 100644 (file)
index 0000000..d6ffab8
--- /dev/null
@@ -0,0 +1,67 @@
+From 79b097974109b091a3d1c63d6d0e20f17f9496f0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Dec 2023 19:25:43 -0800
+Subject: platform/x86/intel/pmc: Add suspend callback
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: David E. Box <david.e.box@linux.intel.com>
+
+[ Upstream commit 7c13f365aee68b01e7e68ee293a71fdc7571c111 ]
+
+Add a suspend callback to struct pmc for performing platform specific tasks
+before device suspend. This is needed in order to perform GBE LTR ignore on
+certain platforms at suspend-time instead of at probe-time and replace the
+GBE LTR ignore removal that was done in order to fix a bug introduced by
+commit 804951203aa5 ("platform/x86:intel/pmc: Combine core_init() and
+core_configure()").
+
+Fixes: 804951203aa5 ("platform/x86:intel/pmc: Combine core_init() and core_configure()")
+Signed-off-by: "David E. Box" <david.e.box@linux.intel.com>
+Link: https://lore.kernel.org/r/20231223032548.1680738-4-david.e.box@linux.intel.com
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/intel/pmc/core.c | 3 +++
+ drivers/platform/x86/intel/pmc/core.h | 2 ++
+ 2 files changed, 5 insertions(+)
+
+diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c
+index e95d3011b9997..5ab470d87ad7e 100644
+--- a/drivers/platform/x86/intel/pmc/core.c
++++ b/drivers/platform/x86/intel/pmc/core.c
+@@ -1279,6 +1279,9 @@ static __maybe_unused int pmc_core_suspend(struct device *dev)
+       struct pmc_dev *pmcdev = dev_get_drvdata(dev);
+       struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
++      if (pmcdev->suspend)
++              pmcdev->suspend(pmcdev);
++
+       /* Check if the syspend will actually use S0ix */
+       if (pm_suspend_via_firmware())
+               return 0;
+diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h
+index 0729f593c6a75..38d888e3afa63 100644
+--- a/drivers/platform/x86/intel/pmc/core.h
++++ b/drivers/platform/x86/intel/pmc/core.h
+@@ -363,6 +363,7 @@ struct pmc {
+  * @s0ix_counter:     S0ix residency (step adjusted)
+  * @num_lpm_modes:    Count of enabled modes
+  * @lpm_en_modes:     Array of enabled modes from lowest to highest priority
++ * @suspend:          Function to perform platform specific suspend
+  * @resume:           Function to perform platform specific resume
+  *
+  * pmc_dev contains info about power management controller device.
+@@ -379,6 +380,7 @@ struct pmc_dev {
+       u64 s0ix_counter;
+       int num_lpm_modes;
+       int lpm_en_modes[LPM_MAX_NUM_MODES];
++      void (*suspend)(struct pmc_dev *pmcdev);
+       int (*resume)(struct pmc_dev *pmcdev);
+       bool has_die_c6;
+-- 
+2.43.0
+
diff --git a/queue-6.6/platform-x86-intel-pmc-allow-reenabling-ltrs.patch b/queue-6.6/platform-x86-intel-pmc-allow-reenabling-ltrs.patch
new file mode 100644 (file)
index 0000000..3ec5bde
--- /dev/null
@@ -0,0 +1,136 @@
+From 72d419cf0c408c480966ff3cf654403bd9441594 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Dec 2023 19:25:44 -0800
+Subject: platform/x86/intel/pmc: Allow reenabling LTRs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: David E. Box <david.e.box@linux.intel.com>
+
+[ Upstream commit 6f9cc5c1f94daa98846b2073733d03ced709704b ]
+
+Commit 804951203aa5 ("platform/x86:intel/pmc: Combine core_init() and
+core_configure()") caused a network performance regression due to the GBE
+LTR ignore that it added during probe. The fix will move the ignore to
+occur at suspend-time (so as to not affect suspend power). This will
+require the ability to enable the LTR again on resume. Modify
+pmc_core_send_ltr_ignore() to allow enabling an LTR.
+
+Fixes: 804951203aa5 ("platform/x86:intel/pmc: Combine core_init() and core_configure()")
+Signed-off-by: "David E. Box" <david.e.box@linux.intel.com>
+Link: https://lore.kernel.org/r/20231223032548.1680738-5-david.e.box@linux.intel.com
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/intel/pmc/adl.c  | 2 +-
+ drivers/platform/x86/intel/pmc/cnp.c  | 2 +-
+ drivers/platform/x86/intel/pmc/core.c | 9 ++++++---
+ drivers/platform/x86/intel/pmc/core.h | 2 +-
+ drivers/platform/x86/intel/pmc/mtl.c  | 2 +-
+ drivers/platform/x86/intel/pmc/tgl.c  | 2 +-
+ 6 files changed, 11 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/platform/x86/intel/pmc/adl.c b/drivers/platform/x86/intel/pmc/adl.c
+index 5006008e01bea..a887c388cf16d 100644
+--- a/drivers/platform/x86/intel/pmc/adl.c
++++ b/drivers/platform/x86/intel/pmc/adl.c
+@@ -323,7 +323,7 @@ int adl_core_init(struct pmc_dev *pmcdev)
+        * when a cable is attached. Tell the PMC to ignore it.
+        */
+       dev_dbg(&pmcdev->pdev->dev, "ignoring GBE LTR\n");
+-      pmc_core_send_ltr_ignore(pmcdev, 3);
++      pmc_core_send_ltr_ignore(pmcdev, 3, 1);
+       return 0;
+ }
+diff --git a/drivers/platform/x86/intel/pmc/cnp.c b/drivers/platform/x86/intel/pmc/cnp.c
+index 420aaa1d7c769..10498204962cd 100644
+--- a/drivers/platform/x86/intel/pmc/cnp.c
++++ b/drivers/platform/x86/intel/pmc/cnp.c
+@@ -218,7 +218,7 @@ int cnp_core_init(struct pmc_dev *pmcdev)
+        * when a cable is attached. Tell the PMC to ignore it.
+        */
+       dev_dbg(&pmcdev->pdev->dev, "ignoring GBE LTR\n");
+-      pmc_core_send_ltr_ignore(pmcdev, 3);
++      pmc_core_send_ltr_ignore(pmcdev, 3, 1);
+       return 0;
+ }
+diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c
+index 5ab470d87ad7e..022afb97d531c 100644
+--- a/drivers/platform/x86/intel/pmc/core.c
++++ b/drivers/platform/x86/intel/pmc/core.c
+@@ -460,7 +460,7 @@ static int pmc_core_pll_show(struct seq_file *s, void *unused)
+ }
+ DEFINE_SHOW_ATTRIBUTE(pmc_core_pll);
+-int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value)
++int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore)
+ {
+       struct pmc *pmc;
+       const struct pmc_reg_map *map;
+@@ -498,7 +498,10 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value)
+       mutex_lock(&pmcdev->lock);
+       reg = pmc_core_reg_read(pmc, map->ltr_ignore_offset);
+-      reg |= BIT(ltr_index);
++      if (ignore)
++              reg |= BIT(ltr_index);
++      else
++              reg &= ~BIT(ltr_index);
+       pmc_core_reg_write(pmc, map->ltr_ignore_offset, reg);
+       mutex_unlock(&pmcdev->lock);
+@@ -521,7 +524,7 @@ static ssize_t pmc_core_ltr_ignore_write(struct file *file,
+       if (err)
+               return err;
+-      err = pmc_core_send_ltr_ignore(pmcdev, value);
++      err = pmc_core_send_ltr_ignore(pmcdev, value, 1);
+       return err == 0 ? count : err;
+ }
+diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h
+index 38d888e3afa63..71ba7d691d691 100644
+--- a/drivers/platform/x86/intel/pmc/core.h
++++ b/drivers/platform/x86/intel/pmc/core.h
+@@ -488,7 +488,7 @@ extern const struct pmc_bit_map *mtl_ioem_lpm_maps[];
+ extern const struct pmc_reg_map mtl_ioem_reg_map;
+ extern void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev);
+-extern int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value);
++int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore);
+ int pmc_core_resume_common(struct pmc_dev *pmcdev);
+ int get_primary_reg_base(struct pmc *pmc);
+diff --git a/drivers/platform/x86/intel/pmc/mtl.c b/drivers/platform/x86/intel/pmc/mtl.c
+index 2204bc666980e..71dc11811e112 100644
+--- a/drivers/platform/x86/intel/pmc/mtl.c
++++ b/drivers/platform/x86/intel/pmc/mtl.c
+@@ -1006,7 +1006,7 @@ int mtl_core_init(struct pmc_dev *pmcdev)
+        * when a cable is attached. Tell the PMC to ignore it.
+        */
+       dev_dbg(&pmcdev->pdev->dev, "ignoring GBE LTR\n");
+-      pmc_core_send_ltr_ignore(pmcdev, 3);
++      pmc_core_send_ltr_ignore(pmcdev, 3, 1);
+       return 0;
+ }
+diff --git a/drivers/platform/x86/intel/pmc/tgl.c b/drivers/platform/x86/intel/pmc/tgl.c
+index 2449940102db4..078263db24c7a 100644
+--- a/drivers/platform/x86/intel/pmc/tgl.c
++++ b/drivers/platform/x86/intel/pmc/tgl.c
+@@ -268,7 +268,7 @@ int tgl_core_init(struct pmc_dev *pmcdev)
+        * when a cable is attached. Tell the PMC to ignore it.
+        */
+       dev_dbg(&pmcdev->pdev->dev, "ignoring GBE LTR\n");
+-      pmc_core_send_ltr_ignore(pmcdev, 3);
++      pmc_core_send_ltr_ignore(pmcdev, 3, 1);
+       return 0;
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.6/platform-x86-intel-pmc-move-gbe-ltr-ignore-to-suspen.patch b/queue-6.6/platform-x86-intel-pmc-move-gbe-ltr-ignore-to-suspen.patch
new file mode 100644 (file)
index 0000000..23b1fc4
--- /dev/null
@@ -0,0 +1,180 @@
+From 135d53f78f786a4e22862e1a5c418a96206048e3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Dec 2023 19:25:45 -0800
+Subject: platform/x86/intel/pmc: Move GBE LTR ignore to suspend callback
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: David E. Box <david.e.box@linux.intel.com>
+
+[ Upstream commit 70681aa0746ae61d7668b9f651221fad5e30c71e ]
+
+Commit 804951203aa5 ("platform/x86:intel/pmc: Combine core_init() and
+core_configure()") caused a network performance regression due to the GBE
+LTR ignore that it added at probe. This was needed in order to allow the
+SoC to enter the deepest Package C state. To fix the regression and at
+least support PC10 during suspend, move the LTR ignore from probe to the
+suspend callback, and enable it again on resume. This solution will allow
+PC10 during suspend but restrict Package C entry at runtime to no deeper
+than PC8/9 while a network cable it attach to the PCH LAN.
+
+Fixes: 804951203aa5 ("platform/x86:intel/pmc: Combine core_init() and core_configure()")
+Signed-off-by: "David E. Box" <david.e.box@linux.intel.com>
+Link: https://lore.kernel.org/r/20231223032548.1680738-6-david.e.box@linux.intel.com
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/intel/pmc/adl.c  |  9 +++------
+ drivers/platform/x86/intel/pmc/cnp.c  | 26 ++++++++++++++++++++------
+ drivers/platform/x86/intel/pmc/core.h |  3 +++
+ drivers/platform/x86/intel/pmc/mtl.c  |  9 +++------
+ drivers/platform/x86/intel/pmc/tgl.c  |  9 ++++-----
+ 5 files changed, 33 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/platform/x86/intel/pmc/adl.c b/drivers/platform/x86/intel/pmc/adl.c
+index a887c388cf16d..606f7678bcb0a 100644
+--- a/drivers/platform/x86/intel/pmc/adl.c
++++ b/drivers/platform/x86/intel/pmc/adl.c
+@@ -314,16 +314,13 @@ int adl_core_init(struct pmc_dev *pmcdev)
+       struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
+       int ret;
++      pmcdev->suspend = cnl_suspend;
++      pmcdev->resume = cnl_resume;
++
+       pmc->map = &adl_reg_map;
+       ret = get_primary_reg_base(pmc);
+       if (ret)
+               return ret;
+-      /* Due to a hardware limitation, the GBE LTR blocks PC10
+-       * when a cable is attached. Tell the PMC to ignore it.
+-       */
+-      dev_dbg(&pmcdev->pdev->dev, "ignoring GBE LTR\n");
+-      pmc_core_send_ltr_ignore(pmcdev, 3, 1);
+-
+       return 0;
+ }
+diff --git a/drivers/platform/x86/intel/pmc/cnp.c b/drivers/platform/x86/intel/pmc/cnp.c
+index 10498204962cd..98b36651201a0 100644
+--- a/drivers/platform/x86/intel/pmc/cnp.c
++++ b/drivers/platform/x86/intel/pmc/cnp.c
+@@ -204,21 +204,35 @@ const struct pmc_reg_map cnp_reg_map = {
+       .etr3_offset = ETR3_OFFSET,
+ };
++void cnl_suspend(struct pmc_dev *pmcdev)
++{
++      /*
++       * Due to a hardware limitation, the GBE LTR blocks PC10
++       * when a cable is attached. To unblock PC10 during suspend,
++       * tell the PMC to ignore it.
++       */
++      pmc_core_send_ltr_ignore(pmcdev, 3, 1);
++}
++
++int cnl_resume(struct pmc_dev *pmcdev)
++{
++      pmc_core_send_ltr_ignore(pmcdev, 3, 0);
++
++      return pmc_core_resume_common(pmcdev);
++}
++
+ int cnp_core_init(struct pmc_dev *pmcdev)
+ {
+       struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
+       int ret;
++      pmcdev->suspend = cnl_suspend;
++      pmcdev->resume = cnl_resume;
++
+       pmc->map = &cnp_reg_map;
+       ret = get_primary_reg_base(pmc);
+       if (ret)
+               return ret;
+-      /* Due to a hardware limitation, the GBE LTR blocks PC10
+-       * when a cable is attached. Tell the PMC to ignore it.
+-       */
+-      dev_dbg(&pmcdev->pdev->dev, "ignoring GBE LTR\n");
+-      pmc_core_send_ltr_ignore(pmcdev, 3, 1);
+-
+       return 0;
+ }
+diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h
+index 71ba7d691d691..b66dacbfb94bf 100644
+--- a/drivers/platform/x86/intel/pmc/core.h
++++ b/drivers/platform/x86/intel/pmc/core.h
+@@ -502,6 +502,9 @@ int tgl_core_init(struct pmc_dev *pmcdev);
+ int adl_core_init(struct pmc_dev *pmcdev);
+ int mtl_core_init(struct pmc_dev *pmcdev);
++void cnl_suspend(struct pmc_dev *pmcdev);
++int cnl_resume(struct pmc_dev *pmcdev);
++
+ #define pmc_for_each_mode(i, mode, pmcdev)            \
+       for (i = 0, mode = pmcdev->lpm_en_modes[i];     \
+            i < pmcdev->num_lpm_modes;                 \
+diff --git a/drivers/platform/x86/intel/pmc/mtl.c b/drivers/platform/x86/intel/pmc/mtl.c
+index 71dc11811e112..504e3e273c323 100644
+--- a/drivers/platform/x86/intel/pmc/mtl.c
++++ b/drivers/platform/x86/intel/pmc/mtl.c
+@@ -979,6 +979,8 @@ static void mtl_d3_fixup(void)
+ static int mtl_resume(struct pmc_dev *pmcdev)
+ {
+       mtl_d3_fixup();
++      pmc_core_send_ltr_ignore(pmcdev, 3, 0);
++
+       return pmc_core_resume_common(pmcdev);
+ }
+@@ -989,6 +991,7 @@ int mtl_core_init(struct pmc_dev *pmcdev)
+       mtl_d3_fixup();
++      pmcdev->suspend = cnl_suspend;
+       pmcdev->resume = mtl_resume;
+       pmcdev->regmap_list = mtl_pmc_info_list;
+@@ -1002,11 +1005,5 @@ int mtl_core_init(struct pmc_dev *pmcdev)
+                       return ret;
+       }
+-      /* Due to a hardware limitation, the GBE LTR blocks PC10
+-       * when a cable is attached. Tell the PMC to ignore it.
+-       */
+-      dev_dbg(&pmcdev->pdev->dev, "ignoring GBE LTR\n");
+-      pmc_core_send_ltr_ignore(pmcdev, 3, 1);
+-
+       return 0;
+ }
+diff --git a/drivers/platform/x86/intel/pmc/tgl.c b/drivers/platform/x86/intel/pmc/tgl.c
+index 078263db24c7a..e88d3d00c8539 100644
+--- a/drivers/platform/x86/intel/pmc/tgl.c
++++ b/drivers/platform/x86/intel/pmc/tgl.c
+@@ -259,16 +259,15 @@ int tgl_core_init(struct pmc_dev *pmcdev)
+       int ret;
+       pmc->map = &tgl_reg_map;
++
++      pmcdev->suspend = cnl_suspend;
++      pmcdev->resume = cnl_resume;
++
+       ret = get_primary_reg_base(pmc);
+       if (ret)
+               return ret;
+       pmc_core_get_tgl_lpm_reqs(pmcdev->pdev);
+-      /* Due to a hardware limitation, the GBE LTR blocks PC10
+-       * when a cable is attached. Tell the PMC to ignore it.
+-       */
+-      dev_dbg(&pmcdev->pdev->dev, "ignoring GBE LTR\n");
+-      pmc_core_send_ltr_ignore(pmcdev, 3, 1);
+       return 0;
+ }
+-- 
+2.43.0
+
diff --git a/queue-6.6/series b/queue-6.6/series
new file mode 100644 (file)
index 0000000..6d681bb
--- /dev/null
@@ -0,0 +1,34 @@
+ksmbd-remove-unused-field-in-ksmbd_user-struct.patch
+ksmbd-reorganize-ksmbd_iov_pin_rsp.patch
+ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_setxattr.patch
+ksmbd-fix-missing-rdma-capable-flag-for-ipoib-device.patch
+ksmbd-add-support-for-surrogate-pair-conversion.patch
+ksmbd-no-need-to-wait-for-binded-connection-terminat.patch
+ksmbd-fix-kernel-doc-comment-of-ksmbd_vfs_kern_path_.patch
+ksmbd-prevent-memory-leak-on-error-return.patch
+ksmbd-separately-allocate-ci-per-dentry.patch
+ksmbd-move-oplock-handling-after-unlock-parent-dir.patch
+ksmbd-release-interim-response-after-sending-status-.patch
+ksmbd-move-setting-smb2_flags_async_command-and-asyn.patch
+ksmbd-don-t-update-op_state-as-oplock_state_none-on-.patch
+ksmbd-set-epoch-in-create-context-v2-lease.patch
+ksmbd-set-v2-lease-capability.patch
+ksmbd-downgrade-rwh-lease-caching-state-to-rh-for-di.patch
+ksmbd-send-v2-lease-break-notification-for-directory.patch
+ksmbd-lazy-v2-lease-break-on-smb2_write.patch
+ksmbd-avoid-duplicate-opinfo_put-call-on-error-of-sm.patch
+fs-new-accessor-methods-for-atime-and-mtime.patch
+client-convert-to-new-timestamp-accessors.patch
+fs-cifs-fix-atime-update-check.patch
+virtio_ring-fix-syncs-dma-memory-with-different-dire.patch
+kexec-fix-kexec_file-dependencies.patch
+kexec-select-crypto-from-kexec_file-instead-of-depen.patch
+linux-export-fix-alignment-for-64-bit-ksymtab-entrie.patch
+linux-export-ensure-natural-alignment-of-kcrctab-arr.patch
+mptcp-refactor-sndbuf-auto-tuning.patch
+mptcp-fix-possible-null-pointer-dereference-on-close.patch
+mptcp-fix-inconsistent-state-on-fastopen-race.patch
+block-renumber-queue_flag_hw_wc.patch
+platform-x86-intel-pmc-add-suspend-callback.patch
+platform-x86-intel-pmc-allow-reenabling-ltrs.patch
+platform-x86-intel-pmc-move-gbe-ltr-ignore-to-suspen.patch
diff --git a/queue-6.6/virtio_ring-fix-syncs-dma-memory-with-different-dire.patch b/queue-6.6/virtio_ring-fix-syncs-dma-memory-with-different-dire.patch
new file mode 100644 (file)
index 0000000..4d4bffa
--- /dev/null
@@ -0,0 +1,100 @@
+From 49d06b3412535c42004abc5175b7e59c8aa4c515 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 1 Dec 2023 11:33:03 +0800
+Subject: virtio_ring: fix syncs DMA memory with different direction
+
+From: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
+
+[ Upstream commit 1f475cd572ea77ae6474a17e693a96bca927efe9 ]
+
+Now the APIs virtqueue_dma_sync_single_range_for_{cpu,device} ignore
+the parameter 'dir', that is a mistake.
+
+[    6.101666] ------------[ cut here ]------------
+[    6.102079] DMA-API: virtio-pci 0000:00:04.0: device driver syncs DMA memory with different direction [device address=0x00000000ae010000] [size=32752 bytes] [mapped with DMA_FROM_DEVICE] [synced with DMA_BIDIRECTIONAL]
+[    6.103630] WARNING: CPU: 6 PID: 0 at kernel/dma/debug.c:1125 check_sync+0x53e/0x6c0
+[    6.107420] CPU: 6 PID: 0 Comm: swapper/6 Tainted: G            E      6.6.0+ #290
+[    6.108030] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.0-0-gd239552ce722-prebuilt.qemu.org 04/01/2014
+[    6.108936] RIP: 0010:check_sync+0x53e/0x6c0
+[    6.109289] Code: 24 10 e8 f5 d9 74 00 4c 8b 4c 24 10 4c 8b 44 24 18 48 8b 4c 24 20 48 89 c6 41 56 4c 89 ea 48 c7 c7 b0 f1 50 82 e8 32 fc f3 ff <0f> 0b 48 c7 c7 48 4b 4a 82 e8 74 d9 fc ff 8b 73 4c 48 8d 7b 50 31
+[    6.110750] RSP: 0018:ffffc90000180cd8 EFLAGS: 00010092
+[    6.111178] RAX: 00000000000000ce RBX: ffff888100aa5900 RCX: 0000000000000000
+[    6.111744] RDX: 0000000000000104 RSI: ffffffff824c3208 RDI: 00000000ffffffff
+[    6.112316] RBP: ffffc90000180d40 R08: 0000000000000000 R09: 00000000fffeffff
+[    6.112893] R10: ffffc90000180b98 R11: ffffffff82f63308 R12: ffffffff83d5af00
+[    6.113460] R13: ffff888100998200 R14: ffffffff824a4b5f R15: 0000000000000286
+[    6.114027] FS:  0000000000000000(0000) GS:ffff88842fd80000(0000) knlGS:0000000000000000
+[    6.114665] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[    6.115128] CR2: 00007f10f1e03030 CR3: 0000000108272004 CR4: 0000000000770ee0
+[    6.115701] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+[    6.116272] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+[    6.116842] PKRU: 55555554
+[    6.117069] Call Trace:
+[    6.117275]  <IRQ>
+[    6.117452]  ? __warn+0x84/0x140
+[    6.117727]  ? check_sync+0x53e/0x6c0
+[    6.118034]  ? __report_bug+0xea/0x100
+[    6.118353]  ? check_sync+0x53e/0x6c0
+[    6.118653]  ? report_bug+0x41/0xc0
+[    6.118944]  ? handle_bug+0x3c/0x70
+[    6.119237]  ? exc_invalid_op+0x18/0x70
+[    6.119551]  ? asm_exc_invalid_op+0x1a/0x20
+[    6.119900]  ? check_sync+0x53e/0x6c0
+[    6.120199]  ? check_sync+0x53e/0x6c0
+[    6.120499]  debug_dma_sync_single_for_cpu+0x5c/0x70
+[    6.120906]  ? dma_sync_single_for_cpu+0xb7/0x100
+[    6.121291]  virtnet_rq_unmap+0x158/0x170 [virtio_net]
+[    6.121716]  virtnet_receive+0x196/0x220 [virtio_net]
+[    6.122135]  virtnet_poll+0x48/0x1b0 [virtio_net]
+[    6.122524]  __napi_poll+0x29/0x1b0
+[    6.123083]  net_rx_action+0x282/0x360
+[    6.123612]  __do_softirq+0xf3/0x2fb
+[    6.124138]  __irq_exit_rcu+0x8e/0xf0
+[    6.124663]  common_interrupt+0xbc/0xe0
+[    6.125202]  </IRQ>
+
+We need to enable CONFIG_DMA_API_DEBUG and work with need sync mode(such
+as swiotlb) to reproduce this warn.
+
+Fixes: 8bd2f71054bd ("virtio_ring: introduce dma sync api for virtqueue")
+Reported-by: "Ning, Hongyu" <hongyu.ning@linux.intel.com>
+Closes: https://lore.kernel.org/all/f37cb55a-6fc8-4e21-8789-46d468325eea@linux.intel.com/
+Suggested-by: Jason Wang <jasowang@redhat.com>
+Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
+Message-Id: <20231201033303.25141-1-xuanzhuo@linux.alibaba.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Reviewed-by: Parav Pandit <parav@nvidia.com>
+Acked-by: Jason Wang <jasowang@redhat.com>
+Tested-by: Hongyu Ning <hongyu.ning@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/virtio/virtio_ring.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
+index 51d8f3299c105..49299b1f9ec74 100644
+--- a/drivers/virtio/virtio_ring.c
++++ b/drivers/virtio/virtio_ring.c
+@@ -3219,8 +3219,7 @@ void virtqueue_dma_sync_single_range_for_cpu(struct virtqueue *_vq,
+       if (!vq->use_dma_api)
+               return;
+-      dma_sync_single_range_for_cpu(dev, addr, offset, size,
+-                                    DMA_BIDIRECTIONAL);
++      dma_sync_single_range_for_cpu(dev, addr, offset, size, dir);
+ }
+ EXPORT_SYMBOL_GPL(virtqueue_dma_sync_single_range_for_cpu);
+@@ -3246,8 +3245,7 @@ void virtqueue_dma_sync_single_range_for_device(struct virtqueue *_vq,
+       if (!vq->use_dma_api)
+               return;
+-      dma_sync_single_range_for_device(dev, addr, offset, size,
+-                                       DMA_BIDIRECTIONAL);
++      dma_sync_single_range_for_device(dev, addr, offset, size, dir);
+ }
+ EXPORT_SYMBOL_GPL(virtqueue_dma_sync_single_range_for_device);
+-- 
+2.43.0
+