Commit 844dc669 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Song Liu
Browse files

md-bitmap: refactor md_bitmap_init_from_disk



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: default avatarkernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202306160552.smw0qbmb-lkp@intel.com/


Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarSong Liu <song@kernel.org>
Link: https://lore.kernel.org/r/20230615064840.629492-7-hch@lst.de
parent d681054c
Loading
Loading
Loading
Loading
+70 −71
Original line number Diff line number Diff line
@@ -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 */
	for (i = 0; i < store->file_pages; i++) {
		struct page *page = store->filemap[i];
		int count;

		/* unmap the old page, we're done with it */
			if (index == store->file_pages-1)
				count = store->bytes - index * PAGE_SIZE;
		if (i == store->file_pages - 1)
			count = store->bytes - i * PAGE_SIZE;
		else
			count = PAGE_SIZE;
			page = store->filemap[index];

		if (file)
				ret = read_file_page(file, index, bitmap,
						count, page);
			ret = read_file_page(file, i, bitmap, count, page);
		else
				ret = read_sb_page(
					bitmap->mddev,
					bitmap->mddev->bitmap_info.offset,
					page,
					index + node_offset, count);

			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));

		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 bitmap is out of date, dirty the
				 * whole page and write it out
			 * 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);
			memset(paddr + offset, 0xff, PAGE_SIZE - offset);
			kunmap_atomic(paddr);
				write_page(bitmap, page, 1);

			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;
			}
		}
	}

	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",