Whamcloud - gitweb
e2fsck: merge bitmaps after thread completes
authorWang Shilong <wshilong@ddn.com>
Wed, 23 Sep 2020 03:17:29 +0000 (11:17 +0800)
committerAndreas Dilger <adilger@whamcloud.com>
Mon, 19 Sep 2022 23:10:45 +0000 (17:10 -0600)
A new method merge_bmap has been added to bitmap operations. But
only red-black bitmap has that operation now.

E2fsprogs-commit: ecf85fb474fb7537f14bddd8f85d8372b808d5e9

Change-Id: Id5c387dd813d633adff3afb9208213086c33b6d2
Signed-off-by: Li Xi <lixi@ddn.com>
Signed-off-by: Wang Shilong <wshilong@ddn.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
e2fsck/pass1.c
lib/ext2fs/bitmaps.c
lib/ext2fs/blkmap64_rb.c
lib/ext2fs/bmap64.h
lib/ext2fs/ext2fs.h
lib/ext2fs/gen_bitmap64.c

index 22b7509..b8e3a7d 100644 (file)
@@ -2161,12 +2161,38 @@ static errcode_t e2fsck_pass1_copy_bitmap(ext2_filsys fs, ext2fs_generic_bitmap
                return ret;
 
        (*dest)->fs = fs;
                return ret;
 
        (*dest)->fs = fs;
-       ext2fs_free_generic_bmap(*src);
-       *src = NULL;
 
        return 0;
 }
 
 
        return 0;
 }
 
+static void e2fsck_pass1_free_bitmap(ext2fs_generic_bitmap *bitmap)
+{
+       if (*bitmap) {
+               ext2fs_free_generic_bmap(*bitmap);
+               *bitmap = NULL;
+       }
+
+}
+
+static errcode_t e2fsck_pass1_merge_bitmap(ext2_filsys fs, ext2fs_generic_bitmap *src,
+                                         ext2fs_generic_bitmap *dest)
+{
+       errcode_t ret = 0;
+
+       if (*src) {
+               if (*dest == NULL) {
+                       *dest = *src;
+                       *src = NULL;
+               } else {
+                       ret = ext2fs_merge_bitmap(*src, *dest, NULL, NULL);
+                       if (ret)
+                               return ret;
+               }
+               (*dest)->fs = fs;
+       }
+
+       return 0;
+}
 
 static errcode_t e2fsck_pass1_copy_fs(ext2_filsys dest, e2fsck_t src_context,
                                      ext2_filsys src)
 
 static errcode_t e2fsck_pass1_copy_fs(ext2_filsys dest, e2fsck_t src_context,
                                      ext2_filsys src)
