dm crypt: use io thread for reads only if mempool exhausted
authorMilan Broz <mbroz@redhat.com>
Thu, 13 Jan 2011 19:59:53 +0000 (19:59 +0000)
committerAlasdair G Kergon <agk@redhat.com>
Thu, 13 Jan 2011 19:59:53 +0000 (19:59 +0000)
If there is enough memory, code can directly submit bio
instead queing this operation in separate thread.

Try to alloc bio clone with GFP_NOWAIT and only if it
fails use separate queue (map function cannot block here).

Signed-off-by: Milan Broz <mbroz@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
drivers/md/dm-crypt.c

index 50ae6ef83738b39ed34370d3bb59405cc55f87bb..dc4403bcc6a0bff010197752803bc7956b7ea9cf 100644 (file)
@@ -787,26 +787,30 @@ static void clone_init(struct dm_crypt_io *io, struct bio *clone)
        clone->bi_destructor = dm_crypt_bio_destructor;
 }
 
-static void kcryptd_io_read(struct dm_crypt_io *io)
+static void kcryptd_unplug(struct crypt_config *cc)
+{
+       blk_unplug(bdev_get_queue(cc->dev->bdev));
+}
+
+static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp)
 {
        struct crypt_config *cc = io->target->private;
        struct bio *base_bio = io->base_bio;
        struct bio *clone;
 
-       crypt_inc_pending(io);
-
        /*
         * The block layer might modify the bvec array, so always
         * copy the required bvecs because we need the original
         * one in order to decrypt the whole bio data *afterwards*.
         */
-       clone = bio_alloc_bioset(GFP_NOIO, bio_segments(base_bio), cc->bs);
-       if (unlikely(!clone)) {
-               io->error = -ENOMEM;
-               crypt_dec_pending(io);
-               return;
+       clone = bio_alloc_bioset(gfp, bio_segments(base_bio), cc->bs);
+       if (!clone) {
+               kcryptd_unplug(cc);
+               return 1;
        }
 
+       crypt_inc_pending(io);
+
        clone_init(io, clone);
        clone->bi_idx = 0;
        clone->bi_vcnt = bio_segments(base_bio);
@@ -816,6 +820,7 @@ static void kcryptd_io_read(struct dm_crypt_io *io)
               sizeof(struct bio_vec) * clone->bi_vcnt);
 
        generic_make_request(clone);
+       return 0;
 }
 
 static void kcryptd_io_write(struct dm_crypt_io *io)
@@ -828,9 +833,12 @@ static void kcryptd_io(struct work_struct *work)
 {
        struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work);
 
-       if (bio_data_dir(io->base_bio) == READ)
-               kcryptd_io_read(io);
-       else
+       if (bio_data_dir(io->base_bio) == READ) {
+               crypt_inc_pending(io);
+               if (kcryptd_io_read(io, GFP_NOIO))
+                       io->error = -ENOMEM;
+               crypt_dec_pending(io);
+       } else
                kcryptd_io_write(io);
 }
 
@@ -1424,9 +1432,10 @@ static int crypt_map(struct dm_target *ti, struct bio *bio,
 
        io = crypt_io_alloc(ti, bio, dm_target_offset(ti, bio->bi_sector));
 
-       if (bio_data_dir(io->base_bio) == READ)
-               kcryptd_queue_io(io);
-       else
+       if (bio_data_dir(io->base_bio) == READ) {
+               if (kcryptd_io_read(io, GFP_NOWAIT))
+                       kcryptd_queue_io(io);
+       } else
                kcryptd_queue_crypt(io);
 
        return DM_MAPIO_SUBMITTED;