linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Ronnie Sahlberg <lsahlber@redhat.com>,
	kernel test robot <lkp@intel.com>,
	Aurelien Aptel <aaptel@suse.com>, Paulo Alcantara <pc@cjr.nz>,
	Steve French <stfrench@microsoft.com>,
	Sasha Levin <sashal@kernel.org>,
	linux-cifs@vger.kernel.org, samba-technical@lists.samba.org
Subject: [PATCH AUTOSEL 5.12 35/52] cifs: improve fallocate emulation
Date: Mon,  5 Jul 2021 11:28:56 -0400	[thread overview]
Message-ID: <20210705152913.1521036-35-sashal@kernel.org> (raw)
In-Reply-To: <20210705152913.1521036-1-sashal@kernel.org>

From: Ronnie Sahlberg <lsahlber@redhat.com>

[ Upstream commit 966a3cb7c7db786452a87afdc3b48858fc4d4d6b ]

RHBZ: 1866684

We don't have a real fallocate in the SMB2 protocol so we used to emulate fallocate
by simply switching the file to become non-sparse. But as that could potantially consume
a lot more data than we intended to fallocate (large sparse file and fallocating a thin
slice in the middle) we would only do this IFF the fallocate request was for virtually
the entire file.

This patch improves this and starts allowing us to fallocate smaller chunks of a file by
overwriting the region with 0, for the parts that are unallocated.

The method used is to first query the server for FSCTL_QUERY_ALLOCATED_RANGES to find what
is unallocated in the fallocate range and then to only overwrite-with-zero the unallocated
ranges to fill in the holes.

As overwriting-with-zero is different from just allocating blocks, and potentially much
more expensive, we limit this to only allow fallocate ranges up to 1Mb in size.

Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
Acked-by: Aurelien Aptel <aaptel@suse.com>
Acked-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 fs/cifs/smb2ops.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 133 insertions(+)

diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index e9a530da4255..ea5e958fd6b0 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -3561,6 +3561,119 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
 	return rc;
 }
 