@@ -2174,6 +2200,8 @@ static errcode_t e2fsck_pass1_copy_fs(ext2_filsys dest, e2fsck_t src_context,
        errcode_t       retval;
 
        memcpy(dest, src, sizeof(struct struct_ext2_filsys));
        errcode_t       retval;
 
        memcpy(dest, src, sizeof(struct struct_ext2_filsys));
+       dest->inode_map = NULL;
+       dest->block_map = NULL;
        if (dest->dblist)
                dest->dblist->fs = dest;
        if (src->block_map) {
        if (dest->dblist)
                dest->dblist->fs = dest;
        if (src->block_map) {
@@ -2233,42 +2261,50 @@ static int e2fsck_pass1_merge_fs(ext2_filsys dest, ext2_filsys src)
        errcode_t retval = 0;
        io_channel dest_io;
        io_channel dest_image_io;
        errcode_t retval = 0;
        io_channel dest_io;
        io_channel dest_image_io;
+       ext2fs_inode_bitmap inode_map;
+       ext2fs_block_bitmap block_map;
 
        dest_io = dest->io;
        dest_image_io = dest->image_io;
 
        dest_io = dest->io;
        dest_image_io = dest->image_io;
+       inode_map = dest->inode_map;
+       block_map = dest->block_map;
 
        memcpy(dest, src, sizeof(struct struct_ext2_filsys));
        dest->io = dest_io;
        dest->image_io = dest_image_io;
        dest->icache = icache;
 
        memcpy(dest, src, sizeof(struct struct_ext2_filsys));
        dest->io = dest_io;
        dest->image_io = dest_image_io;
        dest->icache = icache;
+       dest->inode_map = inode_map;
+       dest->block_map = block_map;
        if (dest->dblist)
                dest->dblist->fs = dest;
        if (dest->dblist)
                dest->dblist->fs = dest;
-       if (src->inode_map) {
-               retval = e2fsck_pass1_copy_bitmap(dest, &src->inode_map,
-                                                 &dest->inode_map);
-               if (retval)
-                       return retval;
-       }
-       if (src->block_map) {
-               retval = e2fsck_pass1_copy_bitmap(dest, &src->block_map,
-                                                 &dest->block_map);
-               if (retval)
-                       return retval;
-       }
 
        if (src->icache) {
                ext2fs_free_inode_cache(src->icache);
                src->icache = NULL;
        }
 
 
        if (src->icache) {
                ext2fs_free_inode_cache(src->icache);
                src->icache = NULL;
        }
 
+       retval = e2fsck_pass1_merge_bitmap(dest, &src->inode_map,
+                                          &dest->inode_map);
+       if (retval)
+               goto out;
+
+       retval = e2fsck_pass1_merge_bitmap(dest, &src->block_map,
+                                         &dest->block_map);
+       if (retval)
+               goto out;
+
        if (src->badblocks) {
                retval = ext2fs_badblocks_copy(src->badblocks, &dest->badblocks);
 
                ext2fs_badblocks_list_free(src->badblocks);
                src->badblocks = NULL;
        }
        if (src->badblocks) {
                retval = ext2fs_badblocks_copy(src->badblocks, &dest->badblocks);
 
                ext2fs_badblocks_list_free(src->badblocks);
                src->badblocks = NULL;
        }
-
+out:
        io_channel_close(src->io);
        io_channel_close(src->io);
+       if (src->inode_map)
+               ext2fs_free_generic_bmap(src->inode_map);
+       if (src->block_map)
+               ext2fs_free_generic_bmap(src->block_map);
        return retval;
 }
 
        return retval;
 }
 
@@ -2358,6 +2394,18 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx
        ext2_filsys      global_fs = global_ctx->fs;
        FILE            *global_logf = global_ctx->logf;
        FILE            *global_problem_logf = global_ctx->problem_logf;
        ext2_filsys      global_fs = global_ctx->fs;
        FILE            *global_logf = global_ctx->logf;
        FILE            *global_problem_logf = global_ctx->problem_logf;
+       ext2fs_inode_bitmap inode_bad_map = global_ctx->inode_bad_map;
+       ext2fs_inode_bitmap inode_used_map = global_ctx->inode_used_map;
+       ext2fs_inode_bitmap inode_dir_map = global_ctx->inode_dir_map;
+       ext2fs_inode_bitmap inode_bb_map = global_ctx->inode_bb_map;
+       ext2fs_inode_bitmap inode_imagic_map = global_ctx->inode_imagic_map;
+       ext2fs_inode_bitmap inode_reg_map = global_ctx->inode_reg_map;
+       ext2fs_block_bitmap block_found_map = global_ctx->block_found_map;
+       ext2fs_block_bitmap block_dup_map = global_ctx->block_dup_map;
+       ext2fs_block_bitmap block_ea_map = global_ctx->block_ea_map;
+       ext2fs_block_bitmap block_metadata_map = global_ctx->block_metadata_map;
+       ext2fs_block_bitmap inodes_to_rebuild = global_ctx->inodes_to_rebuild;
+
 #ifdef HAVE_SETJMP_H
        jmp_buf          old_jmp;
 
 #ifdef HAVE_SETJMP_H
        jmp_buf          old_jmp;
 
@@ -2367,6 +2415,19 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx
 #ifdef HAVE_SETJMP_H
        memcpy(global_ctx->abort_loc, old_jmp, sizeof(jmp_buf));
 #endif
 #ifdef HAVE_SETJMP_H
        memcpy(global_ctx->abort_loc, old_jmp, sizeof(jmp_buf));
 #endif
+
+       global_ctx->inode_used_map = inode_used_map;
+       global_ctx->inode_bad_map = inode_bad_map;
+       global_ctx->inode_dir_map = inode_dir_map;
+       global_ctx->inode_bb_map = inode_bb_map;
+       global_ctx->inode_imagic_map = inode_imagic_map;
+       global_ctx->inodes_to_rebuild = inodes_to_rebuild;
+       global_ctx->inode_reg_map = inode_reg_map;
+       global_ctx->block_found_map = block_found_map;
+       global_ctx->block_dup_map = block_dup_map;
+       global_ctx->block_ea_map = block_ea_map;
+       global_ctx->block_metadata_map = block_metadata_map;
+
        /* Keep the global singal flags*/
        global_ctx->flags |= (flags & E2F_FLAG_SIGNAL_MASK) |
                             (global_ctx->flags & E2F_FLAG_SIGNAL_MASK);
        /* Keep the global singal flags*/
        global_ctx->flags |= (flags & E2F_FLAG_SIGNAL_MASK) |
                             (global_ctx->flags & E2F_FLAG_SIGNAL_MASK);
@@ -2382,83 +2443,62 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx
        global_ctx->problem_logf = global_problem_logf;
        global_ctx->global_ctx = NULL;
 
        global_ctx->problem_logf = global_problem_logf;
        global_ctx->global_ctx = NULL;
 
-       if (thread_ctx->inode_used_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->inode_used_map,
-                                       &global_ctx->inode_used_map);
-               if (retval)
-                       return retval;
-       }
-       if (thread_ctx->inode_bad_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->inode_bad_map,
-                                       &global_ctx->inode_bad_map);
-               if (retval)
-                       return retval;
-       }
-       if (thread_ctx->inode_dir_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->inode_used_map,
+                               &global_ctx->inode_used_map);
+       if (retval)
+               return retval;
+
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->inode_bad_map,
+                               &global_ctx->inode_bad_map);
+       if (retval)
+               return retval;
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
                                        &thread_ctx->inode_dir_map,
                                        &global_ctx->inode_dir_map);
                                        &thread_ctx->inode_dir_map,
                                        &global_ctx->inode_dir_map);
