diff options
Diffstat (limited to 'fs/ext4/ialloc.c')
-rw-r--r-- | fs/ext4/ialloc.c | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 45853e0d1f21..e428f23215c0 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -107,6 +107,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) | |||
107 | desc = ext4_get_group_desc(sb, block_group, NULL); | 107 | desc = ext4_get_group_desc(sb, block_group, NULL); |
108 | if (!desc) | 108 | if (!desc) |
109 | return NULL; | 109 | return NULL; |
110 | |||
110 | bitmap_blk = ext4_inode_bitmap(sb, desc); | 111 | bitmap_blk = ext4_inode_bitmap(sb, desc); |
111 | bh = sb_getblk(sb, bitmap_blk); | 112 | bh = sb_getblk(sb, bitmap_blk); |
112 | if (unlikely(!bh)) { | 113 | if (unlikely(!bh)) { |
@@ -123,6 +124,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) | |||
123 | unlock_buffer(bh); | 124 | unlock_buffer(bh); |
124 | return bh; | 125 | return bh; |
125 | } | 126 | } |
127 | |||
126 | ext4_lock_group(sb, block_group); | 128 | ext4_lock_group(sb, block_group); |
127 | if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { | 129 | if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { |
128 | ext4_init_inode_bitmap(sb, bh, block_group, desc); | 130 | ext4_init_inode_bitmap(sb, bh, block_group, desc); |
@@ -133,6 +135,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) | |||
133 | return bh; | 135 | return bh; |
134 | } | 136 | } |
135 | ext4_unlock_group(sb, block_group); | 137 | ext4_unlock_group(sb, block_group); |
138 | |||
136 | if (buffer_uptodate(bh)) { | 139 | if (buffer_uptodate(bh)) { |
137 | /* | 140 | /* |
138 | * if not uninit if bh is uptodate, | 141 | * if not uninit if bh is uptodate, |
@@ -712,8 +715,17 @@ static int ext4_claim_inode(struct super_block *sb, | |||
712 | { | 715 | { |
713 | int free = 0, retval = 0, count; | 716 | int free = 0, retval = 0, count; |
714 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 717 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
718 | struct ext4_group_info *grp = ext4_get_group_info(sb, group); | ||
715 | struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group, NULL); | 719 | struct ext4_group_desc *gdp = ext4_get_group_desc(sb, group, NULL); |
716 | 720 | ||
721 | /* | ||
722 | * We have to be sure that new inode allocation does not race with | ||
723 | * inode table initialization, because otherwise we may end up | ||
724 | * allocating and writing new inode right before sb_issue_zeroout | ||
725 | * takes place and overwriting our new inode with zeroes. So we | ||
726 | * take alloc_sem to prevent it. | ||
727 | */ | ||
728 | down_read(&grp->alloc_sem); | ||
717 | ext4_lock_group(sb, group); | 729 | ext4_lock_group(sb, group); |
718 | if (ext4_set_bit(ino, inode_bitmap_bh->b_data)) { | 730 | if (ext4_set_bit(ino, inode_bitmap_bh->b_data)) { |
719 | /* not a free inode */ | 731 | /* not a free inode */ |
@@ -724,6 +736,7 @@ static int ext4_claim_inode(struct super_block *sb, | |||
724 | if ((group == 0 && ino < EXT4_FIRST_INO(sb)) || | 736 | if ((group == 0 && ino < EXT4_FIRST_INO(sb)) || |
725 | ino > EXT4_INODES_PER_GROUP(sb)) { | 737 | ino > EXT4_INODES_PER_GROUP(sb)) { |
726 | ext4_unlock_group(sb, group); | 738 | ext4_unlock_group(sb, group); |
739 | up_read(&grp->alloc_sem); | ||
727 | ext4_error(sb, "reserved inode or inode > inodes count - " | 740 | ext4_error(sb, "reserved inode or inode > inodes count - " |
728 | "block_group = %u, inode=%lu", group, | 741 | "block_group = %u, inode=%lu", group, |
729 | ino + group * EXT4_INODES_PER_GROUP(sb)); | 742 | ino + group * EXT4_INODES_PER_GROUP(sb)); |
@@ -772,6 +785,7 @@ static int ext4_claim_inode(struct super_block *sb, | |||
772 | gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp); | 785 | gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp); |
773 | err_ret: | 786 | err_ret: |
774 | ext4_unlock_group(sb, group); | 787 | ext4_unlock_group(sb, group); |
788 | up_read(&grp->alloc_sem); | ||
775 | return retval; | 789 | return retval; |
776 | } | 790 | } |
777 | 791 | ||
@@ -1205,3 +1219,109 @@ unsigned long ext4_count_dirs(struct super_block * sb) | |||
1205 | } | 1219 | } |
1206 | return count; | 1220 | return count; |
1207 | } | 1221 | } |
1222 | |||
1223 | /* | ||
1224 | * Zeroes not yet zeroed inode table - just write zeroes through the whole | ||
1225 | * inode table. Must be called without any spinlock held. The only place | ||
1226 | * where it is called from on active part of filesystem is ext4lazyinit | ||
1227 | * thread, so we do not need any special locks, however we have to prevent | ||
1228 | * inode allocation from the current group, so we take alloc_sem lock, to | ||
1229 | * block ext4_claim_inode until we are finished. | ||
1230 | */ | ||
1231 | extern int ext4_init_inode_table(struct super_block *sb, ext4_group_t group, | ||
1232 | int barrier) | ||
1233 | { | ||
1234 | struct ext4_group_info *grp = ext4_get_group_info(sb, group); | ||
1235 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
1236 | struct ext4_group_desc *gdp = NULL; | ||
1237 | struct buffer_head *group_desc_bh; | ||
1238 | handle_t *handle; | ||
1239 | ext4_fsblk_t blk; | ||
1240 | int num, ret = 0, used_blks = 0; | ||
1241 | unsigned long flags = BLKDEV_IFL_WAIT; | ||
1242 | |||
1243 | /* This should not happen, but just to be sure check this */ | ||
1244 | if (sb->s_flags & MS_RDONLY) { | ||
1245 | ret = 1; | ||
1246 | goto out; | ||
1247 | } | ||
1248 | |||
1249 | gdp = ext4_get_group_desc(sb, group, &group_desc_bh); | ||
1250 | if (!gdp) | ||
1251 | goto out; | ||
1252 | |||
1253 | /* | ||
1254 | * We do not need to lock this, because we are the only one | ||
1255 | * handling this flag. | ||
1256 | */ | ||
1257 | if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED)) | ||
1258 | goto out; | ||
1259 | |||
1260 | handle = ext4_journal_start_sb(sb, 1); | ||
1261 | if (IS_ERR(handle)) { | ||
1262 | ret = PTR_ERR(handle); | ||
1263 | goto out; | ||
1264 | } | ||
1265 | |||
1266 | down_write(&grp->alloc_sem); | ||
1267 | /* | ||
1268 | * If inode bitmap was already initialized there may be some | ||
1269 | * used inodes so we need to skip blocks with used inodes in | ||
1270 | * inode table. | ||
1271 | */ | ||
1272 | if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT))) | ||
1273 | used_blks = DIV_ROUND_UP((EXT4_INODES_PER_GROUP(sb) - | ||
1274 | ext4_itable_unused_count(sb, gdp)), | ||
1275 | sbi->s_inodes_per_block); | ||
1276 | |||
1277 | blk = ext4_inode_table(sb, gdp) + used_blks; | ||
1278 | num = sbi->s_itb_per_group - used_blks; | ||
1279 | |||
1280 | BUFFER_TRACE(group_desc_bh, "get_write_access"); | ||
1281 | ret = ext4_journal_get_write_access(handle, | ||
1282 | group_desc_bh); | ||
1283 | if (ret) | ||
1284 | goto err_out; | ||
1285 | |||
1286 | if (unlikely(num > EXT4_INODES_PER_GROUP(sb))) { | ||
1287 | ext4_error(sb, "Something is wrong with group %u\n" | ||
1288 | "Used itable blocks: %d" | ||
1289 | "Itable blocks per group: %lu\n", | ||
1290 | group, used_blks, sbi->s_itb_per_group); | ||
1291 | ret = 1; | ||
1292 | goto err_out; | ||
1293 | } | ||
1294 | |||
1295 | /* | ||
1296 | * Skip zeroout if the inode table is full. But we set the ZEROED | ||
1297 | * flag anyway, because obviously, when it is full it does not need | ||
1298 | * further zeroing. | ||
1299 | */ | ||
1300 | if (unlikely(num == 0)) | ||
1301 | goto skip_zeroout; | ||
1302 | |||
1303 | ext4_debug("going to zero out inode table in group %d\n", | ||
1304 | group); | ||
1305 | if (barrier) | ||
1306 | flags |= BLKDEV_IFL_BARRIER; | ||
1307 | ret = sb_issue_zeroout(sb, blk, num, GFP_NOFS, flags); | ||
1308 | if (ret < 0) | ||
1309 | goto err_out; | ||
1310 | |||
1311 | skip_zeroout: | ||
1312 | ext4_lock_group(sb, group); | ||
1313 | gdp->bg_flags |= cpu_to_le16(EXT4_BG_INODE_ZEROED); | ||
1314 | gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp); | ||
1315 | ext4_unlock_group(sb, group); | ||
1316 | |||
1317 | BUFFER_TRACE(group_desc_bh, | ||
1318 | "call ext4_handle_dirty_metadata"); | ||
1319 | ret = ext4_handle_dirty_metadata(handle, NULL, | ||
1320 | group_desc_bh); | ||
1321 | |||
1322 | err_out: | ||
1323 | up_write(&grp->alloc_sem); | ||
1324 | ext4_journal_stop(handle); | ||
1325 | out: | ||
1326 | return ret; | ||
1327 | } | ||