@@ -388,6 +388,89 @@ static int delete_old_data_csums(struct btrfs_fs_info *fs_info)
388388 return ret ;
389389}
390390
391+ static int change_csum_objectids (struct btrfs_fs_info * fs_info )
392+ {
393+ struct btrfs_root * csum_root = btrfs_csum_root (fs_info , 0 );
394+ struct btrfs_trans_handle * trans ;
395+ struct btrfs_path path = { 0 };
396+ struct btrfs_key last_key ;
397+ u64 super_flags ;
398+ int ret = 0 ;
399+
400+ last_key .objectid = BTRFS_CSUM_CHANGE_OBJECTID ;
401+ last_key .type = BTRFS_EXTENT_CSUM_KEY ;
402+ last_key .offset = (u64 )- 1 ;
403+
404+ trans = btrfs_start_transaction (csum_root , 1 );
405+ if (IS_ERR (trans )) {
406+ ret = PTR_ERR (trans );
407+ errno = - ret ;
408+ error ("failed to start transaction to change csum objectids: %m" );
409+ return ret ;
410+ }
411+ while (true) {
412+ struct btrfs_key found_key ;
413+ int nr ;
414+
415+ ret = btrfs_search_slot (trans , csum_root , & last_key , & path , 0 , 1 );
416+ if (ret < 0 )
417+ goto out ;
418+ assert (ret > 0 );
419+
420+ nr = btrfs_header_nritems (path .nodes [0 ]);
421+ /* No item left (empty csum tree), exit. */
422+ if (!nr )
423+ goto out ;
424+ /* No more temporary csum items, all converted, exit. */
425+ if (path .slots [0 ] == 0 )
426+ goto out ;
427+
428+ /* All csum items should be new csums. */
429+ btrfs_item_key_to_cpu (path .nodes [0 ], & found_key , 0 );
430+ assert (found_key .objectid == BTRFS_CSUM_CHANGE_OBJECTID );
431+
432+ /*
433+ * Start changing the objectids, since EXTENT_CSUM (-10) is
434+ * larger than CSUM_CHANGE (-13), we always change from the tail.
435+ */
436+ for (int i = nr - 1 ; i >= 0 ; i -- ) {
437+ btrfs_item_key_to_cpu (path .nodes [0 ], & found_key , i );
438+ found_key .objectid = BTRFS_EXTENT_CSUM_OBJECTID ;
439+ path .slots [0 ] = i ;
440+ ret = btrfs_set_item_key_safe (csum_root , & path , & found_key );
441+ if (ret < 0 ) {
442+ errno = - ret ;
443+ error ("failed to set item key for data csum at logical %llu: %m" ,
444+ found_key .offset );
445+ goto out ;
446+ }
447+ }
448+ btrfs_release_path (& path );
449+ }
450+ out :
451+ btrfs_release_path (& path );
452+ if (ret < 0 ) {
453+ btrfs_abort_transaction (trans , ret );
454+ return ret ;
455+ }
456+
457+ /*
458+ * All data csum items has been changed to the new type, we can clear
459+ * the superblock flag for data csum change, and go to the metadata csum
460+ * change phase.
461+ */
462+ super_flags = btrfs_super_flags (fs_info -> super_copy );
463+ super_flags &= ~BTRFS_SUPER_FLAG_CHANGING_DATA_CSUM ;
464+ super_flags |= BTRFS_SUPER_FLAG_CHANGING_META_CSUM ;
465+ btrfs_set_super_flags (fs_info -> super_copy , super_flags );
466+ ret = btrfs_commit_transaction (trans , csum_root );
467+ if (ret < 0 ) {
468+ errno = - ret ;
469+ error ("failed to commit transaction after changing data csum objectids: %m" );
470+ }
471+ return ret ;
472+ }
473+
391474int btrfs_change_csum_type (struct btrfs_fs_info * fs_info , u16 new_csum_type )
392475{
393476 int ret ;
@@ -417,6 +500,9 @@ int btrfs_change_csum_type(struct btrfs_fs_info *fs_info, u16 new_csum_type)
417500 return ret ;
418501
419502 /* Phase 3, change the new csum key objectid */
503+ ret = change_csum_objectids (fs_info );
504+ if (ret < 0 )
505+ return ret ;
420506
421507 /*
422508 * Phase 4, change the csums for metadata.
0 commit comments