-               if (retval)
-                       return retval;
-       }
-       if (thread_ctx->inode_bb_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->inode_bb_map,
-                                       &global_ctx->inode_bb_map);
-               if (retval)
-                       return retval;
-       }
-       if (thread_ctx->inode_imagic_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->inode_imagic_map,
-                                       &global_ctx->inode_imagic_map);
-               if (retval)
-                       return retval;
-       }
-       if (thread_ctx->inode_reg_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->inode_reg_map,
-                                       &global_ctx->inode_reg_map);
-               if (retval)
-                       return retval;
-       }
-       if (thread_ctx->inodes_to_rebuild) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->inodes_to_rebuild,
-                                       &global_ctx->inodes_to_rebuild);
-               if (retval)
-                       return retval;
-       }
-       if (thread_ctx->block_found_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->block_found_map,
-                                       &global_ctx->block_found_map);
-               if (retval)
-                       return retval;
-       }
-       if (thread_ctx->block_dup_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->block_dup_map,
-                                       &global_ctx->block_dup_map);
-               if (retval)
-                       return retval;
-       }
-       if (thread_ctx->block_ea_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->block_ea_map,
-                                       &global_ctx->block_ea_map);
-               if (retval)
-                       return retval;
-       }
-       if (thread_ctx->block_metadata_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->block_metadata_map,
-                                       &global_ctx->block_metadata_map);
-               if (retval)
-                       return retval;
-       }
+       if (retval)
+               return retval;
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->inode_bb_map,
+                               &global_ctx->inode_bb_map);
+       if (retval)
+               return retval;
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->inode_imagic_map,
+                               &global_ctx->inode_imagic_map);
+       if (retval)
+               return retval;
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->inode_reg_map,
+                               &global_ctx->inode_reg_map);
+       if (retval)
+               return retval;
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->inodes_to_rebuild,
+                               &global_ctx->inodes_to_rebuild);
+       if (retval)
+               return retval;
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->block_found_map,
+                               &global_ctx->block_found_map);
+       if (retval)
+               return retval;
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->block_dup_map,
+                               &global_ctx->block_dup_map);
+       if (retval)
+               return retval;
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->block_ea_map,
+                               &global_ctx->block_ea_map);
+       if (retval)
+               return retval;
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->block_metadata_map,
+                               &global_ctx->block_metadata_map);
+       if (retval)
+               return retval;
 
        return 0;
 }
 
        return 0;
 }
