/*
  * Mark start of chunk relocation that is cancellable. Check if the cancellation
  * has been requested meanwhile and don't start in that case.
+ * NOTE: if this returns an error, reloc_chunk_end() must not be called.
  *
  * Return:
  *   0             success
 
        if (atomic_read(&fs_info->reloc_cancel_req) > 0) {
                btrfs_info(fs_info, "chunk relocation canceled on start");
-               /*
-                * On cancel, clear all requests but let the caller mark
-                * the end after cleanup operations.
-                */
+               /* On cancel, clear all requests. */
+               clear_and_wake_up_bit(BTRFS_FS_RELOC_RUNNING, &fs_info->flags);
                atomic_set(&fs_info->reloc_cancel_req, 0);
                return -ECANCELED;
        }
 
 /*
  * Mark end of chunk relocation that is cancellable and wake any waiters.
+ * NOTE: call only if a previous call to reloc_chunk_start() succeeded.
  */
 static void reloc_chunk_end(struct btrfs_fs_info *fs_info)
 {
+       ASSERT(test_bit(BTRFS_FS_RELOC_RUNNING, &fs_info->flags));
        /* Requested after start, clear bit first so any waiters can continue */
        if (atomic_read(&fs_info->reloc_cancel_req) > 0)
                btrfs_info(fs_info, "chunk relocation canceled during operation");
        if (err && rw)
                btrfs_dec_block_group_ro(rc->block_group);
        iput(rc->data_inode);
+       reloc_chunk_end(fs_info);
 out_put_bg:
        btrfs_put_block_group(bg);
-       reloc_chunk_end(fs_info);
        free_reloc_control(rc);
        return err;
 }
                ret = ret2;
 out_unset:
        unset_reloc_control(rc);
-out_end:
        reloc_chunk_end(fs_info);
+out_end:
        free_reloc_control(rc);
 out:
        free_reloc_roots(&reloc_roots);