commit 3ee1a1fc39819906f04d6c62c180e760cd3a689d upstream.
Add cifs_limit_kvec_subset() and select the appropriate limiter in cifs_send_async_read() to handle kvec iterators in async read path, fixing the EIO bug when running executables in cifs shares mounted with nolease.
This patch -- or equivalent patch, does not exist upstream, as the upstream code has suffered considerable API changes. The affected path is currently handled by netfs lib and located under netfs/direct_read.c.
Reproducer:
$ mount.cifs //server/share /mnt -o nolease $ cat - > /mnt/test.sh <<EOL echo hallo EOL $ chmod +x /mnt/test.sh $ /mnt/test.sh bash: /mnt/test.sh: /bin/bash: Defekter Interpreter: Eingabe-/Ausgabefehler $ rm -f /mnt/test.sh
Fixes: d08089f649a0 ("cifs: Change the I/O paths to use an iterator rather than a page list") Reported-by: Laura Kerner laura.kerner@ichaus.de Closes: https://bugzilla.suse.com/show_bug.cgi?id=1245449 Signed-off-by: Henrique Carvalho henrique.carvalho@suse.com --- fs/smb/client/file.c | 46 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-)
diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index d883ed75022c..4878c74bae6f 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -3527,6 +3527,42 @@ static size_t cifs_limit_bvec_subset(const struct iov_iter *iter, size_t max_siz return span; }
+static size_t cifs_limit_kvec_subset(const struct iov_iter *iter, size_t max_size, + size_t max_segs, unsigned int *_nsegs) +{ + const struct kvec *kvecs = iter->kvec; + unsigned int nkv = iter->nr_segs, ix = 0, nsegs = 0; + size_t len, span = 0, n = iter->count; + size_t skip = iter->iov_offset; + + if (WARN_ON(!iov_iter_is_kvec(iter)) || n == 0) + return 0; + + while (n && ix < nkv && skip) { + len = kvecs[ix].iov_len; + if (skip < len) + break; + skip -= len; + n -= len; + ix++; + } + + while (n && ix < nkv) { + len = min3(n, kvecs[ix].iov_len - skip, max_size); + span += len; + max_size -= len; + nsegs++; + ix++; + if (max_size == 0 || nsegs >= max_segs) + break; + skip = 0; + n -= len; + } + + *_nsegs = nsegs; + return span; +} + static int cifs_write_from_iter(loff_t fpos, size_t len, struct iov_iter *from, struct cifsFileInfo *open_file, @@ -4079,6 +4115,13 @@ cifs_send_async_read(loff_t fpos, size_t len, struct cifsFileInfo *open_file, int rc; pid_t pid; struct TCP_Server_Info *server; + size_t (*limit_iov_subset)(const struct iov_iter *iter, size_t max_size, + size_t max_segs, unsigned int *_nsegs); + + if (iov_iter_is_kvec(&ctx->iter)) + limit_iov_subset = cifs_limit_kvec_subset; + else + limit_iov_subset = cifs_limit_bvec_subset;
server = cifs_pick_channel(tlink_tcon(open_file->tlink)->ses);
@@ -4113,8 +4156,7 @@ cifs_send_async_read(loff_t fpos, size_t len, struct cifsFileInfo *open_file,
max_len = min_t(size_t, len, rsize);
- cur_len = cifs_limit_bvec_subset(&ctx->iter, max_len, - max_segs, &nsegs); + cur_len = limit_iov_subset(&ctx->iter, max_len, max_segs, &nsegs); cifs_dbg(FYI, "read-to-iter len=%zx/%zx nsegs=%u/%lu/%u\n", cur_len, max_len, nsegs, ctx->iter.nr_segs, max_segs); if (cur_len == 0) {
Henrique Carvalho henrique.carvalho@suse.com wrote:
Add cifs_limit_kvec_subset() and select the appropriate limiter in cifs_send_async_read() to handle kvec iterators in async read path, fixing the EIO bug when running executables in cifs shares mounted with nolease.
This patch -- or equivalent patch, does not exist upstream, as the upstream code has suffered considerable API changes. The affected path is currently handled by netfs lib and located under netfs/direct_read.c.
Are you saying that you do see this upstream too?
Reproducer:
$ mount.cifs //server/share /mnt -o nolease $ cat - > /mnt/test.sh <<EOL echo hallo EOL $ chmod +x /mnt/test.sh $ /mnt/test.sh bash: /mnt/test.sh: /bin/bash: Defekter Interpreter: Eingabe-/Ausgabefehler $ rm -f /mnt/test.sh
Is this what you are expecting to see when it works or when it fails?
David
On Fri, Jul 11, 2025 at 10:01:58AM +0100, David Howells wrote:
Henrique Carvalho henrique.carvalho@suse.com wrote:
Add cifs_limit_kvec_subset() and select the appropriate limiter in cifs_send_async_read() to handle kvec iterators in async read path, fixing the EIO bug when running executables in cifs shares mounted with nolease.
This patch -- or equivalent patch, does not exist upstream, as the upstream code has suffered considerable API changes. The affected path is currently handled by netfs lib and located under netfs/direct_read.c.
Are you saying that you do see this upstream too?
No, the patch only targets the 6.6.y stable tree. Since version 6.8, this path has moved into the netfs layer, so the original bug no longer exists.
The bug was fixed at least since the commit referred in the commit message -- 3ee1a1fc3981. In this commit, the call to cifs_user_readv() is replaced by a call to netfs_unbuffered_read_iter(), inside the function cifs_strict_readv().
netfs_unbuffered_read_iter() itself was introduced in commit 016dc8516aec8, along with other netfs api changes, present in kernel versions 6.8+.
Backporting netfs directly would be non-trivial. Instead, I:
- add cifs_limit_kvec_subset(), modeled on the existing cifs_limit_bvec_subset() - choose between the kvec or bvec limiter function early in cifs_write_from_iter().
The Fixes tag references d08089f649a0c, which implements cifs_limit_bvec_subset() and uses it inside cifs_write_from_iter().
Reproducer:
$ mount.cifs //server/share /mnt -o nolease $ cat - > /mnt/test.sh <<EOL echo hallo EOL $ chmod +x /mnt/test.sh $ /mnt/test.sh bash: /mnt/test.sh: /bin/bash: Defekter Interpreter: Eingabe-/Ausgabefehler $ rm -f /mnt/test.sh
Is this what you are expecting to see when it works or when it fails?
This is the reproducer for the observed bug. In english it reads "Bad interpreter: Input/Output error".
FYI: I tried to follow Option 3 of the stable-kernel rules for submission: https://www.kernel.org/doc/html/v6.15/process/stable-kernel-rules.html Please let me know if you'd prefer a different approach or any further changes.
Henrique
[ Sasha's backport helper bot ]
Hi,
Summary of potential issues: ⚠️ Found follow-up fixes in mainline
The upstream commit SHA1 provided is correct: 3ee1a1fc39819906f04d6c62c180e760cd3a689d
WARNING: Author mismatch between patch and upstream commit: Backport author: Henrique Carvalhohenrique.carvalho@suse.com Commit author: David Howellsdhowells@redhat.com
Status in newer kernel trees: 6.15.y | Present (exact SHA1) 6.12.y | Present (exact SHA1)
Found fixes commits: 92941c7f2c95 smb: fix bytes written value in /proc/fs/cifs/Stats bb57c81e97e0 cifs: Fix rmdir failure due to ongoing I/O on deleted file 307f77e7f585 cifs: Fix reversion of the iter in cifs_readv_receive(). a68c74865f51 cifs: Fix SMB1 readv/writev callback in the same way as SMB2/3 517b58c1f924 cifs: Fix zero_point init on inode initialisation a07d38afd152 cifs: Fix missing fscache invalidation 61ea6b3a3104 cifs: Fix setting of zero_point after DIO write de40579b9038 cifs: Fix server re-repick on subrequest retry ce5291e56081 cifs: Defer read completion a88d60903696 cifs: Don't advance the I/O iterator before terminating subrequest 8a1607233566 cifs: Fix smb3_insert_range() to move the zero_point a395726cf823 cifs: fix data corruption in read after invalidate edfc6481faf8 smb3: fix perf regression with cached writes with netfs conversion 14b1cd25346b cifs: Fix locking in cifs_strict_readv()
Note: The patch differs from the upstream commit: --- 1: 3ee1a1fc39819 < -: ------------- cifs: Cut over to using netfslib -: ------------- > 1: f5c5a2c4149fb smb: client: support kvec iterators in async read path ---
Results of testing on various branches:
| Branch | Patch Apply | Build Test | |---------------------------|-------------|------------| | stable/linux-6.6.y | Success | Success |
linux-stable-mirror@lists.linaro.org