Skip to content

Commit

Permalink
dm vdo: allow variable-sized metadata I/O
Browse files Browse the repository at this point in the history
Previously all metadata I/O was done with the size that was allocated
at initialization time. With most metadata I/O being done using
multiple 4kB VIOs, that made sense. With larger-sized metadata VIO
pools allowed now, sometimes we may want to do I/O with a smaller size
than the allocated size.

Since vio_reset_bio is where the bvec array and I/O size are
initialized, this reset interface now needs to know about the I/O size
intended.

Signed-off-by: Ken Raeburn <[email protected]>
Signed-off-by: Matthew Sakai <[email protected]>
  • Loading branch information
raeburn authored and lorelei-sakai committed Jan 15, 2025
1 parent efc8341 commit be27a72
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 19 deletions.
6 changes: 4 additions & 2 deletions drivers/md/dm-vdo/io-submitter.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ void vdo_submit_data_vio(struct data_vio *data_vio)
* @error_handler: the handler for submission or I/O errors (may be NULL)
* @operation: the type of I/O to perform
* @data: the buffer to read or write (may be NULL)
* @size: the I/O amount in bytes
*
* The vio is enqueued on a vdo bio queue so that bio submission (which may block) does not block
* other vdo threads.
Expand All @@ -338,7 +339,7 @@ void vdo_submit_data_vio(struct data_vio *data_vio)
*/
void __submit_metadata_vio(struct vio *vio, physical_block_number_t physical,
bio_end_io_t callback, vdo_action_fn error_handler,
blk_opf_t operation, char *data)
blk_opf_t operation, char *data, int size)
{
int result;
struct vdo_completion *completion = &vio->completion;
Expand All @@ -349,7 +350,8 @@ void __submit_metadata_vio(struct vio *vio, physical_block_number_t physical,

vdo_reset_completion(completion);
completion->error_handler = error_handler;
result = vio_reset_bio(vio, data, callback, operation | REQ_META, physical);
result = vio_reset_bio_with_size(vio, data, size, callback, operation | REQ_META,
physical);
if (result != VDO_SUCCESS) {
continue_vio(vio, result);
return;
Expand Down
18 changes: 15 additions & 3 deletions drivers/md/dm-vdo/io-submitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <linux/bio.h>

#include "constants.h"
#include "types.h"

struct io_submitter;
Expand All @@ -26,22 +27,33 @@ void vdo_submit_data_vio(struct data_vio *data_vio);

void __submit_metadata_vio(struct vio *vio, physical_block_number_t physical,
bio_end_io_t callback, vdo_action_fn error_handler,
blk_opf_t operation, char *data);
blk_opf_t operation, char *data, int size);

static inline void vdo_submit_metadata_vio(struct vio *vio, physical_block_number_t physical,
bio_end_io_t callback, vdo_action_fn error_handler,
blk_opf_t operation)
{
__submit_metadata_vio(vio, physical, callback, error_handler,
operation, vio->data);
operation, vio->data, vio->block_count * VDO_BLOCK_SIZE);
}

static inline void vdo_submit_metadata_vio_with_size(struct vio *vio,
physical_block_number_t physical,
bio_end_io_t callback,
vdo_action_fn error_handler,
blk_opf_t operation,
int size)
{
__submit_metadata_vio(vio, physical, callback, error_handler,
operation, vio->data, size);
}

static inline void vdo_submit_flush_vio(struct vio *vio, bio_end_io_t callback,
vdo_action_fn error_handler)
{
/* FIXME: Can we just use REQ_OP_FLUSH? */
__submit_metadata_vio(vio, 0, callback, error_handler,
REQ_OP_WRITE | REQ_PREFLUSH, NULL);
REQ_OP_WRITE | REQ_PREFLUSH, NULL, 0);
}

