Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d1244cb0 authored by NeilBrown's avatar NeilBrown
Browse files

md/bitmap: separate bitmap file allocation to its own function.



This will allow allocation before swapping in a new bitmap.

Signed-off-by: default avatarNeilBrown <neilb@suse.de>
parent 9b1215c1
Loading
Loading
Loading
Loading
+67 −46
Original line number Diff line number Diff line
@@ -716,6 +716,58 @@ static inline struct page *filemap_get_page(struct bitmap_storage *store,
			      - file_page_index(store, 0)];
}

static int bitmap_storage_alloc(struct bitmap_storage *store,
				unsigned long chunks, int with_super)
{
	int pnum;
	unsigned long num_pages;
	unsigned long bytes;

	bytes = DIV_ROUND_UP(chunks, 8);
	if (with_super)
		bytes += sizeof(bitmap_super_t);

	num_pages = DIV_ROUND_UP(bytes, PAGE_SIZE);

	store->filemap = kmalloc(sizeof(struct page *)
				 * num_pages, GFP_KERNEL);
	if (!store->filemap)
		return -ENOMEM;

	if (with_super && !store->sb_page) {
		store->sb_page = alloc_page(GFP_KERNEL);
		if (store->sb_page == NULL)
			return -ENOMEM;
		store->sb_page->index = 0;
	}
	pnum = 0;
	if (store->sb_page) {
		store->filemap[0] = store->sb_page;
		pnum = 1;
	}
	for ( ; pnum < num_pages; pnum++) {
		store->filemap[pnum] = alloc_page(GFP_KERNEL);
		if (!store->filemap[pnum]) {
			store->file_pages = pnum;
			return -ENOMEM;
		}
		store->filemap[pnum]->index = pnum;
	}
	store->file_pages = pnum;

	/* We need 4 bits per page, rounded up to a multiple
	 * of sizeof(unsigned long) */
	store->filemap_attr = kzalloc(
		roundup(DIV_ROUND_UP(num_pages*4, 8), sizeof(unsigned long)),
		GFP_KERNEL);
	if (!store->filemap_attr)
		return -ENOMEM;

	store->bytes = bytes;

	return 0;
}

static void bitmap_file_unmap(struct bitmap *bitmap)
{
	struct page **map, *sb_page;
@@ -940,11 +992,10 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int n
static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
{
	unsigned long i, chunks, index, oldindex, bit;
	int pnum;
	struct page *page = NULL;
	unsigned long num_pages, bit_cnt = 0;
	unsigned long bit_cnt = 0;
	struct file *file;
	unsigned long bytes, offset;
	unsigned long offset;
	int outofdate;
	int ret = -ENOSPC;
	void *paddr;
@@ -973,53 +1024,23 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
		printk(KERN_INFO "%s: bitmap file is out of date, doing full "
			"recovery\n", bmname(bitmap));

	bytes = DIV_ROUND_UP(bitmap->chunks, 8);
	if (!bitmap->mddev->bitmap_info.external)
		bytes += sizeof(bitmap_super_t);

	store->bytes = bytes;

	num_pages = DIV_ROUND_UP(bytes, PAGE_SIZE);

	if (file && i_size_read(file->f_mapping->host) < bytes) {
	if (file && i_size_read(file->f_mapping->host) < store->bytes) {
		printk(KERN_INFO "%s: bitmap file too short %lu < %lu\n",
		       bmname(bitmap),
		       (unsigned long) i_size_read(file->f_mapping->host),
			bytes);
		       store->bytes);
		goto err;
	}

	ret = -ENOMEM;

	store->filemap = kmalloc(sizeof(struct page *)
					  * num_pages, GFP_KERNEL);
	if (!store->filemap)
	ret = bitmap_storage_alloc(&bitmap->storage, bitmap->chunks,
				   !bitmap->mddev->bitmap_info.external);
	if (ret)
		goto err;

	pnum = 0;
	oldindex = ~0L;
	offset = 0;
	if (store->sb_page) {
		store->filemap[0] = store->sb_page;
		pnum = 1;
	if (!bitmap->mddev->bitmap_info.external)
		offset = sizeof(bitmap_super_t);
	}
	for ( ; pnum < num_pages; pnum++) {
		store->filemap[pnum] = alloc_page(GFP_KERNEL);
		if (!store->filemap[pnum]) {
			store->file_pages = pnum;
			goto err;
		}
	}
	store->file_pages = pnum;

	/* We need 4 bits per page, rounded up to a multiple of sizeof(unsigned long) */
	store->filemap_attr = kzalloc(
		roundup(DIV_ROUND_UP(num_pages*4, 8), sizeof(unsigned long)),
		GFP_KERNEL);
	if (!store->filemap_attr)
		goto err;

	oldindex = ~0L;

	for (i = 0; i < chunks; i++) {
		int b;
@@ -1028,8 +1049,8 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
		if (index != oldindex) { /* this is a new page, read it in */
			int count;
			/* unmap the old page, we're done with it */
			if (index == num_pages-1)
				count = bytes - index * PAGE_SIZE;
			if (index == store->file_pages-1)
				count = store->bytes - index * PAGE_SIZE;
			else
				count = PAGE_SIZE;
			page = store->filemap[index];
@@ -1083,9 +1104,9 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
	}

	printk(KERN_INFO "%s: bitmap initialized from disk: "
	       "read %lu/%lu pages, set %lu of %lu bits\n",
	       "read %lu pages, set %lu of %lu bits\n",
	       bmname(bitmap), store->file_pages,
	       num_pages, bit_cnt, chunks);
	       bit_cnt, chunks);

	return 0;