linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / md / dm-crypt.c
index ebf7351..aa9b772 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/crypto.h>
 #include <linux/workqueue.h>
 #include <asm/atomic.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
 #include <asm/page.h>
 
 #include "dm.h"
@@ -96,7 +96,7 @@ static kmem_cache_t *_crypt_io_pool;
 /*
  * Mempool alloc and free functions for the page
  */
-static void *mempool_alloc_page(int gfp_mask, void *data)
+static void *mempool_alloc_page(gfp_t gfp_mask, void *data)
 {
        return alloc_page(gfp_mask);
 }
@@ -144,7 +144,7 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
        }
 
        /* Hash the cipher key with the given hash algorithm */
-       hash_tfm = crypto_alloc_tfm(opts, 0);
+       hash_tfm = crypto_alloc_tfm(opts, CRYPTO_TFM_REQ_MAY_SLEEP);
        if (hash_tfm == NULL) {
                ti->error = PFX "Error initializing ESSIV hash";
                return -EINVAL;
@@ -164,15 +164,14 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
                return -ENOMEM;
        }
 
-       sg.page = virt_to_page(cc->key);
-       sg.offset = offset_in_page(cc->key);
-       sg.length = cc->key_size;
+       sg_set_buf(&sg, cc->key, cc->key_size);
        crypto_digest_digest(hash_tfm, &sg, 1, salt);
        crypto_free_tfm(hash_tfm);
 
        /* Setup the essiv_tfm with the given salt */
        essiv_tfm = crypto_alloc_tfm(crypto_tfm_alg_name(cc->tfm),
-                                    CRYPTO_TFM_MODE_ECB);
+                                    CRYPTO_TFM_MODE_ECB |
+                                    CRYPTO_TFM_REQ_MAY_SLEEP);
        if (essiv_tfm == NULL) {
                ti->error = PFX "Error allocating crypto tfm for ESSIV";
                kfree(salt);
@@ -206,14 +205,12 @@ static void crypt_iv_essiv_dtr(struct crypt_config *cc)
 
 static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
 {
-       struct scatterlist sg = { NULL, };
+       struct scatterlist sg;
 
        memset(iv, 0, cc->iv_size);
        *(u64 *)iv = cpu_to_le64(sector);
 
-       sg.page = virt_to_page(iv);
-       sg.offset = offset_in_page(iv);
-       sg.length = cc->iv_size;
+       sg_set_buf(&sg, iv, cc->iv_size);
        crypto_cipher_encrypt((struct crypto_tfm *)cc->iv_gen_private,
                              &sg, &sg, cc->iv_size);
 
@@ -231,7 +228,7 @@ static struct crypt_iv_operations crypt_iv_essiv_ops = {
 };
 
 
-static inline int
+static int
 crypt_convert_scatterlist(struct crypt_config *cc, struct scatterlist *out,
                           struct scatterlist *in, unsigned int length,
                           int write, sector_t sector)
@@ -329,27 +326,21 @@ crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
                    struct bio *base_bio, unsigned int *bio_vec_idx)
 {
        struct bio *bio;
-       unsigned int nr_iovecs = dm_div_up(size, PAGE_SIZE);
-       int gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
-       unsigned long flags = current->flags;
+       unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
        unsigned int i;
 
        /*
-        * Tell VM to act less aggressively and fail earlier.
-        * This is not necessary but increases throughput.
+        * Use __GFP_NOMEMALLOC to tell the VM to act less aggressively and
+        * to fail earlier.  This is not necessary but increases throughput.
         * FIXME: Is this really intelligent?
         */
-       current->flags &= ~PF_MEMALLOC;
-
        if (base_bio)
-               bio = bio_clone(base_bio, GFP_NOIO);
+               bio = bio_clone(base_bio, GFP_NOIO|__GFP_NOMEMALLOC);
        else
-               bio = bio_alloc(GFP_NOIO, nr_iovecs);
-       if (!bio) {
-               if (flags & PF_MEMALLOC)
-                       current->flags |= PF_MEMALLOC;
+               bio = bio_alloc(GFP_NOIO|__GFP_NOMEMALLOC, nr_iovecs);
+       if (!bio)
                return NULL;
-       }
 
        /* if the last bio was not complete, continue where that one ended */
        bio->bi_idx = *bio_vec_idx;
@@ -386,9 +377,6 @@ crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
                size -= bv->bv_len;
        }
 
-       if (flags & PF_MEMALLOC)
-               current->flags |= PF_MEMALLOC;
-
        if (!bio->bi_size) {
                bio_put(bio);
                return NULL;
@@ -596,7 +584,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto bad1;
        }
 
-       tfm = crypto_alloc_tfm(cipher, crypto_flags);
+       tfm = crypto_alloc_tfm(cipher, crypto_flags | CRYPTO_TFM_REQ_MAY_SLEEP);
        if (!tfm) {
                ti->error = PFX "Error allocating crypto tfm";
                goto bad1;
@@ -702,6 +690,8 @@ bad3:
 bad2:
        crypto_free_tfm(tfm);
 bad1:
+       /* Must zero key material before freeing */
+       memset(cc, 0, sizeof(*cc) + cc->key_size * sizeof(u8));
        kfree(cc);
        return -EINVAL;
 }
@@ -713,12 +703,14 @@ static void crypt_dtr(struct dm_target *ti)
        mempool_destroy(cc->page_pool);
        mempool_destroy(cc->io_pool);
 
-       if (cc->iv_mode)
-               kfree(cc->iv_mode);
+       kfree(cc->iv_mode);
        if (cc->iv_gen_ops && cc->iv_gen_ops->dtr)
                cc->iv_gen_ops->dtr(cc);
        crypto_free_tfm(cc->tfm);
        dm_put_device(ti, cc->dev);
+
+       /* Must zero key material before freeing */
+       memset(cc, 0, sizeof(*cc) + cc->key_size * sizeof(u8));
        kfree(cc);
 }
 
@@ -738,13 +730,15 @@ static int crypt_endio(struct bio *bio, unsigned int done, int error)
        if (bio->bi_size)
                return 1;
 
+       if (!bio_flagged(bio, BIO_UPTODATE) && !error)
+               error = -EIO;
+
        bio_put(bio);
 
        /*
         * successful reads are decrypted by the worker thread
         */
-       if ((bio_data_dir(bio) == READ)
-           && bio_flagged(bio, BIO_UPTODATE)) {
+       if (bio_data_dir(io->bio) == READ && !error) {
                kcryptd_queue_io(io);
                return 0;
        }
@@ -869,7 +863,6 @@ static int crypt_status(struct dm_target *ti, status_type_t type,
                        char *result, unsigned int maxlen)
 {
        struct crypt_config *cc = (struct crypt_config *) ti->private;
-       char buffer[32];
        const char *cipher;
        const char *chainmode = NULL;
        unsigned int sz = 0;
@@ -910,9 +903,8 @@ static int crypt_status(struct dm_target *ti, status_type_t type,
                        result[sz++] = '-';
                }
 
-               format_dev_t(buffer, cc->dev->bdev->bd_dev);
                DMEMIT(" " SECTOR_FORMAT " %s " SECTOR_FORMAT,
-                      cc->iv_offset, buffer, cc->start);
+                      cc->iv_offset, cc->dev->name, cc->start);
                break;
        }
        return 0;