md-bitmap: refactor md_bitmap_init_from_disk
authorChristoph Hellwig <hch@lst.de>
Thu, 15 Jun 2023 06:48:35 +0000 (08:48 +0200)
committerSong Liu <song@kernel.org>
Thu, 27 Jul 2023 07:13:29 +0000 (00:13 -0700)
Split the confusing loop in md_bitmap_init_from_disk that iterates over
all chunks but also needs to read and map the pages into three separate
loops: one that iterates over the pages to read them, a second optional
one to iterate over the pages to mark them invalid if the bitmaps are
out of date, and a final one that actually iterates over the chunks.

Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202306160552.smw0qbmb-lkp@intel.com/
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Song Liu <song@kernel.org>
Link: https://lore.kernel.org/r/20230615064840.629492-7-hch@lst.de
drivers/md/md-bitmap.c

index fa0f6ca..db5725b 100644 (file)
@@ -1065,33 +1065,31 @@ void md_bitmap_unplug_async(struct bitmap *bitmap)
 EXPORT_SYMBOL(md_bitmap_unplug_async);
 
 static void md_bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int needed);
-/* * bitmap_init_from_disk -- called at bitmap_create time to initialize
- * the in-memory bitmap from the on-disk bitmap -- also, sets up the
- * memory mapping of the bitmap file
- * Special cases:
- *   if there's no bitmap file, or if the bitmap file had been
- *   previously kicked from the array, we mark all the bits as
- *   1's in order to cause a full resync.
+
+/*
+ * Initialize the in-memory bitmap from the on-disk bitmap and set up the memory
+ * mapping of the bitmap file.
+ *
+ * Special case: If there's no bitmap file, or if the bitmap file had been
+ * previously kicked from the array, we mark all the bits as 1's in order to
+ * cause a full resync.
  *
  * We ignore all bits for sectors that end earlier than 'start'.
- * This is used when reading an out-of-date bitmap...
+ * This is used when reading an out-of-date bitmap.
  */
 static int md_bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
 {
-       unsigned long i, chunks, index, oldindex, bit, node_offset = 0;
-       struct page *page = NULL;
-       unsigned long bit_cnt = 0;
-       struct file *file;
-       unsigned long offset;
-       int outofdate;
-       int ret = -ENOSPC;
-       void *paddr;
+       bool outofdate = test_bit(BITMAP_STALE, &bitmap->flags);
+       struct mddev *mddev = bitmap->mddev;
+       unsigned long chunks = bitmap->counts.chunks;
        struct bitmap_storage *store = &bitmap->storage;
+       struct file *file = store->file;
+       unsigned long node_offset = 0;
+       unsigned long bit_cnt = 0;
+       unsigned long i;
+       int ret;
 
-       chunks = bitmap->counts.chunks;
-       file = store->file;
-
-       if (!file && !bitmap->mddev->bitmap_info.offset) {
+       if (!file && !mddev->bitmap_info.offset) {
                /* No permanent bitmap - fill with '1s'. */
                store->filemap = NULL;
                store->file_pages = 0;
@@ -1106,77 +1104,79 @@ static int md_bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
                return 0;
        }
 
-       outofdate = test_bit(BITMAP_STALE, &bitmap->flags);
-       if (outofdate)
-               pr_warn("%s: bitmap file is out of date, doing full recovery\n", bmname(bitmap));
-
        if (file && i_size_read(file->f_mapping->host) < store->bytes) {
                pr_warn("%s: bitmap file too short %lu < %lu\n",
                        bmname(bitmap),
                        (unsigned long) i_size_read(file->f_mapping->host),
                        store->bytes);
+               ret = -ENOSPC;
                goto err;
        }
 
-       oldindex = ~0L;
-       offset = 0;
-       if (!bitmap->mddev->bitmap_info.external)
-               offset = sizeof(bitmap_super_t);
-
-       if (mddev_is_clustered(bitmap->mddev))
+       if (mddev_is_clustered(mddev))
                node_offset = bitmap->cluster_slot * (DIV_ROUND_UP(store->bytes, PAGE_SIZE));
 
-       for (i = 0; i < chunks; i++) {
-               int b;
-               index = file_page_index(&bitmap->storage, i);
-               bit = file_page_offset(&bitmap->storage, i);
-               if (index != oldindex) { /* this is a new page, read it in */
-                       int count;
-                       /* unmap the old page, we're done with it */
-                       if (index == store->file_pages-1)
-                               count = store->bytes - index * PAGE_SIZE;
-                       else
-                               count = PAGE_SIZE;
-                       page = store->filemap[index];
-                       if (file)
-                               ret = read_file_page(file, index, bitmap,
-                                               count, page);
-                       else
-                               ret = read_sb_page(
-                                       bitmap->mddev,
-                                       bitmap->mddev->bitmap_info.offset,
-                                       page,
-                                       index + node_offset, count);
+       for (i = 0; i < store->file_pages; i++) {
+               struct page *page = store->filemap[i];
+               int count;
 
-                       if (ret)
-                               goto err;
+               /* unmap the old page, we're done with it */
+               if (i == store->file_pages - 1)
+                       count = store->bytes - i * PAGE_SIZE;
+               else
+                       count = PAGE_SIZE;
+
+               if (file)
+                       ret = read_file_page(file, i, bitmap, count, page);
+               else
+                       ret = read_sb_page(mddev, mddev->bitmap_info.offset,
+                                          page, i + node_offset, count);
+               if (ret)
+                       goto err;
+       }
 
-                       oldindex = index;
+       if (outofdate) {
+               pr_warn("%s: bitmap file is out of date, doing full recovery\n",
+                       bmname(bitmap));
 
-                       if (outofdate) {
-                               /*
-                                * if bitmap is out of date, dirty the
-                                * whole page and write it out
-                                */
-                               paddr = kmap_atomic(page);
-                               memset(paddr + offset, 0xff,
-                                      PAGE_SIZE - offset);
-                               kunmap_atomic(paddr);
-                               write_page(bitmap, page, 1);
+               for (i = 0; i < store->file_pages; i++) {
+                       struct page *page = store->filemap[i];
+                       unsigned long offset = 0;
+                       void *paddr;
+
+                       if (i == 0 && !mddev->bitmap_info.external)
+                               offset = sizeof(bitmap_super_t);
 
+                       /*
+                        * If the bitmap is out of date, dirty the whole page
+                        * and write it out
+                        */
+                       paddr = kmap_atomic(page);
+                       memset(paddr + offset, 0xff, PAGE_SIZE - offset);
+                       kunmap_atomic(paddr);
+
+                       write_page(bitmap, page, 1);
+                       if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags)) {
                                ret = -EIO;
-                               if (test_bit(BITMAP_WRITE_ERROR,
-                                            &bitmap->flags))
-                                       goto err;
+                               goto err;
                        }
                }
+       }
+
+       for (i = 0; i < chunks; i++) {
+               struct page *page = filemap_get_page(&bitmap->storage, i);
+               unsigned long bit = file_page_offset(&bitmap->storage, i);
+               void *paddr;
+               bool was_set;
+
                paddr = kmap_atomic(page);
                if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags))
-                       b = test_bit(bit, paddr);
+                       was_set = test_bit(bit, paddr);
                else
-                       b = test_bit_le(bit, paddr);
+                       was_set = test_bit_le(bit, paddr);
                kunmap_atomic(paddr);
-               if (b) {
+
+               if (was_set) {
                        /* if the disk bit is set, set the memory bit */
                        int needed = ((sector_t)(i+1) << bitmap->counts.chunkshift
                                      >= start);
@@ -1185,7 +1185,6 @@ static int md_bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
                                                  needed);
                        bit_cnt++;
                }
-               offset = 0;
        }
 
        pr_debug("%s: bitmap initialized from disk: read %lu pages, set %lu of %lu bits\n",