@@ -2475,6 +2515,17 @@ static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx)
                fputs("</problem_log>\n", thread_ctx->problem_logf);
                fclose(thread_ctx->problem_logf);
        }
                fputs("</problem_log>\n", thread_ctx->problem_logf);
                fclose(thread_ctx->problem_logf);
        }
+       e2fsck_pass1_free_bitmap(&thread_ctx->inode_used_map);
+       e2fsck_pass1_free_bitmap(&thread_ctx->inode_bad_map);
+       e2fsck_pass1_free_bitmap(&thread_ctx->inode_dir_map);
+       e2fsck_pass1_free_bitmap(&thread_ctx->inode_bb_map);
+       e2fsck_pass1_free_bitmap(&thread_ctx->inode_imagic_map);
+       e2fsck_pass1_free_bitmap(&thread_ctx->inode_reg_map);
+       e2fsck_pass1_free_bitmap(&thread_ctx->inodes_to_rebuild);
+       e2fsck_pass1_free_bitmap(&thread_ctx->block_found_map);
+       e2fsck_pass1_free_bitmap(&thread_ctx->block_dup_map);
+       e2fsck_pass1_free_bitmap(&thread_ctx->block_ea_map);
+       e2fsck_pass1_free_bitmap(&thread_ctx->block_metadata_map);
        ext2fs_free_mem(&thread_ctx);
 
        return retval;
        ext2fs_free_mem(&thread_ctx);
 
        return retval;
@@ -2501,7 +2552,13 @@ static int e2fsck_pass1_threads_join(struct e2fsck_thread_info *infos,
                        if (ret == 0)
                                ret = rc;
                }
                        if (ret == 0)
                                ret = rc;
                }
-               e2fsck_pass1_thread_join(global_ctx, infos[i].eti_thread_ctx);
+               rc = e2fsck_pass1_thread_join(global_ctx, infos[i].eti_thread_ctx);
+               if (rc) {
+                       com_err(global_ctx->program_name, rc,
+                               _("while joining pass1 thread\n"));
+                       if (ret == 0)
+                               ret = rc;
+               }
        }
        free(infos);
 
        }
        free(infos);
 
index 8bfa24b..9437331 100644 (file)
@@ -45,6 +45,16 @@ errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
 {
        return (ext2fs_copy_generic_bmap(src, dest));
 }
 {
        return (ext2fs_copy_generic_bmap(src, dest));
 }
+
+errcode_t ext2fs_merge_bitmap(ext2fs_generic_bitmap src,
+                             ext2fs_generic_bitmap dest,
+                             ext2fs_generic_bitmap dup,
+                             ext2fs_generic_bitmap dup_allowed)
+{
+       return ext2fs_merge_generic_bmap(src, dest, dup,
+                                        dup_allowed);
+}
+
 void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map)
 {
        ext2fs_set_generic_bmap_padding(map);
 void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map)
 {
        ext2fs_set_generic_bmap_padding(map);
index 0df58dc..d7c88ae 100644 (file)
@@ -977,11 +977,76 @@ static void rb_print_stats(ext2fs_generic_bitmap_64 bitmap EXT2FS_ATTR((unused))
 }
 #endif
 
 }
 #endif
 
