|
| 1 | +dm-crypt: limit the size of encryption requests |
| 2 | + |
| 3 | +jira LE-3201 |
| 4 | +Rebuild_History Non-Buildable kernel-rt-4.18.0-553.22.1.rt7.363.el8_10 |
| 5 | +commit-author Mikulas Patocka < [email protected]> |
| 6 | +commit 0d815e3400e631d227a3a95968b8c8e7e0c0ef9e |
| 7 | +Empty-Commit: Cherry-Pick Conflicts during history rebuild. |
| 8 | +Will be included in final tarball splat. Ref for failed cherry-pick at: |
| 9 | +ciq/ciq_backports/kernel-rt-4.18.0-553.22.1.rt7.363.el8_10/0d815e34.failed |
| 10 | + |
| 11 | +There was a performance regression reported where dm-crypt would perform |
| 12 | +worse on new kernels than on old kernels. The reason is that the old |
| 13 | +kernels split the bios to NVMe request size (that is usually 65536 or |
| 14 | +131072 bytes) and the new kernels pass the big bios through dm-crypt and |
| 15 | +split them underneath. |
| 16 | + |
| 17 | +If a big 1MiB bio is passed to dm-crypt, dm-crypt processes it on a single |
| 18 | +core without parallelization and this is what causes the performance |
| 19 | +degradation. |
| 20 | + |
| 21 | +This commit introduces new tunable variables |
| 22 | +/sys/module/dm_crypt/parameters/max_read_size and |
| 23 | +/sys/module/dm_crypt/parameters/max_write_size that specify the maximum |
| 24 | +bio size for dm-crypt. Bios larger than this value are split, so that |
| 25 | +they can be encrypted in parallel by multiple cores. If these variables |
| 26 | +are '0', a default 131072 is used. |
| 27 | + |
| 28 | +Splitting bios may cause performance regressions in other workloads - if |
| 29 | +this happens, the user should increase the value in max_read_size and |
| 30 | +max_write_size variables. |
| 31 | + |
| 32 | +max_read_size: |
| 33 | +128k 2399MiB/s |
| 34 | +256k 2368MiB/s |
| 35 | +512k 1986MiB/s |
| 36 | +1024 1790MiB/s |
| 37 | + |
| 38 | +max_write_size: |
| 39 | +128k 1712MiB/s |
| 40 | +256k 1651MiB/s |
| 41 | +512k 1537MiB/s |
| 42 | +1024k 1332MiB/s |
| 43 | + |
| 44 | +Note that if you run dm-crypt inside a virtual machine, you may need to do |
| 45 | +"echo numa >/sys/module/workqueue/parameters/default_affinity_scope" to |
| 46 | +improve performance. |
| 47 | + |
| 48 | + Signed-off-by: Mikulas Patocka < [email protected]> |
| 49 | + Tested-by: Laurence Oberman < [email protected]> |
| 50 | +(cherry picked from commit 0d815e3400e631d227a3a95968b8c8e7e0c0ef9e) |
| 51 | + Signed-off-by: Jonathan Maple < [email protected]> |
| 52 | + |
| 53 | +# Conflicts: |
| 54 | +# drivers/md/dm-crypt.c |
| 55 | +diff --cc drivers/md/dm-crypt.c |
| 56 | +index ba5dbca6ca9f,f46ff843d4c3..000000000000 |
| 57 | +--- a/drivers/md/dm-crypt.c |
| 58 | ++++ b/drivers/md/dm-crypt.c |
| 59 | +@@@ -229,12 -237,37 +229,41 @@@ struct crypt_config |
| 60 | + #define POOL_ENTRY_SIZE 512 |
| 61 | + |
| 62 | + static DEFINE_SPINLOCK(dm_crypt_clients_lock); |
| 63 | + -static unsigned int dm_crypt_clients_n; |
| 64 | + +static unsigned dm_crypt_clients_n = 0; |
| 65 | + static volatile unsigned long dm_crypt_pages_per_client; |
| 66 | + #define DM_CRYPT_MEMORY_PERCENT 2 |
| 67 | +++<<<<<<< HEAD |
| 68 | + +#define DM_CRYPT_MIN_PAGES_PER_CLIENT (BIO_MAX_PAGES * 16) |
| 69 | +++======= |
| 70 | ++ #define DM_CRYPT_MIN_PAGES_PER_CLIENT (BIO_MAX_VECS * 16) |
| 71 | ++ #define DM_CRYPT_DEFAULT_MAX_READ_SIZE 131072 |
| 72 | ++ #define DM_CRYPT_DEFAULT_MAX_WRITE_SIZE 131072 |
| 73 | ++ |
| 74 | ++ static unsigned int max_read_size = 0; |
| 75 | ++ module_param(max_read_size, uint, 0644); |
| 76 | ++ MODULE_PARM_DESC(max_read_size, "Maximum size of a read request"); |
| 77 | ++ static unsigned int max_write_size = 0; |
| 78 | ++ module_param(max_write_size, uint, 0644); |
| 79 | ++ MODULE_PARM_DESC(max_write_size, "Maximum size of a write request"); |
| 80 | ++ static unsigned get_max_request_size(struct crypt_config *cc, bool wrt) |
| 81 | ++ { |
| 82 | ++ unsigned val, sector_align; |
| 83 | ++ val = !wrt ? READ_ONCE(max_read_size) : READ_ONCE(max_write_size); |
| 84 | ++ if (likely(!val)) |
| 85 | ++ val = !wrt ? DM_CRYPT_DEFAULT_MAX_READ_SIZE : DM_CRYPT_DEFAULT_MAX_WRITE_SIZE; |
| 86 | ++ if (wrt || cc->on_disk_tag_size) { |
| 87 | ++ if (unlikely(val > BIO_MAX_VECS << PAGE_SHIFT)) |
| 88 | ++ val = BIO_MAX_VECS << PAGE_SHIFT; |
| 89 | ++ } |
| 90 | ++ sector_align = max(bdev_logical_block_size(cc->dev->bdev), (unsigned)cc->sector_size); |
| 91 | ++ val = round_down(val, sector_align); |
| 92 | ++ if (unlikely(!val)) |
| 93 | ++ val = sector_align; |
| 94 | ++ return val >> SECTOR_SHIFT; |
| 95 | ++ } |
| 96 | +++>>>>>>> 0d815e3400e6 (dm-crypt: limit the size of encryption requests) |
| 97 | + |
| 98 | + -static void crypt_endio(struct bio *clone); |
| 99 | + +static void clone_init(struct dm_crypt_io *, struct bio *); |
| 100 | + static void kcryptd_queue_crypt(struct dm_crypt_io *io); |
| 101 | + static struct scatterlist *crypt_get_sg_data(struct crypt_config *cc, |
| 102 | + struct scatterlist *sg); |
| 103 | +@@@ -3345,9 -3518,9 +3375,15 @@@ static int crypt_map(struct dm_target * |
| 104 | + /* |
| 105 | + * Check if bio is too large, split as needed. |
| 106 | + */ |
| 107 | +++<<<<<<< HEAD |
| 108 | + + if (unlikely(bio->bi_iter.bi_size > (BIO_MAX_PAGES << PAGE_SHIFT)) && |
| 109 | + + (bio_data_dir(bio) == WRITE || cc->on_disk_tag_size)) |
| 110 | + + dm_accept_partial_bio(bio, ((BIO_MAX_PAGES << PAGE_SHIFT) >> SECTOR_SHIFT)); |
| 111 | +++======= |
| 112 | ++ max_sectors = get_max_request_size(cc, bio_data_dir(bio) == WRITE); |
| 113 | ++ if (unlikely(bio_sectors(bio) > max_sectors)) |
| 114 | ++ dm_accept_partial_bio(bio, max_sectors); |
| 115 | +++>>>>>>> 0d815e3400e6 (dm-crypt: limit the size of encryption requests) |
| 116 | + |
| 117 | + /* |
| 118 | + * Ensure that bio is a multiple of internal sector encryption size |
| 119 | +diff --git a/Documentation/admin-guide/device-mapper/dm-crypt.rst b/Documentation/admin-guide/device-mapper/dm-crypt.rst |
| 120 | +index 4ba56c256c05..8d9af4ba1948 100644 |
| 121 | +--- a/Documentation/admin-guide/device-mapper/dm-crypt.rst |
| 122 | ++++ b/Documentation/admin-guide/device-mapper/dm-crypt.rst |
| 123 | +@@ -155,6 +155,17 @@ iv_large_sectors |
| 124 | + The <iv_offset> must be multiple of <sector_size> (in 512 bytes units) |
| 125 | + if this flag is specified. |
| 126 | + |
| 127 | ++ |
| 128 | ++Module parameters:: |
| 129 | ++max_read_size |
| 130 | ++max_write_size |
| 131 | ++ Maximum size of read or write requests. When a request larger than this size |
| 132 | ++ is received, dm-crypt will split the request. The splitting improves |
| 133 | ++ concurrency (the split requests could be encrypted in parallel by multiple |
| 134 | ++ cores), but it also causes overhead. The user should tune these parameters to |
| 135 | ++ fit the actual workload. |
| 136 | ++ |
| 137 | ++ |
| 138 | + Example scripts |
| 139 | + =============== |
| 140 | + LUKS (Linux Unified Key Setup) is now the preferred way to set up disk |
| 141 | +* Unmerged path drivers/md/dm-crypt.c |
0 commit comments