From: Keith Busch <kbusch@meta.com>
To: <linux-block@vger.kernel.org>, <linux-nvme@lists.infradead.org>
Cc: Keith Busch <kbusch@kernel.org>
Subject: [PATCH 1/5] block: new sector copy api
Date: Wed, 21 May 2025 15:31:03 -0700 [thread overview]
Message-ID: <20250521223107.709131-2-kbusch@meta.com> (raw)
In-Reply-To: <20250521223107.709131-1-kbusch@meta.com>
From: Keith Busch <kbusch@kernel.org>
Provide a basic block level api to copy a range of a block device's
sectors to a new destination on the same device. This just reads the
source data into host memory, then writes it back out to the device at
the requested destination.
Signed-off-by: Keith Busch <kbusch@kernel.org>
---
block/blk-lib.c | 62 +++++++++++++++++++++++++++++++++++++++++
block/ioctl.c | 30 ++++++++++++++++++++
include/linux/blkdev.h | 2 ++
include/uapi/linux/fs.h | 3 ++
4 files changed, 97 insertions(+)
diff --git a/block/blk-lib.c b/block/blk-lib.c
index 4c9f20a689f7b..a819ded0ed3a9 100644
--- a/block/blk-lib.c
+++ b/block/blk-lib.c
@@ -368,3 +368,65 @@ int blkdev_issue_secure_erase(struct block_device *bdev, sector_t sector,
return ret;
}
EXPORT_SYMBOL(blkdev_issue_secure_erase);
+
+/**
+ * blkdev_copy - copy source sectors to a destination on the same block device
+ * @dst_sector: start sector of the destination to copy to
+ * @src_sector: start sector of the source to copy from
+ * @nr_sects: number of sectors to copy
+ * @gfp: allocation flags to use
+ */
+int blkdev_copy(struct block_device *bdev, sector_t dst_sector,
+ sector_t src_sector, sector_t nr_sects, gfp_t gfp)
+{
+ unsigned int nr_vecs = __blkdev_sectors_to_bio_pages(nr_sects);
+ unsigned int len = (unsigned int)nr_sects << SECTOR_SHIFT;
+ unsigned int size = min(len, nr_vecs * PAGE_SIZE);
+ struct bio *bio;
+ int ret = 0;
+ void *buf;
+
+ if (nr_sects > UINT_MAX >> SECTOR_SHIFT)
+ return -EINVAL;
+
+ buf = kvmalloc(size, gfp);
+ if (!buf)
+ return -ENOMEM;
+
+ nr_vecs = bio_add_max_vecs(buf, size);
+ bio = bio_alloc(bdev, nr_vecs, 0, gfp);
+
+ if (is_vmalloc_addr(buf))
+ bio_add_vmalloc(bio, buf, size);
+ else
+ bio_add_virt_nofail(bio, buf, size);
+
+ while (len) {
+ size = min(len, size);
+
+ bio_reset(bio, bdev, REQ_OP_READ);
+ bio->bi_iter.bi_sector = src_sector;
+ bio->bi_iter.bi_size = size;
+
+ ret = submit_bio_wait(bio);
+ if (ret)
+ break;
+
+ bio_reset(bio, bdev, REQ_OP_WRITE);
+ bio->bi_iter.bi_sector = dst_sector;
+ bio->bi_iter.bi_size = size;
+
+ ret = submit_bio_wait(bio);
+ if (ret)
+ break;
+
+ src_sector += size >> SECTOR_SHIFT;
+ dst_sector += size >> SECTOR_SHIFT;
+ len -= size;
+ }
+
+ bio_put(bio);
+ kvfree(buf);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(blkdev_copy);
diff --git a/block/ioctl.c b/block/ioctl.c
index e472cc1030c60..6f03c65867348 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -212,6 +212,34 @@ static int blk_ioctl_secure_erase(struct block_device *bdev, blk_mode_t mode,
return err;
}
+static int blk_ioctl_copy(struct block_device *bdev, blk_mode_t mode,
+ void __user *argp)
+{
+ unsigned int lbs = bdev_logical_block_size(bdev) >> SECTOR_SHIFT;
+ uint64_t dst, src, end, nr, range[3];
+
+ if (!(mode & BLK_OPEN_WRITE))
+ return -EBADF;
+ if (copy_from_user(range, argp, sizeof(range)))
+ return -EFAULT;
+
+ dst = range[0];
+ src = range[1];
+ nr = range[2];
+
+ if (!(IS_ALIGNED(dst | src | nr, lbs)))
+ return -EINVAL;
+ if (check_add_overflow(src, nr - 1, &end))
+ return -EINVAL;
+ if (end >= bdev_nr_sectors(bdev))
+ return -EINVAL;
+ if (src < dst && src + nr > dst)
+ return -EINVAL;
+ if (dst < src && dst + nr > src)
+ return -EINVAL;
+
+ return blkdev_copy(bdev, dst, src, nr, GFP_KERNEL);
+}
static int blk_ioctl_zeroout(struct block_device *bdev, blk_mode_t mode,
unsigned long arg)
@@ -575,6 +603,8 @@ static int blkdev_common_ioctl(struct block_device *bdev, blk_mode_t mode,
return blk_ioctl_discard(bdev, mode, arg);
case BLKSECDISCARD:
return blk_ioctl_secure_erase(bdev, mode, argp);
+ case BLKCPY:
+ return blk_ioctl_copy(bdev, mode, argp);
case BLKZEROOUT:
return blk_ioctl_zeroout(bdev, mode, arg);
case BLKGETDISKSEQ:
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 332b56f323d92..b7d71b126ec9b 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1176,6 +1176,8 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
sector_t nr_sects, gfp_t gfp_mask, struct bio **biop);
int blkdev_issue_secure_erase(struct block_device *bdev, sector_t sector,
sector_t nr_sects, gfp_t gfp);
+int blkdev_copy(struct block_device *bdev, sector_t dst_sector,
+ sector_t src_sector, sector_t nr_sects, gfp_t gfp);
#define BLKDEV_ZERO_NOUNMAP (1 << 0) /* do not free blocks */
#define BLKDEV_ZERO_NOFALLBACK (1 << 1) /* don't write explicit zeroes */
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index e762e1af650c4..534f157ce22e9 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -215,6 +215,9 @@ struct fsxattr {
/* 130-136 are used by zoned block device ioctls (uapi/linux/blkzoned.h) */
/* 137-141 are used by blk-crypto ioctls (uapi/linux/blk-crypto.h) */
+/* [0] = destination lba, [1] = source lba, [2] = number of sectors */
+#define BLKCPY _IOWR(0x12,142,__u64[3])
+
#define BMAP_IOCTL 1 /* obsolete - kept for compatibility */
#define FIBMAP _IO(0x00,1) /* bmap access */
#define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */
--
2.47.1
next prev parent reply other threads:[~2025-05-21 22:31 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-05-21 22:31 [PATCH 0/5] block: another block copy offload Keith Busch
2025-05-21 22:31 ` Keith Busch [this message]
2025-05-22 10:02 ` [PATCH 1/5] block: new sector copy api Hannes Reinecke
2025-05-22 16:43 ` Keith Busch
2025-05-22 19:22 ` Bart Van Assche
2025-05-22 20:04 ` Keith Busch
2025-05-23 12:45 ` Christoph Hellwig
2025-05-23 17:02 ` Keith Busch
2025-05-26 5:18 ` Christoph Hellwig
2025-05-27 17:45 ` Keith Busch
2025-05-28 7:46 ` Christoph Hellwig
2025-05-28 22:41 ` Keith Busch
2025-06-02 4:58 ` Christoph Hellwig
2025-05-21 22:31 ` [PATCH 2/5] block: add support for copy offload Keith Busch
2025-05-22 13:49 ` Hannes Reinecke
2025-05-23 12:46 ` Christoph Hellwig
2025-05-23 13:26 ` Keith Busch
2025-05-23 13:37 ` Christoph Hellwig
2025-05-23 13:48 ` Keith Busch
2025-05-26 5:22 ` Christoph Hellwig
2025-05-27 21:33 ` Keith Busch
2025-05-28 7:47 ` Christoph Hellwig
2025-05-21 22:31 ` [PATCH 3/5] nvme: " Keith Busch
2025-05-22 0:47 ` Caleb Sander Mateos
2025-05-22 0:51 ` Caleb Sander Mateos
2025-05-22 3:23 ` Keith Busch
2025-05-22 3:41 ` Caleb Sander Mateos
2025-05-22 4:29 ` Keith Busch
2025-05-22 14:16 ` Caleb Sander Mateos
2025-05-23 12:49 ` Christoph Hellwig
2025-05-23 12:48 ` Christoph Hellwig
2025-05-22 13:54 ` Hannes Reinecke
2025-05-23 12:50 ` Christoph Hellwig
2025-05-23 14:22 ` Caleb Sander Mateos
2025-06-09 9:29 ` Niklas Cassel
2025-05-21 22:31 ` [PATCH 4/5] block: add support for vectored copies Keith Busch
2025-05-22 13:58 ` Hannes Reinecke
2025-05-22 16:36 ` Keith Busch
2025-05-21 22:31 ` [PATCH 5/5] nvmet: implement copy support for bdev backed target Keith Busch
2025-05-22 13:59 ` Hannes Reinecke
2025-05-23 13:18 ` Christoph Hellwig
2025-05-23 14:00 ` Keith Busch
2025-05-23 14:02 ` Christoph Hellwig
2025-05-22 15:52 ` [PATCH 0/5] block: another block copy offload Bart Van Assche
2025-05-23 12:53 ` Christoph Hellwig
2025-07-03 14:47 ` Niklas Cassel
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=20250521223107.709131-2-kbusch@meta.com \
--to=kbusch@meta.com \
--cc=kbusch@kernel.org \
--cc=linux-block@vger.kernel.org \
--cc=linux-nvme@lists.infradead.org \
/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