Permalink
Browse files

e4snap: add uninit_exclude_blocks flag in snapshot's group descripors

This patch adds uninit_exclude_blocks flag in snapshot's group descriptors,
so that snapshot could fix group counters.
  • Loading branch information...
1 parent 96e8649 commit 90bcb2c821dc164c832e589c375759be22ae8e3e @YANGYongqiang committed Aug 16, 2012
Showing with 68 additions and 7 deletions.
  1. +3 −0 fs/ext4/ext4.h
  2. +30 −0 fs/ext4/mballoc.c
  3. +29 −7 fs/ext4/snapshot.c
  4. +6 −0 fs/ext4/snapshot.h
View
@@ -396,6 +396,8 @@ struct flex_groups {
#ifdef CONFIG_EXT4_FS_SNAPSHOT_EXCLUDE_BITMAP
#define EXT4_BG_EXCLUDE_UNINIT 0x0008 /* Exclude bitmap not in use */
#endif
+#define EXT4_BG_SNAP_UNFIXED 0x0010 /* Blocks used by snapshot is */
+ /* not excluded */
/*
* Macro-instructions used to manage group descriptors
@@ -2130,6 +2132,7 @@ extern int ext4_trim_fs(struct super_block *, struct fstrim_range *);
#ifdef CONFIG_EXT4_FS_SNAPSHOT_BLOCK_COW
extern int ext4_mb_test_bit_range(int bit, void *addr, int *pcount);
#endif
+extern int ext4_mb_count_zero_bits(void *addr, int max, int start);
/* inode.c */
struct buffer_head *ext4_getblk(handle_t *, struct inode *,
View
@@ -422,6 +422,17 @@ static inline int mb_find_next_bit(void *addr, int max, int start)
return ret;
}
+int ext4_mb_count_zero_bits(void *addr, int max, int start)
+{
+ int bit = 0, count = 0;
+ while (start < max) {
+ bit = mb_find_next_zero_bit(addr, max, start);
+ start = mb_find_next_bit(addr, max, bit);
+ count += start - bit;
+ }
+
+ return count;
+}
#ifdef CONFIG_EXT4_FS_SNAPSHOT_BLOCK_COW
/*
* Find the largest range of set or clear bits.
@@ -917,6 +928,25 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
if (bh[i] && !buffer_uptodate(bh[i]))
goto out;
+ if (!(sb->s_flags & EXT4_FLAGS_IS_SNAPSHOT))
+ goto bg_fixed;
+ for (i = 0; i < groups_per_page; i++) {
+ struct ext4_group_desc *desc;
+ if (first_group + i >= ngroups)
+ break;
+ desc = ext4_get_group_desc(sb, first_group + i, NULL);
+ if (desc == NULL)
+ goto out;
+ if (!(desc->bg_flags & cpu_to_le16(EXT4_BG_SNAP_UNFIXED)))
+ continue;
+ ext4_lock_group(sb, first_group + i);
+ if (desc->bg_flags & cpu_to_le16(EXT4_BG_SNAP_UNFIXED))
+ ext4_snapshot_fix_group_counters(sb, bh[i], desc,
+ first_group + i);
+ ext4_unlock_group(sb, first_group + i);
+ }
+
+bg_fixed:
err = 0;
first_block = page->index * blocks_per_page;
for (i = 0; i < blocks_per_page; i++) {
View
@@ -521,13 +521,14 @@ int ext4_snapshot_test_and_exclude(const char *where, handle_t *handle,
goto out;
}
- exclude_uninit = gdp->bg_flags & cpu_to_le16(EXT4_BG_EXCLUDE_UNINIT);
- if (exclude && exclude_uninit) {
+ if (exclude) {
err = ext4_journal_get_write_access(handle, gdp_bh);
if (err)
goto out;
}
+ exclude_uninit = gdp->bg_flags & cpu_to_le16(EXT4_BG_EXCLUDE_UNINIT);
+
while (count > 0 && bit < SNAPSHOT_BLOCKS_PER_GROUP) {
if (!ext4_set_bit_atomic(sb_bgl_lock(EXT4_SB(sb),
block_group),
@@ -568,15 +569,17 @@ int ext4_snapshot_test_and_exclude(const char *where, handle_t *handle,
if (err)
goto out;
- if (exclude_uninit) {
+ if (exclude_uninit)
gdp->bg_flags &= cpu_to_le16(~EXT4_BG_EXCLUDE_UNINIT);
- gdp->bg_checksum = ext4_group_desc_csum(EXT4_SB(sb),
- block_group, gdp);
- err = ext4_handle_dirty_metadata(handle, NULL, gdp_bh);
- }
+
+ gdp->bg_flags |= cpu_to_le16(EXT4_BG_SNAP_UNFIXED);
@amir73il

amir73il Aug 16, 2012

I feel kind of silly for not having noticed it before, but if the flags EXCLUDE_UNINIT and SNAP_UNFIXED are always mutually exclusive,
then the new flag adds zero information.
you could just as well check for !flag_set(EXCLUDE_UNINIT) in snapshot/clone for group counters fixing
and set it in clones after fixing the counters.

@YANGYongqiang

YANGYongqiang Aug 17, 2012

Owner

exlcude bitmap is not snapshotted, so we can not get exclude bitmap info in snapshots. The block bitmap is fixed in ext4 when a snapshot is read with exclude bitmaps in original ext4. Currently in group_counter_fixing routine, I just calculate the blocks of block bitmap without exclude bitmap info, so it depends on rightness of snapshot taking.

@amir73il

amir73il Aug 17, 2012

yeh, I know that exclude bitmap is not snapshotted, but the EXCLUDE_UNINIT flag is group descriptors is snapshotted.
and testing !EXCLUDE_UNINIT in snapshot is quivalent to testing SNAP_UNFIXED in snapshot

@YANGYongqiang

YANGYongqiang Aug 19, 2012

Owner

Understood. I will fix it later before or after GSoC.

+ gdp->bg_checksum = ext4_group_desc_csum(EXT4_SB(sb),
+ block_group, gdp);
+ err = ext4_handle_dirty_metadata(handle, NULL, gdp_bh);
trace_cow_add(handle, excluded, excluded);
}
+
out:
brelse(exclude_bitmap_bh);
return err ? err : excluded;
@@ -1061,4 +1064,23 @@ int ext4_snapshot_test_and_move(const char *where, handle_t *handle,
return err;
}
+/*
+ * ext4_snapshot_fix_block_bitmap fixes group counters in snapshot.
+ * Callers should hold block group's lock.
+ */
+void ext4_snapshot_fix_group_counters(struct super_block *sb,
+ struct buffer_head *block_bitmap,
+ struct ext4_group_desc *gdp,
+ ext4_group_t group)
+{
+ ext4_grpblk_t free_clusters, orig;
+ orig = ext4_free_group_clusters(sb, gdp);
+ free_clusters = ext4_mb_count_zero_bits(block_bitmap->b_data,
+ EXT4_BLOCKS_PER_GROUP(sb), 0);
+ BUG_ON(free_clusters - orig < 0);
+ ext4_free_group_clusters_set(sb, gdp, free_clusters);
+ gdp->bg_flags &= ~cpu_to_le16(EXT4_BG_SNAP_UNFIXED);
+ gdp->bg_checksum = ext4_group_desc_csum(EXT4_SB(sb), group, gdp);
+ percpu_counter_add(&EXT4_SB(sb)->s_freeclusters_counter, free_clusters - orig);
+}
#endif
View
@@ -208,6 +208,10 @@ extern int ext4_snapshot_test_and_move(const char *where,
#define ext4_snapshot_move(handle, inode, block, pcount, move) (0)
#endif
+extern void ext4_snapshot_fix_group_counters(struct super_block *sb,
+ struct buffer_head *block_bitmap,
+ struct ext4_group_desc *gdp,
+ ext4_group_t group);
/*
* Block access functions
*/
@@ -728,5 +732,7 @@ ext4_sb_find_get_block(const char *fn, struct super_block *sb, sector_t block)
#define ext4_snapshot_is_active(inode) (0)
#define ext4_snapshot_mow_in_tid(inode) (1)
+#define ext4_snapshot_fix_group_counters(sb, bh, gdp, group) (0)
+
#endif /* CONFIG_EXT4_FS_SNAPSHOT */
#endif /* _LINUX_EXT4_SNAPSHOT_H */

1 comment on commit 90bcb2c

there is a typo in the commit message the flag name is wrong

Please sign in to comment.