* [PATCH v14 04/11] block: add emulation for copy
2023-08-11 10:52 ` [dm-devel] [PATCH v14 00/11] Implement copy offload support Nitesh Shetty
@ 2023-08-11 10:52 ` Nitesh Shetty
0 siblings, 0 replies; 2+ messages in thread
From: Nitesh Shetty @ 2023-08-11 10:52 UTC (permalink / raw)
To: Jens Axboe, Jonathan Corbet, Alasdair Kergon, Mike Snitzer,
dm-devel, Keith Busch, Christoph Hellwig, Sagi Grimberg,
Chaitanya Kulkarni, Alexander Viro, Christian Brauner
Cc: martin.petersen, mcgrof, dlemoal, gost.dev, Nitesh Shetty,
Vincent Fu, Anuj Gupta, linux-block, linux-kernel, linux-doc,
linux-nvme, linux-fsdevel
For the devices which does not support copy, copy emulation is added.
It is required for in-kernel users like fabrics, where file descriptor is
not available and hence they can't use copy_file_range.
Copy-emulation is implemented by reading from source into memory and
writing to the corresponding destination.
Also emulation can be used, if copy offload fails or partially completes.
At present in kernel user of emulation is NVMe fabrics.
Signed-off-by: Nitesh Shetty <nj.shetty@samsung.com>
Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
Signed-off-by: Anuj Gupta <anuj20.g@samsung.com>
---
block/blk-lib.c | 223 +++++++++++++++++++++++++++++++++++++++++
include/linux/blkdev.h | 4 +
2 files changed, 227 insertions(+)
diff --git a/block/blk-lib.c b/block/blk-lib.c
index ad512293730b..5eeb5af20a9a 100644
--- a/block/blk-lib.c
+++ b/block/blk-lib.c
@@ -26,6 +26,20 @@ struct blkdev_copy_offload_io {
loff_t offset;
};
+/* Keeps track of single outstanding copy emulation IO */
+struct blkdev_copy_emulation_io {
+ struct blkdev_copy_io *cio;
+ struct work_struct emulation_work;
+ void *buf;
+ ssize_t buf_len;
+ loff_t pos_in;
+ loff_t pos_out;
+ ssize_t len;
+ struct block_device *bdev_in;
+ struct block_device *bdev_out;
+ gfp_t gfp;
+};
+
static sector_t bio_discard_limit(struct block_device *bdev, sector_t sector)
{
unsigned int discard_granularity = bdev_discard_granularity(bdev);
@@ -311,6 +325,215 @@ ssize_t blkdev_copy_offload(struct block_device *bdev, loff_t pos_in,
}
EXPORT_SYMBOL_GPL(blkdev_copy_offload);
+static void *blkdev_copy_alloc_buf(ssize_t req_size, ssize_t *alloc_size,
+ gfp_t gfp)
+{
+ int min_size = PAGE_SIZE;
+ char *buf;
+
+ while (req_size >= min_size) {
+ buf = kvmalloc(req_size, gfp);
+ if (buf) {
+ *alloc_size = req_size;
+ return buf;
+ }
+ req_size >>= 1;
+ }
+
+ return NULL;
+}
+
+static struct bio *bio_map_buf(void *data, unsigned int len, gfp_t gfp)
+{
+ unsigned long kaddr = (unsigned long)data;
+ unsigned long end = (kaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ unsigned long start = kaddr >> PAGE_SHIFT;
+ const int nr_pages = end - start;
+ bool is_vmalloc = is_vmalloc_addr(data);
+ struct page *page;
+ int offset, i;
+ struct bio *bio;
+
+ bio = bio_kmalloc(nr_pages, gfp);
+ if (!bio)
+ return ERR_PTR(-ENOMEM);
+ bio_init(bio, NULL, bio->bi_inline_vecs, nr_pages, 0);
+
+ if (is_vmalloc) {
+ flush_kernel_vmap_range(data, len);
+ bio->bi_private = data;
+ }
+
+ offset = offset_in_page(kaddr);
+ for (i = 0; i < nr_pages; i++) {
+ unsigned int bytes = PAGE_SIZE - offset;
+
+ if (len <= 0)
+ break;
+
+ if (bytes > len)
+ bytes = len;
+
+ if (!is_vmalloc)
+ page = virt_to_page(data);
+ else
+ page = vmalloc_to_page(data);
+ if (bio_add_page(bio, page, bytes, offset) < bytes) {
+ /* we don't support partial mappings */
+ bio_uninit(bio);
+ kfree(bio);
+ return ERR_PTR(-EINVAL);
+ }
+
+ data += bytes;
+ len -= bytes;
+ offset = 0;
+ }
+
+ return bio;
+}
+
+static void blkdev_copy_emulation_work(struct work_struct *work)
+{
+ struct blkdev_copy_emulation_io *emulation_io = container_of(work,
+ struct blkdev_copy_emulation_io, emulation_work);
+ struct blkdev_copy_io *cio = emulation_io->cio;
+ struct bio *read_bio, *write_bio;
+ loff_t pos_in = emulation_io->pos_in, pos_out = emulation_io->pos_out;
+ ssize_t rem, chunk;
+ int ret = 0;
+
+ for (rem = emulation_io->len; rem > 0; rem -= chunk) {
+ chunk = min_t(int, emulation_io->buf_len, rem);
+
+ read_bio = bio_map_buf(emulation_io->buf,
+ emulation_io->buf_len,
+ emulation_io->gfp);
+ if (IS_ERR(read_bio)) {
+ ret = PTR_ERR(read_bio);
+ break;
+ }
+ read_bio->bi_opf = REQ_OP_READ | REQ_SYNC;
+ bio_set_dev(read_bio, emulation_io->bdev_in);
+ read_bio->bi_iter.bi_sector = pos_in >> SECTOR_SHIFT;
+ read_bio->bi_iter.bi_size = chunk;
+ ret = submit_bio_wait(read_bio);
+ kfree(read_bio);
+ if (ret)
+ break;
+
+ write_bio = bio_map_buf(emulation_io->buf,
+ emulation_io->buf_len,
+ emulation_io->gfp);
+ if (IS_ERR(write_bio)) {
+ ret = PTR_ERR(write_bio);
+ break;
+ }
+ write_bio->bi_opf = REQ_OP_WRITE | REQ_SYNC;
+ bio_set_dev(write_bio, emulation_io->bdev_out);
+ write_bio->bi_iter.bi_sector = pos_out >> SECTOR_SHIFT;
+ write_bio->bi_iter.bi_size = chunk;
+ ret = submit_bio_wait(write_bio);
+ kfree(write_bio);
+ if (ret)
+ break;
+
+ pos_in += chunk;
+ pos_out += chunk;
+ }
+ cio->status = ret;
+ kvfree(emulation_io->buf);
+ kfree(emulation_io);
+ blkdev_copy_endio(cio);
+}
+
+static inline ssize_t queue_max_hw_bytes(struct request_queue *q)
+{
+ return min_t(ssize_t, queue_max_hw_sectors(q) << SECTOR_SHIFT,
+ queue_max_segments(q) << PAGE_SHIFT);
+}
+/*
+ * @bdev_in: source block device
+ * @pos_in: source offset
+ * @bdev_out: destination block device
+ * @pos_out: destination offset
+ * @len: length in bytes to be copied
+ * @endio: endio function to be called on completion of copy operation,
+ * for synchronous operation this should be NULL
+ * @private: endio function will be called with this private data,
+ * for synchronous operation this should be NULL
+ * @gfp_mask: memory allocation flags (for bio_alloc)
+ *
+ * For synchronous operation returns the length of bytes copied or error
+ * For asynchronous operation returns -EIOCBQUEUED or error
+ *
+ * Description:
+ * If native copy offload feature is absent, caller can use this function
+ * as fallback to perform copy.
+ * We store information required to perform the copy along with temporary
+ * buffer allocation. We async punt copy emulation to a worker. And worker
+ * performs copy in 2 steps.
+ * 1. Read data from source to temporary buffer
+ * 2. Write data to destination from temporary buffer
+ */
+ssize_t blkdev_copy_emulation(struct block_device *bdev_in, loff_t pos_in,
+ struct block_device *bdev_out, loff_t pos_out,
+ size_t len, void (*endio)(void *, int, ssize_t),
+ void *private, gfp_t gfp)
+{
+ struct request_queue *in = bdev_get_queue(bdev_in);
+ struct request_queue *out = bdev_get_queue(bdev_out);
+ struct blkdev_copy_emulation_io *emulation_io;
+ struct blkdev_copy_io *cio;
+ ssize_t ret;
+ size_t max_hw_bytes = min(queue_max_hw_bytes(in),
+ queue_max_hw_bytes(out));
+
+ ret = blkdev_copy_sanity_check(bdev_in, pos_in, bdev_out, pos_out, len);
+ if (ret)
+ return ret;
+
+ cio = kzalloc(sizeof(*cio), GFP_KERNEL);
+ if (!cio)
+ return -ENOMEM;
+
+ cio->waiter = current;
+ cio->copied = len;
+ cio->endio = endio;
+ cio->private = private;
+
+ emulation_io = kzalloc(sizeof(*emulation_io), gfp);
+ if (!emulation_io)
+ goto err_free_cio;
+ emulation_io->cio = cio;
+ INIT_WORK(&emulation_io->emulation_work, blkdev_copy_emulation_work);
+ emulation_io->pos_in = pos_in;
+ emulation_io->pos_out = pos_out;
+ emulation_io->len = len;
+ emulation_io->bdev_in = bdev_in;
+ emulation_io->bdev_out = bdev_out;
+ emulation_io->gfp = gfp;
+
+ emulation_io->buf = blkdev_copy_alloc_buf(min(max_hw_bytes, len),
+ &emulation_io->buf_len, gfp);
+ if (!emulation_io->buf)
+ goto err_free_emulation_io;
+
+ schedule_work(&emulation_io->emulation_work);
+
+ if (cio->endio)
+ return -EIOCBQUEUED;
+
+ return blkdev_copy_wait_io_completion(cio);
+
+err_free_emulation_io:
+ kfree(emulation_io);
+err_free_cio:
+ kfree(cio);
+ return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(blkdev_copy_emulation);
+
static int __blkdev_issue_write_zeroes(struct block_device *bdev,
sector_t sector, sector_t nr_sects, gfp_t gfp_mask,
struct bio **biop, unsigned flags)
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 81558cb7c019..67eab354592c 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1046,6 +1046,10 @@ ssize_t blkdev_copy_offload(struct block_device *bdev, loff_t pos_in,
loff_t pos_out, size_t len,
void (*endio)(void *, int, ssize_t),
void *private, gfp_t gfp_mask);
+ssize_t blkdev_copy_emulation(struct block_device *bdev_in, loff_t pos_in,
+ struct block_device *bdev_out, loff_t pos_out,
+ size_t len, void (*endio)(void *, int, ssize_t),
+ void *private, gfp_t gfp);
#define BLKDEV_ZERO_NOUNMAP (1 << 0) /* do not free blocks */
#define BLKDEV_ZERO_NOFALLBACK (1 << 1) /* don't write explicit zeroes */
--
2.35.1.500.gb896f729e2
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH v14 04/11] block: add emulation for copy
@ 2023-08-13 5:00 kernel test robot
0 siblings, 0 replies; 2+ messages in thread
From: kernel test robot @ 2023-08-13 5:00 UTC (permalink / raw)
To: oe-kbuild; +Cc: lkp, Dan Carpenter
BCC: lkp@intel.com
CC: oe-kbuild-all@lists.linux.dev
In-Reply-To: <20230811105300.15889-5-nj.shetty@samsung.com>
References: <20230811105300.15889-5-nj.shetty@samsung.com>
TO: Nitesh Shetty <nj.shetty@samsung.com>
TO: Jens Axboe <axboe@kernel.dk>
TO: Jonathan Corbet <corbet@lwn.net>
TO: Alasdair Kergon <agk@redhat.com>
TO: Mike Snitzer <snitzer@kernel.org>
TO: dm-devel@redhat.com
TO: Keith Busch <kbusch@kernel.org>
TO: Christoph Hellwig <hch@lst.de>
TO: Sagi Grimberg <sagi@grimberg.me>
TO: Chaitanya Kulkarni <kch@nvidia.com>
TO: Alexander Viro <viro@zeniv.linux.org.uk>
TO: Christian Brauner <brauner@kernel.org>
CC: martin.petersen@oracle.com
CC: mcgrof@kernel.org
CC: dlemoal@kernel.org
CC: gost.dev@samsung.com
CC: Nitesh Shetty <nj.shetty@samsung.com>
CC: Vincent Fu <vincent.fu@samsung.com>
CC: Anuj Gupta <anuj20.g@samsung.com>
CC: linux-block@vger.kernel.org
CC: linux-kernel@vger.kernel.org
CC: linux-doc@vger.kernel.org
CC: linux-nvme@lists.infradead.org
CC: linux-fsdevel@vger.kernel.org
Hi Nitesh,
kernel test robot noticed the following build warnings:
[auto build test WARNING on f7dc24b3413851109c4047b22997bd0d95ed52a2]
url: https://github.com/intel-lab-lkp/linux/commits/Nitesh-Shetty/block-Introduce-queue-limits-and-sysfs-for-copy-offload-support/20230811-192259
base: f7dc24b3413851109c4047b22997bd0d95ed52a2
patch link: https://lore.kernel.org/r/20230811105300.15889-5-nj.shetty%40samsung.com
patch subject: [PATCH v14 04/11] block: add emulation for copy
:::::: branch date: 2 days ago
:::::: commit date: 2 days ago
config: x86_64-allnoconfig (https://download.01.org/0day-ci/archive/20230813/202308131233.B29RhKuB-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce: (https://download.01.org/0day-ci/archive/20230813/202308131233.B29RhKuB-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <error27@gmail.com>
| Closes: https://lore.kernel.org/r/202308131233.B29RhKuB-lkp@intel.com/
New smatch warnings:
block/blk-lib.c:496 blkdev_copy_emulation() warn: use 'gfp' here instead of GFP_KERNEL?
Old smatch warnings:
block/blk-lib.c:260 blkdev_copy_offload() warn: use 'gfp' here instead of GFP_KERNEL?
block/blk-lib.c:276 blkdev_copy_offload() warn: use 'gfp' here instead of GFP_KERNEL?
block/blk-lib.c:319 blkdev_copy_offload() error: dereferencing freed memory 'cio'
vim +/gfp +496 block/blk-lib.c
71342ad1494fdc Nitesh Shetty 2023-08-11 449
71342ad1494fdc Nitesh Shetty 2023-08-11 450 static inline ssize_t queue_max_hw_bytes(struct request_queue *q)
71342ad1494fdc Nitesh Shetty 2023-08-11 451 {
71342ad1494fdc Nitesh Shetty 2023-08-11 452 return min_t(ssize_t, queue_max_hw_sectors(q) << SECTOR_SHIFT,
71342ad1494fdc Nitesh Shetty 2023-08-11 453 queue_max_segments(q) << PAGE_SHIFT);
71342ad1494fdc Nitesh Shetty 2023-08-11 454 }
71342ad1494fdc Nitesh Shetty 2023-08-11 455 /*
71342ad1494fdc Nitesh Shetty 2023-08-11 456 * @bdev_in: source block device
71342ad1494fdc Nitesh Shetty 2023-08-11 457 * @pos_in: source offset
71342ad1494fdc Nitesh Shetty 2023-08-11 458 * @bdev_out: destination block device
71342ad1494fdc Nitesh Shetty 2023-08-11 459 * @pos_out: destination offset
71342ad1494fdc Nitesh Shetty 2023-08-11 460 * @len: length in bytes to be copied
71342ad1494fdc Nitesh Shetty 2023-08-11 461 * @endio: endio function to be called on completion of copy operation,
71342ad1494fdc Nitesh Shetty 2023-08-11 462 * for synchronous operation this should be NULL
71342ad1494fdc Nitesh Shetty 2023-08-11 463 * @private: endio function will be called with this private data,
71342ad1494fdc Nitesh Shetty 2023-08-11 464 * for synchronous operation this should be NULL
71342ad1494fdc Nitesh Shetty 2023-08-11 465 * @gfp_mask: memory allocation flags (for bio_alloc)
71342ad1494fdc Nitesh Shetty 2023-08-11 466 *
71342ad1494fdc Nitesh Shetty 2023-08-11 467 * For synchronous operation returns the length of bytes copied or error
71342ad1494fdc Nitesh Shetty 2023-08-11 468 * For asynchronous operation returns -EIOCBQUEUED or error
71342ad1494fdc Nitesh Shetty 2023-08-11 469 *
71342ad1494fdc Nitesh Shetty 2023-08-11 470 * Description:
71342ad1494fdc Nitesh Shetty 2023-08-11 471 * If native copy offload feature is absent, caller can use this function
71342ad1494fdc Nitesh Shetty 2023-08-11 472 * as fallback to perform copy.
71342ad1494fdc Nitesh Shetty 2023-08-11 473 * We store information required to perform the copy along with temporary
71342ad1494fdc Nitesh Shetty 2023-08-11 474 * buffer allocation. We async punt copy emulation to a worker. And worker
71342ad1494fdc Nitesh Shetty 2023-08-11 475 * performs copy in 2 steps.
71342ad1494fdc Nitesh Shetty 2023-08-11 476 * 1. Read data from source to temporary buffer
71342ad1494fdc Nitesh Shetty 2023-08-11 477 * 2. Write data to destination from temporary buffer
71342ad1494fdc Nitesh Shetty 2023-08-11 478 */
71342ad1494fdc Nitesh Shetty 2023-08-11 479 ssize_t blkdev_copy_emulation(struct block_device *bdev_in, loff_t pos_in,
71342ad1494fdc Nitesh Shetty 2023-08-11 480 struct block_device *bdev_out, loff_t pos_out,
71342ad1494fdc Nitesh Shetty 2023-08-11 481 size_t len, void (*endio)(void *, int, ssize_t),
71342ad1494fdc Nitesh Shetty 2023-08-11 482 void *private, gfp_t gfp)
71342ad1494fdc Nitesh Shetty 2023-08-11 483 {
71342ad1494fdc Nitesh Shetty 2023-08-11 484 struct request_queue *in = bdev_get_queue(bdev_in);
71342ad1494fdc Nitesh Shetty 2023-08-11 485 struct request_queue *out = bdev_get_queue(bdev_out);
71342ad1494fdc Nitesh Shetty 2023-08-11 486 struct blkdev_copy_emulation_io *emulation_io;
71342ad1494fdc Nitesh Shetty 2023-08-11 487 struct blkdev_copy_io *cio;
71342ad1494fdc Nitesh Shetty 2023-08-11 488 ssize_t ret;
71342ad1494fdc Nitesh Shetty 2023-08-11 489 size_t max_hw_bytes = min(queue_max_hw_bytes(in),
71342ad1494fdc Nitesh Shetty 2023-08-11 490 queue_max_hw_bytes(out));
71342ad1494fdc Nitesh Shetty 2023-08-11 491
71342ad1494fdc Nitesh Shetty 2023-08-11 492 ret = blkdev_copy_sanity_check(bdev_in, pos_in, bdev_out, pos_out, len);
71342ad1494fdc Nitesh Shetty 2023-08-11 493 if (ret)
71342ad1494fdc Nitesh Shetty 2023-08-11 494 return ret;
71342ad1494fdc Nitesh Shetty 2023-08-11 495
71342ad1494fdc Nitesh Shetty 2023-08-11 @496 cio = kzalloc(sizeof(*cio), GFP_KERNEL);
71342ad1494fdc Nitesh Shetty 2023-08-11 497 if (!cio)
71342ad1494fdc Nitesh Shetty 2023-08-11 498 return -ENOMEM;
71342ad1494fdc Nitesh Shetty 2023-08-11 499
71342ad1494fdc Nitesh Shetty 2023-08-11 500 cio->waiter = current;
71342ad1494fdc Nitesh Shetty 2023-08-11 501 cio->copied = len;
71342ad1494fdc Nitesh Shetty 2023-08-11 502 cio->endio = endio;
71342ad1494fdc Nitesh Shetty 2023-08-11 503 cio->private = private;
71342ad1494fdc Nitesh Shetty 2023-08-11 504
71342ad1494fdc Nitesh Shetty 2023-08-11 505 emulation_io = kzalloc(sizeof(*emulation_io), gfp);
71342ad1494fdc Nitesh Shetty 2023-08-11 506 if (!emulation_io)
71342ad1494fdc Nitesh Shetty 2023-08-11 507 goto err_free_cio;
71342ad1494fdc Nitesh Shetty 2023-08-11 508 emulation_io->cio = cio;
71342ad1494fdc Nitesh Shetty 2023-08-11 509 INIT_WORK(&emulation_io->emulation_work, blkdev_copy_emulation_work);
71342ad1494fdc Nitesh Shetty 2023-08-11 510 emulation_io->pos_in = pos_in;
71342ad1494fdc Nitesh Shetty 2023-08-11 511 emulation_io->pos_out = pos_out;
71342ad1494fdc Nitesh Shetty 2023-08-11 512 emulation_io->len = len;
71342ad1494fdc Nitesh Shetty 2023-08-11 513 emulation_io->bdev_in = bdev_in;
71342ad1494fdc Nitesh Shetty 2023-08-11 514 emulation_io->bdev_out = bdev_out;
71342ad1494fdc Nitesh Shetty 2023-08-11 515 emulation_io->gfp = gfp;
71342ad1494fdc Nitesh Shetty 2023-08-11 516
71342ad1494fdc Nitesh Shetty 2023-08-11 517 emulation_io->buf = blkdev_copy_alloc_buf(min(max_hw_bytes, len),
71342ad1494fdc Nitesh Shetty 2023-08-11 518 &emulation_io->buf_len, gfp);
71342ad1494fdc Nitesh Shetty 2023-08-11 519 if (!emulation_io->buf)
71342ad1494fdc Nitesh Shetty 2023-08-11 520 goto err_free_emulation_io;
71342ad1494fdc Nitesh Shetty 2023-08-11 521
71342ad1494fdc Nitesh Shetty 2023-08-11 522 schedule_work(&emulation_io->emulation_work);
71342ad1494fdc Nitesh Shetty 2023-08-11 523
71342ad1494fdc Nitesh Shetty 2023-08-11 524 if (cio->endio)
71342ad1494fdc Nitesh Shetty 2023-08-11 525 return -EIOCBQUEUED;
71342ad1494fdc Nitesh Shetty 2023-08-11 526
71342ad1494fdc Nitesh Shetty 2023-08-11 527 return blkdev_copy_wait_io_completion(cio);
71342ad1494fdc Nitesh Shetty 2023-08-11 528
71342ad1494fdc Nitesh Shetty 2023-08-11 529 err_free_emulation_io:
71342ad1494fdc Nitesh Shetty 2023-08-11 530 kfree(emulation_io);
71342ad1494fdc Nitesh Shetty 2023-08-11 531 err_free_cio:
71342ad1494fdc Nitesh Shetty 2023-08-11 532 kfree(cio);
71342ad1494fdc Nitesh Shetty 2023-08-11 533 return -ENOMEM;
71342ad1494fdc Nitesh Shetty 2023-08-11 534 }
71342ad1494fdc Nitesh Shetty 2023-08-11 535 EXPORT_SYMBOL_GPL(blkdev_copy_emulation);
71342ad1494fdc Nitesh Shetty 2023-08-11 536
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2023-08-13 5:00 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-08-13 5:00 [PATCH v14 04/11] block: add emulation for copy kernel test robot
[not found] <CGME20230811105713epcas5p3b5323a0c553006e60671dde6c72fc4c6@epcas5p3.samsung.com>
2023-08-11 10:52 ` [dm-devel] [PATCH v14 00/11] Implement copy offload support Nitesh Shetty
2023-08-11 10:52 ` [PATCH v14 04/11] block: add emulation for copy Nitesh Shetty
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.