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

Commit 9b8b7d35 authored by Amir Goldstein's avatar Amir Goldstein Committed by Theodore Ts'o
Browse files

ext4: teach ext4_mb_init_cache() to skip uptodate buddy caches



After online resize which adds new groups, some of the groups
in a buddy page may be initialized and uptodate, while other
(new ones) may be uninitialized.

The indication for init of new block groups is when ext4_mb_init_cache()
is called with an uptodate buddy page. In this case, initialized groups
on that buddy page must be skipped when initializing the buddy cache.

Signed-off-by: default avatarAmir Goldstein <amir73il@users.sf.net>
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent 2de8807b
Loading
Loading
Loading
Loading
+25 −8
Original line number Original line Diff line number Diff line
@@ -787,6 +787,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
	struct inode *inode;
	struct inode *inode;
	char *data;
	char *data;
	char *bitmap;
	char *bitmap;
	struct ext4_group_info *grinfo;


	mb_debug(1, "init page %lu\n", page->index);
	mb_debug(1, "init page %lu\n", page->index);


@@ -819,6 +820,18 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
		if (first_group + i >= ngroups)
		if (first_group + i >= ngroups)
			break;
			break;


		grinfo = ext4_get_group_info(sb, first_group + i);
		/*
		 * If page is uptodate then we came here after online resize
		 * which added some new uninitialized group info structs, so
		 * we must skip all initialized uptodate buddies on the page,
		 * which may be currently in use by an allocating task.
		 */
		if (PageUptodate(page) && !EXT4_MB_GRP_NEED_INIT(grinfo)) {
			bh[i] = NULL;
			continue;
		}

		err = -EIO;
		err = -EIO;
		desc = ext4_get_group_desc(sb, first_group + i, NULL);
		desc = ext4_get_group_desc(sb, first_group + i, NULL);
		if (desc == NULL)
		if (desc == NULL)
@@ -871,26 +884,28 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
	}
	}


	/* wait for I/O completion */
	/* wait for I/O completion */
	for (i = 0; i < groups_per_page && bh[i]; i++)
	for (i = 0; i < groups_per_page; i++)
		if (bh[i])
			wait_on_buffer(bh[i]);
			wait_on_buffer(bh[i]);


	err = -EIO;
	err = -EIO;
	for (i = 0; i < groups_per_page && bh[i]; i++)
	for (i = 0; i < groups_per_page; i++)
		if (!buffer_uptodate(bh[i]))
		if (bh[i] && !buffer_uptodate(bh[i]))
			goto out;
			goto out;


	err = 0;
	err = 0;
	first_block = page->index * blocks_per_page;
	first_block = page->index * blocks_per_page;
	/* init the page  */
	memset(page_address(page), 0xff, PAGE_CACHE_SIZE);
	for (i = 0; i < blocks_per_page; i++) {
	for (i = 0; i < blocks_per_page; i++) {
		int group;
		int group;
		struct ext4_group_info *grinfo;


		group = (first_block + i) >> 1;
		group = (first_block + i) >> 1;
		if (group >= ngroups)
		if (group >= ngroups)
			break;
			break;


		if (!bh[group - first_group])
			/* skip initialized uptodate buddy */
			continue;

		/*
		/*
		 * data carry information regarding this
		 * data carry information regarding this
		 * particular group in the format specified
		 * particular group in the format specified
@@ -919,6 +934,8 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
			 * incore got set to the group block bitmap below
			 * incore got set to the group block bitmap below
			 */
			 */
			ext4_lock_group(sb, group);
			ext4_lock_group(sb, group);
			/* init the buddy */
			memset(data, 0xff, blocksize);
			ext4_mb_generate_buddy(sb, data, incore, group);
			ext4_mb_generate_buddy(sb, data, incore, group);
			ext4_unlock_group(sb, group);
			ext4_unlock_group(sb, group);
			incore = NULL;
			incore = NULL;
@@ -948,7 +965,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)


out:
out:
	if (bh) {
	if (bh) {
		for (i = 0; i < groups_per_page && bh[i]; i++)
		for (i = 0; i < groups_per_page; i++)
			brelse(bh[i]);
			brelse(bh[i]);
		if (bh != &bhs)
		if (bh != &bhs)
			kfree(bh);
			kfree(bh);