Merge tag 'for-4.14/dm-changes' of git://git.kernel.org/pub/scm/linux/kernel/git...
[GitHub/LineageOS/android_kernel_motorola_exynos9610.git] / drivers / md / dm-integrity.c
index 27c0f223f8ea8f6164293283f2da8ad50d2d034d..096fe9b66c50749cb841bcbafc4bc6cb6ca63be7 100644 (file)
@@ -225,6 +225,8 @@ struct dm_integrity_c {
        struct alg_spec internal_hash_alg;
        struct alg_spec journal_crypt_alg;
        struct alg_spec journal_mac_alg;
+
+       atomic64_t number_of_mismatches;
 };
 
 struct dm_integrity_range {
@@ -298,7 +300,7 @@ static void __DEBUG_bytes(__u8 *bytes, size_t len, const char *msg, ...)
 /*
  * DM Integrity profile, protection is performed layer above (dm-crypt)
  */
-static struct blk_integrity_profile dm_integrity_profile = {
+static const struct blk_integrity_profile dm_integrity_profile = {
        .name                   = "DM-DIF-EXT-TAG",
        .generate_fn            = NULL,
        .verify_fn              = NULL,
@@ -310,6 +312,8 @@ static void dm_integrity_dtr(struct dm_target *ti);
 
 static void dm_integrity_io_error(struct dm_integrity_c *ic, const char *msg, int err)
 {
+       if (err == -EILSEQ)
+               atomic64_inc(&ic->number_of_mismatches);
        if (!cmpxchg(&ic->failed, 0, err))
                DMERR("Error on %s: %d", msg, err);
 }
@@ -770,13 +774,13 @@ static void write_journal(struct dm_integrity_c *ic, unsigned commit_start, unsi
        unsigned i;
 
        io_comp.ic = ic;
-       io_comp.comp = COMPLETION_INITIALIZER_ONSTACK(io_comp.comp);
+       init_completion(&io_comp.comp);
 
        if (commit_start + commit_sections <= ic->journal_sections) {
                io_comp.in_flight = (atomic_t)ATOMIC_INIT(1);
                if (ic->journal_io) {
                        crypt_comp_1.ic = ic;
-                       crypt_comp_1.comp = COMPLETION_INITIALIZER_ONSTACK(crypt_comp_1.comp);
+                       init_completion(&crypt_comp_1.comp);
                        crypt_comp_1.in_flight = (atomic_t)ATOMIC_INIT(0);
                        encrypt_journal(ic, true, commit_start, commit_sections, &crypt_comp_1);
                        wait_for_completion_io(&crypt_comp_1.comp);
@@ -792,18 +796,18 @@ static void write_journal(struct dm_integrity_c *ic, unsigned commit_start, unsi
                to_end = ic->journal_sections - commit_start;
                if (ic->journal_io) {
                        crypt_comp_1.ic = ic;
-                       crypt_comp_1.comp = COMPLETION_INITIALIZER_ONSTACK(crypt_comp_1.comp);
+                       init_completion(&crypt_comp_1.comp);
                        crypt_comp_1.in_flight = (atomic_t)ATOMIC_INIT(0);
                        encrypt_journal(ic, true, commit_start, to_end, &crypt_comp_1);
                        if (try_wait_for_completion(&crypt_comp_1.comp)) {
                                rw_journal(ic, REQ_OP_WRITE, REQ_FUA, commit_start, to_end, &io_comp);
-                               crypt_comp_1.comp = COMPLETION_INITIALIZER_ONSTACK(crypt_comp_1.comp);
+                               reinit_completion(&crypt_comp_1.comp);
                                crypt_comp_1.in_flight = (atomic_t)ATOMIC_INIT(0);
                                encrypt_journal(ic, true, 0, commit_sections - to_end, &crypt_comp_1);
                                wait_for_completion_io(&crypt_comp_1.comp);
                        } else {
                                crypt_comp_2.ic = ic;
-                               crypt_comp_2.comp = COMPLETION_INITIALIZER_ONSTACK(crypt_comp_2.comp);
+                               init_completion(&crypt_comp_2.comp);
                                crypt_comp_2.in_flight = (atomic_t)ATOMIC_INIT(0);
                                encrypt_journal(ic, true, 0, commit_sections - to_end, &crypt_comp_2);
                                wait_for_completion_io(&crypt_comp_1.comp);
@@ -1041,7 +1045,7 @@ static int dm_integrity_rw_tag(struct dm_integrity_c *ic, unsigned char *tag, se
                        memcpy(tag, dp, to_copy);
                } else if (op == TAG_WRITE) {
                        memcpy(dp, tag, to_copy);
-                       dm_bufio_mark_buffer_dirty(b);
+                       dm_bufio_mark_partial_buffer_dirty(b, *metadata_offset, *metadata_offset + to_copy);
                } else  {
                        /* e.g.: op == TAG_CMP */
                        if (unlikely(memcmp(dp, tag, to_copy))) {
@@ -1275,6 +1279,7 @@ again:
                                        DMERR("Checksum failed at sector 0x%llx",
                                              (unsigned long long)(sector - ((r + ic->tag_size - 1) / ic->tag_size)));
                                        r = -EILSEQ;
+                                       atomic64_inc(&ic->number_of_mismatches);
                                }
                                if (likely(checksums != checksums_onstack))
                                        kfree(checksums);
@@ -1676,7 +1681,7 @@ sleep:
        dio->in_flight = (atomic_t)ATOMIC_INIT(2);
 
        if (need_sync_io) {
-               read_comp = COMPLETION_INITIALIZER_ONSTACK(read_comp);
+               init_completion(&read_comp);
                dio->completion = &read_comp;
        } else
                dio->completion = NULL;
@@ -1700,7 +1705,11 @@ sleep:
 
        if (need_sync_io) {
                wait_for_completion_io(&read_comp);
-               integrity_metadata(&dio->work);
+               if (likely(!bio->bi_status))
+                       integrity_metadata(&dio->work);
+               else
+                       dec_in_flight(dio);
+
        } else {
                INIT_WORK(&dio->work, integrity_metadata);
                queue_work(ic->metadata_wq, &dio->work);
@@ -1834,7 +1843,7 @@ static void do_journal_write(struct dm_integrity_c *ic, unsigned write_start,
 
        comp.ic = ic;
        comp.in_flight = (atomic_t)ATOMIC_INIT(1);
-       comp.comp = COMPLETION_INITIALIZER_ONSTACK(comp.comp);
+       init_completion(&comp.comp);
 
        i = write_start;
        for (n = 0; n < write_sections; n++, i++, wraparound_section(ic, &i)) {
@@ -2061,7 +2070,7 @@ static void replay_journal(struct dm_integrity_c *ic)
                if (ic->journal_io) {
                        struct journal_completion crypt_comp;
                        crypt_comp.ic = ic;
-                       crypt_comp.comp = COMPLETION_INITIALIZER_ONSTACK(crypt_comp.comp);
+                       init_completion(&crypt_comp.comp);
                        crypt_comp.in_flight = (atomic_t)ATOMIC_INIT(0);
                        encrypt_journal(ic, false, 0, ic->journal_sections, &crypt_comp);
                        wait_for_completion(&crypt_comp.comp);
@@ -2233,7 +2242,7 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,
 
        switch (type) {
        case STATUSTYPE_INFO:
-               result[0] = '\0';
+               DMEMIT("%llu", (unsigned long long)atomic64_read(&ic->number_of_mismatches));
                break;
 
        case STATUSTYPE_TABLE: {
@@ -2634,7 +2643,7 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
                        memset(iv, 0x00, ivsize);
 
                        skcipher_request_set_crypt(req, sg, sg, PAGE_SIZE * ic->journal_pages + sizeof ic->commit_ids, iv);
-                       comp.comp = COMPLETION_INITIALIZER_ONSTACK(comp.comp);
+                       init_completion(&comp.comp);
                        comp.in_flight = (atomic_t)ATOMIC_INIT(1);
                        if (do_crypt(true, req, &comp))
                                wait_for_completion(&comp.comp);
@@ -2691,7 +2700,7 @@ static int create_journal(struct dm_integrity_c *ic, char **error)
 
                                sg_init_one(&sg, crypt_data, crypt_len);
                                skcipher_request_set_crypt(req, &sg, &sg, crypt_len, iv);
-                               comp.comp = COMPLETION_INITIALIZER_ONSTACK(comp.comp);
+                               init_completion(&comp.comp);
                                comp.in_flight = (atomic_t)ATOMIC_INIT(1);
                                if (do_crypt(true, req, &comp))
                                        wait_for_completion(&comp.comp);
@@ -2778,7 +2787,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
        int r;
        unsigned extra_args;
        struct dm_arg_set as;
-       static struct dm_arg _args[] = {
+       static const struct dm_arg _args[] = {
                {0, 9, "Invalid number of feature args"},
        };
        unsigned journal_sectors, interleave_sectors, buffer_sectors, journal_watermark, sync_msec;
@@ -2806,6 +2815,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
        bio_list_init(&ic->flush_bio_list);
        init_waitqueue_head(&ic->copy_to_journal_wait);
        init_completion(&ic->crypto_backoff);
+       atomic64_set(&ic->number_of_mismatches, 0);
 
        r = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &ic->dev);
        if (r) {
@@ -3202,7 +3212,7 @@ static void dm_integrity_dtr(struct dm_target *ti)
 
 static struct target_type integrity_target = {
        .name                   = "integrity",
-       .version                = {1, 0, 0},
+       .version                = {1, 1, 0},
        .module                 = THIS_MODULE,
        .features               = DM_TARGET_SINGLETON | DM_TARGET_INTEGRITY,
        .ctr                    = dm_integrity_ctr,