From: Douglas Gilbert <dgilbert@interlog.com>
To: linux-scsi@vger.kernel.org, linux-block@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 v7 3/4] scatterlist: add sgl_equal_sgl() function
Date: Mon, 31 Jan 2022 22:49:14 -0500 [thread overview]
Message-ID: <20220201034915.183117-4-dgilbert@interlog.com> (raw)
In-Reply-To: <20220201034915.183117-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 1291ff63fe83..a96874a8b791 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -380,6 +380,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 d4d56eece250..1fb14b2e320a 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -1161,3 +1161,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.25.1
next prev parent reply other threads:[~2022-02-01 3:57 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-02-01 3:49 [PATCH v7 0/4] scatterlist: add new capabilities Douglas Gilbert
2022-02-01 3:49 ` [PATCH v7 1/4] sgl_alloc_order: remove 4 GiB limit Douglas Gilbert
2022-02-01 12:36 ` Jason Gunthorpe
2022-02-01 13:46 ` kernel test robot
2022-02-01 13:46 ` kernel test robot
2022-02-01 3:49 ` [PATCH v7 2/4] scatterlist: add sgl_copy_sgl() function Douglas Gilbert
2022-02-01 3:49 ` Douglas Gilbert [this message]
2022-02-01 3:49 ` [PATCH v7 4/4] scatterlist: add sgl_memset() Douglas Gilbert
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=20220201034915.183117-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-block@vger.kernel.org \
--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.