]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
dm vdo: handle unaligned discards correctly
authorMatthew Sakai <msakai@redhat.com>
Wed, 18 Sep 2024 03:24:37 +0000 (23:24 -0400)
committerMikulas Patocka <mpatocka@redhat.com>
Mon, 23 Sep 2024 13:15:41 +0000 (15:15 +0200)
Reset the data_vio properly for each discard block, and delay
acknowledgement and cleanup until all discard blocks are complete.

Signed-off-by: Matthew Sakai <msakai@redhat.com>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
drivers/md/dm-vdo/data-vio.c

index ab3ea833780946de71c11a8108e8db78a79cd037..0d502f6a86ad02f1b06c071c877a8435a013fd72 100644 (file)
@@ -501,6 +501,7 @@ static void launch_data_vio(struct data_vio *data_vio, logical_block_number_t lb
 
        memset(&data_vio->record_name, 0, sizeof(data_vio->record_name));
        memset(&data_vio->duplicate, 0, sizeof(data_vio->duplicate));
+       vdo_reset_completion(&data_vio->decrement_completion);
        vdo_reset_completion(completion);
        completion->error_handler = handle_data_vio_error;
        set_data_vio_logical_callback(data_vio, attempt_logical_block_lock);
@@ -1273,12 +1274,14 @@ static void clean_hash_lock(struct vdo_completion *completion)
 static void finish_cleanup(struct data_vio *data_vio)
 {
        struct vdo_completion *completion = &data_vio->vio.completion;
+       u32 discard_size = min_t(u32, data_vio->remaining_discard,
+                                VDO_BLOCK_SIZE - data_vio->offset);
 
        VDO_ASSERT_LOG_ONLY(data_vio->allocation.lock == NULL,
                            "complete data_vio has no allocation lock");
        VDO_ASSERT_LOG_ONLY(data_vio->hash_lock == NULL,
                            "complete data_vio has no hash lock");
-       if ((data_vio->remaining_discard <= VDO_BLOCK_SIZE) ||
+       if ((data_vio->remaining_discard <= discard_size) ||
            (completion->result != VDO_SUCCESS)) {
                struct data_vio_pool *pool = completion->vdo->data_vio_pool;
 
@@ -1287,12 +1290,12 @@ static void finish_cleanup(struct data_vio *data_vio)
                return;
        }
 
-       data_vio->remaining_discard -= min_t(u32, data_vio->remaining_discard,
-                                            VDO_BLOCK_SIZE - data_vio->offset);
+       data_vio->remaining_discard -= discard_size;
        data_vio->is_partial = (data_vio->remaining_discard < VDO_BLOCK_SIZE);
        data_vio->read = data_vio->is_partial;
        data_vio->offset = 0;
        completion->requeue = true;
+       data_vio->first_reference_operation_complete = false;
        launch_data_vio(data_vio, data_vio->logical.lbn + 1);
 }
 
@@ -1965,7 +1968,8 @@ static void allocate_block(struct vdo_completion *completion)
                .state = VDO_MAPPING_STATE_UNCOMPRESSED,
        };
 
-       if (data_vio->fua) {
+       if (data_vio->fua ||
+           data_vio->remaining_discard > (u32) (VDO_BLOCK_SIZE - data_vio->offset)) {
                prepare_for_dedupe(data_vio);
                return;
        }
@@ -2042,7 +2046,6 @@ void continue_data_vio_with_block_map_slot(struct vdo_completion *completion)
                return;
        }
 
-
        /*
         * We don't need to write any data, so skip allocation and just update the block map and
         * reference counts (via the journal).
@@ -2051,7 +2054,7 @@ void continue_data_vio_with_block_map_slot(struct vdo_completion *completion)
        if (data_vio->is_zero)
                data_vio->new_mapped.state = VDO_MAPPING_STATE_UNCOMPRESSED;
 
-       if (data_vio->remaining_discard > VDO_BLOCK_SIZE) {
+       if (data_vio->remaining_discard > (u32) (VDO_BLOCK_SIZE - data_vio->offset)) {
                /* This is not the final block of a discard so we can't acknowledge it yet. */
                update_metadata_for_data_vio_write(data_vio, NULL);
                return;