From: Douglas Gilbert <dgilbert@interlog.com>
To: linux-scsi@vger.kernel.org
Cc: martin.petersen@oracle.com, jejb@linux.vnet.ibm.com,
hare@suse.de, bvanassche@acm.org,
Bodo Stroesser <bostroesser@gmail.com>,
David Disseldorp <ddiss@suse.de>
Subject: [PATCH 3/5] scatterlist: add sgl_equal_sgl() function
Date: Sun, 23 Oct 2022 21:02:42 -0400 [thread overview]
Message-ID: <20221024010244.9522-4-dgilbert@interlog.com> (raw)
In-Reply-To: <20221024010244.9522-1-dgilbert@interlog.com>
After enabling copies between scatter gather lists (sgl_s), another
storage related operation is to compare two sgl_s for equality. This
new function is designed to partially implement NVMe's Compare
command and the SCSI VERIFY(BYTCHK=1) command. Like memcmp() this
function begins scanning at the start (of each sgl) and returns
false on the first miscompare and stops comparing.
The sgl_equal_sgl_idx() function additionally yields the index (i.e.
byte position) of the first miscompare. The additional parameter,
miscompare_idx, is a pointer. If it is non-NULL and a miscompare is
detected (i.e. the function returns false) then the byte index of
the first miscompare is written to *miscompare_idx. Knowing the
location of the first miscompare is needed to implement properly
the SCSI COMPARE AND WRITE command.
Reviewed-by: Bodo Stroesser <bostroesser@gmail.com>
Reviewed-by: David Disseldorp <ddiss@suse.de>
Signed-off-by: Douglas Gilbert <dgilbert@interlog.com>
---
include/linux/scatterlist.h | 8 +++
lib/scatterlist.c | 110 ++++++++++++++++++++++++++++++++++++
2 files changed, 118 insertions(+)
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index cea1edd246cb..e1552a3e9e13 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -449,6 +449,14 @@ size_t sgl_copy_sgl(struct scatterlist *d_sgl, unsigned int d_nents, off_t d_ski
struct scatterlist *s_sgl, unsigned int s_nents, off_t s_skip,
size_t n_bytes);
+bool sgl_equal_sgl(struct scatterlist *x_sgl, unsigned int x_nents, off_t x_skip,
+ struct scatterlist *y_sgl, unsigned int y_nents, off_t y_skip,
+ size_t n_bytes);
+
+bool sgl_equal_sgl_idx(struct scatterlist *x_sgl, unsigned int x_nents, off_t x_skip,
+ struct scatterlist *y_sgl, unsigned int y_nents, off_t y_skip,
+ size_t n_bytes, size_t *miscompare_idx);
+
/*
* Maximum number of entries that will be allocated in one piece, if
* a list larger than this is required then chaining will be utilized.
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index 5d873bd0cb96..426d73ba464a 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -1162,3 +1162,113 @@ size_t sgl_copy_sgl(struct scatterlist *d_sgl, unsigned int d_nents, off_t d_ski
return offset;
}
EXPORT_SYMBOL(sgl_copy_sgl);
+
+/**
+ * sgl_equal_sgl_idx - check if x and y (both sgl_s) compare equal, report
+ * index for first unequal bytes
+ * @x_sgl: x (left) sgl
+ * @x_nents: Number of SG entries in x (left) sgl
+ * @x_skip: Number of bytes to skip in x (left) before starting
+ * @y_sgl: y (right) sgl
+ * @y_nents: Number of SG entries in y (right) sgl
+ * @y_skip: Number of bytes to skip in y (right) before starting
+ * @n_bytes: The (maximum) number of bytes to compare
+ * @miscompare_idx: if return is false, index of first miscompare written
+ * to this pointer (if non-NULL). Value will be < n_bytes
+ *
+ * Returns:
+ * true if x and y compare equal before x, y or n_bytes is exhausted.
+ * Otherwise on a miscompare, returns false (and stops comparing). If return
+ * is false and miscompare_idx is non-NULL, then index of first miscompared
+ * byte written to *miscompare_idx.
+ *
+ * Notes:
+ * x and y are symmetrical: they can be swapped and the result is the same.
+ *
+ * Implementation is based on memcmp(). x and y segments may overlap.
+ *
+ * The notes in sgl_copy_sgl() about large sgl_s _applies here as well.
+ *
+ **/
+bool sgl_equal_sgl_idx(struct scatterlist *x_sgl, unsigned int x_nents, off_t x_skip,
+ struct scatterlist *y_sgl, unsigned int y_nents, off_t y_skip,
+ size_t n_bytes, size_t *miscompare_idx)
+{
+ bool equ = true;
+ size_t len;
+ size_t offset = 0;
+ struct sg_mapping_iter x_iter, y_iter;
+
+ if (n_bytes == 0)
+ return true;
+ sg_miter_start(&x_iter, x_sgl, x_nents, SG_MITER_ATOMIC | SG_MITER_FROM_SG);
+ sg_miter_start(&y_iter, y_sgl, y_nents, SG_MITER_ATOMIC | SG_MITER_FROM_SG);
+ if (!sg_miter_skip(&x_iter, x_skip))
+ goto fini;
+ if (!sg_miter_skip(&y_iter, y_skip))
+ goto fini;
+
+ while (offset < n_bytes) {
+ if (!sg_miter_next(&x_iter))
+ break;
+ if (!sg_miter_next(&y_iter))
+ break;
+ len = min3(x_iter.length, y_iter.length, n_bytes - offset);
+
+ equ = !memcmp(x_iter.addr, y_iter.addr, len);
+ if (!equ)
+ goto fini;
+ offset += len;
+ /* LIFO order is important when SG_MITER_ATOMIC is used */
+ y_iter.consumed = len;
+ sg_miter_stop(&y_iter);
+ x_iter.consumed = len;
+ sg_miter_stop(&x_iter);
+ }
+fini:
+ if (miscompare_idx && !equ) {
+ u8 *xp = x_iter.addr;
+ u8 *yp = y_iter.addr;
+ u8 *x_endp;
+
+ for (x_endp = xp + len ; xp < x_endp; ++xp, ++yp) {
+ if (*xp != *yp)
+ break;
+ }
+ *miscompare_idx = offset + len - (x_endp - xp);
+ }
+ sg_miter_stop(&y_iter);
+ sg_miter_stop(&x_iter);
+ return equ;
+}
+EXPORT_SYMBOL(sgl_equal_sgl_idx);
+
+/**
+ * sgl_equal_sgl - check if x and y (both sgl_s) compare equal
+ * @x_sgl: x (left) sgl
+ * @x_nents: Number of SG entries in x (left) sgl
+ * @x_skip: Number of bytes to skip in x (left) before starting
+ * @y_sgl: y (right) sgl
+ * @y_nents: Number of SG entries in y (right) sgl
+ * @y_skip: Number of bytes to skip in y (right) before starting
+ * @n_bytes: The (maximum) number of bytes to compare
+ *
+ * Returns:
+ * true if x and y compare equal before x, y or n_bytes is exhausted.
+ * Otherwise on a miscompare, returns false (and stops comparing).
+ *
+ * Notes:
+ * x and y are symmetrical: they can be swapped and the result is the same.
+ *
+ * Implementation is based on memcmp(). x and y segments may overlap.
+ *
+ * The notes in sgl_copy_sgl() about large sgl_s _applies here as well.
+ *
+ **/
+bool sgl_equal_sgl(struct scatterlist *x_sgl, unsigned int x_nents, off_t x_skip,
+ struct scatterlist *y_sgl, unsigned int y_nents, off_t y_skip,
+ size_t n_bytes)
+{
+ return sgl_equal_sgl_idx(x_sgl, x_nents, x_skip, y_sgl, y_nents, y_skip, n_bytes, NULL);
+}
+EXPORT_SYMBOL(sgl_equal_sgl);
--
2.37.3
next prev parent reply other threads:[~2022-10-24 1:12 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-10-24 1:02 [PATCH 0/5] scatterlist: add operations for scsi_debug Douglas Gilbert
2022-10-24 1:02 ` [PATCH 1/5] sgl_alloc_order: remove 4 GiB limit Douglas Gilbert
2022-10-24 12:21 ` Jason Gunthorpe
2022-10-24 14:32 ` Bodo Stroesser
2022-10-24 17:32 ` Jason Gunthorpe
2022-10-24 19:58 ` Douglas Gilbert
2022-10-25 12:19 ` Jason Gunthorpe
2022-10-25 10:46 ` Bodo Stroesser
2022-10-25 12:18 ` Jason Gunthorpe
2022-10-24 1:02 ` [PATCH 2/5] scatterlist: add sgl_copy_sgl() function Douglas Gilbert
2022-10-24 1:02 ` Douglas Gilbert [this message]
2022-10-24 1:02 ` [PATCH 4/5] scatterlist: add sgl_memset() Douglas Gilbert
2022-10-24 1:02 ` [PATCH 5/5] scsi_debug: change store from vmalloc to sgl Douglas Gilbert
2022-10-24 15:08 ` Bodo Stroesser
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=20221024010244.9522-4-dgilbert@interlog.com \
--to=dgilbert@interlog.com \
--cc=bostroesser@gmail.com \
--cc=bvanassche@acm.org \
--cc=ddiss@suse.de \
--cc=hare@suse.de \
--cc=jejb@linux.vnet.ibm.com \
--cc=linux-scsi@vger.kernel.org \
--cc=martin.petersen@oracle.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.