+static errcode_t rb_merge_bmap(ext2fs_generic_bitmap_64 src,
+                              ext2fs_generic_bitmap_64 dest,
+                              ext2fs_generic_bitmap_64 dup,
+                              ext2fs_generic_bitmap_64 dup_allowed)
+{
+       struct ext2fs_rb_private *src_bp, *dest_bp, *dup_bp = NULL;
+       struct bmap_rb_extent *src_ext;
+       struct rb_node *src_node;
+       errcode_t retval = 0;
+       int dup_found = 0;
+       __u64 i;
+
+       src_bp = (struct ext2fs_rb_private *) src->private;
+       dest_bp = (struct ext2fs_rb_private *) dest->private;
+       if (dup)
+               dup_bp = (struct ext2fs_rb_private *)dup->private;
+       src_bp->rcursor = NULL;
+       dest_bp->rcursor = NULL;
+
+       src_node = ext2fs_rb_first(&src_bp->root);
+       while (src_node) {
+               src_ext = node_to_extent(src_node);
+               retval = rb_test_clear_bmap_extent(dest,
+                                       src_ext->start + src->start,
+                                       src_ext->count);
+               if (retval) {
+                       rb_insert_extent(src_ext->start, src_ext->count,
+                                        dest_bp);
+                       goto next;
+               }
+
+               /* unlikely case, do it one by one block */
+               for (i = src_ext->start;
+                    i < src_ext->start + src_ext->count; i++) {
+                       retval = rb_test_clear_bmap_extent(dest, i + src->start, 1);
+                       if (retval) {
+                               rb_insert_extent(i, 1, dest_bp);
+                               continue;
+                       }
+                       if (dup_allowed) {
+                               retval = rb_test_clear_bmap_extent(dup_allowed,
+                                                       i + src->start, 1);
+                               /* not existed in dup_allowed */
+                               if (retval) {
+                                       dup_found = 1;
+                                       if (dup_bp)
+                                               rb_insert_extent(i, 1, dup_bp);
+                               } /* else we conside it not duplicated */
+                       } else {
+                               if (dup_bp)
+                                       rb_insert_extent(i, 1, dup_bp);
+                               dup_found = 1;
+                       }
+               }
+next:
+               src_node = ext2fs_rb_next(src_node);
+       }
+
+       if (dup_found && dup)
+               return EEXIST;
+
+       return 0;
+}
+
 struct ext2_bitmap_ops ext2fs_blkmap64_rbtree = {
        .type = EXT2FS_BMAP64_RBTREE,
        .new_bmap = rb_new_bmap,
        .free_bmap = rb_free_bmap,
        .copy_bmap = rb_copy_bmap,
 struct ext2_bitmap_ops ext2fs_blkmap64_rbtree = {
        .type = EXT2FS_BMAP64_RBTREE,
        .new_bmap = rb_new_bmap,
        .free_bmap = rb_free_bmap,
        .copy_bmap = rb_copy_bmap,
+       .merge_bmap = rb_merge_bmap,
        .resize_bmap = rb_resize_bmap,
        .mark_bmap = rb_mark_bmap,
        .unmark_bmap = rb_unmark_bmap,
        .resize_bmap = rb_resize_bmap,
        .mark_bmap = rb_mark_bmap,
        .unmark_bmap = rb_unmark_bmap,
index de33454..555193e 100644 (file)
@@ -72,6 +72,10 @@ struct ext2_bitmap_ops {
        void    (*free_bmap)(ext2fs_generic_bitmap_64 bitmap);
        errcode_t (*copy_bmap)(ext2fs_generic_bitmap_64 src,
                             ext2fs_generic_bitmap_64 dest);
        void    (*free_bmap)(ext2fs_generic_bitmap_64 bitmap);
        errcode_t (*copy_bmap)(ext2fs_generic_bitmap_64 src,
                             ext2fs_generic_bitmap_64 dest);
+       errcode_t (*merge_bmap)(ext2fs_generic_bitmap_64 src,
+                               ext2fs_generic_bitmap_64 dest,
+                               ext2fs_generic_bitmap_64 dup,
+                               ext2fs_generic_bitmap_64 dup_allowed);
        errcode_t (*resize_bmap)(ext2fs_generic_bitmap_64 bitmap,
                               __u64 new_end,
                               __u64 new_real_end);
        errcode_t (*resize_bmap)(ext2fs_generic_bitmap_64 bitmap,
                               __u64 new_end,
                               __u64 new_real_end);
index b4ed108..5eb9526 100644 (file)
@@ -865,6 +865,10 @@ extern void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap);
 extern void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap);
 extern errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
                                    ext2fs_generic_bitmap *dest);
 extern void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap);
 extern errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
                                    ext2fs_generic_bitmap *dest);
