Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Amir Goldstein and committed by
Theodore Ts'o
9b8b7d35 2de8807b

+25 -8
+25 -8
fs/ext4/mballoc.c
··· 787 787 struct inode *inode; 788 788 char *data; 789 789 char *bitmap; 790 + struct ext4_group_info *grinfo; 790 791 791 792 mb_debug(1, "init page %lu\n", page->index); 792 793 ··· 819 818 820 819 if (first_group + i >= ngroups) 821 820 break; 821 + 822 + grinfo = ext4_get_group_info(sb, first_group + i); 823 + /* 824 + * If page is uptodate then we came here after online resize 825 + * which added some new uninitialized group info structs, so 826 + * we must skip all initialized uptodate buddies on the page, 827 + * which may be currently in use by an allocating task. 828 + */ 829 + if (PageUptodate(page) && !EXT4_MB_GRP_NEED_INIT(grinfo)) { 830 + bh[i] = NULL; 831 + continue; 832 + } 822 833 823 834 err = -EIO; 824 835 desc = ext4_get_group_desc(sb, first_group + i, NULL); ··· 884 871 } 885 872 886 873 /* wait for I/O completion */ 887 - for (i = 0; i < groups_per_page && bh[i]; i++) 888 - wait_on_buffer(bh[i]); 874 + for (i = 0; i < groups_per_page; i++) 875 + if (bh[i]) 876 + wait_on_buffer(bh[i]); 889 877 890 878 err = -EIO; 891 - for (i = 0; i < groups_per_page && bh[i]; i++) 892 - if (!buffer_uptodate(bh[i])) 879 + for (i = 0; i < groups_per_page; i++) 880 + if (bh[i] && !buffer_uptodate(bh[i])) 893 881 goto out; 894 882 895 883 err = 0; 896 884 first_block = page->index * blocks_per_page; 897 - /* init the page */ 898 - memset(page_address(page), 0xff, PAGE_CACHE_SIZE); 899 885 for (i = 0; i < blocks_per_page; i++) { 900 886 int group; 901 - struct ext4_group_info *grinfo; 902 887 903 888 group = (first_block + i) >> 1; 904 889 if (group >= ngroups) 905 890 break; 891 + 892 + if (!bh[group - first_group]) 893 + /* skip initialized uptodate buddy */ 894 + continue; 906 895 907 896 /* 908 897 * data carry information regarding this ··· 934 919 * incore got set to the group block bitmap below 935 920 */ 936 921 ext4_lock_group(sb, group); 922 + /* init the buddy */ 923 + memset(data, 0xff, blocksize); 937 924 ext4_mb_generate_buddy(sb, data, incore, group); 938 925 ext4_unlock_group(sb, group); 939 926 incore = NULL; ··· 965 948 966 949 out: 967 950 if (bh) { 968 - for (i = 0; i < groups_per_page && bh[i]; i++) 951 + for (i = 0; i < groups_per_page; i++) 969 952 brelse(bh[i]); 970 953 if (bh != &bhs) 971 954 kfree(bh);