dm crypt: constrain crypt device's max_segment_size to PAGE_SIZE
[cascardo/linux.git] / drivers / md / dm-crypt.c
index 0f48fed..4b3b6f8 100644 (file)
@@ -968,7 +968,8 @@ static void crypt_free_buffer_pages(struct crypt_config *cc, struct bio *clone);
 
 /*
  * Generate a new unfragmented bio with the given size
- * This should never violate the device limitations
+ * This should never violate the device limitations (but only because
+ * max_segment_size is being constrained to PAGE_SIZE).
  *
  * This function may be called concurrently. If we allocate from the mempool
  * concurrently, there is a possibility of deadlock. For example, if we have
@@ -1076,7 +1077,8 @@ static void crypt_dec_pending(struct dm_crypt_io *io)
        if (io->ctx.req)
                crypt_free_req(cc, io->ctx.req, base_bio);
 
-       bio_endio(base_bio, error);
+       base_bio->bi_error = error;
+       bio_endio(base_bio);
 }
 
 /*
@@ -1096,14 +1098,12 @@ static void crypt_dec_pending(struct dm_crypt_io *io)
  * The work is done per CPU global for all dm-crypt instances.
  * They should not depend on each other and do not block.
  */
-static void crypt_endio(struct bio *clone, int error)
+static void crypt_endio(struct bio *clone)
 {
        struct dm_crypt_io *io = clone->bi_private;
        struct crypt_config *cc = io->cc;
        unsigned rw = bio_data_dir(clone);
-
-       if (unlikely(!bio_flagged(clone, BIO_UPTODATE) && !error))
-               error = -EIO;
+       int error;
 
        /*
         * free the processed pages
@@ -1111,6 +1111,7 @@ static void crypt_endio(struct bio *clone, int error)
        if (rw == WRITE)
                crypt_free_buffer_pages(cc, clone);
 
+       error = clone->bi_error;
        bio_put(clone);
 
        if (rw == READ && !error) {
@@ -1811,11 +1812,13 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        }
        cc->iv_offset = tmpll;
 
-       if (dm_get_device(ti, argv[3], dm_table_get_mode(ti->table), &cc->dev)) {
+       ret = dm_get_device(ti, argv[3], dm_table_get_mode(ti->table), &cc->dev);
+       if (ret) {
                ti->error = "Device lookup failed";
                goto bad;
        }
 
+       ret = -EINVAL;
        if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) {
                ti->error = "Invalid device sector";
                goto bad;
@@ -2035,21 +2038,6 @@ error:
        return -EINVAL;
 }
 
-static int crypt_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
-                      struct bio_vec *biovec, int max_size)
-{
-       struct crypt_config *cc = ti->private;
-       struct request_queue *q = bdev_get_queue(cc->dev->bdev);
-
-       if (!q->merge_bvec_fn)
-               return max_size;
-
-       bvm->bi_bdev = cc->dev->bdev;
-       bvm->bi_sector = cc->start + dm_target_offset(ti, bvm->bi_sector);
-
-       return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
-}
-
 static int crypt_iterate_devices(struct dm_target *ti,
                                 iterate_devices_callout_fn fn, void *data)
 {
@@ -2058,9 +2046,20 @@ static int crypt_iterate_devices(struct dm_target *ti,
        return fn(ti, cc->dev, cc->start, ti->len, data);
 }
 
+static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
+{
+       /*
+        * Unfortunate constraint that is required to avoid the potential
+        * for exceeding underlying device's max_segments limits -- due to
+        * crypt_alloc_buffer() possibly allocating pages for the encryption
+        * bio that are not as physically contiguous as the original bio.
+        */
+       limits->max_segment_size = PAGE_SIZE;
+}
+
 static struct target_type crypt_target = {
        .name   = "crypt",
-       .version = {1, 14, 0},
+       .version = {1, 14, 1},
        .module = THIS_MODULE,
        .ctr    = crypt_ctr,
        .dtr    = crypt_dtr,
@@ -2070,8 +2069,8 @@ static struct target_type crypt_target = {
        .preresume = crypt_preresume,
        .resume = crypt_resume,
        .message = crypt_message,
-       .merge  = crypt_merge,
        .iterate_devices = crypt_iterate_devices,
+       .io_hints = crypt_io_hints,
 };
 
 static int __init dm_crypt_init(void)