+errcode_t ext2fs_merge_bitmap(ext2fs_generic_bitmap src,
+                             ext2fs_generic_bitmap dest,
+                             ext2fs_generic_bitmap dup,
+                             ext2fs_generic_bitmap dup_allowed);
 extern errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
                                              const char *descr,
                                              ext2fs_block_bitmap *ret);
 extern errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
                                              const char *descr,
                                              ext2fs_block_bitmap *ret);
@@ -1459,6 +1463,10 @@ void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap);
 errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap bmap,
                                     __u64 new_end,
                                     __u64 new_real_end);
 errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap bmap,
                                     __u64 new_end,
                                     __u64 new_real_end);
+errcode_t ext2fs_merge_generic_bmap(ext2fs_generic_bitmap gen_src,
+                                    ext2fs_generic_bitmap gen_dest,
+                                   ext2fs_generic_bitmap gen_dup,
+                                   ext2fs_generic_bitmap dup_allowed);
 errcode_t ext2fs_compare_generic_bmap(errcode_t neq,
                                      ext2fs_generic_bitmap bm1,
                                      ext2fs_generic_bitmap bm2);
 errcode_t ext2fs_compare_generic_bmap(errcode_t neq,
                                      ext2fs_generic_bitmap bm1,
                                      ext2fs_generic_bitmap bm2);
index c860c10..4ea930a 100644 (file)
@@ -346,6 +346,35 @@ errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap gen_src,
        return 0;
 }
 
        return 0;
 }
 
+errcode_t ext2fs_merge_generic_bmap(ext2fs_generic_bitmap gen_src,
+                                   ext2fs_generic_bitmap gen_dest,
+                                   ext2fs_generic_bitmap gen_dup,
+                                   ext2fs_generic_bitmap gen_dup_allowed)
+{
+       ext2fs_generic_bitmap_64 src = (ext2fs_generic_bitmap_64)gen_src;
+       ext2fs_generic_bitmap_64 dest = (ext2fs_generic_bitmap_64)gen_dest;
+       ext2fs_generic_bitmap_64 dup = (ext2fs_generic_bitmap_64)gen_dup;
+       ext2fs_generic_bitmap_64 dup_allowed = (ext2fs_generic_bitmap_64)gen_dup_allowed;
+
+       if (!src || !dest)
+               return EINVAL;
+
+       if (!EXT2FS_IS_64_BITMAP(src) || !EXT2FS_IS_64_BITMAP(dest) ||
+           (dup && !EXT2FS_IS_64_BITMAP(dup)) ||
+               (dup_allowed && !EXT2FS_IS_64_BITMAP(dup_allowed)))
+               return EINVAL;
+
+       if (src->bitmap_ops != dest->bitmap_ops ||
+           (dup && src->bitmap_ops != dup->bitmap_ops) ||
+           (dup_allowed && src->bitmap_ops != dup_allowed->bitmap_ops))
+               return EINVAL;
+
+       if (src->bitmap_ops->merge_bmap == NULL)
+               return EOPNOTSUPP;
+
+       return src->bitmap_ops->merge_bmap(src, dest, dup, dup_allowed);
+}
+
 errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap gen_bmap,
                                     __u64 new_end,
                                     __u64 new_real_end)
 errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap gen_bmap,
                                     __u64 new_end,
                                     __u64 new_real_end)