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: Amir Goldstein <amir73il@users.sf.net> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
This commit is contained in:
Родитель
2de8807b25
Коммит
9b8b7d353f
|
@ -787,6 +787,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
|
|||
struct inode *inode;
|
||||
char *data;
|
||||
char *bitmap;
|
||||
struct ext4_group_info *grinfo;
|
||||
|
||||
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)
|
||||
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;
|
||||
desc = ext4_get_group_desc(sb, first_group + i, NULL);
|
||||
if (desc == NULL)
|
||||
|
@ -871,26 +884,28 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
|
|||
}
|
||||
|
||||
/* wait for I/O completion */
|
||||
for (i = 0; i < groups_per_page && bh[i]; i++)
|
||||
wait_on_buffer(bh[i]);
|
||||
for (i = 0; i < groups_per_page; i++)
|
||||
if (bh[i])
|
||||
wait_on_buffer(bh[i]);
|
||||
|
||||
err = -EIO;
|
||||
for (i = 0; i < groups_per_page && bh[i]; i++)
|
||||
if (!buffer_uptodate(bh[i]))
|
||||
for (i = 0; i < groups_per_page; i++)
|
||||
if (bh[i] && !buffer_uptodate(bh[i]))
|
||||
goto out;
|
||||
|
||||
err = 0;
|
||||
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++) {
|
||||
int group;
|
||||
struct ext4_group_info *grinfo;
|
||||
|
||||
group = (first_block + i) >> 1;
|
||||
if (group >= ngroups)
|
||||
break;
|
||||
|
||||
if (!bh[group - first_group])
|
||||
/* skip initialized uptodate buddy */
|
||||
continue;
|
||||
|
||||
/*
|
||||
* data carry information regarding this
|
||||
* 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
|
||||
*/
|
||||
ext4_lock_group(sb, group);
|
||||
/* init the buddy */
|
||||
memset(data, 0xff, blocksize);
|
||||
ext4_mb_generate_buddy(sb, data, incore, group);
|
||||
ext4_unlock_group(sb, group);
|
||||
incore = NULL;
|
||||
|
@ -948,7 +965,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
|
|||
|
||||
out:
|
||||
if (bh) {
|
||||
for (i = 0; i < groups_per_page && bh[i]; i++)
|
||||
for (i = 0; i < groups_per_page; i++)
|
||||
brelse(bh[i]);
|
||||
if (bh != &bhs)
|
||||
kfree(bh);
|
||||
|
|
Загрузка…
Ссылка в новой задаче