Author: scottph
Date: Tue Nov 12 16:24:37 2019
New Revision: 354648
URL: https://svnweb.freebsd.org/changeset/base/354648

Log:
  nvdimm(4): Fix various problems when the using the second label index block
  
  struct nvdimm_label_index is dynamically sized, with the `free`
  bitfield expanding to hold `slot_cnt` entries. Fix a few places
  where we were treating the struct as though it had a fixed sized.
  
  Reviewed by:  cem
  Approved by:  scottl (mentor)
  MFC after:    1 week
  Sponsored by: Intel Corporation
  Differential Revision:        https://reviews.freebsd.org/D22253

Modified:
  head/sys/dev/nvdimm/nvdimm.c

Modified: head/sys/dev/nvdimm/nvdimm.c
==============================================================================
--- head/sys/dev/nvdimm/nvdimm.c        Tue Nov 12 15:56:27 2019        
(r354647)
+++ head/sys/dev/nvdimm/nvdimm.c        Tue Nov 12 16:24:37 2019        
(r354648)
@@ -183,7 +183,7 @@ label_index_is_valid(struct nvdimm_label_index *index,
 {
        uint64_t checksum;
 
-       index = (struct nvdimm_label_index *)((uint8_t *)index + offset);
+       index = (struct nvdimm_label_index *)((uint8_t *)index + size * offset);
        if (strcmp(index->signature, NVDIMM_INDEX_BLOCK_SIGNATURE) != 0)
                return false;
        checksum = index->checksum;
@@ -242,7 +242,7 @@ read_label(struct nvdimm_dev *nv, int num)
 static int
 read_labels(struct nvdimm_dev *nv)
 {
-       struct nvdimm_label_index *indices;
+       struct nvdimm_label_index *indices, *index1;
        size_t bitfield_size, index_size, num_labels;
        int error, n;
        bool index_0_valid, index_1_valid;
@@ -258,6 +258,7 @@ read_labels(struct nvdimm_dev *nv)
            sizeof(struct nvdimm_label);
        bitfield_size = roundup2(num_labels, 8) / 8;
        indices = malloc(2 * index_size, M_NVDIMM, M_WAITOK);
+       index1 = (void *)((uint8_t *)indices + index_size);
        error = read_label_area(nv, (void *)indices, 0, 2 * index_size);
        if (error != 0) {
                free(indices, M_NVDIMM);
@@ -271,18 +272,29 @@ read_labels(struct nvdimm_dev *nv)
                free(indices, M_NVDIMM);
                return (ENXIO);
        }
-       if (index_0_valid && index_1_valid &&
-           (indices[1].seq > indices[0].seq ||
-           (indices[1].seq == 1 && indices[0].seq == 3)))
-               index_0_valid = false;
+       if (index_0_valid && index_1_valid) {
+               if (((int)indices->seq - (int)index1->seq + 3) % 3 == 1) {
+                       /* index 0 was more recently updated */
+                       index_1_valid = false;
+               } else {
+                       /*
+                        * either index 1 was more recently updated,
+                        * or the sequence numbers are equal, in which
+                        * case the specification says the block with
+                        * the higher offset is to be treated as valid
+                        */
+                       index_0_valid = false;
+               }
+       }
        nv->label_index = malloc(index_size, M_NVDIMM, M_WAITOK);
-       bcopy(indices + (index_0_valid ? 0 : 1), nv->label_index, index_size);
+       bcopy(index_0_valid ? indices : index1, nv->label_index, index_size);
        free(indices, M_NVDIMM);
-       for (bit_ffc_at((bitstr_t *)nv->label_index->free, 0, num_labels, &n);
-            n >= 0;
-            bit_ffc_at((bitstr_t *)nv->label_index->free, n + 1, num_labels,
-            &n)) {
+       bit_ffc_at((bitstr_t *)nv->label_index->free, 0,
+           nv->label_index->slot_cnt, &n);
+       while (n >= 0) {
                read_label(nv, n);
+               bit_ffc_at((bitstr_t *)nv->label_index->free, n + 1,
+                   nv->label_index->slot_cnt, &n);
        }
        return (0);
 }
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to