All of lore.kernel.org
 help / color / mirror / Atom feed
From: Huiwen He <huiwen.he@linux.dev>
To: smfrench@gmail.com, linkinjeon@kernel.org, pc@manguebit.org,
	ronniesahlberg@gmail.com, sprasad@microsoft.com, tom@talpey.com,
	bharathsm@microsoft.com, senozhatsky@chromium.org,
	dhowells@redhat.com, metze@samba.org, chenxiaosong@kylinos.cn
Cc: linux-cifs@vger.kernel.org
Subject: [PATCH v3 8/9] smb/client: emulate small mode 0 fallocate ranges at or past EOF
Date: Fri, 26 Jun 2026 00:01:53 +0800	[thread overview]
Message-ID: <20260625160154.104450-9-huiwen.he@linux.dev> (raw)
In-Reply-To: <20260625160154.104450-1-huiwen.he@linux.dev>

From: Huiwen He <hehuiwen@kylinos.cn>

The xfstest generic/213 has a mode 0 fallocate case like:

        falloc 0 1G
        falloc 2G 1M
        truncate 3G

The expected layout is:

        allocated [0, 1G)
        hole      [1G, 2G)
        allocated [2G, 2G + 1M)

Current CIFS can pass this test while allocating the intervening hole.
Before this change, the server-side layout was effectively:

        allocated [0, 1G)
        allocated [1G, 2G + 1M)

so [1G, 2G) was allocated as part of the second extent.

Emulate small mode 0 fallocate ranges that start at or past EOF by writing
zeroes only to the requested range.  For off > old_eof, this preserves the
hole between old_eof and off. Keep this emulation limited to 1 MiB so the
client-side I/O cost remains bounded; larger unsupported ranges remain
rejected.

After this change, the same pattern gives the intended layout:

        allocated [0, 1G)
        hole      [1G, 2G)
        allocated [2G, 2G + 1M)

This changes generic/213 from a false pass into a range-correct pass.

Signed-off-by: Huiwen He <hehuiwen@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
---
 fs/smb/client/smb2ops.c | 50 ++++++++++++++++++++++++++++++++++++++---
 1 file changed, 47 insertions(+), 3 deletions(-)

diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 5f2e4a0722a6..73a80671a584 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -3677,18 +3677,22 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
 	struct cifsFileInfo *cfile = file->private_data;
 	long rc = -EOPNOTSUPP;
 	unsigned int xid;
-	loff_t new_eof;
+	loff_t old_eof, new_eof;
+	struct smb2_file_all_info file_inf;
+	u64 asize;
+	int qrc;
 
 	xid = get_xid();
 
 	inode = d_inode(cfile->dentry);
 	cifsi = CIFS_I(inode);
+	old_eof = i_size_read(inode);
 
 	trace_smb3_falloc_enter(xid, cfile->fid.persistent_fid, tcon->tid,
 				tcon->ses->Suid, off, len);
 	/* if file not oplocked can't be sure whether asking to extend size */
 	if (!CIFS_CACHE_READ(cifsi))
-		if (keep_size == false) {
+		if (!keep_size) {
 			trace_smb3_falloc_err(xid, cfile->fid.persistent_fid,
 				tcon->tid, tcon->ses->Suid, off, len, rc);
 			free_xid(xid);
@@ -3698,11 +3702,51 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
 	/*
 	 * Extending the file
 	 */
-	if ((keep_size == false) && i_size_read(inode) < off + len) {
+	if (!keep_size && old_eof < off + len) {
 		rc = inode_newsize_ok(inode, off + len);
 		if (rc)
 			goto out;
 
+		/*
+		 * A small range at or beyond EOF can be allocated by writing
+		 * zeroes.  For off > old_eof, this preserves the intervening
+		 * hole instead of allocating from offset 0.
+		 */
+		if (off > old_eof ||
+		    (off == old_eof && old_eof != 0 &&
+		     (cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE))) {
+			if (len > 1024 * 1024) {
+				rc = -EOPNOTSUPP;
+				goto out;
+			}
+
+			rc = smb3_simple_fallocate_range(xid, tcon, cfile,
+							 off, len);
+			if (rc) {
+				spin_lock(&inode->i_lock);
+				cifsi->time = 0;
+				spin_unlock(&inode->i_lock);
+				goto out;
+			}
+
+			new_eof = off + len;
+			netfs_resize_file(&cifsi->netfs, new_eof, true);
+			cifs_setsize(inode, new_eof);
+
+			qrc = SMB2_query_info(xid, tcon,
+					      cfile->fid.persistent_fid,
+					      cfile->fid.volatile_fid, &file_inf);
+			spin_lock(&inode->i_lock);
+			if (qrc == 0) {
+				asize = le64_to_cpu(file_inf.AllocationSize);
+				inode->i_blocks = CIFS_INO_BLOCKS(asize);
+			} else {
+				cifsi->time = 0;
+			}
+			spin_unlock(&inode->i_lock);
+			goto out;
+		}
+
 		if (cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) {
 			rc = smb2_set_sparse(xid, tcon, cfile, inode, false);
 			if (rc)
-- 
2.43.0


  parent reply	other threads:[~2026-06-25 16:04 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-25 16:01 [PATCH v3 0/9] smb/client: fix mode 0 fallocate handling Huiwen He
2026-06-25 16:01 ` [PATCH v3 1/9] smb/client: name the default fallocate mode Huiwen He
2026-06-25 16:01 ` [PATCH v3 2/9] smb/client: preserve errors from smb2_set_sparse() Huiwen He
2026-06-25 16:01 ` [PATCH v3 3/9] smb/client: handle smb2_set_sparse() failure in EOF-extending fallocate Huiwen He
2026-06-25 16:01 ` [PATCH v3 4/9] smb/client: handle smb2_set_sparse() failure in non-extending fallocate Huiwen He
2026-06-25 16:01 ` [PATCH v3 5/9] smb/client: do not account EOF extension as allocation Huiwen He
2026-06-25 16:01 ` [PATCH v3 6/9] smb/client: handle overlapping allocated ranges in fallocate Huiwen He
2026-06-25 16:01 ` [PATCH v3 7/9] smb/client: reduce fallocate zero buffer allocation Huiwen He
2026-06-25 16:01 ` Huiwen He [this message]
2026-06-25 16:01 ` [PATCH v3 9/9] smb/client: verify allocation after EOF-extending fallocate Huiwen He

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260625160154.104450-9-huiwen.he@linux.dev \
    --to=huiwen.he@linux.dev \
    --cc=bharathsm@microsoft.com \
    --cc=chenxiaosong@kylinos.cn \
    --cc=dhowells@redhat.com \
    --cc=linkinjeon@kernel.org \
    --cc=linux-cifs@vger.kernel.org \
    --cc=metze@samba.org \
    --cc=pc@manguebit.org \
    --cc=ronniesahlberg@gmail.com \
    --cc=senozhatsky@chromium.org \
    --cc=smfrench@gmail.com \
    --cc=sprasad@microsoft.com \
    --cc=tom@talpey.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.