diff options
author | Mikulas Patocka <mpatocka@redhat.com> | 2018-03-26 14:29:46 -0400 |
---|---|---|
committer | Mike Snitzer <snitzer@redhat.com> | 2018-04-03 15:04:28 -0400 |
commit | f51f2e0a7fb17af57634c65687c985c9b3449263 (patch) | |
tree | 16bc63fe23e61bb154d566ebd23f02051ab95ed0 /drivers/md/dm-bufio.c | |
parent | 359dbf19ab524652a2208a2a2cddccec2eede2ad (diff) |
dm bufio: support non-power-of-two block sizes
Support block sizes that are not a power-of-two (but they must be a
multiple of 512b). As always, a slab cache is used for allocations.
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Diffstat (limited to 'drivers/md/dm-bufio.c')
-rw-r--r-- | drivers/md/dm-bufio.c | 64 |
1 files changed, 39 insertions, 25 deletions
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 4a216926ee19..e88797e04fcc 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c | |||
@@ -57,12 +57,6 @@ | |||
57 | #define DM_BUFIO_INLINE_VECS 16 | 57 | #define DM_BUFIO_INLINE_VECS 16 |
58 | 58 | ||
59 | /* | 59 | /* |
60 | * Don't try to use alloc_pages for blocks larger than this. | ||
61 | * For explanation, see alloc_buffer_data below. | ||
62 | */ | ||
63 | #define DM_BUFIO_BLOCK_SIZE_GFP_LIMIT (PAGE_SIZE << (MAX_ORDER - 1)) | ||
64 | |||
65 | /* | ||
66 | * Align buffer writes to this boundary. | 60 | * Align buffer writes to this boundary. |
67 | * Tests show that SSDs have the highest IOPS when using 4k writes. | 61 | * Tests show that SSDs have the highest IOPS when using 4k writes. |
68 | */ | 62 | */ |
@@ -98,8 +92,7 @@ struct dm_bufio_client { | |||
98 | 92 | ||
99 | struct block_device *bdev; | 93 | struct block_device *bdev; |
100 | unsigned block_size; | 94 | unsigned block_size; |
101 | unsigned char sectors_per_block_bits; | 95 | s8 sectors_per_block_bits; |
102 | unsigned char pages_per_block_bits; | ||
103 | void (*alloc_callback)(struct dm_buffer *); | 96 | void (*alloc_callback)(struct dm_buffer *); |
104 | void (*write_callback)(struct dm_buffer *); | 97 | void (*write_callback)(struct dm_buffer *); |
105 | 98 | ||
@@ -375,11 +368,11 @@ static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask, | |||
375 | return kmem_cache_alloc(c->slab_cache, gfp_mask); | 368 | return kmem_cache_alloc(c->slab_cache, gfp_mask); |
376 | } | 369 | } |
377 | 370 | ||
378 | if (c->block_size <= DM_BUFIO_BLOCK_SIZE_GFP_LIMIT && | 371 | if (c->block_size <= KMALLOC_MAX_SIZE && |
379 | gfp_mask & __GFP_NORETRY) { | 372 | gfp_mask & __GFP_NORETRY) { |
380 | *data_mode = DATA_MODE_GET_FREE_PAGES; | 373 | *data_mode = DATA_MODE_GET_FREE_PAGES; |
381 | return (void *)__get_free_pages(gfp_mask, | 374 | return (void *)__get_free_pages(gfp_mask, |
382 | c->pages_per_block_bits); | 375 | c->sectors_per_block_bits - (PAGE_SHIFT - SECTOR_SHIFT)); |
383 | } | 376 | } |
384 | 377 | ||
385 | *data_mode = DATA_MODE_VMALLOC; | 378 | *data_mode = DATA_MODE_VMALLOC; |
@@ -416,7 +409,8 @@ static void free_buffer_data(struct dm_bufio_client *c, | |||
416 | break; | 409 | break; |
417 | 410 | ||
418 | case DATA_MODE_GET_FREE_PAGES: | 411 | case DATA_MODE_GET_FREE_PAGES: |
419 | free_pages((unsigned long)data, c->pages_per_block_bits); | 412 | free_pages((unsigned long)data, |
413 | c->sectors_per_block_bits - (PAGE_SHIFT - SECTOR_SHIFT)); | ||
420 | break; | 414 | break; |
421 | 415 | ||
422 | case DATA_MODE_VMALLOC: | 416 | case DATA_MODE_VMALLOC: |
@@ -634,10 +628,14 @@ static void submit_io(struct dm_buffer *b, int rw, bio_end_io_t *end_io) | |||
634 | sector_t sector; | 628 | sector_t sector; |
635 | unsigned offset, end; | 629 | unsigned offset, end; |
636 | 630 | ||
637 | sector = (b->block << b->c->sectors_per_block_bits) + b->c->start; | 631 | if (likely(b->c->sectors_per_block_bits >= 0)) |
632 | sector = b->block << b->c->sectors_per_block_bits; | ||
633 | else | ||
634 | sector = b->block * (b->c->block_size >> SECTOR_SHIFT); | ||
635 | sector += b->c->start; | ||
638 | 636 | ||
639 | if (rw != REQ_OP_WRITE) { | 637 | if (rw != REQ_OP_WRITE) { |
640 | n_sectors = 1 << b->c->sectors_per_block_bits; | 638 | n_sectors = b->c->block_size >> SECTOR_SHIFT; |
641 | offset = 0; | 639 | offset = 0; |
642 | } else { | 640 | } else { |
643 | if (b->c->write_callback) | 641 | if (b->c->write_callback) |
@@ -941,8 +939,11 @@ static void __get_memory_limit(struct dm_bufio_client *c, | |||
941 | } | 939 | } |
942 | } | 940 | } |
943 | 941 | ||
944 | buffers = dm_bufio_cache_size_per_client >> | 942 | buffers = dm_bufio_cache_size_per_client; |
945 | (c->sectors_per_block_bits + SECTOR_SHIFT); | 943 | if (likely(c->sectors_per_block_bits >= 0)) |
944 | buffers >>= c->sectors_per_block_bits + SECTOR_SHIFT; | ||
945 | else | ||
946 | buffers /= c->block_size; | ||
946 | 947 | ||
947 | if (buffers < c->minimum_buffers) | 948 | if (buffers < c->minimum_buffers) |
948 | buffers = c->minimum_buffers; | 949 | buffers = c->minimum_buffers; |
@@ -1476,8 +1477,12 @@ EXPORT_SYMBOL_GPL(dm_bufio_get_block_size); | |||
1476 | 1477 | ||
1477 | sector_t dm_bufio_get_device_size(struct dm_bufio_client *c) | 1478 | sector_t dm_bufio_get_device_size(struct dm_bufio_client *c) |
1478 | { | 1479 | { |
1479 | return i_size_read(c->bdev->bd_inode) >> | 1480 | sector_t s = i_size_read(c->bdev->bd_inode) >> SECTOR_SHIFT; |
1480 | (SECTOR_SHIFT + c->sectors_per_block_bits); | 1481 | if (likely(c->sectors_per_block_bits >= 0)) |
1482 | s >>= c->sectors_per_block_bits; | ||
1483 | else | ||
1484 | sector_div(s, c->block_size >> SECTOR_SHIFT); | ||
1485 | return s; | ||
1481 | } | 1486 | } |
1482 | EXPORT_SYMBOL_GPL(dm_bufio_get_device_size); | 1487 | EXPORT_SYMBOL_GPL(dm_bufio_get_device_size); |
1483 | 1488 | ||
@@ -1575,8 +1580,12 @@ static bool __try_evict_buffer(struct dm_buffer *b, gfp_t gfp) | |||
1575 | 1580 | ||
1576 | static unsigned long get_retain_buffers(struct dm_bufio_client *c) | 1581 | static unsigned long get_retain_buffers(struct dm_bufio_client *c) |
1577 | { | 1582 | { |
1578 | unsigned long retain_bytes = READ_ONCE(dm_bufio_retain_bytes); | 1583 | unsigned long retain_bytes = READ_ONCE(dm_bufio_retain_bytes); |
1579 | return retain_bytes >> (c->sectors_per_block_bits + SECTOR_SHIFT); | 1584 | if (likely(c->sectors_per_block_bits >= 0)) |
1585 | retain_bytes >>= c->sectors_per_block_bits + SECTOR_SHIFT; | ||
1586 | else | ||
1587 | retain_bytes /= c->block_size; | ||
1588 | return retain_bytes; | ||
1580 | } | 1589 | } |
1581 | 1590 | ||
1582 | static unsigned long __scan(struct dm_bufio_client *c, unsigned long nr_to_scan, | 1591 | static unsigned long __scan(struct dm_bufio_client *c, unsigned long nr_to_scan, |
@@ -1642,8 +1651,11 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign | |||
1642 | unsigned i; | 1651 | unsigned i; |
1643 | char slab_name[27]; | 1652 | char slab_name[27]; |
1644 | 1653 | ||
1645 | BUG_ON(block_size < 1 << SECTOR_SHIFT || | 1654 | if (!block_size || block_size & ((1 << SECTOR_SHIFT) - 1)) { |
1646 | (block_size & (block_size - 1))); | 1655 | DMERR("%s: block size not specified or is not multiple of 512b", __func__); |
1656 | r = -EINVAL; | ||
1657 | goto bad_client; | ||
1658 | } | ||
1647 | 1659 | ||
1648 | c = kzalloc(sizeof(*c), GFP_KERNEL); | 1660 | c = kzalloc(sizeof(*c), GFP_KERNEL); |
1649 | if (!c) { | 1661 | if (!c) { |
@@ -1654,9 +1666,10 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign | |||
1654 | 1666 | ||
1655 | c->bdev = bdev; | 1667 | c->bdev = bdev; |
1656 | c->block_size = block_size; | 1668 | c->block_size = block_size; |
1657 | c->sectors_per_block_bits = __ffs(block_size) - SECTOR_SHIFT; | 1669 | if (is_power_of_2(block_size)) |
1658 | c->pages_per_block_bits = (__ffs(block_size) >= PAGE_SHIFT) ? | 1670 | c->sectors_per_block_bits = __ffs(block_size) - SECTOR_SHIFT; |
1659 | __ffs(block_size) - PAGE_SHIFT : 0; | 1671 | else |
1672 | c->sectors_per_block_bits = -1; | ||
1660 | 1673 | ||
1661 | c->alloc_callback = alloc_callback; | 1674 | c->alloc_callback = alloc_callback; |
1662 | c->write_callback = write_callback; | 1675 | c->write_callback = write_callback; |
@@ -1681,7 +1694,8 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign | |||
1681 | goto bad_dm_io; | 1694 | goto bad_dm_io; |
1682 | } | 1695 | } |
1683 | 1696 | ||
1684 | if (block_size < PAGE_SIZE) { | 1697 | if (block_size <= KMALLOC_MAX_SIZE && |
1698 | (block_size < PAGE_SIZE || !is_power_of_2(block_size))) { | ||
1685 | snprintf(slab_name, sizeof slab_name, "dm_bufio_cache-%u", c->block_size); | 1699 | snprintf(slab_name, sizeof slab_name, "dm_bufio_cache-%u", c->block_size); |
1686 | c->slab_cache = kmem_cache_create(slab_name, c->block_size, ARCH_KMALLOC_MINALIGN, | 1700 | c->slab_cache = kmem_cache_create(slab_name, c->block_size, ARCH_KMALLOC_MINALIGN, |
1687 | SLAB_RECLAIM_ACCOUNT, NULL); | 1701 | SLAB_RECLAIM_ACCOUNT, NULL); |