#endif /* VDO_IO_SUBMITTER_H */
3 changes: 3 additions & 0 deletions drivers/md/dm-vdo/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,9 @@ struct vio {
/* The size of this vio in blocks */
unsigned int block_count;

/* The amount of data to be read or written, in bytes */
unsigned int io_size;

/* The data being read or written. */
char *data;

Expand Down
36 changes: 22 additions & 14 deletions drivers/md/dm-vdo/vio.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,14 +188,23 @@ void vdo_set_bio_properties(struct bio *bio, struct vio *vio, bio_end_io_t callb

/*
* Prepares the bio to perform IO with the specified buffer. May only be used on a VDO-allocated
* bio, as it assumes the bio wraps a 4k buffer that is 4k aligned, but there does not have to be a
* vio associated with the bio.
* bio, as it assumes the bio wraps a 4k-multiple buffer that is 4k aligned, but there does not
* have to be a vio associated with the bio.
*/
int vio_reset_bio(struct vio *vio, char *data, bio_end_io_t callback,
blk_opf_t bi_opf, physical_block_number_t pbn)
{
int bvec_count, offset, len, i;
return vio_reset_bio_with_size(vio, data, vio->block_count * VDO_BLOCK_SIZE,
callback, bi_opf, pbn);
}

int vio_reset_bio_with_size(struct vio *vio, char *data, int size, bio_end_io_t callback,
blk_opf_t bi_opf, physical_block_number_t pbn)
{
int bvec_count, offset, i;
struct bio *bio = vio->bio;
int vio_size = vio->block_count * VDO_BLOCK_SIZE;
int remaining;

bio_reset(bio, bio->bi_bdev, bi_opf);
vdo_set_bio_properties(bio, vio, callback, bi_opf, pbn);
Expand All @@ -205,22 +214,21 @@ int vio_reset_bio(struct vio *vio, char *data, bio_end_io_t callback,
bio->bi_ioprio = 0;
bio->bi_io_vec = bio->bi_inline_vecs;
bio->bi_max_vecs = vio->block_count + 1;
len = VDO_BLOCK_SIZE * vio->block_count;
if (VDO_ASSERT(size <= vio_size, "specified size %d is not greater than allocated %d",
size, vio_size) != VDO_SUCCESS)
size = vio_size;
vio->io_size = size;
offset = offset_in_page(data);
bvec_count = DIV_ROUND_UP(offset + len, PAGE_SIZE);
bvec_count = DIV_ROUND_UP(offset + size, PAGE_SIZE);
remaining = size;

/*
* If we knew that data was always on one page, or contiguous pages, we wouldn't need the
* loop. But if we're using vmalloc, it's not impossible that the data is in different
* pages that can't be merged in bio_add_page...
*/
for (i = 0; (i < bvec_count) && (len > 0); i++) {
for (i = 0; (i < bvec_count) && (remaining > 0); i++) {
struct page *page;
int bytes_added;
int bytes = PAGE_SIZE - offset;

if (bytes > len)
bytes = len;
if (bytes > remaining)
bytes = remaining;

page = is_vmalloc_addr(data) ? vmalloc_to_page(data) : virt_to_page(data);
bytes_added = bio_add_page(bio, page, bytes, offset);
Expand All @@ -232,7 +240,7 @@ int vio_reset_bio(struct vio *vio, char *data, bio_end_io_t callback,
}

data += bytes;
len -= bytes;
remaining -= bytes;
offset = 0;
}

Expand Down
2 changes: 2 additions & 0 deletions drivers/md/dm-vdo/vio.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ void vdo_set_bio_properties(struct bio *bio, struct vio *vio, bio_end_io_t callb

int vio_reset_bio(struct vio *vio, char *data, bio_end_io_t callback,
blk_opf_t bi_opf, physical_block_number_t pbn);
int vio_reset_bio_with_size(struct vio *vio, char *data, int size, bio_end_io_t callback,
blk_opf_t bi_opf, physical_block_number_t pbn);

void update_vio_error_stats(struct vio *vio, const char *format, ...)
__printf(2, 3);
Expand Down

0 comments on commit be27a72

Please sign in to comment.