Whamcloud - gitweb
LU-16712 cksum: fix generating T10PI guard tags for partial brw page 40/50540/3
authorLi Dongyang <dongyangli@ddn.com>
Wed, 5 Apr 2023 02:54:13 +0000 (12:54 +1000)
committerOleg Drokin <green@whamcloud.com>
Fri, 19 May 2023 07:07:22 +0000 (07:07 +0000)
To get better performance, we allocate a page as the buffer for
T10PI guard tags, we fill the buffer going over every page for brw,
when the buffer is considered full, we use
cfs_crypto_hash_update_page() to update the hash and reuse the buffer.

It doesn't work when there's a page in the brw gets clipped, and the
checksum sector size is 512. For a page with PAGE_SIZE of 4096,
and offset at 1024, we will end up with 6 guard tags, and won't have
enough space in the very end of the buffer for a full brw page, which
needs 8.

Work out the number of guard tags for each page, update the
checksum hash and reuse the buffer when needed.

Change-Id: Ic591e63b24534f2a42b670669520895cb35a9546
Fixes: b1e7be00cb ("LU-10472 osc: add T10PI support for RPC checksum")
Signed-off-by: Li Dongyang <dongyangli@ddn.com>
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/50540
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Li Xi <lixi@ddn.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/osc/osc_request.c
lustre/target/tgt_handler.c

index 5ee8a36..1d0c2b0 100644 (file)
@@ -1189,12 +1189,12 @@ static int osc_checksum_bulk_t10pi(const char *obd_name, int nob,
        struct page *__page;
        unsigned char *buffer;
        __be16 *guard_start;
-       unsigned int bufsize;
        int guard_number;
        int used_number = 0;
        int used;
        u32 cksum;
-       int rc = 0;
+       unsigned int bufsize = sizeof(cksum);
+       int rc = 0, rc2;
        int i = 0;
 
        LASSERT(pg_count > 0);
@@ -1219,14 +1219,22 @@ static int osc_checksum_bulk_t10pi(const char *obd_name, int nob,
               guard_number, resend, nob, pg_count);
 
        while (nob > 0 && pg_count > 0) {
+               int off = pga[i]->off & ~PAGE_MASK;
                unsigned int count = pga[i]->count > nob ? nob : pga[i]->count;
+               int guards_needed = DIV_ROUND_UP(off + count, sector_size) -
+                                       (off / sector_size);
+
+               if (guards_needed > guard_number - used_number) {
+                       cfs_crypto_hash_update_page(req, __page, 0,
+                               used_number * sizeof(*guard_start));
+                       used_number = 0;
+               }
 
                /* corrupt the data before we compute the checksum, to
                 * simulate an OST->client data error */
                if (unlikely(i == 0 && opc == OST_READ &&
                             OBD_FAIL_CHECK(OBD_FAIL_OSC_CHECKSUM_RECEIVE))) {
                        unsigned char *ptr = kmap(pga[i]->pg);
-                       int off = pga[i]->off & ~PAGE_MASK;
 
                        memcpy(ptr + off, "bad1", min_t(typeof(nob), 4, nob));
                        kunmap(pga[i]->pg);
@@ -1253,33 +1261,31 @@ static int osc_checksum_bulk_t10pi(const char *obd_name, int nob,
                        break;
 
                used_number += used;
-               if (used_number == guard_number) {
-                       cfs_crypto_hash_update_page(req, __page, 0,
-                               used_number * sizeof(*guard_start));
-                       used_number = 0;
-               }
-
                nob -= pga[i]->count;
                pg_count--;
                i++;
        }
        kunmap(__page);
        if (rc)
-               GOTO(out, rc);
+               GOTO(out_hash, rc);
 
        if (used_number != 0)
                cfs_crypto_hash_update_page(req, __page, 0,
                        used_number * sizeof(*guard_start));
 
-       bufsize = sizeof(cksum);
-       cfs_crypto_hash_final(req, (unsigned char *)&cksum, &bufsize);
-
-       /* For sending we only compute the wrong checksum instead
-        * of corrupting the data so it is still correct on a redo */
-       if (opc == OST_WRITE && OBD_FAIL_CHECK(OBD_FAIL_OSC_CHECKSUM_SEND))
-               cksum++;
+out_hash:
+       rc2 = cfs_crypto_hash_final(req, (unsigned char *)&cksum, &bufsize);
+       if (!rc)
+               rc = rc2;
+       if (rc == 0) {
+               /* For sending we only compute the wrong checksum instead
+                * of corrupting the data so it is still correct on a redo */
+               if (opc == OST_WRITE &&
+                               OBD_FAIL_CHECK(OBD_FAIL_OSC_CHECKSUM_SEND))
+                       cksum++;
 
-       *check_sum = cksum;
+               *check_sum = cksum;
+       }
 out:
        __free_page(__page);
        return rc;
index c1d08ba..6c0192b 100644 (file)
@@ -2101,13 +2101,21 @@ static int tgt_checksum_niobuf_t10pi(struct lu_target *tgt,
                CDEBUG(D_PAGE | D_HA, "GRD tags per page = %u\n", guard_number);
        for (i = 0; i < npages; i++) {
                bool use_t10_grd;
+               int off = local_nb[i].lnb_page_offset & ~PAGE_MASK;
+               int len = local_nb[i].lnb_len;
+               int guards_needed = DIV_ROUND_UP(off + len, sector_size) -
+                                       (off / sector_size);
+
+               if (guards_needed > guard_number - used_number) {
+                       cfs_crypto_hash_update_page(req, __page, 0,
+                               used_number * sizeof(*guard_start));
+                       used_number = 0;
+               }
 
                /* corrupt the data before we compute the checksum, to
                 * simulate a client->OST data error */
                if (i == 0 && opc == OST_WRITE &&
                    OBD_FAIL_CHECK(OBD_FAIL_OST_CHECKSUM_RECEIVE)) {
-                       int off = local_nb[i].lnb_page_offset & ~PAGE_MASK;
-                       int len = local_nb[i].lnb_len;
                        struct page *np = tgt_page_to_corrupt;
 
                        if (np) {
@@ -2140,7 +2148,7 @@ static int tgt_checksum_niobuf_t10pi(struct lu_target *tgt,
                              local_nb[i].lnb_len == PAGE_SIZE &&
                              local_nb[i].lnb_guard_disk;
                if (use_t10_grd) {
-                       used = DIV_ROUND_UP(local_nb[i].lnb_len, sector_size);
+                       used = guards_needed;
                        if (used > (guard_number - used_number)) {
                                rc = -E2BIG;
                                CDEBUG(D_PAGE | D_HA,
@@ -2223,18 +2231,11 @@ static int tgt_checksum_niobuf_t10pi(struct lu_target *tgt,
                }
 
                used_number += used;
-               if (used_number == guard_number) {
-                       cfs_crypto_hash_update_page(req, __page, 0,
-                               used_number * sizeof(*guard_start));
-                       used_number = 0;
-               }
 
                 /* corrupt the data after we compute the checksum, to
                 * simulate an OST->client data error */
                if (unlikely(i == 0 && opc == OST_READ &&
                             OBD_FAIL_CHECK(OBD_FAIL_OST_CHECKSUM_SEND))) {
-                       int off = local_nb[i].lnb_page_offset & ~PAGE_MASK;
-                       int len = local_nb[i].lnb_len;
                        struct page *np = tgt_page_to_corrupt;
 
                        if (np) {