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 <[email protected]>
Cc: [email protected]

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,21 @@ struct crypt_config {
        mempool_t page_pool;
 
        struct bio_set bs;
+
+       struct semaphore bio_limit;
        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 +1718,7 @@ static void crypt_dec_pending(struct dm_
                kfree(io->integrity_metadata);
 
        base_bio->bi_status = error;
+       up(&cc->bio_limit);
        bio_endio(base_bio);
 }
 
@@ -3106,6 +3112,7 @@ static int crypt_ctr(struct dm_target *t
                goto bad;
        }
 
+       sema_init(&cc->bio_limit, bio_limit);
        mutex_init(&cc->bio_alloc_lock);
 
        ret = -EINVAL;
@@ -3234,6 +3241,8 @@ static int crypt_map(struct dm_target *t
        if (unlikely(bio->bi_iter.bi_size & (cc->sector_size - 1)))
                return DM_MAPIO_KILL;
 
+       down(&cc->bio_limit);
+
        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 +3470,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 <[email protected]>");
 MODULE_DESCRIPTION(DM_NAME " target for transparent encryption / decryption");
 MODULE_LICENSE("GPL");

--
dm-devel mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/dm-devel

Reply via email to