Hi This is second version of the dm-crypt swapping patch. Changes since the first version: - we only count write bios - when the user changes /sys/module/dm_crypt/parameters/max_bios_in_flight, the change is instantly applied to all dm-crypt instances - do not lock up if the user sets max_bios_in_flight to zero I was considering making the default value some fraction of memory, but it didn't work - i.e. for eaxmple, if we have 8GB machine and 256MB or more dm-crypt memory, it doesn't work (it doesn't deadlock, but it slows down the machine very much, to the point that it's unuseable). With smaller dm-crypt memory, it is more responsive. Mikulas From: Mikulas Patocka <mpatocka@xxxxxxxxxx> The system would deadlock when swapping to a dm-crypt device. The reason is that for each incoming write bio, dm-crypt allocates memory that holds encrypted data. These excessive allocations exhaust all the memory and the result is either deadlock or OOM trigger. This patch limits the number of in-flight bios, so that the memory consumed by dm-crypt is limited. If we are over the limit, we block in the function crypt_map, so that the caller will not attempt to send more bios. This is similar to request-based drivers - they will also block when the number of bios is over the limit. Signed-off-by: Mikulas Patocka <mpatocka@xxxxxxxxxx> Cc: stable@xxxxxxxxxxxxxxx Index: linux-2.6/drivers/md/dm-crypt.c =================================================================== --- linux-2.6.orig/drivers/md/dm-crypt.c +++ linux-2.6/drivers/md/dm-crypt.c @@ -214,16 +214,24 @@ struct crypt_config { mempool_t page_pool; struct bio_set bs; + + int bio_limit; + struct semaphore bio_limit_semaphore; + struct mutex bio_limit_lock; + struct mutex bio_alloc_lock; u8 *authenc_key; /* space for keys in authenc() format (if used) */ u8 key[]; }; +#define MAX_BIOS 4096 #define MIN_IOS 64 #define MAX_TAG_SIZE 480 #define POOL_ENTRY_SIZE 512 +static int bio_limit = MAX_BIOS; + static DEFINE_SPINLOCK(dm_crypt_clients_lock); static unsigned dm_crypt_clients_n = 0; static volatile unsigned long dm_crypt_pages_per_client; @@ -1713,6 +1721,8 @@ static void crypt_dec_pending(struct dm_ kfree(io->integrity_metadata); base_bio->bi_status = error; + if (bio_data_dir(base_bio) == WRITE) + up(&cc->bio_limit_semaphore); bio_endio(base_bio); } @@ -2567,6 +2577,7 @@ static void crypt_dtr(struct dm_target * kfree_sensitive(cc->cipher_auth); kfree_sensitive(cc->authenc_key); + mutex_destroy(&cc->bio_limit_lock); mutex_destroy(&cc->bio_alloc_lock); /* Must zero key material before freeing */ @@ -3007,6 +3018,7 @@ static int crypt_ctr(struct dm_target *t int key_size; unsigned int align_mask; unsigned long long tmpll; + int latch; int ret; size_t iv_size_padding, additional_req_size; char dummy; @@ -3106,6 +3118,12 @@ static int crypt_ctr(struct dm_target *t goto bad; } + latch = READ_ONCE(bio_limit); + if (unlikely(latch <= 0)) + latch = MAX_BIOS; + cc->bio_limit = latch; + sema_init(&cc->bio_limit_semaphore, latch); + mutex_init(&cc->bio_limit_lock); mutex_init(&cc->bio_alloc_lock); ret = -EINVAL; @@ -3234,6 +3252,25 @@ static int crypt_map(struct dm_target *t if (unlikely(bio->bi_iter.bi_size & (cc->sector_size - 1))) return DM_MAPIO_KILL; + if (bio_data_dir(bio) == WRITE) { + int latch = READ_ONCE(bio_limit); + if (unlikely(latch <= 0)) + latch = MAX_BIOS; + if (unlikely(cc->bio_limit != latch)) { + mutex_lock(&cc->bio_limit_lock); + while (latch < cc->bio_limit) { + down(&cc->bio_limit_semaphore); + cc->bio_limit--; + } + while (latch > cc->bio_limit) { + up(&cc->bio_limit_semaphore); + cc->bio_limit++; + } + mutex_unlock(&cc->bio_limit_lock); + } + down(&cc->bio_limit_semaphore); + } + io = dm_per_bio_data(bio, cc->per_bio_data_size); crypt_io_init(io, cc, bio, dm_target_offset(ti, bio->bi_iter.bi_sector)); @@ -3461,6 +3498,9 @@ static void __exit dm_crypt_exit(void) module_init(dm_crypt_init); module_exit(dm_crypt_exit); +module_param_named(max_bios_in_flight, bio_limit, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(max_bios_in_flight, "maximum number of bios in flight"); + MODULE_AUTHOR("Jana Saout <jana@xxxxxxxx>"); MODULE_DESCRIPTION(DM_NAME " target for transparent encryption / decryption"); MODULE_LICENSE("GPL"); -- dm-devel mailing list dm-devel@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/dm-devel