+static int smb3_simple_fallocate_write_range(unsigned int xid,
+					     struct cifs_tcon *tcon,
+					     struct cifsFileInfo *cfile,
+					     loff_t off, loff_t len,
+					     char *buf)
+{
+	struct cifs_io_parms io_parms = {0};
+	int nbytes;
+	struct kvec iov[2];
+
+	io_parms.netfid = cfile->fid.netfid;
+	io_parms.pid = current->tgid;
+	io_parms.tcon = tcon;
+	io_parms.persistent_fid = cfile->fid.persistent_fid;
+	io_parms.volatile_fid = cfile->fid.volatile_fid;
+	io_parms.offset = off;
+	io_parms.length = len;
+
+	/* iov[0] is reserved for smb header */
+	iov[1].iov_base = buf;
+	iov[1].iov_len = io_parms.length;
+	return SMB2_write(xid, &io_parms, &nbytes, iov, 1);
+}
+
+static int smb3_simple_fallocate_range(unsigned int xid,
+				       struct cifs_tcon *tcon,
+				       struct cifsFileInfo *cfile,
+				       loff_t off, loff_t len)
+{
+	struct file_allocated_range_buffer in_data, *out_data = NULL, *tmp_data;
+	u32 out_data_len;
+	char *buf = NULL;
+	loff_t l;
+	int rc;
+
+	in_data.file_offset = cpu_to_le64(off);
+	in_data.length = cpu_to_le64(len);
+	rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
+			cfile->fid.volatile_fid,
+			FSCTL_QUERY_ALLOCATED_RANGES, true,
+			(char *)&in_data, sizeof(in_data),
+			1024 * sizeof(struct file_allocated_range_buffer),
+			(char **)&out_data, &out_data_len);
+	if (rc)
+		goto out;
+	/*
+	 * It is already all allocated
+	 */
+	if (out_data_len == 0)
+		goto out;
+
+	buf = kzalloc(1024 * 1024, GFP_KERNEL);
+	if (buf == NULL) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	tmp_data = out_data;
+	while (len) {
+		/*
+		 * The rest of the region is unmapped so write it all.
+		 */
+		if (out_data_len == 0) {
+			rc = smb3_simple_fallocate_write_range(xid, tcon,
+					       cfile, off, len, buf);
+			goto out;
+		}
+
+		if (out_data_len < sizeof(struct file_allocated_range_buffer)) {
+			rc = -EINVAL;
+			goto out;
+		}
+
+		if (off < le64_to_cpu(tmp_data->file_offset)) {
+			/*
+			 * We are at a hole. Write until the end of the region
+			 * or until the next allocated data,
+			 * whichever comes next.
+			 */
+			l = le64_to_cpu(tmp_data->file_offset) - off;
+			if (len < l)
+				l = len;
+			rc = smb3_simple_fallocate_write_range(xid, tcon,
+					       cfile, off, l, buf);
+			if (rc)
+				goto out;
+			off = off + l;
+			len = len - l;
+			if (len == 0)
+				goto out;
+		}
+		/*
+		 * We are at a section of allocated data, just skip forward
+		 * until the end of the data or the end of the region
+		 * we are supposed to fallocate, whichever comes first.
+		 */
+		l = le64_to_cpu(tmp_data->length);
+		if (len < l)
+			l = len;
+		off += l;
+		len -= l;
+
+		tmp_data = &tmp_data[1];
+		out_data_len -= sizeof(struct file_allocated_range_buffer);
+	}
+
+ out:
+	kfree(out_data);
+	kfree(buf);
+	return rc;
+}
+
+
 static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
 			    loff_t off, loff_t len, bool keep_size)
 {
@@ -3621,6 +3734,26 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
 	}
 
 	if ((keep_size == true) || (i_size_read(inode) >= off + len)) {
+		/*
+		 * At this point, we are trying to fallocate an internal
+		 * regions of a sparse file. Since smb2 does not have a
+		 * fallocate command we have two otions on how to emulate this.
+		 * We can either turn the entire file to become non-sparse
+		 * which we only do if the fallocate is for virtually
+		 * the whole file,  or we can overwrite the region with zeroes
+		 * using SMB2_write, which could be prohibitevly expensive
+		 * if len is large.
+		 */
+		/*
+		 * We are only trying to fallocate a small region so
+		 * just write it with zero.
+		 */
+		if (len <= 1024 * 1024) {
+			rc = smb3_simple_fallocate_range(xid, tcon, cfile,
+							 off, len);
+			goto out;
+		}
+
 		/*
 		 * Check if falloc starts within first few pages of file
 		 * and ends within a few pages of the end of file to
-- 
2.30.2


  parent reply	other threads:[~2021-07-05 15:31 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-05 15:28 [PATCH AUTOSEL 5.12 01/52] HID: do not use down_interruptible() when unbinding devices Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 02/52] EDAC/ti: Add missing MODULE_DEVICE_TABLE Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 03/52] ACPI: PM: s2idle: Add missing LPS0 functions for AMD Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 04/52] ACPI: processor idle: Fix up C-state latency if not ordered Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 05/52] hv_utils: Fix passing zero to 'PTR_ERR' warning Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 06/52] lib: vsprintf: Fix handling of number field widths in vsscanf Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 07/52] Input: goodix - platform/x86: touchscreen_dmi - Move upside down quirks to touchscreen_dmi.c Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 08/52] platform/x86: touchscreen_dmi: Add an extra entry for the upside down Goodix touchscreen on Teclast X89 tablets Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 09/52] platform/x86: touchscreen_dmi: Add info for the Goodix GT912 panel of TM800A550L tablets Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 10/52] ACPI: EC: Make more Asus laptops use ECDT _GPE Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 11/52] block_dump: remove block_dump feature in mark_inode_dirty() Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 12/52] blk-mq: grab rq->refcount before calling ->fn in blk_mq_tagset_busy_iter Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 13/52] blk-mq: clear stale request in tags->rq[] before freeing one request pool Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 14/52] fs: dlm: reconnect if socket error report occurs Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 15/52] fs: dlm: cancel work sync othercon Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 16/52] random32: Fix implicit truncation warning in prandom_seed_state() Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 17/52] open: don't silently ignore unknown O-flags in openat2() Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 18/52] drivers: hv: Fix missing error code in vmbus_connect() Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 19/52] fs: dlm: fix lowcomms_start error case Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 20/52] fs: dlm: fix memory leak when fenced Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 21/52] ACPICA: Fix memory leak caused by _CID repair function Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 22/52] ACPI: bus: Call kobject_put() in acpi_init() error path Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 23/52] ACPI: resources: Add checks for ACPI IRQ override Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 24/52] HID: hid-input: add Surface Go battery quirk Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 25/52] HID: sony: fix freeze when inserting ghlive ps3/wii dongles Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 26/52] block: fix race between adding/removing rq qos and normal IO Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 27/52] platform/x86: asus-nb-wmi: Revert "Drop duplicate DMI quirk structures" Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 28/52] platform/x86: asus-nb-wmi: Revert "add support for ASUS ROG Zephyrus G14 and G15" Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 29/52] platform/x86: toshiba_acpi: Fix missing error code in toshiba_acpi_setup_keyboard() Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 30/52] nvme-pci: fix var. type for increasing cq_head Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 31/52] nvmet-fc: do not check for invalid target port in nvmet_fc_handle_fcp_rqst() Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 32/52] EDAC/Intel: Do not load EDAC driver when running as a guest Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 33/52] tools/power/x86/intel-speed-select: Fix uncore memory frequency display Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 34/52] PCI: hv: Add check for hyperv_initialized in init_hv_pci_drv() Sasha Levin
2021-07-05 15:28 ` Sasha Levin [this message]
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 36/52] cifs: fix check of dfs interlinks Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 37/52] smb3: fix uninitialized value for port in witness protocol move Sasha Levin

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=20210705152913.1521036-35-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=aaptel@suse.com \
    --cc=linux-cifs@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lkp@intel.com \
    --cc=lsahlber@redhat.com \
    --cc=pc@cjr.nz \
    --cc=samba-technical@lists.samba.org \
    --cc=stable@vger.kernel.org \
    --cc=stfrench@microsoft.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).