ext4: Respect group descriptor size when adjusting free counts

Also adjust high 16/32 bits when free inode/block counts are modified.

Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c
index 90e7602..1336068 100644
--- a/fs/ext4/ext4_common.c
+++ b/fs/ext4/ext4_common.c
@@ -60,22 +60,51 @@
 
 static inline void ext4fs_sb_free_blocks_dec(struct ext2_sblock *sb)
 {
-	sb->free_blocks = cpu_to_le32(le32_to_cpu(sb->free_blocks) - 1);
+	uint64_t free_blocks = le32_to_cpu(sb->free_blocks);
+	free_blocks += (uint64_t)le32_to_cpu(sb->free_blocks_high) << 32;
+	free_blocks--;
+
+	sb->free_blocks = cpu_to_le32(free_blocks & 0xffffffff);
+	sb->free_blocks_high = cpu_to_le16(free_blocks >> 32);
 }
 
-static inline void ext4fs_bg_free_inodes_dec(struct ext2_block_group *bg)
+static inline void ext4fs_bg_free_inodes_dec
+	(struct ext2_block_group *bg, const struct ext_filesystem *fs)
 {
-	bg->free_inodes = cpu_to_le16(le16_to_cpu(bg->free_inodes) - 1);
+	uint32_t free_inodes = le16_to_cpu(bg->free_inodes);
+	if (fs->gdsize == 64)
+		free_inodes += le16_to_cpu(bg->free_inodes_high) << 16;
+	free_inodes--;
+
+	bg->free_inodes = cpu_to_le16(free_inodes & 0xffff);
+	if (fs->gdsize == 64)
+		bg->free_inodes_high = cpu_to_le16(free_inodes >> 16);
 }
 
-static inline void ext4fs_bg_free_blocks_dec(struct ext2_block_group *bg)
+static inline void ext4fs_bg_free_blocks_dec
+	(struct ext2_block_group *bg, const struct ext_filesystem *fs)
 {
-	bg->free_blocks = cpu_to_le16(le16_to_cpu(bg->free_blocks) - 1);
+	uint32_t free_blocks = le16_to_cpu(bg->free_blocks);
+	if (fs->gdsize == 64)
+		free_blocks += le16_to_cpu(bg->free_blocks_high) << 16;
+	free_blocks--;
+
+	bg->free_blocks = cpu_to_le16(free_blocks & 0xffff);
+	if (fs->gdsize == 64)
+		bg->free_blocks_high = cpu_to_le16(free_blocks >> 16);
 }
 
-static inline void ext4fs_bg_itable_unused_dec(struct ext2_block_group *bg)
+static inline void ext4fs_bg_itable_unused_dec
+	(struct ext2_block_group *bg, const struct ext_filesystem *fs)
 {
-	bg->bg_itable_unused = cpu_to_le16(le16_to_cpu(bg->bg_itable_unused) - 1);
+	uint32_t free_inodes = le16_to_cpu(bg->bg_itable_unused);
+	if (fs->gdsize == 64)
+		free_inodes += le16_to_cpu(bg->bg_itable_unused_high) << 16;
+	free_inodes--;
+
+	bg->bg_itable_unused = cpu_to_le16(free_inodes & 0xffff);
+	if (fs->gdsize == 64)
+		bg->bg_itable_unused_high = cpu_to_le16(free_inodes >> 16);
 }
 
 uint64_t ext4fs_sb_get_free_blocks(const struct ext2_sblock *sb)
@@ -958,7 +987,7 @@
 				fs->curr_blkno = fs->curr_blkno +
 						(i * fs->blksz * 8);
 				fs->first_pass_bbmap++;
-				ext4fs_bg_free_blocks_dec(bgd);
+				ext4fs_bg_free_blocks_dec(bgd, fs);
 				ext4fs_sb_free_blocks_dec(fs->sb);
 				status = ext4fs_devread(b_bitmap_blk *
 							fs->sect_perblk,
@@ -1033,7 +1062,7 @@
 
 			prev_bg_bitmap_index = bg_idx;
 		}
-		ext4fs_bg_free_blocks_dec(bgd);
+		ext4fs_bg_free_blocks_dec(bgd, fs);
 		ext4fs_sb_free_blocks_dec(fs->sb);
 		goto success;
 	}
@@ -1092,9 +1121,9 @@
 				fs->curr_inode_no = fs->curr_inode_no +
 							(i * inodes_per_grp);
 				fs->first_pass_ibmap++;
-				ext4fs_bg_free_inodes_dec(bgd);
+				ext4fs_bg_free_inodes_dec(bgd, fs);
 				if (has_gdt_chksum)
-					ext4fs_bg_itable_unused_dec(bgd);
+					ext4fs_bg_itable_unused_dec(bgd, fs);
 				ext4fs_sb_free_inodes_dec(fs->sb);
 				status = ext4fs_devread(i_bitmap_blk *
 							fs->sect_perblk,
@@ -1148,7 +1177,7 @@
 				goto fail;
 			prev_inode_bitmap_index = ibmap_idx;
 		}
-		ext4fs_bg_free_inodes_dec(bgd);
+		ext4fs_bg_free_inodes_dec(bgd, fs);
 		if (has_gdt_chksum)
 			bgd->bg_itable_unused = bgd->free_inodes;
 		ext4fs_sb_free_inodes_dec(fs->sb);