162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. 462306a36Sopenharmony_ci * Copyright (C) 2016-2017 Milan Broz 562306a36Sopenharmony_ci * Copyright (C) 2016-2017 Mikulas Patocka 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This file is released under the GPL. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "dm-bio-record.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/compiler.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/device-mapper.h> 1562306a36Sopenharmony_ci#include <linux/dm-io.h> 1662306a36Sopenharmony_ci#include <linux/vmalloc.h> 1762306a36Sopenharmony_ci#include <linux/sort.h> 1862306a36Sopenharmony_ci#include <linux/rbtree.h> 1962306a36Sopenharmony_ci#include <linux/delay.h> 2062306a36Sopenharmony_ci#include <linux/random.h> 2162306a36Sopenharmony_ci#include <linux/reboot.h> 2262306a36Sopenharmony_ci#include <crypto/hash.h> 2362306a36Sopenharmony_ci#include <crypto/skcipher.h> 2462306a36Sopenharmony_ci#include <linux/async_tx.h> 2562306a36Sopenharmony_ci#include <linux/dm-bufio.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include "dm-audit.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define DM_MSG_PREFIX "integrity" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define DEFAULT_INTERLEAVE_SECTORS 32768 3262306a36Sopenharmony_ci#define DEFAULT_JOURNAL_SIZE_FACTOR 7 3362306a36Sopenharmony_ci#define DEFAULT_SECTORS_PER_BITMAP_BIT 32768 3462306a36Sopenharmony_ci#define DEFAULT_BUFFER_SECTORS 128 3562306a36Sopenharmony_ci#define DEFAULT_JOURNAL_WATERMARK 50 3662306a36Sopenharmony_ci#define DEFAULT_SYNC_MSEC 10000 3762306a36Sopenharmony_ci#define DEFAULT_MAX_JOURNAL_SECTORS (IS_ENABLED(CONFIG_64BIT) ? 131072 : 8192) 3862306a36Sopenharmony_ci#define MIN_LOG2_INTERLEAVE_SECTORS 3 3962306a36Sopenharmony_ci#define MAX_LOG2_INTERLEAVE_SECTORS 31 4062306a36Sopenharmony_ci#define METADATA_WORKQUEUE_MAX_ACTIVE 16 4162306a36Sopenharmony_ci#define RECALC_SECTORS (IS_ENABLED(CONFIG_64BIT) ? 32768 : 2048) 4262306a36Sopenharmony_ci#define RECALC_WRITE_SUPER 16 4362306a36Sopenharmony_ci#define BITMAP_BLOCK_SIZE 4096 /* don't change it */ 4462306a36Sopenharmony_ci#define BITMAP_FLUSH_INTERVAL (10 * HZ) 4562306a36Sopenharmony_ci#define DISCARD_FILLER 0xf6 4662306a36Sopenharmony_ci#define SALT_SIZE 16 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* 4962306a36Sopenharmony_ci * Warning - DEBUG_PRINT prints security-sensitive data to the log, 5062306a36Sopenharmony_ci * so it should not be enabled in the official kernel 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_ci//#define DEBUG_PRINT 5362306a36Sopenharmony_ci//#define INTERNAL_VERIFY 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* 5662306a36Sopenharmony_ci * On disk structures 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define SB_MAGIC "integrt" 6062306a36Sopenharmony_ci#define SB_VERSION_1 1 6162306a36Sopenharmony_ci#define SB_VERSION_2 2 6262306a36Sopenharmony_ci#define SB_VERSION_3 3 6362306a36Sopenharmony_ci#define SB_VERSION_4 4 6462306a36Sopenharmony_ci#define SB_VERSION_5 5 6562306a36Sopenharmony_ci#define SB_SECTORS 8 6662306a36Sopenharmony_ci#define MAX_SECTORS_PER_BLOCK 8 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistruct superblock { 6962306a36Sopenharmony_ci __u8 magic[8]; 7062306a36Sopenharmony_ci __u8 version; 7162306a36Sopenharmony_ci __u8 log2_interleave_sectors; 7262306a36Sopenharmony_ci __le16 integrity_tag_size; 7362306a36Sopenharmony_ci __le32 journal_sections; 7462306a36Sopenharmony_ci __le64 provided_data_sectors; /* userspace uses this value */ 7562306a36Sopenharmony_ci __le32 flags; 7662306a36Sopenharmony_ci __u8 log2_sectors_per_block; 7762306a36Sopenharmony_ci __u8 log2_blocks_per_bitmap_bit; 7862306a36Sopenharmony_ci __u8 pad[2]; 7962306a36Sopenharmony_ci __le64 recalc_sector; 8062306a36Sopenharmony_ci __u8 pad2[8]; 8162306a36Sopenharmony_ci __u8 salt[SALT_SIZE]; 8262306a36Sopenharmony_ci}; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define SB_FLAG_HAVE_JOURNAL_MAC 0x1 8562306a36Sopenharmony_ci#define SB_FLAG_RECALCULATING 0x2 8662306a36Sopenharmony_ci#define SB_FLAG_DIRTY_BITMAP 0x4 8762306a36Sopenharmony_ci#define SB_FLAG_FIXED_PADDING 0x8 8862306a36Sopenharmony_ci#define SB_FLAG_FIXED_HMAC 0x10 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci#define JOURNAL_ENTRY_ROUNDUP 8 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_citypedef __le64 commit_id_t; 9362306a36Sopenharmony_ci#define JOURNAL_MAC_PER_SECTOR 8 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistruct journal_entry { 9662306a36Sopenharmony_ci union { 9762306a36Sopenharmony_ci struct { 9862306a36Sopenharmony_ci __le32 sector_lo; 9962306a36Sopenharmony_ci __le32 sector_hi; 10062306a36Sopenharmony_ci } s; 10162306a36Sopenharmony_ci __le64 sector; 10262306a36Sopenharmony_ci } u; 10362306a36Sopenharmony_ci commit_id_t last_bytes[]; 10462306a36Sopenharmony_ci /* __u8 tag[0]; */ 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci#define journal_entry_tag(ic, je) ((__u8 *)&(je)->last_bytes[(ic)->sectors_per_block]) 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci#if BITS_PER_LONG == 64 11062306a36Sopenharmony_ci#define journal_entry_set_sector(je, x) do { smp_wmb(); WRITE_ONCE((je)->u.sector, cpu_to_le64(x)); } while (0) 11162306a36Sopenharmony_ci#else 11262306a36Sopenharmony_ci#define journal_entry_set_sector(je, x) do { (je)->u.s.sector_lo = cpu_to_le32(x); smp_wmb(); WRITE_ONCE((je)->u.s.sector_hi, cpu_to_le32((x) >> 32)); } while (0) 11362306a36Sopenharmony_ci#endif 11462306a36Sopenharmony_ci#define journal_entry_get_sector(je) le64_to_cpu((je)->u.sector) 11562306a36Sopenharmony_ci#define journal_entry_is_unused(je) ((je)->u.s.sector_hi == cpu_to_le32(-1)) 11662306a36Sopenharmony_ci#define journal_entry_set_unused(je) ((je)->u.s.sector_hi = cpu_to_le32(-1)) 11762306a36Sopenharmony_ci#define journal_entry_is_inprogress(je) ((je)->u.s.sector_hi == cpu_to_le32(-2)) 11862306a36Sopenharmony_ci#define journal_entry_set_inprogress(je) ((je)->u.s.sector_hi = cpu_to_le32(-2)) 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci#define JOURNAL_BLOCK_SECTORS 8 12162306a36Sopenharmony_ci#define JOURNAL_SECTOR_DATA ((1 << SECTOR_SHIFT) - sizeof(commit_id_t)) 12262306a36Sopenharmony_ci#define JOURNAL_MAC_SIZE (JOURNAL_MAC_PER_SECTOR * JOURNAL_BLOCK_SECTORS) 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistruct journal_sector { 12562306a36Sopenharmony_ci struct_group(sectors, 12662306a36Sopenharmony_ci __u8 entries[JOURNAL_SECTOR_DATA - JOURNAL_MAC_PER_SECTOR]; 12762306a36Sopenharmony_ci __u8 mac[JOURNAL_MAC_PER_SECTOR]; 12862306a36Sopenharmony_ci ); 12962306a36Sopenharmony_ci commit_id_t commit_id; 13062306a36Sopenharmony_ci}; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci#define MAX_TAG_SIZE (JOURNAL_SECTOR_DATA - JOURNAL_MAC_PER_SECTOR - offsetof(struct journal_entry, last_bytes[MAX_SECTORS_PER_BLOCK])) 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci#define METADATA_PADDING_SECTORS 8 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci#define N_COMMIT_IDS 4 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic unsigned char prev_commit_seq(unsigned char seq) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci return (seq + N_COMMIT_IDS - 1) % N_COMMIT_IDS; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic unsigned char next_commit_seq(unsigned char seq) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci return (seq + 1) % N_COMMIT_IDS; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci/* 14962306a36Sopenharmony_ci * In-memory structures 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistruct journal_node { 15362306a36Sopenharmony_ci struct rb_node node; 15462306a36Sopenharmony_ci sector_t sector; 15562306a36Sopenharmony_ci}; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistruct alg_spec { 15862306a36Sopenharmony_ci char *alg_string; 15962306a36Sopenharmony_ci char *key_string; 16062306a36Sopenharmony_ci __u8 *key; 16162306a36Sopenharmony_ci unsigned int key_size; 16262306a36Sopenharmony_ci}; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistruct dm_integrity_c { 16562306a36Sopenharmony_ci struct dm_dev *dev; 16662306a36Sopenharmony_ci struct dm_dev *meta_dev; 16762306a36Sopenharmony_ci unsigned int tag_size; 16862306a36Sopenharmony_ci __s8 log2_tag_size; 16962306a36Sopenharmony_ci sector_t start; 17062306a36Sopenharmony_ci mempool_t journal_io_mempool; 17162306a36Sopenharmony_ci struct dm_io_client *io; 17262306a36Sopenharmony_ci struct dm_bufio_client *bufio; 17362306a36Sopenharmony_ci struct workqueue_struct *metadata_wq; 17462306a36Sopenharmony_ci struct superblock *sb; 17562306a36Sopenharmony_ci unsigned int journal_pages; 17662306a36Sopenharmony_ci unsigned int n_bitmap_blocks; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci struct page_list *journal; 17962306a36Sopenharmony_ci struct page_list *journal_io; 18062306a36Sopenharmony_ci struct page_list *journal_xor; 18162306a36Sopenharmony_ci struct page_list *recalc_bitmap; 18262306a36Sopenharmony_ci struct page_list *may_write_bitmap; 18362306a36Sopenharmony_ci struct bitmap_block_status *bbs; 18462306a36Sopenharmony_ci unsigned int bitmap_flush_interval; 18562306a36Sopenharmony_ci int synchronous_mode; 18662306a36Sopenharmony_ci struct bio_list synchronous_bios; 18762306a36Sopenharmony_ci struct delayed_work bitmap_flush_work; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci struct crypto_skcipher *journal_crypt; 19062306a36Sopenharmony_ci struct scatterlist **journal_scatterlist; 19162306a36Sopenharmony_ci struct scatterlist **journal_io_scatterlist; 19262306a36Sopenharmony_ci struct skcipher_request **sk_requests; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci struct crypto_shash *journal_mac; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci struct journal_node *journal_tree; 19762306a36Sopenharmony_ci struct rb_root journal_tree_root; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci sector_t provided_data_sectors; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci unsigned short journal_entry_size; 20262306a36Sopenharmony_ci unsigned char journal_entries_per_sector; 20362306a36Sopenharmony_ci unsigned char journal_section_entries; 20462306a36Sopenharmony_ci unsigned short journal_section_sectors; 20562306a36Sopenharmony_ci unsigned int journal_sections; 20662306a36Sopenharmony_ci unsigned int journal_entries; 20762306a36Sopenharmony_ci sector_t data_device_sectors; 20862306a36Sopenharmony_ci sector_t meta_device_sectors; 20962306a36Sopenharmony_ci unsigned int initial_sectors; 21062306a36Sopenharmony_ci unsigned int metadata_run; 21162306a36Sopenharmony_ci __s8 log2_metadata_run; 21262306a36Sopenharmony_ci __u8 log2_buffer_sectors; 21362306a36Sopenharmony_ci __u8 sectors_per_block; 21462306a36Sopenharmony_ci __u8 log2_blocks_per_bitmap_bit; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci unsigned char mode; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci int failed; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci struct crypto_shash *internal_hash; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci struct dm_target *ti; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* these variables are locked with endio_wait.lock */ 22562306a36Sopenharmony_ci struct rb_root in_progress; 22662306a36Sopenharmony_ci struct list_head wait_list; 22762306a36Sopenharmony_ci wait_queue_head_t endio_wait; 22862306a36Sopenharmony_ci struct workqueue_struct *wait_wq; 22962306a36Sopenharmony_ci struct workqueue_struct *offload_wq; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci unsigned char commit_seq; 23262306a36Sopenharmony_ci commit_id_t commit_ids[N_COMMIT_IDS]; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci unsigned int committed_section; 23562306a36Sopenharmony_ci unsigned int n_committed_sections; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci unsigned int uncommitted_section; 23862306a36Sopenharmony_ci unsigned int n_uncommitted_sections; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci unsigned int free_section; 24162306a36Sopenharmony_ci unsigned char free_section_entry; 24262306a36Sopenharmony_ci unsigned int free_sectors; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci unsigned int free_sectors_threshold; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci struct workqueue_struct *commit_wq; 24762306a36Sopenharmony_ci struct work_struct commit_work; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci struct workqueue_struct *writer_wq; 25062306a36Sopenharmony_ci struct work_struct writer_work; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci struct workqueue_struct *recalc_wq; 25362306a36Sopenharmony_ci struct work_struct recalc_work; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci struct bio_list flush_bio_list; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci unsigned long autocommit_jiffies; 25862306a36Sopenharmony_ci struct timer_list autocommit_timer; 25962306a36Sopenharmony_ci unsigned int autocommit_msec; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci wait_queue_head_t copy_to_journal_wait; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci struct completion crypto_backoff; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci bool wrote_to_journal; 26662306a36Sopenharmony_ci bool journal_uptodate; 26762306a36Sopenharmony_ci bool just_formatted; 26862306a36Sopenharmony_ci bool recalculate_flag; 26962306a36Sopenharmony_ci bool reset_recalculate_flag; 27062306a36Sopenharmony_ci bool discard; 27162306a36Sopenharmony_ci bool fix_padding; 27262306a36Sopenharmony_ci bool fix_hmac; 27362306a36Sopenharmony_ci bool legacy_recalculate; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci struct alg_spec internal_hash_alg; 27662306a36Sopenharmony_ci struct alg_spec journal_crypt_alg; 27762306a36Sopenharmony_ci struct alg_spec journal_mac_alg; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci atomic64_t number_of_mismatches; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci mempool_t recheck_pool; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci struct notifier_block reboot_notifier; 28462306a36Sopenharmony_ci}; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistruct dm_integrity_range { 28762306a36Sopenharmony_ci sector_t logical_sector; 28862306a36Sopenharmony_ci sector_t n_sectors; 28962306a36Sopenharmony_ci bool waiting; 29062306a36Sopenharmony_ci union { 29162306a36Sopenharmony_ci struct rb_node node; 29262306a36Sopenharmony_ci struct { 29362306a36Sopenharmony_ci struct task_struct *task; 29462306a36Sopenharmony_ci struct list_head wait_entry; 29562306a36Sopenharmony_ci }; 29662306a36Sopenharmony_ci }; 29762306a36Sopenharmony_ci}; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistruct dm_integrity_io { 30062306a36Sopenharmony_ci struct work_struct work; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci struct dm_integrity_c *ic; 30362306a36Sopenharmony_ci enum req_op op; 30462306a36Sopenharmony_ci bool fua; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci struct dm_integrity_range range; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci sector_t metadata_block; 30962306a36Sopenharmony_ci unsigned int metadata_offset; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci atomic_t in_flight; 31262306a36Sopenharmony_ci blk_status_t bi_status; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci struct completion *completion; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci struct dm_bio_details bio_details; 31762306a36Sopenharmony_ci}; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistruct journal_completion { 32062306a36Sopenharmony_ci struct dm_integrity_c *ic; 32162306a36Sopenharmony_ci atomic_t in_flight; 32262306a36Sopenharmony_ci struct completion comp; 32362306a36Sopenharmony_ci}; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistruct journal_io { 32662306a36Sopenharmony_ci struct dm_integrity_range range; 32762306a36Sopenharmony_ci struct journal_completion *comp; 32862306a36Sopenharmony_ci}; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistruct bitmap_block_status { 33162306a36Sopenharmony_ci struct work_struct work; 33262306a36Sopenharmony_ci struct dm_integrity_c *ic; 33362306a36Sopenharmony_ci unsigned int idx; 33462306a36Sopenharmony_ci unsigned long *bitmap; 33562306a36Sopenharmony_ci struct bio_list bio_queue; 33662306a36Sopenharmony_ci spinlock_t bio_queue_lock; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci}; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic struct kmem_cache *journal_io_cache; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci#define JOURNAL_IO_MEMPOOL 32 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci#ifdef DEBUG_PRINT 34562306a36Sopenharmony_ci#define DEBUG_print(x, ...) printk(KERN_DEBUG x, ##__VA_ARGS__) 34662306a36Sopenharmony_ci#define DEBUG_bytes(bytes, len, msg, ...) printk(KERN_DEBUG msg "%s%*ph\n", ##__VA_ARGS__, \ 34762306a36Sopenharmony_ci len ? ": " : "", len, bytes) 34862306a36Sopenharmony_ci#else 34962306a36Sopenharmony_ci#define DEBUG_print(x, ...) do { } while (0) 35062306a36Sopenharmony_ci#define DEBUG_bytes(bytes, len, msg, ...) do { } while (0) 35162306a36Sopenharmony_ci#endif 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic void dm_integrity_prepare(struct request *rq) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic void dm_integrity_complete(struct request *rq, unsigned int nr_bytes) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci/* 36262306a36Sopenharmony_ci * DM Integrity profile, protection is performed layer above (dm-crypt) 36362306a36Sopenharmony_ci */ 36462306a36Sopenharmony_cistatic const struct blk_integrity_profile dm_integrity_profile = { 36562306a36Sopenharmony_ci .name = "DM-DIF-EXT-TAG", 36662306a36Sopenharmony_ci .generate_fn = NULL, 36762306a36Sopenharmony_ci .verify_fn = NULL, 36862306a36Sopenharmony_ci .prepare_fn = dm_integrity_prepare, 36962306a36Sopenharmony_ci .complete_fn = dm_integrity_complete, 37062306a36Sopenharmony_ci}; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic void dm_integrity_map_continue(struct dm_integrity_io *dio, bool from_map); 37362306a36Sopenharmony_cistatic void integrity_bio_wait(struct work_struct *w); 37462306a36Sopenharmony_cistatic void dm_integrity_dtr(struct dm_target *ti); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic void dm_integrity_io_error(struct dm_integrity_c *ic, const char *msg, int err) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci if (err == -EILSEQ) 37962306a36Sopenharmony_ci atomic64_inc(&ic->number_of_mismatches); 38062306a36Sopenharmony_ci if (!cmpxchg(&ic->failed, 0, err)) 38162306a36Sopenharmony_ci DMERR("Error on %s: %d", msg, err); 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic int dm_integrity_failed(struct dm_integrity_c *ic) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci return READ_ONCE(ic->failed); 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cistatic bool dm_integrity_disable_recalculate(struct dm_integrity_c *ic) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci if (ic->legacy_recalculate) 39262306a36Sopenharmony_ci return false; 39362306a36Sopenharmony_ci if (!(ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_HMAC)) ? 39462306a36Sopenharmony_ci ic->internal_hash_alg.key || ic->journal_mac_alg.key : 39562306a36Sopenharmony_ci ic->internal_hash_alg.key && !ic->journal_mac_alg.key) 39662306a36Sopenharmony_ci return true; 39762306a36Sopenharmony_ci return false; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic commit_id_t dm_integrity_commit_id(struct dm_integrity_c *ic, unsigned int i, 40162306a36Sopenharmony_ci unsigned int j, unsigned char seq) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci /* 40462306a36Sopenharmony_ci * Xor the number with section and sector, so that if a piece of 40562306a36Sopenharmony_ci * journal is written at wrong place, it is detected. 40662306a36Sopenharmony_ci */ 40762306a36Sopenharmony_ci return ic->commit_ids[seq] ^ cpu_to_le64(((__u64)i << 32) ^ j); 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic void get_area_and_offset(struct dm_integrity_c *ic, sector_t data_sector, 41162306a36Sopenharmony_ci sector_t *area, sector_t *offset) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci if (!ic->meta_dev) { 41462306a36Sopenharmony_ci __u8 log2_interleave_sectors = ic->sb->log2_interleave_sectors; 41562306a36Sopenharmony_ci *area = data_sector >> log2_interleave_sectors; 41662306a36Sopenharmony_ci *offset = (unsigned int)data_sector & ((1U << log2_interleave_sectors) - 1); 41762306a36Sopenharmony_ci } else { 41862306a36Sopenharmony_ci *area = 0; 41962306a36Sopenharmony_ci *offset = data_sector; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci#define sector_to_block(ic, n) \ 42462306a36Sopenharmony_cido { \ 42562306a36Sopenharmony_ci BUG_ON((n) & (unsigned int)((ic)->sectors_per_block - 1)); \ 42662306a36Sopenharmony_ci (n) >>= (ic)->sb->log2_sectors_per_block; \ 42762306a36Sopenharmony_ci} while (0) 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic __u64 get_metadata_sector_and_offset(struct dm_integrity_c *ic, sector_t area, 43062306a36Sopenharmony_ci sector_t offset, unsigned int *metadata_offset) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci __u64 ms; 43362306a36Sopenharmony_ci unsigned int mo; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci ms = area << ic->sb->log2_interleave_sectors; 43662306a36Sopenharmony_ci if (likely(ic->log2_metadata_run >= 0)) 43762306a36Sopenharmony_ci ms += area << ic->log2_metadata_run; 43862306a36Sopenharmony_ci else 43962306a36Sopenharmony_ci ms += area * ic->metadata_run; 44062306a36Sopenharmony_ci ms >>= ic->log2_buffer_sectors; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci sector_to_block(ic, offset); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (likely(ic->log2_tag_size >= 0)) { 44562306a36Sopenharmony_ci ms += offset >> (SECTOR_SHIFT + ic->log2_buffer_sectors - ic->log2_tag_size); 44662306a36Sopenharmony_ci mo = (offset << ic->log2_tag_size) & ((1U << SECTOR_SHIFT << ic->log2_buffer_sectors) - 1); 44762306a36Sopenharmony_ci } else { 44862306a36Sopenharmony_ci ms += (__u64)offset * ic->tag_size >> (SECTOR_SHIFT + ic->log2_buffer_sectors); 44962306a36Sopenharmony_ci mo = (offset * ic->tag_size) & ((1U << SECTOR_SHIFT << ic->log2_buffer_sectors) - 1); 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci *metadata_offset = mo; 45262306a36Sopenharmony_ci return ms; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic sector_t get_data_sector(struct dm_integrity_c *ic, sector_t area, sector_t offset) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci sector_t result; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (ic->meta_dev) 46062306a36Sopenharmony_ci return offset; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci result = area << ic->sb->log2_interleave_sectors; 46362306a36Sopenharmony_ci if (likely(ic->log2_metadata_run >= 0)) 46462306a36Sopenharmony_ci result += (area + 1) << ic->log2_metadata_run; 46562306a36Sopenharmony_ci else 46662306a36Sopenharmony_ci result += (area + 1) * ic->metadata_run; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci result += (sector_t)ic->initial_sectors + offset; 46962306a36Sopenharmony_ci result += ic->start; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci return result; 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic void wraparound_section(struct dm_integrity_c *ic, unsigned int *sec_ptr) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci if (unlikely(*sec_ptr >= ic->journal_sections)) 47762306a36Sopenharmony_ci *sec_ptr -= ic->journal_sections; 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic void sb_set_version(struct dm_integrity_c *ic) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci if (ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_HMAC)) 48362306a36Sopenharmony_ci ic->sb->version = SB_VERSION_5; 48462306a36Sopenharmony_ci else if (ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_PADDING)) 48562306a36Sopenharmony_ci ic->sb->version = SB_VERSION_4; 48662306a36Sopenharmony_ci else if (ic->mode == 'B' || ic->sb->flags & cpu_to_le32(SB_FLAG_DIRTY_BITMAP)) 48762306a36Sopenharmony_ci ic->sb->version = SB_VERSION_3; 48862306a36Sopenharmony_ci else if (ic->meta_dev || ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) 48962306a36Sopenharmony_ci ic->sb->version = SB_VERSION_2; 49062306a36Sopenharmony_ci else 49162306a36Sopenharmony_ci ic->sb->version = SB_VERSION_1; 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cistatic int sb_mac(struct dm_integrity_c *ic, bool wr) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci SHASH_DESC_ON_STACK(desc, ic->journal_mac); 49762306a36Sopenharmony_ci int r; 49862306a36Sopenharmony_ci unsigned int size = crypto_shash_digestsize(ic->journal_mac); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (sizeof(struct superblock) + size > 1 << SECTOR_SHIFT) { 50162306a36Sopenharmony_ci dm_integrity_io_error(ic, "digest is too long", -EINVAL); 50262306a36Sopenharmony_ci return -EINVAL; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci desc->tfm = ic->journal_mac; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci r = crypto_shash_init(desc); 50862306a36Sopenharmony_ci if (unlikely(r < 0)) { 50962306a36Sopenharmony_ci dm_integrity_io_error(ic, "crypto_shash_init", r); 51062306a36Sopenharmony_ci return r; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci r = crypto_shash_update(desc, (__u8 *)ic->sb, (1 << SECTOR_SHIFT) - size); 51462306a36Sopenharmony_ci if (unlikely(r < 0)) { 51562306a36Sopenharmony_ci dm_integrity_io_error(ic, "crypto_shash_update", r); 51662306a36Sopenharmony_ci return r; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (likely(wr)) { 52062306a36Sopenharmony_ci r = crypto_shash_final(desc, (__u8 *)ic->sb + (1 << SECTOR_SHIFT) - size); 52162306a36Sopenharmony_ci if (unlikely(r < 0)) { 52262306a36Sopenharmony_ci dm_integrity_io_error(ic, "crypto_shash_final", r); 52362306a36Sopenharmony_ci return r; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci } else { 52662306a36Sopenharmony_ci __u8 result[HASH_MAX_DIGESTSIZE]; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci r = crypto_shash_final(desc, result); 52962306a36Sopenharmony_ci if (unlikely(r < 0)) { 53062306a36Sopenharmony_ci dm_integrity_io_error(ic, "crypto_shash_final", r); 53162306a36Sopenharmony_ci return r; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci if (memcmp((__u8 *)ic->sb + (1 << SECTOR_SHIFT) - size, result, size)) { 53462306a36Sopenharmony_ci dm_integrity_io_error(ic, "superblock mac", -EILSEQ); 53562306a36Sopenharmony_ci dm_audit_log_target(DM_MSG_PREFIX, "mac-superblock", ic->ti, 0); 53662306a36Sopenharmony_ci return -EILSEQ; 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci return 0; 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistatic int sync_rw_sb(struct dm_integrity_c *ic, blk_opf_t opf) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci struct dm_io_request io_req; 54662306a36Sopenharmony_ci struct dm_io_region io_loc; 54762306a36Sopenharmony_ci const enum req_op op = opf & REQ_OP_MASK; 54862306a36Sopenharmony_ci int r; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci io_req.bi_opf = opf; 55162306a36Sopenharmony_ci io_req.mem.type = DM_IO_KMEM; 55262306a36Sopenharmony_ci io_req.mem.ptr.addr = ic->sb; 55362306a36Sopenharmony_ci io_req.notify.fn = NULL; 55462306a36Sopenharmony_ci io_req.client = ic->io; 55562306a36Sopenharmony_ci io_loc.bdev = ic->meta_dev ? ic->meta_dev->bdev : ic->dev->bdev; 55662306a36Sopenharmony_ci io_loc.sector = ic->start; 55762306a36Sopenharmony_ci io_loc.count = SB_SECTORS; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (op == REQ_OP_WRITE) { 56062306a36Sopenharmony_ci sb_set_version(ic); 56162306a36Sopenharmony_ci if (ic->journal_mac && ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_HMAC)) { 56262306a36Sopenharmony_ci r = sb_mac(ic, true); 56362306a36Sopenharmony_ci if (unlikely(r)) 56462306a36Sopenharmony_ci return r; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci r = dm_io(&io_req, 1, &io_loc, NULL, IOPRIO_DEFAULT); 56962306a36Sopenharmony_ci if (unlikely(r)) 57062306a36Sopenharmony_ci return r; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci if (op == REQ_OP_READ) { 57362306a36Sopenharmony_ci if (ic->mode != 'R' && ic->journal_mac && ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_HMAC)) { 57462306a36Sopenharmony_ci r = sb_mac(ic, false); 57562306a36Sopenharmony_ci if (unlikely(r)) 57662306a36Sopenharmony_ci return r; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci return 0; 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci#define BITMAP_OP_TEST_ALL_SET 0 58462306a36Sopenharmony_ci#define BITMAP_OP_TEST_ALL_CLEAR 1 58562306a36Sopenharmony_ci#define BITMAP_OP_SET 2 58662306a36Sopenharmony_ci#define BITMAP_OP_CLEAR 3 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic bool block_bitmap_op(struct dm_integrity_c *ic, struct page_list *bitmap, 58962306a36Sopenharmony_ci sector_t sector, sector_t n_sectors, int mode) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci unsigned long bit, end_bit, this_end_bit, page, end_page; 59262306a36Sopenharmony_ci unsigned long *data; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (unlikely(((sector | n_sectors) & ((1 << ic->sb->log2_sectors_per_block) - 1)) != 0)) { 59562306a36Sopenharmony_ci DMCRIT("invalid bitmap access (%llx,%llx,%d,%d,%d)", 59662306a36Sopenharmony_ci sector, 59762306a36Sopenharmony_ci n_sectors, 59862306a36Sopenharmony_ci ic->sb->log2_sectors_per_block, 59962306a36Sopenharmony_ci ic->log2_blocks_per_bitmap_bit, 60062306a36Sopenharmony_ci mode); 60162306a36Sopenharmony_ci BUG(); 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (unlikely(!n_sectors)) 60562306a36Sopenharmony_ci return true; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci bit = sector >> (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit); 60862306a36Sopenharmony_ci end_bit = (sector + n_sectors - 1) >> 60962306a36Sopenharmony_ci (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci page = bit / (PAGE_SIZE * 8); 61262306a36Sopenharmony_ci bit %= PAGE_SIZE * 8; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci end_page = end_bit / (PAGE_SIZE * 8); 61562306a36Sopenharmony_ci end_bit %= PAGE_SIZE * 8; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cirepeat: 61862306a36Sopenharmony_ci if (page < end_page) 61962306a36Sopenharmony_ci this_end_bit = PAGE_SIZE * 8 - 1; 62062306a36Sopenharmony_ci else 62162306a36Sopenharmony_ci this_end_bit = end_bit; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci data = lowmem_page_address(bitmap[page].page); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (mode == BITMAP_OP_TEST_ALL_SET) { 62662306a36Sopenharmony_ci while (bit <= this_end_bit) { 62762306a36Sopenharmony_ci if (!(bit % BITS_PER_LONG) && this_end_bit >= bit + BITS_PER_LONG - 1) { 62862306a36Sopenharmony_ci do { 62962306a36Sopenharmony_ci if (data[bit / BITS_PER_LONG] != -1) 63062306a36Sopenharmony_ci return false; 63162306a36Sopenharmony_ci bit += BITS_PER_LONG; 63262306a36Sopenharmony_ci } while (this_end_bit >= bit + BITS_PER_LONG - 1); 63362306a36Sopenharmony_ci continue; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci if (!test_bit(bit, data)) 63662306a36Sopenharmony_ci return false; 63762306a36Sopenharmony_ci bit++; 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci } else if (mode == BITMAP_OP_TEST_ALL_CLEAR) { 64062306a36Sopenharmony_ci while (bit <= this_end_bit) { 64162306a36Sopenharmony_ci if (!(bit % BITS_PER_LONG) && this_end_bit >= bit + BITS_PER_LONG - 1) { 64262306a36Sopenharmony_ci do { 64362306a36Sopenharmony_ci if (data[bit / BITS_PER_LONG] != 0) 64462306a36Sopenharmony_ci return false; 64562306a36Sopenharmony_ci bit += BITS_PER_LONG; 64662306a36Sopenharmony_ci } while (this_end_bit >= bit + BITS_PER_LONG - 1); 64762306a36Sopenharmony_ci continue; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci if (test_bit(bit, data)) 65062306a36Sopenharmony_ci return false; 65162306a36Sopenharmony_ci bit++; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci } else if (mode == BITMAP_OP_SET) { 65462306a36Sopenharmony_ci while (bit <= this_end_bit) { 65562306a36Sopenharmony_ci if (!(bit % BITS_PER_LONG) && this_end_bit >= bit + BITS_PER_LONG - 1) { 65662306a36Sopenharmony_ci do { 65762306a36Sopenharmony_ci data[bit / BITS_PER_LONG] = -1; 65862306a36Sopenharmony_ci bit += BITS_PER_LONG; 65962306a36Sopenharmony_ci } while (this_end_bit >= bit + BITS_PER_LONG - 1); 66062306a36Sopenharmony_ci continue; 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci __set_bit(bit, data); 66362306a36Sopenharmony_ci bit++; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci } else if (mode == BITMAP_OP_CLEAR) { 66662306a36Sopenharmony_ci if (!bit && this_end_bit == PAGE_SIZE * 8 - 1) 66762306a36Sopenharmony_ci clear_page(data); 66862306a36Sopenharmony_ci else { 66962306a36Sopenharmony_ci while (bit <= this_end_bit) { 67062306a36Sopenharmony_ci if (!(bit % BITS_PER_LONG) && this_end_bit >= bit + BITS_PER_LONG - 1) { 67162306a36Sopenharmony_ci do { 67262306a36Sopenharmony_ci data[bit / BITS_PER_LONG] = 0; 67362306a36Sopenharmony_ci bit += BITS_PER_LONG; 67462306a36Sopenharmony_ci } while (this_end_bit >= bit + BITS_PER_LONG - 1); 67562306a36Sopenharmony_ci continue; 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci __clear_bit(bit, data); 67862306a36Sopenharmony_ci bit++; 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci } else { 68262306a36Sopenharmony_ci BUG(); 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (unlikely(page < end_page)) { 68662306a36Sopenharmony_ci bit = 0; 68762306a36Sopenharmony_ci page++; 68862306a36Sopenharmony_ci goto repeat; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return true; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic void block_bitmap_copy(struct dm_integrity_c *ic, struct page_list *dst, struct page_list *src) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci unsigned int n_bitmap_pages = DIV_ROUND_UP(ic->n_bitmap_blocks, PAGE_SIZE / BITMAP_BLOCK_SIZE); 69762306a36Sopenharmony_ci unsigned int i; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci for (i = 0; i < n_bitmap_pages; i++) { 70062306a36Sopenharmony_ci unsigned long *dst_data = lowmem_page_address(dst[i].page); 70162306a36Sopenharmony_ci unsigned long *src_data = lowmem_page_address(src[i].page); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci copy_page(dst_data, src_data); 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_cistatic struct bitmap_block_status *sector_to_bitmap_block(struct dm_integrity_c *ic, sector_t sector) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci unsigned int bit = sector >> (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit); 71062306a36Sopenharmony_ci unsigned int bitmap_block = bit / (BITMAP_BLOCK_SIZE * 8); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci BUG_ON(bitmap_block >= ic->n_bitmap_blocks); 71362306a36Sopenharmony_ci return &ic->bbs[bitmap_block]; 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic void access_journal_check(struct dm_integrity_c *ic, unsigned int section, unsigned int offset, 71762306a36Sopenharmony_ci bool e, const char *function) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci#if defined(CONFIG_DM_DEBUG) || defined(INTERNAL_VERIFY) 72062306a36Sopenharmony_ci unsigned int limit = e ? ic->journal_section_entries : ic->journal_section_sectors; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci if (unlikely(section >= ic->journal_sections) || 72362306a36Sopenharmony_ci unlikely(offset >= limit)) { 72462306a36Sopenharmony_ci DMCRIT("%s: invalid access at (%u,%u), limit (%u,%u)", 72562306a36Sopenharmony_ci function, section, offset, ic->journal_sections, limit); 72662306a36Sopenharmony_ci BUG(); 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci#endif 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic void page_list_location(struct dm_integrity_c *ic, unsigned int section, unsigned int offset, 73262306a36Sopenharmony_ci unsigned int *pl_index, unsigned int *pl_offset) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci unsigned int sector; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci access_journal_check(ic, section, offset, false, "page_list_location"); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci sector = section * ic->journal_section_sectors + offset; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci *pl_index = sector >> (PAGE_SHIFT - SECTOR_SHIFT); 74162306a36Sopenharmony_ci *pl_offset = (sector << SECTOR_SHIFT) & (PAGE_SIZE - 1); 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_cistatic struct journal_sector *access_page_list(struct dm_integrity_c *ic, struct page_list *pl, 74562306a36Sopenharmony_ci unsigned int section, unsigned int offset, unsigned int *n_sectors) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci unsigned int pl_index, pl_offset; 74862306a36Sopenharmony_ci char *va; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci page_list_location(ic, section, offset, &pl_index, &pl_offset); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci if (n_sectors) 75362306a36Sopenharmony_ci *n_sectors = (PAGE_SIZE - pl_offset) >> SECTOR_SHIFT; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci va = lowmem_page_address(pl[pl_index].page); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci return (struct journal_sector *)(va + pl_offset); 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic struct journal_sector *access_journal(struct dm_integrity_c *ic, unsigned int section, unsigned int offset) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci return access_page_list(ic, ic->journal, section, offset, NULL); 76362306a36Sopenharmony_ci} 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_cistatic struct journal_entry *access_journal_entry(struct dm_integrity_c *ic, unsigned int section, unsigned int n) 76662306a36Sopenharmony_ci{ 76762306a36Sopenharmony_ci unsigned int rel_sector, offset; 76862306a36Sopenharmony_ci struct journal_sector *js; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci access_journal_check(ic, section, n, true, "access_journal_entry"); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci rel_sector = n % JOURNAL_BLOCK_SECTORS; 77362306a36Sopenharmony_ci offset = n / JOURNAL_BLOCK_SECTORS; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci js = access_journal(ic, section, rel_sector); 77662306a36Sopenharmony_ci return (struct journal_entry *)((char *)js + offset * ic->journal_entry_size); 77762306a36Sopenharmony_ci} 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_cistatic struct journal_sector *access_journal_data(struct dm_integrity_c *ic, unsigned int section, unsigned int n) 78062306a36Sopenharmony_ci{ 78162306a36Sopenharmony_ci n <<= ic->sb->log2_sectors_per_block; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci n += JOURNAL_BLOCK_SECTORS; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci access_journal_check(ic, section, n, false, "access_journal_data"); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci return access_journal(ic, section, n); 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_cistatic void section_mac(struct dm_integrity_c *ic, unsigned int section, __u8 result[JOURNAL_MAC_SIZE]) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci SHASH_DESC_ON_STACK(desc, ic->journal_mac); 79362306a36Sopenharmony_ci int r; 79462306a36Sopenharmony_ci unsigned int j, size; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci desc->tfm = ic->journal_mac; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci r = crypto_shash_init(desc); 79962306a36Sopenharmony_ci if (unlikely(r < 0)) { 80062306a36Sopenharmony_ci dm_integrity_io_error(ic, "crypto_shash_init", r); 80162306a36Sopenharmony_ci goto err; 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci if (ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_HMAC)) { 80562306a36Sopenharmony_ci __le64 section_le; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci r = crypto_shash_update(desc, (__u8 *)&ic->sb->salt, SALT_SIZE); 80862306a36Sopenharmony_ci if (unlikely(r < 0)) { 80962306a36Sopenharmony_ci dm_integrity_io_error(ic, "crypto_shash_update", r); 81062306a36Sopenharmony_ci goto err; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci section_le = cpu_to_le64(section); 81462306a36Sopenharmony_ci r = crypto_shash_update(desc, (__u8 *)§ion_le, sizeof(section_le)); 81562306a36Sopenharmony_ci if (unlikely(r < 0)) { 81662306a36Sopenharmony_ci dm_integrity_io_error(ic, "crypto_shash_update", r); 81762306a36Sopenharmony_ci goto err; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci for (j = 0; j < ic->journal_section_entries; j++) { 82262306a36Sopenharmony_ci struct journal_entry *je = access_journal_entry(ic, section, j); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci r = crypto_shash_update(desc, (__u8 *)&je->u.sector, sizeof(je->u.sector)); 82562306a36Sopenharmony_ci if (unlikely(r < 0)) { 82662306a36Sopenharmony_ci dm_integrity_io_error(ic, "crypto_shash_update", r); 82762306a36Sopenharmony_ci goto err; 82862306a36Sopenharmony_ci } 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci size = crypto_shash_digestsize(ic->journal_mac); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci if (likely(size <= JOURNAL_MAC_SIZE)) { 83462306a36Sopenharmony_ci r = crypto_shash_final(desc, result); 83562306a36Sopenharmony_ci if (unlikely(r < 0)) { 83662306a36Sopenharmony_ci dm_integrity_io_error(ic, "crypto_shash_final", r); 83762306a36Sopenharmony_ci goto err; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci memset(result + size, 0, JOURNAL_MAC_SIZE - size); 84062306a36Sopenharmony_ci } else { 84162306a36Sopenharmony_ci __u8 digest[HASH_MAX_DIGESTSIZE]; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci if (WARN_ON(size > sizeof(digest))) { 84462306a36Sopenharmony_ci dm_integrity_io_error(ic, "digest_size", -EINVAL); 84562306a36Sopenharmony_ci goto err; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci r = crypto_shash_final(desc, digest); 84862306a36Sopenharmony_ci if (unlikely(r < 0)) { 84962306a36Sopenharmony_ci dm_integrity_io_error(ic, "crypto_shash_final", r); 85062306a36Sopenharmony_ci goto err; 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci memcpy(result, digest, JOURNAL_MAC_SIZE); 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci return; 85662306a36Sopenharmony_cierr: 85762306a36Sopenharmony_ci memset(result, 0, JOURNAL_MAC_SIZE); 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_cistatic void rw_section_mac(struct dm_integrity_c *ic, unsigned int section, bool wr) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci __u8 result[JOURNAL_MAC_SIZE]; 86362306a36Sopenharmony_ci unsigned int j; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if (!ic->journal_mac) 86662306a36Sopenharmony_ci return; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci section_mac(ic, section, result); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci for (j = 0; j < JOURNAL_BLOCK_SECTORS; j++) { 87162306a36Sopenharmony_ci struct journal_sector *js = access_journal(ic, section, j); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (likely(wr)) 87462306a36Sopenharmony_ci memcpy(&js->mac, result + (j * JOURNAL_MAC_PER_SECTOR), JOURNAL_MAC_PER_SECTOR); 87562306a36Sopenharmony_ci else { 87662306a36Sopenharmony_ci if (memcmp(&js->mac, result + (j * JOURNAL_MAC_PER_SECTOR), JOURNAL_MAC_PER_SECTOR)) { 87762306a36Sopenharmony_ci dm_integrity_io_error(ic, "journal mac", -EILSEQ); 87862306a36Sopenharmony_ci dm_audit_log_target(DM_MSG_PREFIX, "mac-journal", ic->ti, 0); 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_cistatic void complete_journal_op(void *context) 88562306a36Sopenharmony_ci{ 88662306a36Sopenharmony_ci struct journal_completion *comp = context; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci BUG_ON(!atomic_read(&comp->in_flight)); 88962306a36Sopenharmony_ci if (likely(atomic_dec_and_test(&comp->in_flight))) 89062306a36Sopenharmony_ci complete(&comp->comp); 89162306a36Sopenharmony_ci} 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_cistatic void xor_journal(struct dm_integrity_c *ic, bool encrypt, unsigned int section, 89462306a36Sopenharmony_ci unsigned int n_sections, struct journal_completion *comp) 89562306a36Sopenharmony_ci{ 89662306a36Sopenharmony_ci struct async_submit_ctl submit; 89762306a36Sopenharmony_ci size_t n_bytes = (size_t)(n_sections * ic->journal_section_sectors) << SECTOR_SHIFT; 89862306a36Sopenharmony_ci unsigned int pl_index, pl_offset, section_index; 89962306a36Sopenharmony_ci struct page_list *source_pl, *target_pl; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if (likely(encrypt)) { 90262306a36Sopenharmony_ci source_pl = ic->journal; 90362306a36Sopenharmony_ci target_pl = ic->journal_io; 90462306a36Sopenharmony_ci } else { 90562306a36Sopenharmony_ci source_pl = ic->journal_io; 90662306a36Sopenharmony_ci target_pl = ic->journal; 90762306a36Sopenharmony_ci } 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci page_list_location(ic, section, 0, &pl_index, &pl_offset); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci atomic_add(roundup(pl_offset + n_bytes, PAGE_SIZE) >> PAGE_SHIFT, &comp->in_flight); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci init_async_submit(&submit, ASYNC_TX_XOR_ZERO_DST, NULL, complete_journal_op, comp, NULL); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci section_index = pl_index; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci do { 91862306a36Sopenharmony_ci size_t this_step; 91962306a36Sopenharmony_ci struct page *src_pages[2]; 92062306a36Sopenharmony_ci struct page *dst_page; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci while (unlikely(pl_index == section_index)) { 92362306a36Sopenharmony_ci unsigned int dummy; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci if (likely(encrypt)) 92662306a36Sopenharmony_ci rw_section_mac(ic, section, true); 92762306a36Sopenharmony_ci section++; 92862306a36Sopenharmony_ci n_sections--; 92962306a36Sopenharmony_ci if (!n_sections) 93062306a36Sopenharmony_ci break; 93162306a36Sopenharmony_ci page_list_location(ic, section, 0, §ion_index, &dummy); 93262306a36Sopenharmony_ci } 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci this_step = min(n_bytes, (size_t)PAGE_SIZE - pl_offset); 93562306a36Sopenharmony_ci dst_page = target_pl[pl_index].page; 93662306a36Sopenharmony_ci src_pages[0] = source_pl[pl_index].page; 93762306a36Sopenharmony_ci src_pages[1] = ic->journal_xor[pl_index].page; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci async_xor(dst_page, src_pages, pl_offset, 2, this_step, &submit); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci pl_index++; 94262306a36Sopenharmony_ci pl_offset = 0; 94362306a36Sopenharmony_ci n_bytes -= this_step; 94462306a36Sopenharmony_ci } while (n_bytes); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci BUG_ON(n_sections); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci async_tx_issue_pending_all(); 94962306a36Sopenharmony_ci} 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_cistatic void complete_journal_encrypt(void *data, int err) 95262306a36Sopenharmony_ci{ 95362306a36Sopenharmony_ci struct journal_completion *comp = data; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci if (unlikely(err)) { 95662306a36Sopenharmony_ci if (likely(err == -EINPROGRESS)) { 95762306a36Sopenharmony_ci complete(&comp->ic->crypto_backoff); 95862306a36Sopenharmony_ci return; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci dm_integrity_io_error(comp->ic, "asynchronous encrypt", err); 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci complete_journal_op(comp); 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_cistatic bool do_crypt(bool encrypt, struct skcipher_request *req, struct journal_completion *comp) 96662306a36Sopenharmony_ci{ 96762306a36Sopenharmony_ci int r; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, 97062306a36Sopenharmony_ci complete_journal_encrypt, comp); 97162306a36Sopenharmony_ci if (likely(encrypt)) 97262306a36Sopenharmony_ci r = crypto_skcipher_encrypt(req); 97362306a36Sopenharmony_ci else 97462306a36Sopenharmony_ci r = crypto_skcipher_decrypt(req); 97562306a36Sopenharmony_ci if (likely(!r)) 97662306a36Sopenharmony_ci return false; 97762306a36Sopenharmony_ci if (likely(r == -EINPROGRESS)) 97862306a36Sopenharmony_ci return true; 97962306a36Sopenharmony_ci if (likely(r == -EBUSY)) { 98062306a36Sopenharmony_ci wait_for_completion(&comp->ic->crypto_backoff); 98162306a36Sopenharmony_ci reinit_completion(&comp->ic->crypto_backoff); 98262306a36Sopenharmony_ci return true; 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci dm_integrity_io_error(comp->ic, "encrypt", r); 98562306a36Sopenharmony_ci return false; 98662306a36Sopenharmony_ci} 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_cistatic void crypt_journal(struct dm_integrity_c *ic, bool encrypt, unsigned int section, 98962306a36Sopenharmony_ci unsigned int n_sections, struct journal_completion *comp) 99062306a36Sopenharmony_ci{ 99162306a36Sopenharmony_ci struct scatterlist **source_sg; 99262306a36Sopenharmony_ci struct scatterlist **target_sg; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci atomic_add(2, &comp->in_flight); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci if (likely(encrypt)) { 99762306a36Sopenharmony_ci source_sg = ic->journal_scatterlist; 99862306a36Sopenharmony_ci target_sg = ic->journal_io_scatterlist; 99962306a36Sopenharmony_ci } else { 100062306a36Sopenharmony_ci source_sg = ic->journal_io_scatterlist; 100162306a36Sopenharmony_ci target_sg = ic->journal_scatterlist; 100262306a36Sopenharmony_ci } 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci do { 100562306a36Sopenharmony_ci struct skcipher_request *req; 100662306a36Sopenharmony_ci unsigned int ivsize; 100762306a36Sopenharmony_ci char *iv; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (likely(encrypt)) 101062306a36Sopenharmony_ci rw_section_mac(ic, section, true); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci req = ic->sk_requests[section]; 101362306a36Sopenharmony_ci ivsize = crypto_skcipher_ivsize(ic->journal_crypt); 101462306a36Sopenharmony_ci iv = req->iv; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci memcpy(iv, iv + ivsize, ivsize); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci req->src = source_sg[section]; 101962306a36Sopenharmony_ci req->dst = target_sg[section]; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci if (unlikely(do_crypt(encrypt, req, comp))) 102262306a36Sopenharmony_ci atomic_inc(&comp->in_flight); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci section++; 102562306a36Sopenharmony_ci n_sections--; 102662306a36Sopenharmony_ci } while (n_sections); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci atomic_dec(&comp->in_flight); 102962306a36Sopenharmony_ci complete_journal_op(comp); 103062306a36Sopenharmony_ci} 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_cistatic void encrypt_journal(struct dm_integrity_c *ic, bool encrypt, unsigned int section, 103362306a36Sopenharmony_ci unsigned int n_sections, struct journal_completion *comp) 103462306a36Sopenharmony_ci{ 103562306a36Sopenharmony_ci if (ic->journal_xor) 103662306a36Sopenharmony_ci return xor_journal(ic, encrypt, section, n_sections, comp); 103762306a36Sopenharmony_ci else 103862306a36Sopenharmony_ci return crypt_journal(ic, encrypt, section, n_sections, comp); 103962306a36Sopenharmony_ci} 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_cistatic void complete_journal_io(unsigned long error, void *context) 104262306a36Sopenharmony_ci{ 104362306a36Sopenharmony_ci struct journal_completion *comp = context; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci if (unlikely(error != 0)) 104662306a36Sopenharmony_ci dm_integrity_io_error(comp->ic, "writing journal", -EIO); 104762306a36Sopenharmony_ci complete_journal_op(comp); 104862306a36Sopenharmony_ci} 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_cistatic void rw_journal_sectors(struct dm_integrity_c *ic, blk_opf_t opf, 105162306a36Sopenharmony_ci unsigned int sector, unsigned int n_sectors, 105262306a36Sopenharmony_ci struct journal_completion *comp) 105362306a36Sopenharmony_ci{ 105462306a36Sopenharmony_ci struct dm_io_request io_req; 105562306a36Sopenharmony_ci struct dm_io_region io_loc; 105662306a36Sopenharmony_ci unsigned int pl_index, pl_offset; 105762306a36Sopenharmony_ci int r; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci if (unlikely(dm_integrity_failed(ic))) { 106062306a36Sopenharmony_ci if (comp) 106162306a36Sopenharmony_ci complete_journal_io(-1UL, comp); 106262306a36Sopenharmony_ci return; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci pl_index = sector >> (PAGE_SHIFT - SECTOR_SHIFT); 106662306a36Sopenharmony_ci pl_offset = (sector << SECTOR_SHIFT) & (PAGE_SIZE - 1); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci io_req.bi_opf = opf; 106962306a36Sopenharmony_ci io_req.mem.type = DM_IO_PAGE_LIST; 107062306a36Sopenharmony_ci if (ic->journal_io) 107162306a36Sopenharmony_ci io_req.mem.ptr.pl = &ic->journal_io[pl_index]; 107262306a36Sopenharmony_ci else 107362306a36Sopenharmony_ci io_req.mem.ptr.pl = &ic->journal[pl_index]; 107462306a36Sopenharmony_ci io_req.mem.offset = pl_offset; 107562306a36Sopenharmony_ci if (likely(comp != NULL)) { 107662306a36Sopenharmony_ci io_req.notify.fn = complete_journal_io; 107762306a36Sopenharmony_ci io_req.notify.context = comp; 107862306a36Sopenharmony_ci } else { 107962306a36Sopenharmony_ci io_req.notify.fn = NULL; 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci io_req.client = ic->io; 108262306a36Sopenharmony_ci io_loc.bdev = ic->meta_dev ? ic->meta_dev->bdev : ic->dev->bdev; 108362306a36Sopenharmony_ci io_loc.sector = ic->start + SB_SECTORS + sector; 108462306a36Sopenharmony_ci io_loc.count = n_sectors; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci r = dm_io(&io_req, 1, &io_loc, NULL, IOPRIO_DEFAULT); 108762306a36Sopenharmony_ci if (unlikely(r)) { 108862306a36Sopenharmony_ci dm_integrity_io_error(ic, (opf & REQ_OP_MASK) == REQ_OP_READ ? 108962306a36Sopenharmony_ci "reading journal" : "writing journal", r); 109062306a36Sopenharmony_ci if (comp) { 109162306a36Sopenharmony_ci WARN_ONCE(1, "asynchronous dm_io failed: %d", r); 109262306a36Sopenharmony_ci complete_journal_io(-1UL, comp); 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci} 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_cistatic void rw_journal(struct dm_integrity_c *ic, blk_opf_t opf, 109862306a36Sopenharmony_ci unsigned int section, unsigned int n_sections, 109962306a36Sopenharmony_ci struct journal_completion *comp) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci unsigned int sector, n_sectors; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci sector = section * ic->journal_section_sectors; 110462306a36Sopenharmony_ci n_sectors = n_sections * ic->journal_section_sectors; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci rw_journal_sectors(ic, opf, sector, n_sectors, comp); 110762306a36Sopenharmony_ci} 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_cistatic void write_journal(struct dm_integrity_c *ic, unsigned int commit_start, unsigned int commit_sections) 111062306a36Sopenharmony_ci{ 111162306a36Sopenharmony_ci struct journal_completion io_comp; 111262306a36Sopenharmony_ci struct journal_completion crypt_comp_1; 111362306a36Sopenharmony_ci struct journal_completion crypt_comp_2; 111462306a36Sopenharmony_ci unsigned int i; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci io_comp.ic = ic; 111762306a36Sopenharmony_ci init_completion(&io_comp.comp); 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci if (commit_start + commit_sections <= ic->journal_sections) { 112062306a36Sopenharmony_ci io_comp.in_flight = (atomic_t)ATOMIC_INIT(1); 112162306a36Sopenharmony_ci if (ic->journal_io) { 112262306a36Sopenharmony_ci crypt_comp_1.ic = ic; 112362306a36Sopenharmony_ci init_completion(&crypt_comp_1.comp); 112462306a36Sopenharmony_ci crypt_comp_1.in_flight = (atomic_t)ATOMIC_INIT(0); 112562306a36Sopenharmony_ci encrypt_journal(ic, true, commit_start, commit_sections, &crypt_comp_1); 112662306a36Sopenharmony_ci wait_for_completion_io(&crypt_comp_1.comp); 112762306a36Sopenharmony_ci } else { 112862306a36Sopenharmony_ci for (i = 0; i < commit_sections; i++) 112962306a36Sopenharmony_ci rw_section_mac(ic, commit_start + i, true); 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci rw_journal(ic, REQ_OP_WRITE | REQ_FUA | REQ_SYNC, commit_start, 113262306a36Sopenharmony_ci commit_sections, &io_comp); 113362306a36Sopenharmony_ci } else { 113462306a36Sopenharmony_ci unsigned int to_end; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci io_comp.in_flight = (atomic_t)ATOMIC_INIT(2); 113762306a36Sopenharmony_ci to_end = ic->journal_sections - commit_start; 113862306a36Sopenharmony_ci if (ic->journal_io) { 113962306a36Sopenharmony_ci crypt_comp_1.ic = ic; 114062306a36Sopenharmony_ci init_completion(&crypt_comp_1.comp); 114162306a36Sopenharmony_ci crypt_comp_1.in_flight = (atomic_t)ATOMIC_INIT(0); 114262306a36Sopenharmony_ci encrypt_journal(ic, true, commit_start, to_end, &crypt_comp_1); 114362306a36Sopenharmony_ci if (try_wait_for_completion(&crypt_comp_1.comp)) { 114462306a36Sopenharmony_ci rw_journal(ic, REQ_OP_WRITE | REQ_FUA, 114562306a36Sopenharmony_ci commit_start, to_end, &io_comp); 114662306a36Sopenharmony_ci reinit_completion(&crypt_comp_1.comp); 114762306a36Sopenharmony_ci crypt_comp_1.in_flight = (atomic_t)ATOMIC_INIT(0); 114862306a36Sopenharmony_ci encrypt_journal(ic, true, 0, commit_sections - to_end, &crypt_comp_1); 114962306a36Sopenharmony_ci wait_for_completion_io(&crypt_comp_1.comp); 115062306a36Sopenharmony_ci } else { 115162306a36Sopenharmony_ci crypt_comp_2.ic = ic; 115262306a36Sopenharmony_ci init_completion(&crypt_comp_2.comp); 115362306a36Sopenharmony_ci crypt_comp_2.in_flight = (atomic_t)ATOMIC_INIT(0); 115462306a36Sopenharmony_ci encrypt_journal(ic, true, 0, commit_sections - to_end, &crypt_comp_2); 115562306a36Sopenharmony_ci wait_for_completion_io(&crypt_comp_1.comp); 115662306a36Sopenharmony_ci rw_journal(ic, REQ_OP_WRITE | REQ_FUA, commit_start, to_end, &io_comp); 115762306a36Sopenharmony_ci wait_for_completion_io(&crypt_comp_2.comp); 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci } else { 116062306a36Sopenharmony_ci for (i = 0; i < to_end; i++) 116162306a36Sopenharmony_ci rw_section_mac(ic, commit_start + i, true); 116262306a36Sopenharmony_ci rw_journal(ic, REQ_OP_WRITE | REQ_FUA, commit_start, to_end, &io_comp); 116362306a36Sopenharmony_ci for (i = 0; i < commit_sections - to_end; i++) 116462306a36Sopenharmony_ci rw_section_mac(ic, i, true); 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci rw_journal(ic, REQ_OP_WRITE | REQ_FUA, 0, commit_sections - to_end, &io_comp); 116762306a36Sopenharmony_ci } 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci wait_for_completion_io(&io_comp.comp); 117062306a36Sopenharmony_ci} 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_cistatic void copy_from_journal(struct dm_integrity_c *ic, unsigned int section, unsigned int offset, 117362306a36Sopenharmony_ci unsigned int n_sectors, sector_t target, io_notify_fn fn, void *data) 117462306a36Sopenharmony_ci{ 117562306a36Sopenharmony_ci struct dm_io_request io_req; 117662306a36Sopenharmony_ci struct dm_io_region io_loc; 117762306a36Sopenharmony_ci int r; 117862306a36Sopenharmony_ci unsigned int sector, pl_index, pl_offset; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci BUG_ON((target | n_sectors | offset) & (unsigned int)(ic->sectors_per_block - 1)); 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci if (unlikely(dm_integrity_failed(ic))) { 118362306a36Sopenharmony_ci fn(-1UL, data); 118462306a36Sopenharmony_ci return; 118562306a36Sopenharmony_ci } 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci sector = section * ic->journal_section_sectors + JOURNAL_BLOCK_SECTORS + offset; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci pl_index = sector >> (PAGE_SHIFT - SECTOR_SHIFT); 119062306a36Sopenharmony_ci pl_offset = (sector << SECTOR_SHIFT) & (PAGE_SIZE - 1); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci io_req.bi_opf = REQ_OP_WRITE; 119362306a36Sopenharmony_ci io_req.mem.type = DM_IO_PAGE_LIST; 119462306a36Sopenharmony_ci io_req.mem.ptr.pl = &ic->journal[pl_index]; 119562306a36Sopenharmony_ci io_req.mem.offset = pl_offset; 119662306a36Sopenharmony_ci io_req.notify.fn = fn; 119762306a36Sopenharmony_ci io_req.notify.context = data; 119862306a36Sopenharmony_ci io_req.client = ic->io; 119962306a36Sopenharmony_ci io_loc.bdev = ic->dev->bdev; 120062306a36Sopenharmony_ci io_loc.sector = target; 120162306a36Sopenharmony_ci io_loc.count = n_sectors; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci r = dm_io(&io_req, 1, &io_loc, NULL, IOPRIO_DEFAULT); 120462306a36Sopenharmony_ci if (unlikely(r)) { 120562306a36Sopenharmony_ci WARN_ONCE(1, "asynchronous dm_io failed: %d", r); 120662306a36Sopenharmony_ci fn(-1UL, data); 120762306a36Sopenharmony_ci } 120862306a36Sopenharmony_ci} 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_cistatic bool ranges_overlap(struct dm_integrity_range *range1, struct dm_integrity_range *range2) 121162306a36Sopenharmony_ci{ 121262306a36Sopenharmony_ci return range1->logical_sector < range2->logical_sector + range2->n_sectors && 121362306a36Sopenharmony_ci range1->logical_sector + range1->n_sectors > range2->logical_sector; 121462306a36Sopenharmony_ci} 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_cistatic bool add_new_range(struct dm_integrity_c *ic, struct dm_integrity_range *new_range, bool check_waiting) 121762306a36Sopenharmony_ci{ 121862306a36Sopenharmony_ci struct rb_node **n = &ic->in_progress.rb_node; 121962306a36Sopenharmony_ci struct rb_node *parent; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci BUG_ON((new_range->logical_sector | new_range->n_sectors) & (unsigned int)(ic->sectors_per_block - 1)); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci if (likely(check_waiting)) { 122462306a36Sopenharmony_ci struct dm_integrity_range *range; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci list_for_each_entry(range, &ic->wait_list, wait_entry) { 122762306a36Sopenharmony_ci if (unlikely(ranges_overlap(range, new_range))) 122862306a36Sopenharmony_ci return false; 122962306a36Sopenharmony_ci } 123062306a36Sopenharmony_ci } 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci parent = NULL; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci while (*n) { 123562306a36Sopenharmony_ci struct dm_integrity_range *range = container_of(*n, struct dm_integrity_range, node); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci parent = *n; 123862306a36Sopenharmony_ci if (new_range->logical_sector + new_range->n_sectors <= range->logical_sector) 123962306a36Sopenharmony_ci n = &range->node.rb_left; 124062306a36Sopenharmony_ci else if (new_range->logical_sector >= range->logical_sector + range->n_sectors) 124162306a36Sopenharmony_ci n = &range->node.rb_right; 124262306a36Sopenharmony_ci else 124362306a36Sopenharmony_ci return false; 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci rb_link_node(&new_range->node, parent, n); 124762306a36Sopenharmony_ci rb_insert_color(&new_range->node, &ic->in_progress); 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci return true; 125062306a36Sopenharmony_ci} 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_cistatic void remove_range_unlocked(struct dm_integrity_c *ic, struct dm_integrity_range *range) 125362306a36Sopenharmony_ci{ 125462306a36Sopenharmony_ci rb_erase(&range->node, &ic->in_progress); 125562306a36Sopenharmony_ci while (unlikely(!list_empty(&ic->wait_list))) { 125662306a36Sopenharmony_ci struct dm_integrity_range *last_range = 125762306a36Sopenharmony_ci list_first_entry(&ic->wait_list, struct dm_integrity_range, wait_entry); 125862306a36Sopenharmony_ci struct task_struct *last_range_task; 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci last_range_task = last_range->task; 126162306a36Sopenharmony_ci list_del(&last_range->wait_entry); 126262306a36Sopenharmony_ci if (!add_new_range(ic, last_range, false)) { 126362306a36Sopenharmony_ci last_range->task = last_range_task; 126462306a36Sopenharmony_ci list_add(&last_range->wait_entry, &ic->wait_list); 126562306a36Sopenharmony_ci break; 126662306a36Sopenharmony_ci } 126762306a36Sopenharmony_ci last_range->waiting = false; 126862306a36Sopenharmony_ci wake_up_process(last_range_task); 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci} 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_cistatic void remove_range(struct dm_integrity_c *ic, struct dm_integrity_range *range) 127362306a36Sopenharmony_ci{ 127462306a36Sopenharmony_ci unsigned long flags; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci spin_lock_irqsave(&ic->endio_wait.lock, flags); 127762306a36Sopenharmony_ci remove_range_unlocked(ic, range); 127862306a36Sopenharmony_ci spin_unlock_irqrestore(&ic->endio_wait.lock, flags); 127962306a36Sopenharmony_ci} 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_cistatic void wait_and_add_new_range(struct dm_integrity_c *ic, struct dm_integrity_range *new_range) 128262306a36Sopenharmony_ci{ 128362306a36Sopenharmony_ci new_range->waiting = true; 128462306a36Sopenharmony_ci list_add_tail(&new_range->wait_entry, &ic->wait_list); 128562306a36Sopenharmony_ci new_range->task = current; 128662306a36Sopenharmony_ci do { 128762306a36Sopenharmony_ci __set_current_state(TASK_UNINTERRUPTIBLE); 128862306a36Sopenharmony_ci spin_unlock_irq(&ic->endio_wait.lock); 128962306a36Sopenharmony_ci io_schedule(); 129062306a36Sopenharmony_ci spin_lock_irq(&ic->endio_wait.lock); 129162306a36Sopenharmony_ci } while (unlikely(new_range->waiting)); 129262306a36Sopenharmony_ci} 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_cistatic void add_new_range_and_wait(struct dm_integrity_c *ic, struct dm_integrity_range *new_range) 129562306a36Sopenharmony_ci{ 129662306a36Sopenharmony_ci if (unlikely(!add_new_range(ic, new_range, true))) 129762306a36Sopenharmony_ci wait_and_add_new_range(ic, new_range); 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_cistatic void init_journal_node(struct journal_node *node) 130162306a36Sopenharmony_ci{ 130262306a36Sopenharmony_ci RB_CLEAR_NODE(&node->node); 130362306a36Sopenharmony_ci node->sector = (sector_t)-1; 130462306a36Sopenharmony_ci} 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_cistatic void add_journal_node(struct dm_integrity_c *ic, struct journal_node *node, sector_t sector) 130762306a36Sopenharmony_ci{ 130862306a36Sopenharmony_ci struct rb_node **link; 130962306a36Sopenharmony_ci struct rb_node *parent; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci node->sector = sector; 131262306a36Sopenharmony_ci BUG_ON(!RB_EMPTY_NODE(&node->node)); 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci link = &ic->journal_tree_root.rb_node; 131562306a36Sopenharmony_ci parent = NULL; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci while (*link) { 131862306a36Sopenharmony_ci struct journal_node *j; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci parent = *link; 132162306a36Sopenharmony_ci j = container_of(parent, struct journal_node, node); 132262306a36Sopenharmony_ci if (sector < j->sector) 132362306a36Sopenharmony_ci link = &j->node.rb_left; 132462306a36Sopenharmony_ci else 132562306a36Sopenharmony_ci link = &j->node.rb_right; 132662306a36Sopenharmony_ci } 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci rb_link_node(&node->node, parent, link); 132962306a36Sopenharmony_ci rb_insert_color(&node->node, &ic->journal_tree_root); 133062306a36Sopenharmony_ci} 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_cistatic void remove_journal_node(struct dm_integrity_c *ic, struct journal_node *node) 133362306a36Sopenharmony_ci{ 133462306a36Sopenharmony_ci BUG_ON(RB_EMPTY_NODE(&node->node)); 133562306a36Sopenharmony_ci rb_erase(&node->node, &ic->journal_tree_root); 133662306a36Sopenharmony_ci init_journal_node(node); 133762306a36Sopenharmony_ci} 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci#define NOT_FOUND (-1U) 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_cistatic unsigned int find_journal_node(struct dm_integrity_c *ic, sector_t sector, sector_t *next_sector) 134262306a36Sopenharmony_ci{ 134362306a36Sopenharmony_ci struct rb_node *n = ic->journal_tree_root.rb_node; 134462306a36Sopenharmony_ci unsigned int found = NOT_FOUND; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci *next_sector = (sector_t)-1; 134762306a36Sopenharmony_ci while (n) { 134862306a36Sopenharmony_ci struct journal_node *j = container_of(n, struct journal_node, node); 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci if (sector == j->sector) 135162306a36Sopenharmony_ci found = j - ic->journal_tree; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci if (sector < j->sector) { 135462306a36Sopenharmony_ci *next_sector = j->sector; 135562306a36Sopenharmony_ci n = j->node.rb_left; 135662306a36Sopenharmony_ci } else 135762306a36Sopenharmony_ci n = j->node.rb_right; 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci return found; 136162306a36Sopenharmony_ci} 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_cistatic bool test_journal_node(struct dm_integrity_c *ic, unsigned int pos, sector_t sector) 136462306a36Sopenharmony_ci{ 136562306a36Sopenharmony_ci struct journal_node *node, *next_node; 136662306a36Sopenharmony_ci struct rb_node *next; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci if (unlikely(pos >= ic->journal_entries)) 136962306a36Sopenharmony_ci return false; 137062306a36Sopenharmony_ci node = &ic->journal_tree[pos]; 137162306a36Sopenharmony_ci if (unlikely(RB_EMPTY_NODE(&node->node))) 137262306a36Sopenharmony_ci return false; 137362306a36Sopenharmony_ci if (unlikely(node->sector != sector)) 137462306a36Sopenharmony_ci return false; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci next = rb_next(&node->node); 137762306a36Sopenharmony_ci if (unlikely(!next)) 137862306a36Sopenharmony_ci return true; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci next_node = container_of(next, struct journal_node, node); 138162306a36Sopenharmony_ci return next_node->sector != sector; 138262306a36Sopenharmony_ci} 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_cistatic bool find_newer_committed_node(struct dm_integrity_c *ic, struct journal_node *node) 138562306a36Sopenharmony_ci{ 138662306a36Sopenharmony_ci struct rb_node *next; 138762306a36Sopenharmony_ci struct journal_node *next_node; 138862306a36Sopenharmony_ci unsigned int next_section; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci BUG_ON(RB_EMPTY_NODE(&node->node)); 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci next = rb_next(&node->node); 139362306a36Sopenharmony_ci if (unlikely(!next)) 139462306a36Sopenharmony_ci return false; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci next_node = container_of(next, struct journal_node, node); 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci if (next_node->sector != node->sector) 139962306a36Sopenharmony_ci return false; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci next_section = (unsigned int)(next_node - ic->journal_tree) / ic->journal_section_entries; 140262306a36Sopenharmony_ci if (next_section >= ic->committed_section && 140362306a36Sopenharmony_ci next_section < ic->committed_section + ic->n_committed_sections) 140462306a36Sopenharmony_ci return true; 140562306a36Sopenharmony_ci if (next_section + ic->journal_sections < ic->committed_section + ic->n_committed_sections) 140662306a36Sopenharmony_ci return true; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci return false; 140962306a36Sopenharmony_ci} 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci#define TAG_READ 0 141262306a36Sopenharmony_ci#define TAG_WRITE 1 141362306a36Sopenharmony_ci#define TAG_CMP 2 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_cistatic int dm_integrity_rw_tag(struct dm_integrity_c *ic, unsigned char *tag, sector_t *metadata_block, 141662306a36Sopenharmony_ci unsigned int *metadata_offset, unsigned int total_size, int op) 141762306a36Sopenharmony_ci{ 141862306a36Sopenharmony_ci#define MAY_BE_FILLER 1 141962306a36Sopenharmony_ci#define MAY_BE_HASH 2 142062306a36Sopenharmony_ci unsigned int hash_offset = 0; 142162306a36Sopenharmony_ci unsigned int may_be = MAY_BE_HASH | (ic->discard ? MAY_BE_FILLER : 0); 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci do { 142462306a36Sopenharmony_ci unsigned char *data, *dp; 142562306a36Sopenharmony_ci struct dm_buffer *b; 142662306a36Sopenharmony_ci unsigned int to_copy; 142762306a36Sopenharmony_ci int r; 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci r = dm_integrity_failed(ic); 143062306a36Sopenharmony_ci if (unlikely(r)) 143162306a36Sopenharmony_ci return r; 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci data = dm_bufio_read(ic->bufio, *metadata_block, &b); 143462306a36Sopenharmony_ci if (IS_ERR(data)) 143562306a36Sopenharmony_ci return PTR_ERR(data); 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci to_copy = min((1U << SECTOR_SHIFT << ic->log2_buffer_sectors) - *metadata_offset, total_size); 143862306a36Sopenharmony_ci dp = data + *metadata_offset; 143962306a36Sopenharmony_ci if (op == TAG_READ) { 144062306a36Sopenharmony_ci memcpy(tag, dp, to_copy); 144162306a36Sopenharmony_ci } else if (op == TAG_WRITE) { 144262306a36Sopenharmony_ci if (memcmp(dp, tag, to_copy)) { 144362306a36Sopenharmony_ci memcpy(dp, tag, to_copy); 144462306a36Sopenharmony_ci dm_bufio_mark_partial_buffer_dirty(b, *metadata_offset, *metadata_offset + to_copy); 144562306a36Sopenharmony_ci } 144662306a36Sopenharmony_ci } else { 144762306a36Sopenharmony_ci /* e.g.: op == TAG_CMP */ 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci if (likely(is_power_of_2(ic->tag_size))) { 145062306a36Sopenharmony_ci if (unlikely(memcmp(dp, tag, to_copy))) 145162306a36Sopenharmony_ci if (unlikely(!ic->discard) || 145262306a36Sopenharmony_ci unlikely(memchr_inv(dp, DISCARD_FILLER, to_copy) != NULL)) { 145362306a36Sopenharmony_ci goto thorough_test; 145462306a36Sopenharmony_ci } 145562306a36Sopenharmony_ci } else { 145662306a36Sopenharmony_ci unsigned int i, ts; 145762306a36Sopenharmony_cithorough_test: 145862306a36Sopenharmony_ci ts = total_size; 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci for (i = 0; i < to_copy; i++, ts--) { 146162306a36Sopenharmony_ci if (unlikely(dp[i] != tag[i])) 146262306a36Sopenharmony_ci may_be &= ~MAY_BE_HASH; 146362306a36Sopenharmony_ci if (likely(dp[i] != DISCARD_FILLER)) 146462306a36Sopenharmony_ci may_be &= ~MAY_BE_FILLER; 146562306a36Sopenharmony_ci hash_offset++; 146662306a36Sopenharmony_ci if (unlikely(hash_offset == ic->tag_size)) { 146762306a36Sopenharmony_ci if (unlikely(!may_be)) { 146862306a36Sopenharmony_ci dm_bufio_release(b); 146962306a36Sopenharmony_ci return ts; 147062306a36Sopenharmony_ci } 147162306a36Sopenharmony_ci hash_offset = 0; 147262306a36Sopenharmony_ci may_be = MAY_BE_HASH | (ic->discard ? MAY_BE_FILLER : 0); 147362306a36Sopenharmony_ci } 147462306a36Sopenharmony_ci } 147562306a36Sopenharmony_ci } 147662306a36Sopenharmony_ci } 147762306a36Sopenharmony_ci dm_bufio_release(b); 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci tag += to_copy; 148062306a36Sopenharmony_ci *metadata_offset += to_copy; 148162306a36Sopenharmony_ci if (unlikely(*metadata_offset == 1U << SECTOR_SHIFT << ic->log2_buffer_sectors)) { 148262306a36Sopenharmony_ci (*metadata_block)++; 148362306a36Sopenharmony_ci *metadata_offset = 0; 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci if (unlikely(!is_power_of_2(ic->tag_size))) 148762306a36Sopenharmony_ci hash_offset = (hash_offset + to_copy) % ic->tag_size; 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci total_size -= to_copy; 149062306a36Sopenharmony_ci } while (unlikely(total_size)); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci return 0; 149362306a36Sopenharmony_ci#undef MAY_BE_FILLER 149462306a36Sopenharmony_ci#undef MAY_BE_HASH 149562306a36Sopenharmony_ci} 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_cistruct flush_request { 149862306a36Sopenharmony_ci struct dm_io_request io_req; 149962306a36Sopenharmony_ci struct dm_io_region io_reg; 150062306a36Sopenharmony_ci struct dm_integrity_c *ic; 150162306a36Sopenharmony_ci struct completion comp; 150262306a36Sopenharmony_ci}; 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_cistatic void flush_notify(unsigned long error, void *fr_) 150562306a36Sopenharmony_ci{ 150662306a36Sopenharmony_ci struct flush_request *fr = fr_; 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci if (unlikely(error != 0)) 150962306a36Sopenharmony_ci dm_integrity_io_error(fr->ic, "flushing disk cache", -EIO); 151062306a36Sopenharmony_ci complete(&fr->comp); 151162306a36Sopenharmony_ci} 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_cistatic void dm_integrity_flush_buffers(struct dm_integrity_c *ic, bool flush_data) 151462306a36Sopenharmony_ci{ 151562306a36Sopenharmony_ci int r; 151662306a36Sopenharmony_ci struct flush_request fr; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci if (!ic->meta_dev) 151962306a36Sopenharmony_ci flush_data = false; 152062306a36Sopenharmony_ci if (flush_data) { 152162306a36Sopenharmony_ci fr.io_req.bi_opf = REQ_OP_WRITE | REQ_PREFLUSH | REQ_SYNC, 152262306a36Sopenharmony_ci fr.io_req.mem.type = DM_IO_KMEM, 152362306a36Sopenharmony_ci fr.io_req.mem.ptr.addr = NULL, 152462306a36Sopenharmony_ci fr.io_req.notify.fn = flush_notify, 152562306a36Sopenharmony_ci fr.io_req.notify.context = &fr; 152662306a36Sopenharmony_ci fr.io_req.client = dm_bufio_get_dm_io_client(ic->bufio), 152762306a36Sopenharmony_ci fr.io_reg.bdev = ic->dev->bdev, 152862306a36Sopenharmony_ci fr.io_reg.sector = 0, 152962306a36Sopenharmony_ci fr.io_reg.count = 0, 153062306a36Sopenharmony_ci fr.ic = ic; 153162306a36Sopenharmony_ci init_completion(&fr.comp); 153262306a36Sopenharmony_ci r = dm_io(&fr.io_req, 1, &fr.io_reg, NULL, IOPRIO_DEFAULT); 153362306a36Sopenharmony_ci BUG_ON(r); 153462306a36Sopenharmony_ci } 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci r = dm_bufio_write_dirty_buffers(ic->bufio); 153762306a36Sopenharmony_ci if (unlikely(r)) 153862306a36Sopenharmony_ci dm_integrity_io_error(ic, "writing tags", r); 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci if (flush_data) 154162306a36Sopenharmony_ci wait_for_completion(&fr.comp); 154262306a36Sopenharmony_ci} 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_cistatic void sleep_on_endio_wait(struct dm_integrity_c *ic) 154562306a36Sopenharmony_ci{ 154662306a36Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci __add_wait_queue(&ic->endio_wait, &wait); 154962306a36Sopenharmony_ci __set_current_state(TASK_UNINTERRUPTIBLE); 155062306a36Sopenharmony_ci spin_unlock_irq(&ic->endio_wait.lock); 155162306a36Sopenharmony_ci io_schedule(); 155262306a36Sopenharmony_ci spin_lock_irq(&ic->endio_wait.lock); 155362306a36Sopenharmony_ci __remove_wait_queue(&ic->endio_wait, &wait); 155462306a36Sopenharmony_ci} 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_cistatic void autocommit_fn(struct timer_list *t) 155762306a36Sopenharmony_ci{ 155862306a36Sopenharmony_ci struct dm_integrity_c *ic = from_timer(ic, t, autocommit_timer); 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci if (likely(!dm_integrity_failed(ic))) 156162306a36Sopenharmony_ci queue_work(ic->commit_wq, &ic->commit_work); 156262306a36Sopenharmony_ci} 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_cistatic void schedule_autocommit(struct dm_integrity_c *ic) 156562306a36Sopenharmony_ci{ 156662306a36Sopenharmony_ci if (!timer_pending(&ic->autocommit_timer)) 156762306a36Sopenharmony_ci mod_timer(&ic->autocommit_timer, jiffies + ic->autocommit_jiffies); 156862306a36Sopenharmony_ci} 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_cistatic void submit_flush_bio(struct dm_integrity_c *ic, struct dm_integrity_io *dio) 157162306a36Sopenharmony_ci{ 157262306a36Sopenharmony_ci struct bio *bio; 157362306a36Sopenharmony_ci unsigned long flags; 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci spin_lock_irqsave(&ic->endio_wait.lock, flags); 157662306a36Sopenharmony_ci bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io)); 157762306a36Sopenharmony_ci bio_list_add(&ic->flush_bio_list, bio); 157862306a36Sopenharmony_ci spin_unlock_irqrestore(&ic->endio_wait.lock, flags); 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci queue_work(ic->commit_wq, &ic->commit_work); 158162306a36Sopenharmony_ci} 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_cistatic void do_endio(struct dm_integrity_c *ic, struct bio *bio) 158462306a36Sopenharmony_ci{ 158562306a36Sopenharmony_ci int r; 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci r = dm_integrity_failed(ic); 158862306a36Sopenharmony_ci if (unlikely(r) && !bio->bi_status) 158962306a36Sopenharmony_ci bio->bi_status = errno_to_blk_status(r); 159062306a36Sopenharmony_ci if (unlikely(ic->synchronous_mode) && bio_op(bio) == REQ_OP_WRITE) { 159162306a36Sopenharmony_ci unsigned long flags; 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci spin_lock_irqsave(&ic->endio_wait.lock, flags); 159462306a36Sopenharmony_ci bio_list_add(&ic->synchronous_bios, bio); 159562306a36Sopenharmony_ci queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, 0); 159662306a36Sopenharmony_ci spin_unlock_irqrestore(&ic->endio_wait.lock, flags); 159762306a36Sopenharmony_ci return; 159862306a36Sopenharmony_ci } 159962306a36Sopenharmony_ci bio_endio(bio); 160062306a36Sopenharmony_ci} 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_cistatic void do_endio_flush(struct dm_integrity_c *ic, struct dm_integrity_io *dio) 160362306a36Sopenharmony_ci{ 160462306a36Sopenharmony_ci struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io)); 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci if (unlikely(dio->fua) && likely(!bio->bi_status) && likely(!dm_integrity_failed(ic))) 160762306a36Sopenharmony_ci submit_flush_bio(ic, dio); 160862306a36Sopenharmony_ci else 160962306a36Sopenharmony_ci do_endio(ic, bio); 161062306a36Sopenharmony_ci} 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_cistatic void dec_in_flight(struct dm_integrity_io *dio) 161362306a36Sopenharmony_ci{ 161462306a36Sopenharmony_ci if (atomic_dec_and_test(&dio->in_flight)) { 161562306a36Sopenharmony_ci struct dm_integrity_c *ic = dio->ic; 161662306a36Sopenharmony_ci struct bio *bio; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci remove_range(ic, &dio->range); 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci if (dio->op == REQ_OP_WRITE || unlikely(dio->op == REQ_OP_DISCARD)) 162162306a36Sopenharmony_ci schedule_autocommit(ic); 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io)); 162462306a36Sopenharmony_ci if (unlikely(dio->bi_status) && !bio->bi_status) 162562306a36Sopenharmony_ci bio->bi_status = dio->bi_status; 162662306a36Sopenharmony_ci if (likely(!bio->bi_status) && unlikely(bio_sectors(bio) != dio->range.n_sectors)) { 162762306a36Sopenharmony_ci dio->range.logical_sector += dio->range.n_sectors; 162862306a36Sopenharmony_ci bio_advance(bio, dio->range.n_sectors << SECTOR_SHIFT); 162962306a36Sopenharmony_ci INIT_WORK(&dio->work, integrity_bio_wait); 163062306a36Sopenharmony_ci queue_work(ic->offload_wq, &dio->work); 163162306a36Sopenharmony_ci return; 163262306a36Sopenharmony_ci } 163362306a36Sopenharmony_ci do_endio_flush(ic, dio); 163462306a36Sopenharmony_ci } 163562306a36Sopenharmony_ci} 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_cistatic void integrity_end_io(struct bio *bio) 163862306a36Sopenharmony_ci{ 163962306a36Sopenharmony_ci struct dm_integrity_io *dio = dm_per_bio_data(bio, sizeof(struct dm_integrity_io)); 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci dm_bio_restore(&dio->bio_details, bio); 164262306a36Sopenharmony_ci if (bio->bi_integrity) 164362306a36Sopenharmony_ci bio->bi_opf |= REQ_INTEGRITY; 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci if (dio->completion) 164662306a36Sopenharmony_ci complete(dio->completion); 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci dec_in_flight(dio); 164962306a36Sopenharmony_ci} 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_cistatic void integrity_sector_checksum(struct dm_integrity_c *ic, sector_t sector, 165262306a36Sopenharmony_ci const char *data, char *result) 165362306a36Sopenharmony_ci{ 165462306a36Sopenharmony_ci __le64 sector_le = cpu_to_le64(sector); 165562306a36Sopenharmony_ci SHASH_DESC_ON_STACK(req, ic->internal_hash); 165662306a36Sopenharmony_ci int r; 165762306a36Sopenharmony_ci unsigned int digest_size; 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci req->tfm = ic->internal_hash; 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci r = crypto_shash_init(req); 166262306a36Sopenharmony_ci if (unlikely(r < 0)) { 166362306a36Sopenharmony_ci dm_integrity_io_error(ic, "crypto_shash_init", r); 166462306a36Sopenharmony_ci goto failed; 166562306a36Sopenharmony_ci } 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci if (ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_HMAC)) { 166862306a36Sopenharmony_ci r = crypto_shash_update(req, (__u8 *)&ic->sb->salt, SALT_SIZE); 166962306a36Sopenharmony_ci if (unlikely(r < 0)) { 167062306a36Sopenharmony_ci dm_integrity_io_error(ic, "crypto_shash_update", r); 167162306a36Sopenharmony_ci goto failed; 167262306a36Sopenharmony_ci } 167362306a36Sopenharmony_ci } 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci r = crypto_shash_update(req, (const __u8 *)§or_le, sizeof(sector_le)); 167662306a36Sopenharmony_ci if (unlikely(r < 0)) { 167762306a36Sopenharmony_ci dm_integrity_io_error(ic, "crypto_shash_update", r); 167862306a36Sopenharmony_ci goto failed; 167962306a36Sopenharmony_ci } 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci r = crypto_shash_update(req, data, ic->sectors_per_block << SECTOR_SHIFT); 168262306a36Sopenharmony_ci if (unlikely(r < 0)) { 168362306a36Sopenharmony_ci dm_integrity_io_error(ic, "crypto_shash_update", r); 168462306a36Sopenharmony_ci goto failed; 168562306a36Sopenharmony_ci } 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci r = crypto_shash_final(req, result); 168862306a36Sopenharmony_ci if (unlikely(r < 0)) { 168962306a36Sopenharmony_ci dm_integrity_io_error(ic, "crypto_shash_final", r); 169062306a36Sopenharmony_ci goto failed; 169162306a36Sopenharmony_ci } 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci digest_size = crypto_shash_digestsize(ic->internal_hash); 169462306a36Sopenharmony_ci if (unlikely(digest_size < ic->tag_size)) 169562306a36Sopenharmony_ci memset(result + digest_size, 0, ic->tag_size - digest_size); 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci return; 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_cifailed: 170062306a36Sopenharmony_ci /* this shouldn't happen anyway, the hash functions have no reason to fail */ 170162306a36Sopenharmony_ci get_random_bytes(result, ic->tag_size); 170262306a36Sopenharmony_ci} 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_cistatic noinline void integrity_recheck(struct dm_integrity_io *dio, char *checksum) 170562306a36Sopenharmony_ci{ 170662306a36Sopenharmony_ci struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io)); 170762306a36Sopenharmony_ci struct dm_integrity_c *ic = dio->ic; 170862306a36Sopenharmony_ci struct bvec_iter iter; 170962306a36Sopenharmony_ci struct bio_vec bv; 171062306a36Sopenharmony_ci sector_t sector, logical_sector, area, offset; 171162306a36Sopenharmony_ci struct page *page; 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci get_area_and_offset(ic, dio->range.logical_sector, &area, &offset); 171462306a36Sopenharmony_ci dio->metadata_block = get_metadata_sector_and_offset(ic, area, offset, 171562306a36Sopenharmony_ci &dio->metadata_offset); 171662306a36Sopenharmony_ci sector = get_data_sector(ic, area, offset); 171762306a36Sopenharmony_ci logical_sector = dio->range.logical_sector; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci page = mempool_alloc(&ic->recheck_pool, GFP_NOIO); 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci __bio_for_each_segment(bv, bio, iter, dio->bio_details.bi_iter) { 172262306a36Sopenharmony_ci unsigned pos = 0; 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci do { 172562306a36Sopenharmony_ci sector_t alignment; 172662306a36Sopenharmony_ci char *mem; 172762306a36Sopenharmony_ci char *buffer = page_to_virt(page); 172862306a36Sopenharmony_ci int r; 172962306a36Sopenharmony_ci struct dm_io_request io_req; 173062306a36Sopenharmony_ci struct dm_io_region io_loc; 173162306a36Sopenharmony_ci io_req.bi_opf = REQ_OP_READ; 173262306a36Sopenharmony_ci io_req.mem.type = DM_IO_KMEM; 173362306a36Sopenharmony_ci io_req.mem.ptr.addr = buffer; 173462306a36Sopenharmony_ci io_req.notify.fn = NULL; 173562306a36Sopenharmony_ci io_req.client = ic->io; 173662306a36Sopenharmony_ci io_loc.bdev = ic->dev->bdev; 173762306a36Sopenharmony_ci io_loc.sector = sector; 173862306a36Sopenharmony_ci io_loc.count = ic->sectors_per_block; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci /* Align the bio to logical block size */ 174162306a36Sopenharmony_ci alignment = dio->range.logical_sector | bio_sectors(bio) | (PAGE_SIZE >> SECTOR_SHIFT); 174262306a36Sopenharmony_ci alignment &= -alignment; 174362306a36Sopenharmony_ci io_loc.sector = round_down(io_loc.sector, alignment); 174462306a36Sopenharmony_ci io_loc.count += sector - io_loc.sector; 174562306a36Sopenharmony_ci buffer += (sector - io_loc.sector) << SECTOR_SHIFT; 174662306a36Sopenharmony_ci io_loc.count = round_up(io_loc.count, alignment); 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci r = dm_io(&io_req, 1, &io_loc, NULL, IOPRIO_DEFAULT); 174962306a36Sopenharmony_ci if (unlikely(r)) { 175062306a36Sopenharmony_ci dio->bi_status = errno_to_blk_status(r); 175162306a36Sopenharmony_ci goto free_ret; 175262306a36Sopenharmony_ci } 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci integrity_sector_checksum(ic, logical_sector, buffer, checksum); 175562306a36Sopenharmony_ci r = dm_integrity_rw_tag(ic, checksum, &dio->metadata_block, 175662306a36Sopenharmony_ci &dio->metadata_offset, ic->tag_size, TAG_CMP); 175762306a36Sopenharmony_ci if (r) { 175862306a36Sopenharmony_ci if (r > 0) { 175962306a36Sopenharmony_ci DMERR_LIMIT("%pg: Checksum failed at sector 0x%llx", 176062306a36Sopenharmony_ci bio->bi_bdev, logical_sector); 176162306a36Sopenharmony_ci atomic64_inc(&ic->number_of_mismatches); 176262306a36Sopenharmony_ci dm_audit_log_bio(DM_MSG_PREFIX, "integrity-checksum", 176362306a36Sopenharmony_ci bio, logical_sector, 0); 176462306a36Sopenharmony_ci r = -EILSEQ; 176562306a36Sopenharmony_ci } 176662306a36Sopenharmony_ci dio->bi_status = errno_to_blk_status(r); 176762306a36Sopenharmony_ci goto free_ret; 176862306a36Sopenharmony_ci } 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci mem = bvec_kmap_local(&bv); 177162306a36Sopenharmony_ci memcpy(mem + pos, buffer, ic->sectors_per_block << SECTOR_SHIFT); 177262306a36Sopenharmony_ci kunmap_local(mem); 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci pos += ic->sectors_per_block << SECTOR_SHIFT; 177562306a36Sopenharmony_ci sector += ic->sectors_per_block; 177662306a36Sopenharmony_ci logical_sector += ic->sectors_per_block; 177762306a36Sopenharmony_ci } while (pos < bv.bv_len); 177862306a36Sopenharmony_ci } 177962306a36Sopenharmony_cifree_ret: 178062306a36Sopenharmony_ci mempool_free(page, &ic->recheck_pool); 178162306a36Sopenharmony_ci} 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_cistatic void integrity_metadata(struct work_struct *w) 178462306a36Sopenharmony_ci{ 178562306a36Sopenharmony_ci struct dm_integrity_io *dio = container_of(w, struct dm_integrity_io, work); 178662306a36Sopenharmony_ci struct dm_integrity_c *ic = dio->ic; 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci int r; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci if (ic->internal_hash) { 179162306a36Sopenharmony_ci struct bvec_iter iter; 179262306a36Sopenharmony_ci struct bio_vec bv; 179362306a36Sopenharmony_ci unsigned int digest_size = crypto_shash_digestsize(ic->internal_hash); 179462306a36Sopenharmony_ci struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io)); 179562306a36Sopenharmony_ci char *checksums; 179662306a36Sopenharmony_ci unsigned int extra_space = unlikely(digest_size > ic->tag_size) ? digest_size - ic->tag_size : 0; 179762306a36Sopenharmony_ci char checksums_onstack[max_t(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)]; 179862306a36Sopenharmony_ci sector_t sector; 179962306a36Sopenharmony_ci unsigned int sectors_to_process; 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci if (unlikely(ic->mode == 'R')) 180262306a36Sopenharmony_ci goto skip_io; 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci if (likely(dio->op != REQ_OP_DISCARD)) 180562306a36Sopenharmony_ci checksums = kmalloc((PAGE_SIZE >> SECTOR_SHIFT >> ic->sb->log2_sectors_per_block) * ic->tag_size + extra_space, 180662306a36Sopenharmony_ci GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN); 180762306a36Sopenharmony_ci else 180862306a36Sopenharmony_ci checksums = kmalloc(PAGE_SIZE, GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN); 180962306a36Sopenharmony_ci if (!checksums) { 181062306a36Sopenharmony_ci checksums = checksums_onstack; 181162306a36Sopenharmony_ci if (WARN_ON(extra_space && 181262306a36Sopenharmony_ci digest_size > sizeof(checksums_onstack))) { 181362306a36Sopenharmony_ci r = -EINVAL; 181462306a36Sopenharmony_ci goto error; 181562306a36Sopenharmony_ci } 181662306a36Sopenharmony_ci } 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci if (unlikely(dio->op == REQ_OP_DISCARD)) { 181962306a36Sopenharmony_ci unsigned int bi_size = dio->bio_details.bi_iter.bi_size; 182062306a36Sopenharmony_ci unsigned int max_size = likely(checksums != checksums_onstack) ? PAGE_SIZE : HASH_MAX_DIGESTSIZE; 182162306a36Sopenharmony_ci unsigned int max_blocks = max_size / ic->tag_size; 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci memset(checksums, DISCARD_FILLER, max_size); 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci while (bi_size) { 182662306a36Sopenharmony_ci unsigned int this_step_blocks = bi_size >> (SECTOR_SHIFT + ic->sb->log2_sectors_per_block); 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci this_step_blocks = min(this_step_blocks, max_blocks); 182962306a36Sopenharmony_ci r = dm_integrity_rw_tag(ic, checksums, &dio->metadata_block, &dio->metadata_offset, 183062306a36Sopenharmony_ci this_step_blocks * ic->tag_size, TAG_WRITE); 183162306a36Sopenharmony_ci if (unlikely(r)) { 183262306a36Sopenharmony_ci if (likely(checksums != checksums_onstack)) 183362306a36Sopenharmony_ci kfree(checksums); 183462306a36Sopenharmony_ci goto error; 183562306a36Sopenharmony_ci } 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci bi_size -= this_step_blocks << (SECTOR_SHIFT + ic->sb->log2_sectors_per_block); 183862306a36Sopenharmony_ci } 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci if (likely(checksums != checksums_onstack)) 184162306a36Sopenharmony_ci kfree(checksums); 184262306a36Sopenharmony_ci goto skip_io; 184362306a36Sopenharmony_ci } 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci sector = dio->range.logical_sector; 184662306a36Sopenharmony_ci sectors_to_process = dio->range.n_sectors; 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci __bio_for_each_segment(bv, bio, iter, dio->bio_details.bi_iter) { 184962306a36Sopenharmony_ci struct bio_vec bv_copy = bv; 185062306a36Sopenharmony_ci unsigned int pos; 185162306a36Sopenharmony_ci char *mem, *checksums_ptr; 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ciagain: 185462306a36Sopenharmony_ci mem = bvec_kmap_local(&bv_copy); 185562306a36Sopenharmony_ci pos = 0; 185662306a36Sopenharmony_ci checksums_ptr = checksums; 185762306a36Sopenharmony_ci do { 185862306a36Sopenharmony_ci integrity_sector_checksum(ic, sector, mem + pos, checksums_ptr); 185962306a36Sopenharmony_ci checksums_ptr += ic->tag_size; 186062306a36Sopenharmony_ci sectors_to_process -= ic->sectors_per_block; 186162306a36Sopenharmony_ci pos += ic->sectors_per_block << SECTOR_SHIFT; 186262306a36Sopenharmony_ci sector += ic->sectors_per_block; 186362306a36Sopenharmony_ci } while (pos < bv_copy.bv_len && sectors_to_process && checksums != checksums_onstack); 186462306a36Sopenharmony_ci kunmap_local(mem); 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci r = dm_integrity_rw_tag(ic, checksums, &dio->metadata_block, &dio->metadata_offset, 186762306a36Sopenharmony_ci checksums_ptr - checksums, dio->op == REQ_OP_READ ? TAG_CMP : TAG_WRITE); 186862306a36Sopenharmony_ci if (unlikely(r)) { 186962306a36Sopenharmony_ci if (likely(checksums != checksums_onstack)) 187062306a36Sopenharmony_ci kfree(checksums); 187162306a36Sopenharmony_ci if (r > 0) { 187262306a36Sopenharmony_ci integrity_recheck(dio, checksums_onstack); 187362306a36Sopenharmony_ci goto skip_io; 187462306a36Sopenharmony_ci } 187562306a36Sopenharmony_ci goto error; 187662306a36Sopenharmony_ci } 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci if (!sectors_to_process) 187962306a36Sopenharmony_ci break; 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci if (unlikely(pos < bv_copy.bv_len)) { 188262306a36Sopenharmony_ci bv_copy.bv_offset += pos; 188362306a36Sopenharmony_ci bv_copy.bv_len -= pos; 188462306a36Sopenharmony_ci goto again; 188562306a36Sopenharmony_ci } 188662306a36Sopenharmony_ci } 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_ci if (likely(checksums != checksums_onstack)) 188962306a36Sopenharmony_ci kfree(checksums); 189062306a36Sopenharmony_ci } else { 189162306a36Sopenharmony_ci struct bio_integrity_payload *bip = dio->bio_details.bi_integrity; 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci if (bip) { 189462306a36Sopenharmony_ci struct bio_vec biv; 189562306a36Sopenharmony_ci struct bvec_iter iter; 189662306a36Sopenharmony_ci unsigned int data_to_process = dio->range.n_sectors; 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci sector_to_block(ic, data_to_process); 189962306a36Sopenharmony_ci data_to_process *= ic->tag_size; 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci bip_for_each_vec(biv, bip, iter) { 190262306a36Sopenharmony_ci unsigned char *tag; 190362306a36Sopenharmony_ci unsigned int this_len; 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci BUG_ON(PageHighMem(biv.bv_page)); 190662306a36Sopenharmony_ci tag = bvec_virt(&biv); 190762306a36Sopenharmony_ci this_len = min(biv.bv_len, data_to_process); 190862306a36Sopenharmony_ci r = dm_integrity_rw_tag(ic, tag, &dio->metadata_block, &dio->metadata_offset, 190962306a36Sopenharmony_ci this_len, dio->op == REQ_OP_READ ? TAG_READ : TAG_WRITE); 191062306a36Sopenharmony_ci if (unlikely(r)) 191162306a36Sopenharmony_ci goto error; 191262306a36Sopenharmony_ci data_to_process -= this_len; 191362306a36Sopenharmony_ci if (!data_to_process) 191462306a36Sopenharmony_ci break; 191562306a36Sopenharmony_ci } 191662306a36Sopenharmony_ci } 191762306a36Sopenharmony_ci } 191862306a36Sopenharmony_ciskip_io: 191962306a36Sopenharmony_ci dec_in_flight(dio); 192062306a36Sopenharmony_ci return; 192162306a36Sopenharmony_cierror: 192262306a36Sopenharmony_ci dio->bi_status = errno_to_blk_status(r); 192362306a36Sopenharmony_ci dec_in_flight(dio); 192462306a36Sopenharmony_ci} 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_cistatic int dm_integrity_map(struct dm_target *ti, struct bio *bio) 192762306a36Sopenharmony_ci{ 192862306a36Sopenharmony_ci struct dm_integrity_c *ic = ti->private; 192962306a36Sopenharmony_ci struct dm_integrity_io *dio = dm_per_bio_data(bio, sizeof(struct dm_integrity_io)); 193062306a36Sopenharmony_ci struct bio_integrity_payload *bip; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci sector_t area, offset; 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci dio->ic = ic; 193562306a36Sopenharmony_ci dio->bi_status = 0; 193662306a36Sopenharmony_ci dio->op = bio_op(bio); 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci if (unlikely(dio->op == REQ_OP_DISCARD)) { 193962306a36Sopenharmony_ci if (ti->max_io_len) { 194062306a36Sopenharmony_ci sector_t sec = dm_target_offset(ti, bio->bi_iter.bi_sector); 194162306a36Sopenharmony_ci unsigned int log2_max_io_len = __fls(ti->max_io_len); 194262306a36Sopenharmony_ci sector_t start_boundary = sec >> log2_max_io_len; 194362306a36Sopenharmony_ci sector_t end_boundary = (sec + bio_sectors(bio) - 1) >> log2_max_io_len; 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci if (start_boundary < end_boundary) { 194662306a36Sopenharmony_ci sector_t len = ti->max_io_len - (sec & (ti->max_io_len - 1)); 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci dm_accept_partial_bio(bio, len); 194962306a36Sopenharmony_ci } 195062306a36Sopenharmony_ci } 195162306a36Sopenharmony_ci } 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci if (unlikely(bio->bi_opf & REQ_PREFLUSH)) { 195462306a36Sopenharmony_ci submit_flush_bio(ic, dio); 195562306a36Sopenharmony_ci return DM_MAPIO_SUBMITTED; 195662306a36Sopenharmony_ci } 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci dio->range.logical_sector = dm_target_offset(ti, bio->bi_iter.bi_sector); 195962306a36Sopenharmony_ci dio->fua = dio->op == REQ_OP_WRITE && bio->bi_opf & REQ_FUA; 196062306a36Sopenharmony_ci if (unlikely(dio->fua)) { 196162306a36Sopenharmony_ci /* 196262306a36Sopenharmony_ci * Don't pass down the FUA flag because we have to flush 196362306a36Sopenharmony_ci * disk cache anyway. 196462306a36Sopenharmony_ci */ 196562306a36Sopenharmony_ci bio->bi_opf &= ~REQ_FUA; 196662306a36Sopenharmony_ci } 196762306a36Sopenharmony_ci if (unlikely(dio->range.logical_sector + bio_sectors(bio) > ic->provided_data_sectors)) { 196862306a36Sopenharmony_ci DMERR("Too big sector number: 0x%llx + 0x%x > 0x%llx", 196962306a36Sopenharmony_ci dio->range.logical_sector, bio_sectors(bio), 197062306a36Sopenharmony_ci ic->provided_data_sectors); 197162306a36Sopenharmony_ci return DM_MAPIO_KILL; 197262306a36Sopenharmony_ci } 197362306a36Sopenharmony_ci if (unlikely((dio->range.logical_sector | bio_sectors(bio)) & (unsigned int)(ic->sectors_per_block - 1))) { 197462306a36Sopenharmony_ci DMERR("Bio not aligned on %u sectors: 0x%llx, 0x%x", 197562306a36Sopenharmony_ci ic->sectors_per_block, 197662306a36Sopenharmony_ci dio->range.logical_sector, bio_sectors(bio)); 197762306a36Sopenharmony_ci return DM_MAPIO_KILL; 197862306a36Sopenharmony_ci } 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci if (ic->sectors_per_block > 1 && likely(dio->op != REQ_OP_DISCARD)) { 198162306a36Sopenharmony_ci struct bvec_iter iter; 198262306a36Sopenharmony_ci struct bio_vec bv; 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_ci bio_for_each_segment(bv, bio, iter) { 198562306a36Sopenharmony_ci if (unlikely(bv.bv_len & ((ic->sectors_per_block << SECTOR_SHIFT) - 1))) { 198662306a36Sopenharmony_ci DMERR("Bio vector (%u,%u) is not aligned on %u-sector boundary", 198762306a36Sopenharmony_ci bv.bv_offset, bv.bv_len, ic->sectors_per_block); 198862306a36Sopenharmony_ci return DM_MAPIO_KILL; 198962306a36Sopenharmony_ci } 199062306a36Sopenharmony_ci } 199162306a36Sopenharmony_ci } 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci bip = bio_integrity(bio); 199462306a36Sopenharmony_ci if (!ic->internal_hash) { 199562306a36Sopenharmony_ci if (bip) { 199662306a36Sopenharmony_ci unsigned int wanted_tag_size = bio_sectors(bio) >> ic->sb->log2_sectors_per_block; 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci if (ic->log2_tag_size >= 0) 199962306a36Sopenharmony_ci wanted_tag_size <<= ic->log2_tag_size; 200062306a36Sopenharmony_ci else 200162306a36Sopenharmony_ci wanted_tag_size *= ic->tag_size; 200262306a36Sopenharmony_ci if (unlikely(wanted_tag_size != bip->bip_iter.bi_size)) { 200362306a36Sopenharmony_ci DMERR("Invalid integrity data size %u, expected %u", 200462306a36Sopenharmony_ci bip->bip_iter.bi_size, wanted_tag_size); 200562306a36Sopenharmony_ci return DM_MAPIO_KILL; 200662306a36Sopenharmony_ci } 200762306a36Sopenharmony_ci } 200862306a36Sopenharmony_ci } else { 200962306a36Sopenharmony_ci if (unlikely(bip != NULL)) { 201062306a36Sopenharmony_ci DMERR("Unexpected integrity data when using internal hash"); 201162306a36Sopenharmony_ci return DM_MAPIO_KILL; 201262306a36Sopenharmony_ci } 201362306a36Sopenharmony_ci } 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci if (unlikely(ic->mode == 'R') && unlikely(dio->op != REQ_OP_READ)) 201662306a36Sopenharmony_ci return DM_MAPIO_KILL; 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci get_area_and_offset(ic, dio->range.logical_sector, &area, &offset); 201962306a36Sopenharmony_ci dio->metadata_block = get_metadata_sector_and_offset(ic, area, offset, &dio->metadata_offset); 202062306a36Sopenharmony_ci bio->bi_iter.bi_sector = get_data_sector(ic, area, offset); 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci dm_integrity_map_continue(dio, true); 202362306a36Sopenharmony_ci return DM_MAPIO_SUBMITTED; 202462306a36Sopenharmony_ci} 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_cistatic bool __journal_read_write(struct dm_integrity_io *dio, struct bio *bio, 202762306a36Sopenharmony_ci unsigned int journal_section, unsigned int journal_entry) 202862306a36Sopenharmony_ci{ 202962306a36Sopenharmony_ci struct dm_integrity_c *ic = dio->ic; 203062306a36Sopenharmony_ci sector_t logical_sector; 203162306a36Sopenharmony_ci unsigned int n_sectors; 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci logical_sector = dio->range.logical_sector; 203462306a36Sopenharmony_ci n_sectors = dio->range.n_sectors; 203562306a36Sopenharmony_ci do { 203662306a36Sopenharmony_ci struct bio_vec bv = bio_iovec(bio); 203762306a36Sopenharmony_ci char *mem; 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci if (unlikely(bv.bv_len >> SECTOR_SHIFT > n_sectors)) 204062306a36Sopenharmony_ci bv.bv_len = n_sectors << SECTOR_SHIFT; 204162306a36Sopenharmony_ci n_sectors -= bv.bv_len >> SECTOR_SHIFT; 204262306a36Sopenharmony_ci bio_advance_iter(bio, &bio->bi_iter, bv.bv_len); 204362306a36Sopenharmony_ciretry_kmap: 204462306a36Sopenharmony_ci mem = kmap_local_page(bv.bv_page); 204562306a36Sopenharmony_ci if (likely(dio->op == REQ_OP_WRITE)) 204662306a36Sopenharmony_ci flush_dcache_page(bv.bv_page); 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci do { 204962306a36Sopenharmony_ci struct journal_entry *je = access_journal_entry(ic, journal_section, journal_entry); 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci if (unlikely(dio->op == REQ_OP_READ)) { 205262306a36Sopenharmony_ci struct journal_sector *js; 205362306a36Sopenharmony_ci char *mem_ptr; 205462306a36Sopenharmony_ci unsigned int s; 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci if (unlikely(journal_entry_is_inprogress(je))) { 205762306a36Sopenharmony_ci flush_dcache_page(bv.bv_page); 205862306a36Sopenharmony_ci kunmap_local(mem); 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ci __io_wait_event(ic->copy_to_journal_wait, !journal_entry_is_inprogress(je)); 206162306a36Sopenharmony_ci goto retry_kmap; 206262306a36Sopenharmony_ci } 206362306a36Sopenharmony_ci smp_rmb(); 206462306a36Sopenharmony_ci BUG_ON(journal_entry_get_sector(je) != logical_sector); 206562306a36Sopenharmony_ci js = access_journal_data(ic, journal_section, journal_entry); 206662306a36Sopenharmony_ci mem_ptr = mem + bv.bv_offset; 206762306a36Sopenharmony_ci s = 0; 206862306a36Sopenharmony_ci do { 206962306a36Sopenharmony_ci memcpy(mem_ptr, js, JOURNAL_SECTOR_DATA); 207062306a36Sopenharmony_ci *(commit_id_t *)(mem_ptr + JOURNAL_SECTOR_DATA) = je->last_bytes[s]; 207162306a36Sopenharmony_ci js++; 207262306a36Sopenharmony_ci mem_ptr += 1 << SECTOR_SHIFT; 207362306a36Sopenharmony_ci } while (++s < ic->sectors_per_block); 207462306a36Sopenharmony_ci#ifdef INTERNAL_VERIFY 207562306a36Sopenharmony_ci if (ic->internal_hash) { 207662306a36Sopenharmony_ci char checksums_onstack[max_t(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)]; 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci integrity_sector_checksum(ic, logical_sector, mem + bv.bv_offset, checksums_onstack); 207962306a36Sopenharmony_ci if (unlikely(memcmp(checksums_onstack, journal_entry_tag(ic, je), ic->tag_size))) { 208062306a36Sopenharmony_ci DMERR_LIMIT("Checksum failed when reading from journal, at sector 0x%llx", 208162306a36Sopenharmony_ci logical_sector); 208262306a36Sopenharmony_ci dm_audit_log_bio(DM_MSG_PREFIX, "journal-checksum", 208362306a36Sopenharmony_ci bio, logical_sector, 0); 208462306a36Sopenharmony_ci } 208562306a36Sopenharmony_ci } 208662306a36Sopenharmony_ci#endif 208762306a36Sopenharmony_ci } 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci if (!ic->internal_hash) { 209062306a36Sopenharmony_ci struct bio_integrity_payload *bip = bio_integrity(bio); 209162306a36Sopenharmony_ci unsigned int tag_todo = ic->tag_size; 209262306a36Sopenharmony_ci char *tag_ptr = journal_entry_tag(ic, je); 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci if (bip) { 209562306a36Sopenharmony_ci do { 209662306a36Sopenharmony_ci struct bio_vec biv = bvec_iter_bvec(bip->bip_vec, bip->bip_iter); 209762306a36Sopenharmony_ci unsigned int tag_now = min(biv.bv_len, tag_todo); 209862306a36Sopenharmony_ci char *tag_addr; 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci BUG_ON(PageHighMem(biv.bv_page)); 210162306a36Sopenharmony_ci tag_addr = bvec_virt(&biv); 210262306a36Sopenharmony_ci if (likely(dio->op == REQ_OP_WRITE)) 210362306a36Sopenharmony_ci memcpy(tag_ptr, tag_addr, tag_now); 210462306a36Sopenharmony_ci else 210562306a36Sopenharmony_ci memcpy(tag_addr, tag_ptr, tag_now); 210662306a36Sopenharmony_ci bvec_iter_advance(bip->bip_vec, &bip->bip_iter, tag_now); 210762306a36Sopenharmony_ci tag_ptr += tag_now; 210862306a36Sopenharmony_ci tag_todo -= tag_now; 210962306a36Sopenharmony_ci } while (unlikely(tag_todo)); 211062306a36Sopenharmony_ci } else if (likely(dio->op == REQ_OP_WRITE)) 211162306a36Sopenharmony_ci memset(tag_ptr, 0, tag_todo); 211262306a36Sopenharmony_ci } 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci if (likely(dio->op == REQ_OP_WRITE)) { 211562306a36Sopenharmony_ci struct journal_sector *js; 211662306a36Sopenharmony_ci unsigned int s; 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci js = access_journal_data(ic, journal_section, journal_entry); 211962306a36Sopenharmony_ci memcpy(js, mem + bv.bv_offset, ic->sectors_per_block << SECTOR_SHIFT); 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci s = 0; 212262306a36Sopenharmony_ci do { 212362306a36Sopenharmony_ci je->last_bytes[s] = js[s].commit_id; 212462306a36Sopenharmony_ci } while (++s < ic->sectors_per_block); 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci if (ic->internal_hash) { 212762306a36Sopenharmony_ci unsigned int digest_size = crypto_shash_digestsize(ic->internal_hash); 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci if (unlikely(digest_size > ic->tag_size)) { 213062306a36Sopenharmony_ci char checksums_onstack[HASH_MAX_DIGESTSIZE]; 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci integrity_sector_checksum(ic, logical_sector, (char *)js, checksums_onstack); 213362306a36Sopenharmony_ci memcpy(journal_entry_tag(ic, je), checksums_onstack, ic->tag_size); 213462306a36Sopenharmony_ci } else 213562306a36Sopenharmony_ci integrity_sector_checksum(ic, logical_sector, (char *)js, journal_entry_tag(ic, je)); 213662306a36Sopenharmony_ci } 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ci journal_entry_set_sector(je, logical_sector); 213962306a36Sopenharmony_ci } 214062306a36Sopenharmony_ci logical_sector += ic->sectors_per_block; 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci journal_entry++; 214362306a36Sopenharmony_ci if (unlikely(journal_entry == ic->journal_section_entries)) { 214462306a36Sopenharmony_ci journal_entry = 0; 214562306a36Sopenharmony_ci journal_section++; 214662306a36Sopenharmony_ci wraparound_section(ic, &journal_section); 214762306a36Sopenharmony_ci } 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci bv.bv_offset += ic->sectors_per_block << SECTOR_SHIFT; 215062306a36Sopenharmony_ci } while (bv.bv_len -= ic->sectors_per_block << SECTOR_SHIFT); 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci if (unlikely(dio->op == REQ_OP_READ)) 215362306a36Sopenharmony_ci flush_dcache_page(bv.bv_page); 215462306a36Sopenharmony_ci kunmap_local(mem); 215562306a36Sopenharmony_ci } while (n_sectors); 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ci if (likely(dio->op == REQ_OP_WRITE)) { 215862306a36Sopenharmony_ci smp_mb(); 215962306a36Sopenharmony_ci if (unlikely(waitqueue_active(&ic->copy_to_journal_wait))) 216062306a36Sopenharmony_ci wake_up(&ic->copy_to_journal_wait); 216162306a36Sopenharmony_ci if (READ_ONCE(ic->free_sectors) <= ic->free_sectors_threshold) 216262306a36Sopenharmony_ci queue_work(ic->commit_wq, &ic->commit_work); 216362306a36Sopenharmony_ci else 216462306a36Sopenharmony_ci schedule_autocommit(ic); 216562306a36Sopenharmony_ci } else 216662306a36Sopenharmony_ci remove_range(ic, &dio->range); 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci if (unlikely(bio->bi_iter.bi_size)) { 216962306a36Sopenharmony_ci sector_t area, offset; 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci dio->range.logical_sector = logical_sector; 217262306a36Sopenharmony_ci get_area_and_offset(ic, dio->range.logical_sector, &area, &offset); 217362306a36Sopenharmony_ci dio->metadata_block = get_metadata_sector_and_offset(ic, area, offset, &dio->metadata_offset); 217462306a36Sopenharmony_ci return true; 217562306a36Sopenharmony_ci } 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci return false; 217862306a36Sopenharmony_ci} 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_cistatic void dm_integrity_map_continue(struct dm_integrity_io *dio, bool from_map) 218162306a36Sopenharmony_ci{ 218262306a36Sopenharmony_ci struct dm_integrity_c *ic = dio->ic; 218362306a36Sopenharmony_ci struct bio *bio = dm_bio_from_per_bio_data(dio, sizeof(struct dm_integrity_io)); 218462306a36Sopenharmony_ci unsigned int journal_section, journal_entry; 218562306a36Sopenharmony_ci unsigned int journal_read_pos; 218662306a36Sopenharmony_ci struct completion read_comp; 218762306a36Sopenharmony_ci bool discard_retried = false; 218862306a36Sopenharmony_ci bool need_sync_io = ic->internal_hash && dio->op == REQ_OP_READ; 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci if (unlikely(dio->op == REQ_OP_DISCARD) && ic->mode != 'D') 219162306a36Sopenharmony_ci need_sync_io = true; 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci if (need_sync_io && from_map) { 219462306a36Sopenharmony_ci INIT_WORK(&dio->work, integrity_bio_wait); 219562306a36Sopenharmony_ci queue_work(ic->offload_wq, &dio->work); 219662306a36Sopenharmony_ci return; 219762306a36Sopenharmony_ci } 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_cilock_retry: 220062306a36Sopenharmony_ci spin_lock_irq(&ic->endio_wait.lock); 220162306a36Sopenharmony_ciretry: 220262306a36Sopenharmony_ci if (unlikely(dm_integrity_failed(ic))) { 220362306a36Sopenharmony_ci spin_unlock_irq(&ic->endio_wait.lock); 220462306a36Sopenharmony_ci do_endio(ic, bio); 220562306a36Sopenharmony_ci return; 220662306a36Sopenharmony_ci } 220762306a36Sopenharmony_ci dio->range.n_sectors = bio_sectors(bio); 220862306a36Sopenharmony_ci journal_read_pos = NOT_FOUND; 220962306a36Sopenharmony_ci if (ic->mode == 'J' && likely(dio->op != REQ_OP_DISCARD)) { 221062306a36Sopenharmony_ci if (dio->op == REQ_OP_WRITE) { 221162306a36Sopenharmony_ci unsigned int next_entry, i, pos; 221262306a36Sopenharmony_ci unsigned int ws, we, range_sectors; 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci dio->range.n_sectors = min(dio->range.n_sectors, 221562306a36Sopenharmony_ci (sector_t)ic->free_sectors << ic->sb->log2_sectors_per_block); 221662306a36Sopenharmony_ci if (unlikely(!dio->range.n_sectors)) { 221762306a36Sopenharmony_ci if (from_map) 221862306a36Sopenharmony_ci goto offload_to_thread; 221962306a36Sopenharmony_ci sleep_on_endio_wait(ic); 222062306a36Sopenharmony_ci goto retry; 222162306a36Sopenharmony_ci } 222262306a36Sopenharmony_ci range_sectors = dio->range.n_sectors >> ic->sb->log2_sectors_per_block; 222362306a36Sopenharmony_ci ic->free_sectors -= range_sectors; 222462306a36Sopenharmony_ci journal_section = ic->free_section; 222562306a36Sopenharmony_ci journal_entry = ic->free_section_entry; 222662306a36Sopenharmony_ci 222762306a36Sopenharmony_ci next_entry = ic->free_section_entry + range_sectors; 222862306a36Sopenharmony_ci ic->free_section_entry = next_entry % ic->journal_section_entries; 222962306a36Sopenharmony_ci ic->free_section += next_entry / ic->journal_section_entries; 223062306a36Sopenharmony_ci ic->n_uncommitted_sections += next_entry / ic->journal_section_entries; 223162306a36Sopenharmony_ci wraparound_section(ic, &ic->free_section); 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci pos = journal_section * ic->journal_section_entries + journal_entry; 223462306a36Sopenharmony_ci ws = journal_section; 223562306a36Sopenharmony_ci we = journal_entry; 223662306a36Sopenharmony_ci i = 0; 223762306a36Sopenharmony_ci do { 223862306a36Sopenharmony_ci struct journal_entry *je; 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_ci add_journal_node(ic, &ic->journal_tree[pos], dio->range.logical_sector + i); 224162306a36Sopenharmony_ci pos++; 224262306a36Sopenharmony_ci if (unlikely(pos >= ic->journal_entries)) 224362306a36Sopenharmony_ci pos = 0; 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_ci je = access_journal_entry(ic, ws, we); 224662306a36Sopenharmony_ci BUG_ON(!journal_entry_is_unused(je)); 224762306a36Sopenharmony_ci journal_entry_set_inprogress(je); 224862306a36Sopenharmony_ci we++; 224962306a36Sopenharmony_ci if (unlikely(we == ic->journal_section_entries)) { 225062306a36Sopenharmony_ci we = 0; 225162306a36Sopenharmony_ci ws++; 225262306a36Sopenharmony_ci wraparound_section(ic, &ws); 225362306a36Sopenharmony_ci } 225462306a36Sopenharmony_ci } while ((i += ic->sectors_per_block) < dio->range.n_sectors); 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci spin_unlock_irq(&ic->endio_wait.lock); 225762306a36Sopenharmony_ci goto journal_read_write; 225862306a36Sopenharmony_ci } else { 225962306a36Sopenharmony_ci sector_t next_sector; 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_ci journal_read_pos = find_journal_node(ic, dio->range.logical_sector, &next_sector); 226262306a36Sopenharmony_ci if (likely(journal_read_pos == NOT_FOUND)) { 226362306a36Sopenharmony_ci if (unlikely(dio->range.n_sectors > next_sector - dio->range.logical_sector)) 226462306a36Sopenharmony_ci dio->range.n_sectors = next_sector - dio->range.logical_sector; 226562306a36Sopenharmony_ci } else { 226662306a36Sopenharmony_ci unsigned int i; 226762306a36Sopenharmony_ci unsigned int jp = journal_read_pos + 1; 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci for (i = ic->sectors_per_block; i < dio->range.n_sectors; i += ic->sectors_per_block, jp++) { 227062306a36Sopenharmony_ci if (!test_journal_node(ic, jp, dio->range.logical_sector + i)) 227162306a36Sopenharmony_ci break; 227262306a36Sopenharmony_ci } 227362306a36Sopenharmony_ci dio->range.n_sectors = i; 227462306a36Sopenharmony_ci } 227562306a36Sopenharmony_ci } 227662306a36Sopenharmony_ci } 227762306a36Sopenharmony_ci if (unlikely(!add_new_range(ic, &dio->range, true))) { 227862306a36Sopenharmony_ci /* 227962306a36Sopenharmony_ci * We must not sleep in the request routine because it could 228062306a36Sopenharmony_ci * stall bios on current->bio_list. 228162306a36Sopenharmony_ci * So, we offload the bio to a workqueue if we have to sleep. 228262306a36Sopenharmony_ci */ 228362306a36Sopenharmony_ci if (from_map) { 228462306a36Sopenharmony_cioffload_to_thread: 228562306a36Sopenharmony_ci spin_unlock_irq(&ic->endio_wait.lock); 228662306a36Sopenharmony_ci INIT_WORK(&dio->work, integrity_bio_wait); 228762306a36Sopenharmony_ci queue_work(ic->wait_wq, &dio->work); 228862306a36Sopenharmony_ci return; 228962306a36Sopenharmony_ci } 229062306a36Sopenharmony_ci if (journal_read_pos != NOT_FOUND) 229162306a36Sopenharmony_ci dio->range.n_sectors = ic->sectors_per_block; 229262306a36Sopenharmony_ci wait_and_add_new_range(ic, &dio->range); 229362306a36Sopenharmony_ci /* 229462306a36Sopenharmony_ci * wait_and_add_new_range drops the spinlock, so the journal 229562306a36Sopenharmony_ci * may have been changed arbitrarily. We need to recheck. 229662306a36Sopenharmony_ci * To simplify the code, we restrict I/O size to just one block. 229762306a36Sopenharmony_ci */ 229862306a36Sopenharmony_ci if (journal_read_pos != NOT_FOUND) { 229962306a36Sopenharmony_ci sector_t next_sector; 230062306a36Sopenharmony_ci unsigned int new_pos; 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci new_pos = find_journal_node(ic, dio->range.logical_sector, &next_sector); 230362306a36Sopenharmony_ci if (unlikely(new_pos != journal_read_pos)) { 230462306a36Sopenharmony_ci remove_range_unlocked(ic, &dio->range); 230562306a36Sopenharmony_ci goto retry; 230662306a36Sopenharmony_ci } 230762306a36Sopenharmony_ci } 230862306a36Sopenharmony_ci } 230962306a36Sopenharmony_ci if (ic->mode == 'J' && likely(dio->op == REQ_OP_DISCARD) && !discard_retried) { 231062306a36Sopenharmony_ci sector_t next_sector; 231162306a36Sopenharmony_ci unsigned int new_pos; 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci new_pos = find_journal_node(ic, dio->range.logical_sector, &next_sector); 231462306a36Sopenharmony_ci if (unlikely(new_pos != NOT_FOUND) || 231562306a36Sopenharmony_ci unlikely(next_sector < dio->range.logical_sector - dio->range.n_sectors)) { 231662306a36Sopenharmony_ci remove_range_unlocked(ic, &dio->range); 231762306a36Sopenharmony_ci spin_unlock_irq(&ic->endio_wait.lock); 231862306a36Sopenharmony_ci queue_work(ic->commit_wq, &ic->commit_work); 231962306a36Sopenharmony_ci flush_workqueue(ic->commit_wq); 232062306a36Sopenharmony_ci queue_work(ic->writer_wq, &ic->writer_work); 232162306a36Sopenharmony_ci flush_workqueue(ic->writer_wq); 232262306a36Sopenharmony_ci discard_retried = true; 232362306a36Sopenharmony_ci goto lock_retry; 232462306a36Sopenharmony_ci } 232562306a36Sopenharmony_ci } 232662306a36Sopenharmony_ci spin_unlock_irq(&ic->endio_wait.lock); 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci if (unlikely(journal_read_pos != NOT_FOUND)) { 232962306a36Sopenharmony_ci journal_section = journal_read_pos / ic->journal_section_entries; 233062306a36Sopenharmony_ci journal_entry = journal_read_pos % ic->journal_section_entries; 233162306a36Sopenharmony_ci goto journal_read_write; 233262306a36Sopenharmony_ci } 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci if (ic->mode == 'B' && (dio->op == REQ_OP_WRITE || unlikely(dio->op == REQ_OP_DISCARD))) { 233562306a36Sopenharmony_ci if (!block_bitmap_op(ic, ic->may_write_bitmap, dio->range.logical_sector, 233662306a36Sopenharmony_ci dio->range.n_sectors, BITMAP_OP_TEST_ALL_SET)) { 233762306a36Sopenharmony_ci struct bitmap_block_status *bbs; 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci bbs = sector_to_bitmap_block(ic, dio->range.logical_sector); 234062306a36Sopenharmony_ci spin_lock(&bbs->bio_queue_lock); 234162306a36Sopenharmony_ci bio_list_add(&bbs->bio_queue, bio); 234262306a36Sopenharmony_ci spin_unlock(&bbs->bio_queue_lock); 234362306a36Sopenharmony_ci queue_work(ic->writer_wq, &bbs->work); 234462306a36Sopenharmony_ci return; 234562306a36Sopenharmony_ci } 234662306a36Sopenharmony_ci } 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci dio->in_flight = (atomic_t)ATOMIC_INIT(2); 234962306a36Sopenharmony_ci 235062306a36Sopenharmony_ci if (need_sync_io) { 235162306a36Sopenharmony_ci init_completion(&read_comp); 235262306a36Sopenharmony_ci dio->completion = &read_comp; 235362306a36Sopenharmony_ci } else 235462306a36Sopenharmony_ci dio->completion = NULL; 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci dm_bio_record(&dio->bio_details, bio); 235762306a36Sopenharmony_ci bio_set_dev(bio, ic->dev->bdev); 235862306a36Sopenharmony_ci bio->bi_integrity = NULL; 235962306a36Sopenharmony_ci bio->bi_opf &= ~REQ_INTEGRITY; 236062306a36Sopenharmony_ci bio->bi_end_io = integrity_end_io; 236162306a36Sopenharmony_ci bio->bi_iter.bi_size = dio->range.n_sectors << SECTOR_SHIFT; 236262306a36Sopenharmony_ci 236362306a36Sopenharmony_ci if (unlikely(dio->op == REQ_OP_DISCARD) && likely(ic->mode != 'D')) { 236462306a36Sopenharmony_ci integrity_metadata(&dio->work); 236562306a36Sopenharmony_ci dm_integrity_flush_buffers(ic, false); 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci dio->in_flight = (atomic_t)ATOMIC_INIT(1); 236862306a36Sopenharmony_ci dio->completion = NULL; 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci submit_bio_noacct(bio); 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_ci return; 237362306a36Sopenharmony_ci } 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci submit_bio_noacct(bio); 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci if (need_sync_io) { 237862306a36Sopenharmony_ci wait_for_completion_io(&read_comp); 237962306a36Sopenharmony_ci if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING) && 238062306a36Sopenharmony_ci dio->range.logical_sector + dio->range.n_sectors > le64_to_cpu(ic->sb->recalc_sector)) 238162306a36Sopenharmony_ci goto skip_check; 238262306a36Sopenharmony_ci if (ic->mode == 'B') { 238362306a36Sopenharmony_ci if (!block_bitmap_op(ic, ic->recalc_bitmap, dio->range.logical_sector, 238462306a36Sopenharmony_ci dio->range.n_sectors, BITMAP_OP_TEST_ALL_CLEAR)) 238562306a36Sopenharmony_ci goto skip_check; 238662306a36Sopenharmony_ci } 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci if (likely(!bio->bi_status)) 238962306a36Sopenharmony_ci integrity_metadata(&dio->work); 239062306a36Sopenharmony_ci else 239162306a36Sopenharmony_ciskip_check: 239262306a36Sopenharmony_ci dec_in_flight(dio); 239362306a36Sopenharmony_ci } else { 239462306a36Sopenharmony_ci INIT_WORK(&dio->work, integrity_metadata); 239562306a36Sopenharmony_ci queue_work(ic->metadata_wq, &dio->work); 239662306a36Sopenharmony_ci } 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_ci return; 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_cijournal_read_write: 240162306a36Sopenharmony_ci if (unlikely(__journal_read_write(dio, bio, journal_section, journal_entry))) 240262306a36Sopenharmony_ci goto lock_retry; 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_ci do_endio_flush(ic, dio); 240562306a36Sopenharmony_ci} 240662306a36Sopenharmony_ci 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_cistatic void integrity_bio_wait(struct work_struct *w) 240962306a36Sopenharmony_ci{ 241062306a36Sopenharmony_ci struct dm_integrity_io *dio = container_of(w, struct dm_integrity_io, work); 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci dm_integrity_map_continue(dio, false); 241362306a36Sopenharmony_ci} 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_cistatic void pad_uncommitted(struct dm_integrity_c *ic) 241662306a36Sopenharmony_ci{ 241762306a36Sopenharmony_ci if (ic->free_section_entry) { 241862306a36Sopenharmony_ci ic->free_sectors -= ic->journal_section_entries - ic->free_section_entry; 241962306a36Sopenharmony_ci ic->free_section_entry = 0; 242062306a36Sopenharmony_ci ic->free_section++; 242162306a36Sopenharmony_ci wraparound_section(ic, &ic->free_section); 242262306a36Sopenharmony_ci ic->n_uncommitted_sections++; 242362306a36Sopenharmony_ci } 242462306a36Sopenharmony_ci if (WARN_ON(ic->journal_sections * ic->journal_section_entries != 242562306a36Sopenharmony_ci (ic->n_uncommitted_sections + ic->n_committed_sections) * 242662306a36Sopenharmony_ci ic->journal_section_entries + ic->free_sectors)) { 242762306a36Sopenharmony_ci DMCRIT("journal_sections %u, journal_section_entries %u, " 242862306a36Sopenharmony_ci "n_uncommitted_sections %u, n_committed_sections %u, " 242962306a36Sopenharmony_ci "journal_section_entries %u, free_sectors %u", 243062306a36Sopenharmony_ci ic->journal_sections, ic->journal_section_entries, 243162306a36Sopenharmony_ci ic->n_uncommitted_sections, ic->n_committed_sections, 243262306a36Sopenharmony_ci ic->journal_section_entries, ic->free_sectors); 243362306a36Sopenharmony_ci } 243462306a36Sopenharmony_ci} 243562306a36Sopenharmony_ci 243662306a36Sopenharmony_cistatic void integrity_commit(struct work_struct *w) 243762306a36Sopenharmony_ci{ 243862306a36Sopenharmony_ci struct dm_integrity_c *ic = container_of(w, struct dm_integrity_c, commit_work); 243962306a36Sopenharmony_ci unsigned int commit_start, commit_sections; 244062306a36Sopenharmony_ci unsigned int i, j, n; 244162306a36Sopenharmony_ci struct bio *flushes; 244262306a36Sopenharmony_ci 244362306a36Sopenharmony_ci del_timer(&ic->autocommit_timer); 244462306a36Sopenharmony_ci 244562306a36Sopenharmony_ci spin_lock_irq(&ic->endio_wait.lock); 244662306a36Sopenharmony_ci flushes = bio_list_get(&ic->flush_bio_list); 244762306a36Sopenharmony_ci if (unlikely(ic->mode != 'J')) { 244862306a36Sopenharmony_ci spin_unlock_irq(&ic->endio_wait.lock); 244962306a36Sopenharmony_ci dm_integrity_flush_buffers(ic, true); 245062306a36Sopenharmony_ci goto release_flush_bios; 245162306a36Sopenharmony_ci } 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci pad_uncommitted(ic); 245462306a36Sopenharmony_ci commit_start = ic->uncommitted_section; 245562306a36Sopenharmony_ci commit_sections = ic->n_uncommitted_sections; 245662306a36Sopenharmony_ci spin_unlock_irq(&ic->endio_wait.lock); 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ci if (!commit_sections) 245962306a36Sopenharmony_ci goto release_flush_bios; 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_ci ic->wrote_to_journal = true; 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci i = commit_start; 246462306a36Sopenharmony_ci for (n = 0; n < commit_sections; n++) { 246562306a36Sopenharmony_ci for (j = 0; j < ic->journal_section_entries; j++) { 246662306a36Sopenharmony_ci struct journal_entry *je; 246762306a36Sopenharmony_ci 246862306a36Sopenharmony_ci je = access_journal_entry(ic, i, j); 246962306a36Sopenharmony_ci io_wait_event(ic->copy_to_journal_wait, !journal_entry_is_inprogress(je)); 247062306a36Sopenharmony_ci } 247162306a36Sopenharmony_ci for (j = 0; j < ic->journal_section_sectors; j++) { 247262306a36Sopenharmony_ci struct journal_sector *js; 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci js = access_journal(ic, i, j); 247562306a36Sopenharmony_ci js->commit_id = dm_integrity_commit_id(ic, i, j, ic->commit_seq); 247662306a36Sopenharmony_ci } 247762306a36Sopenharmony_ci i++; 247862306a36Sopenharmony_ci if (unlikely(i >= ic->journal_sections)) 247962306a36Sopenharmony_ci ic->commit_seq = next_commit_seq(ic->commit_seq); 248062306a36Sopenharmony_ci wraparound_section(ic, &i); 248162306a36Sopenharmony_ci } 248262306a36Sopenharmony_ci smp_rmb(); 248362306a36Sopenharmony_ci 248462306a36Sopenharmony_ci write_journal(ic, commit_start, commit_sections); 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci spin_lock_irq(&ic->endio_wait.lock); 248762306a36Sopenharmony_ci ic->uncommitted_section += commit_sections; 248862306a36Sopenharmony_ci wraparound_section(ic, &ic->uncommitted_section); 248962306a36Sopenharmony_ci ic->n_uncommitted_sections -= commit_sections; 249062306a36Sopenharmony_ci ic->n_committed_sections += commit_sections; 249162306a36Sopenharmony_ci spin_unlock_irq(&ic->endio_wait.lock); 249262306a36Sopenharmony_ci 249362306a36Sopenharmony_ci if (READ_ONCE(ic->free_sectors) <= ic->free_sectors_threshold) 249462306a36Sopenharmony_ci queue_work(ic->writer_wq, &ic->writer_work); 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_cirelease_flush_bios: 249762306a36Sopenharmony_ci while (flushes) { 249862306a36Sopenharmony_ci struct bio *next = flushes->bi_next; 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_ci flushes->bi_next = NULL; 250162306a36Sopenharmony_ci do_endio(ic, flushes); 250262306a36Sopenharmony_ci flushes = next; 250362306a36Sopenharmony_ci } 250462306a36Sopenharmony_ci} 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_cistatic void complete_copy_from_journal(unsigned long error, void *context) 250762306a36Sopenharmony_ci{ 250862306a36Sopenharmony_ci struct journal_io *io = context; 250962306a36Sopenharmony_ci struct journal_completion *comp = io->comp; 251062306a36Sopenharmony_ci struct dm_integrity_c *ic = comp->ic; 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci remove_range(ic, &io->range); 251362306a36Sopenharmony_ci mempool_free(io, &ic->journal_io_mempool); 251462306a36Sopenharmony_ci if (unlikely(error != 0)) 251562306a36Sopenharmony_ci dm_integrity_io_error(ic, "copying from journal", -EIO); 251662306a36Sopenharmony_ci complete_journal_op(comp); 251762306a36Sopenharmony_ci} 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_cistatic void restore_last_bytes(struct dm_integrity_c *ic, struct journal_sector *js, 252062306a36Sopenharmony_ci struct journal_entry *je) 252162306a36Sopenharmony_ci{ 252262306a36Sopenharmony_ci unsigned int s = 0; 252362306a36Sopenharmony_ci 252462306a36Sopenharmony_ci do { 252562306a36Sopenharmony_ci js->commit_id = je->last_bytes[s]; 252662306a36Sopenharmony_ci js++; 252762306a36Sopenharmony_ci } while (++s < ic->sectors_per_block); 252862306a36Sopenharmony_ci} 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_cistatic void do_journal_write(struct dm_integrity_c *ic, unsigned int write_start, 253162306a36Sopenharmony_ci unsigned int write_sections, bool from_replay) 253262306a36Sopenharmony_ci{ 253362306a36Sopenharmony_ci unsigned int i, j, n; 253462306a36Sopenharmony_ci struct journal_completion comp; 253562306a36Sopenharmony_ci struct blk_plug plug; 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_ci blk_start_plug(&plug); 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_ci comp.ic = ic; 254062306a36Sopenharmony_ci comp.in_flight = (atomic_t)ATOMIC_INIT(1); 254162306a36Sopenharmony_ci init_completion(&comp.comp); 254262306a36Sopenharmony_ci 254362306a36Sopenharmony_ci i = write_start; 254462306a36Sopenharmony_ci for (n = 0; n < write_sections; n++, i++, wraparound_section(ic, &i)) { 254562306a36Sopenharmony_ci#ifndef INTERNAL_VERIFY 254662306a36Sopenharmony_ci if (unlikely(from_replay)) 254762306a36Sopenharmony_ci#endif 254862306a36Sopenharmony_ci rw_section_mac(ic, i, false); 254962306a36Sopenharmony_ci for (j = 0; j < ic->journal_section_entries; j++) { 255062306a36Sopenharmony_ci struct journal_entry *je = access_journal_entry(ic, i, j); 255162306a36Sopenharmony_ci sector_t sec, area, offset; 255262306a36Sopenharmony_ci unsigned int k, l, next_loop; 255362306a36Sopenharmony_ci sector_t metadata_block; 255462306a36Sopenharmony_ci unsigned int metadata_offset; 255562306a36Sopenharmony_ci struct journal_io *io; 255662306a36Sopenharmony_ci 255762306a36Sopenharmony_ci if (journal_entry_is_unused(je)) 255862306a36Sopenharmony_ci continue; 255962306a36Sopenharmony_ci BUG_ON(unlikely(journal_entry_is_inprogress(je)) && !from_replay); 256062306a36Sopenharmony_ci sec = journal_entry_get_sector(je); 256162306a36Sopenharmony_ci if (unlikely(from_replay)) { 256262306a36Sopenharmony_ci if (unlikely(sec & (unsigned int)(ic->sectors_per_block - 1))) { 256362306a36Sopenharmony_ci dm_integrity_io_error(ic, "invalid sector in journal", -EIO); 256462306a36Sopenharmony_ci sec &= ~(sector_t)(ic->sectors_per_block - 1); 256562306a36Sopenharmony_ci } 256662306a36Sopenharmony_ci if (unlikely(sec >= ic->provided_data_sectors)) { 256762306a36Sopenharmony_ci journal_entry_set_unused(je); 256862306a36Sopenharmony_ci continue; 256962306a36Sopenharmony_ci } 257062306a36Sopenharmony_ci } 257162306a36Sopenharmony_ci get_area_and_offset(ic, sec, &area, &offset); 257262306a36Sopenharmony_ci restore_last_bytes(ic, access_journal_data(ic, i, j), je); 257362306a36Sopenharmony_ci for (k = j + 1; k < ic->journal_section_entries; k++) { 257462306a36Sopenharmony_ci struct journal_entry *je2 = access_journal_entry(ic, i, k); 257562306a36Sopenharmony_ci sector_t sec2, area2, offset2; 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci if (journal_entry_is_unused(je2)) 257862306a36Sopenharmony_ci break; 257962306a36Sopenharmony_ci BUG_ON(unlikely(journal_entry_is_inprogress(je2)) && !from_replay); 258062306a36Sopenharmony_ci sec2 = journal_entry_get_sector(je2); 258162306a36Sopenharmony_ci if (unlikely(sec2 >= ic->provided_data_sectors)) 258262306a36Sopenharmony_ci break; 258362306a36Sopenharmony_ci get_area_and_offset(ic, sec2, &area2, &offset2); 258462306a36Sopenharmony_ci if (area2 != area || offset2 != offset + ((k - j) << ic->sb->log2_sectors_per_block)) 258562306a36Sopenharmony_ci break; 258662306a36Sopenharmony_ci restore_last_bytes(ic, access_journal_data(ic, i, k), je2); 258762306a36Sopenharmony_ci } 258862306a36Sopenharmony_ci next_loop = k - 1; 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci io = mempool_alloc(&ic->journal_io_mempool, GFP_NOIO); 259162306a36Sopenharmony_ci io->comp = ∁ 259262306a36Sopenharmony_ci io->range.logical_sector = sec; 259362306a36Sopenharmony_ci io->range.n_sectors = (k - j) << ic->sb->log2_sectors_per_block; 259462306a36Sopenharmony_ci 259562306a36Sopenharmony_ci spin_lock_irq(&ic->endio_wait.lock); 259662306a36Sopenharmony_ci add_new_range_and_wait(ic, &io->range); 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_ci if (likely(!from_replay)) { 259962306a36Sopenharmony_ci struct journal_node *section_node = &ic->journal_tree[i * ic->journal_section_entries]; 260062306a36Sopenharmony_ci 260162306a36Sopenharmony_ci /* don't write if there is newer committed sector */ 260262306a36Sopenharmony_ci while (j < k && find_newer_committed_node(ic, §ion_node[j])) { 260362306a36Sopenharmony_ci struct journal_entry *je2 = access_journal_entry(ic, i, j); 260462306a36Sopenharmony_ci 260562306a36Sopenharmony_ci journal_entry_set_unused(je2); 260662306a36Sopenharmony_ci remove_journal_node(ic, §ion_node[j]); 260762306a36Sopenharmony_ci j++; 260862306a36Sopenharmony_ci sec += ic->sectors_per_block; 260962306a36Sopenharmony_ci offset += ic->sectors_per_block; 261062306a36Sopenharmony_ci } 261162306a36Sopenharmony_ci while (j < k && find_newer_committed_node(ic, §ion_node[k - 1])) { 261262306a36Sopenharmony_ci struct journal_entry *je2 = access_journal_entry(ic, i, k - 1); 261362306a36Sopenharmony_ci 261462306a36Sopenharmony_ci journal_entry_set_unused(je2); 261562306a36Sopenharmony_ci remove_journal_node(ic, §ion_node[k - 1]); 261662306a36Sopenharmony_ci k--; 261762306a36Sopenharmony_ci } 261862306a36Sopenharmony_ci if (j == k) { 261962306a36Sopenharmony_ci remove_range_unlocked(ic, &io->range); 262062306a36Sopenharmony_ci spin_unlock_irq(&ic->endio_wait.lock); 262162306a36Sopenharmony_ci mempool_free(io, &ic->journal_io_mempool); 262262306a36Sopenharmony_ci goto skip_io; 262362306a36Sopenharmony_ci } 262462306a36Sopenharmony_ci for (l = j; l < k; l++) 262562306a36Sopenharmony_ci remove_journal_node(ic, §ion_node[l]); 262662306a36Sopenharmony_ci } 262762306a36Sopenharmony_ci spin_unlock_irq(&ic->endio_wait.lock); 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_ci metadata_block = get_metadata_sector_and_offset(ic, area, offset, &metadata_offset); 263062306a36Sopenharmony_ci for (l = j; l < k; l++) { 263162306a36Sopenharmony_ci int r; 263262306a36Sopenharmony_ci struct journal_entry *je2 = access_journal_entry(ic, i, l); 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ci if ( 263562306a36Sopenharmony_ci#ifndef INTERNAL_VERIFY 263662306a36Sopenharmony_ci unlikely(from_replay) && 263762306a36Sopenharmony_ci#endif 263862306a36Sopenharmony_ci ic->internal_hash) { 263962306a36Sopenharmony_ci char test_tag[max_t(size_t, HASH_MAX_DIGESTSIZE, MAX_TAG_SIZE)]; 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci integrity_sector_checksum(ic, sec + ((l - j) << ic->sb->log2_sectors_per_block), 264262306a36Sopenharmony_ci (char *)access_journal_data(ic, i, l), test_tag); 264362306a36Sopenharmony_ci if (unlikely(memcmp(test_tag, journal_entry_tag(ic, je2), ic->tag_size))) { 264462306a36Sopenharmony_ci dm_integrity_io_error(ic, "tag mismatch when replaying journal", -EILSEQ); 264562306a36Sopenharmony_ci dm_audit_log_target(DM_MSG_PREFIX, "integrity-replay-journal", ic->ti, 0); 264662306a36Sopenharmony_ci } 264762306a36Sopenharmony_ci } 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_ci journal_entry_set_unused(je2); 265062306a36Sopenharmony_ci r = dm_integrity_rw_tag(ic, journal_entry_tag(ic, je2), &metadata_block, &metadata_offset, 265162306a36Sopenharmony_ci ic->tag_size, TAG_WRITE); 265262306a36Sopenharmony_ci if (unlikely(r)) 265362306a36Sopenharmony_ci dm_integrity_io_error(ic, "reading tags", r); 265462306a36Sopenharmony_ci } 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci atomic_inc(&comp.in_flight); 265762306a36Sopenharmony_ci copy_from_journal(ic, i, j << ic->sb->log2_sectors_per_block, 265862306a36Sopenharmony_ci (k - j) << ic->sb->log2_sectors_per_block, 265962306a36Sopenharmony_ci get_data_sector(ic, area, offset), 266062306a36Sopenharmony_ci complete_copy_from_journal, io); 266162306a36Sopenharmony_ciskip_io: 266262306a36Sopenharmony_ci j = next_loop; 266362306a36Sopenharmony_ci } 266462306a36Sopenharmony_ci } 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_ci dm_bufio_write_dirty_buffers_async(ic->bufio); 266762306a36Sopenharmony_ci 266862306a36Sopenharmony_ci blk_finish_plug(&plug); 266962306a36Sopenharmony_ci 267062306a36Sopenharmony_ci complete_journal_op(&comp); 267162306a36Sopenharmony_ci wait_for_completion_io(&comp.comp); 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci dm_integrity_flush_buffers(ic, true); 267462306a36Sopenharmony_ci} 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_cistatic void integrity_writer(struct work_struct *w) 267762306a36Sopenharmony_ci{ 267862306a36Sopenharmony_ci struct dm_integrity_c *ic = container_of(w, struct dm_integrity_c, writer_work); 267962306a36Sopenharmony_ci unsigned int write_start, write_sections; 268062306a36Sopenharmony_ci unsigned int prev_free_sectors; 268162306a36Sopenharmony_ci 268262306a36Sopenharmony_ci spin_lock_irq(&ic->endio_wait.lock); 268362306a36Sopenharmony_ci write_start = ic->committed_section; 268462306a36Sopenharmony_ci write_sections = ic->n_committed_sections; 268562306a36Sopenharmony_ci spin_unlock_irq(&ic->endio_wait.lock); 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci if (!write_sections) 268862306a36Sopenharmony_ci return; 268962306a36Sopenharmony_ci 269062306a36Sopenharmony_ci do_journal_write(ic, write_start, write_sections, false); 269162306a36Sopenharmony_ci 269262306a36Sopenharmony_ci spin_lock_irq(&ic->endio_wait.lock); 269362306a36Sopenharmony_ci 269462306a36Sopenharmony_ci ic->committed_section += write_sections; 269562306a36Sopenharmony_ci wraparound_section(ic, &ic->committed_section); 269662306a36Sopenharmony_ci ic->n_committed_sections -= write_sections; 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_ci prev_free_sectors = ic->free_sectors; 269962306a36Sopenharmony_ci ic->free_sectors += write_sections * ic->journal_section_entries; 270062306a36Sopenharmony_ci if (unlikely(!prev_free_sectors)) 270162306a36Sopenharmony_ci wake_up_locked(&ic->endio_wait); 270262306a36Sopenharmony_ci 270362306a36Sopenharmony_ci spin_unlock_irq(&ic->endio_wait.lock); 270462306a36Sopenharmony_ci} 270562306a36Sopenharmony_ci 270662306a36Sopenharmony_cistatic void recalc_write_super(struct dm_integrity_c *ic) 270762306a36Sopenharmony_ci{ 270862306a36Sopenharmony_ci int r; 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci dm_integrity_flush_buffers(ic, false); 271162306a36Sopenharmony_ci if (dm_integrity_failed(ic)) 271262306a36Sopenharmony_ci return; 271362306a36Sopenharmony_ci 271462306a36Sopenharmony_ci r = sync_rw_sb(ic, REQ_OP_WRITE); 271562306a36Sopenharmony_ci if (unlikely(r)) 271662306a36Sopenharmony_ci dm_integrity_io_error(ic, "writing superblock", r); 271762306a36Sopenharmony_ci} 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_cistatic void integrity_recalc(struct work_struct *w) 272062306a36Sopenharmony_ci{ 272162306a36Sopenharmony_ci struct dm_integrity_c *ic = container_of(w, struct dm_integrity_c, recalc_work); 272262306a36Sopenharmony_ci size_t recalc_tags_size; 272362306a36Sopenharmony_ci u8 *recalc_buffer = NULL; 272462306a36Sopenharmony_ci u8 *recalc_tags = NULL; 272562306a36Sopenharmony_ci struct dm_integrity_range range; 272662306a36Sopenharmony_ci struct dm_io_request io_req; 272762306a36Sopenharmony_ci struct dm_io_region io_loc; 272862306a36Sopenharmony_ci sector_t area, offset; 272962306a36Sopenharmony_ci sector_t metadata_block; 273062306a36Sopenharmony_ci unsigned int metadata_offset; 273162306a36Sopenharmony_ci sector_t logical_sector, n_sectors; 273262306a36Sopenharmony_ci __u8 *t; 273362306a36Sopenharmony_ci unsigned int i; 273462306a36Sopenharmony_ci int r; 273562306a36Sopenharmony_ci unsigned int super_counter = 0; 273662306a36Sopenharmony_ci unsigned recalc_sectors = RECALC_SECTORS; 273762306a36Sopenharmony_ci 273862306a36Sopenharmony_ciretry: 273962306a36Sopenharmony_ci recalc_buffer = __vmalloc(recalc_sectors << SECTOR_SHIFT, GFP_NOIO); 274062306a36Sopenharmony_ci if (!recalc_buffer) { 274162306a36Sopenharmony_cioom: 274262306a36Sopenharmony_ci recalc_sectors >>= 1; 274362306a36Sopenharmony_ci if (recalc_sectors >= 1U << ic->sb->log2_sectors_per_block) 274462306a36Sopenharmony_ci goto retry; 274562306a36Sopenharmony_ci DMCRIT("out of memory for recalculate buffer - recalculation disabled"); 274662306a36Sopenharmony_ci goto free_ret; 274762306a36Sopenharmony_ci } 274862306a36Sopenharmony_ci recalc_tags_size = (recalc_sectors >> ic->sb->log2_sectors_per_block) * ic->tag_size; 274962306a36Sopenharmony_ci if (crypto_shash_digestsize(ic->internal_hash) > ic->tag_size) 275062306a36Sopenharmony_ci recalc_tags_size += crypto_shash_digestsize(ic->internal_hash) - ic->tag_size; 275162306a36Sopenharmony_ci recalc_tags = kvmalloc(recalc_tags_size, GFP_NOIO); 275262306a36Sopenharmony_ci if (!recalc_tags) { 275362306a36Sopenharmony_ci vfree(recalc_buffer); 275462306a36Sopenharmony_ci recalc_buffer = NULL; 275562306a36Sopenharmony_ci goto oom; 275662306a36Sopenharmony_ci } 275762306a36Sopenharmony_ci 275862306a36Sopenharmony_ci DEBUG_print("start recalculation... (position %llx)\n", le64_to_cpu(ic->sb->recalc_sector)); 275962306a36Sopenharmony_ci 276062306a36Sopenharmony_ci spin_lock_irq(&ic->endio_wait.lock); 276162306a36Sopenharmony_ci 276262306a36Sopenharmony_cinext_chunk: 276362306a36Sopenharmony_ci 276462306a36Sopenharmony_ci if (unlikely(dm_post_suspending(ic->ti))) 276562306a36Sopenharmony_ci goto unlock_ret; 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_ci range.logical_sector = le64_to_cpu(ic->sb->recalc_sector); 276862306a36Sopenharmony_ci if (unlikely(range.logical_sector >= ic->provided_data_sectors)) { 276962306a36Sopenharmony_ci if (ic->mode == 'B') { 277062306a36Sopenharmony_ci block_bitmap_op(ic, ic->recalc_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR); 277162306a36Sopenharmony_ci DEBUG_print("queue_delayed_work: bitmap_flush_work\n"); 277262306a36Sopenharmony_ci queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, 0); 277362306a36Sopenharmony_ci } 277462306a36Sopenharmony_ci goto unlock_ret; 277562306a36Sopenharmony_ci } 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_ci get_area_and_offset(ic, range.logical_sector, &area, &offset); 277862306a36Sopenharmony_ci range.n_sectors = min((sector_t)recalc_sectors, ic->provided_data_sectors - range.logical_sector); 277962306a36Sopenharmony_ci if (!ic->meta_dev) 278062306a36Sopenharmony_ci range.n_sectors = min(range.n_sectors, ((sector_t)1U << ic->sb->log2_interleave_sectors) - (unsigned int)offset); 278162306a36Sopenharmony_ci 278262306a36Sopenharmony_ci add_new_range_and_wait(ic, &range); 278362306a36Sopenharmony_ci spin_unlock_irq(&ic->endio_wait.lock); 278462306a36Sopenharmony_ci logical_sector = range.logical_sector; 278562306a36Sopenharmony_ci n_sectors = range.n_sectors; 278662306a36Sopenharmony_ci 278762306a36Sopenharmony_ci if (ic->mode == 'B') { 278862306a36Sopenharmony_ci if (block_bitmap_op(ic, ic->recalc_bitmap, logical_sector, n_sectors, BITMAP_OP_TEST_ALL_CLEAR)) 278962306a36Sopenharmony_ci goto advance_and_next; 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ci while (block_bitmap_op(ic, ic->recalc_bitmap, logical_sector, 279262306a36Sopenharmony_ci ic->sectors_per_block, BITMAP_OP_TEST_ALL_CLEAR)) { 279362306a36Sopenharmony_ci logical_sector += ic->sectors_per_block; 279462306a36Sopenharmony_ci n_sectors -= ic->sectors_per_block; 279562306a36Sopenharmony_ci cond_resched(); 279662306a36Sopenharmony_ci } 279762306a36Sopenharmony_ci while (block_bitmap_op(ic, ic->recalc_bitmap, logical_sector + n_sectors - ic->sectors_per_block, 279862306a36Sopenharmony_ci ic->sectors_per_block, BITMAP_OP_TEST_ALL_CLEAR)) { 279962306a36Sopenharmony_ci n_sectors -= ic->sectors_per_block; 280062306a36Sopenharmony_ci cond_resched(); 280162306a36Sopenharmony_ci } 280262306a36Sopenharmony_ci get_area_and_offset(ic, logical_sector, &area, &offset); 280362306a36Sopenharmony_ci } 280462306a36Sopenharmony_ci 280562306a36Sopenharmony_ci DEBUG_print("recalculating: %llx, %llx\n", logical_sector, n_sectors); 280662306a36Sopenharmony_ci 280762306a36Sopenharmony_ci if (unlikely(++super_counter == RECALC_WRITE_SUPER)) { 280862306a36Sopenharmony_ci recalc_write_super(ic); 280962306a36Sopenharmony_ci if (ic->mode == 'B') 281062306a36Sopenharmony_ci queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, ic->bitmap_flush_interval); 281162306a36Sopenharmony_ci 281262306a36Sopenharmony_ci super_counter = 0; 281362306a36Sopenharmony_ci } 281462306a36Sopenharmony_ci 281562306a36Sopenharmony_ci if (unlikely(dm_integrity_failed(ic))) 281662306a36Sopenharmony_ci goto err; 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_ci io_req.bi_opf = REQ_OP_READ; 281962306a36Sopenharmony_ci io_req.mem.type = DM_IO_VMA; 282062306a36Sopenharmony_ci io_req.mem.ptr.addr = recalc_buffer; 282162306a36Sopenharmony_ci io_req.notify.fn = NULL; 282262306a36Sopenharmony_ci io_req.client = ic->io; 282362306a36Sopenharmony_ci io_loc.bdev = ic->dev->bdev; 282462306a36Sopenharmony_ci io_loc.sector = get_data_sector(ic, area, offset); 282562306a36Sopenharmony_ci io_loc.count = n_sectors; 282662306a36Sopenharmony_ci 282762306a36Sopenharmony_ci r = dm_io(&io_req, 1, &io_loc, NULL, IOPRIO_DEFAULT); 282862306a36Sopenharmony_ci if (unlikely(r)) { 282962306a36Sopenharmony_ci dm_integrity_io_error(ic, "reading data", r); 283062306a36Sopenharmony_ci goto err; 283162306a36Sopenharmony_ci } 283262306a36Sopenharmony_ci 283362306a36Sopenharmony_ci t = recalc_tags; 283462306a36Sopenharmony_ci for (i = 0; i < n_sectors; i += ic->sectors_per_block) { 283562306a36Sopenharmony_ci integrity_sector_checksum(ic, logical_sector + i, recalc_buffer + (i << SECTOR_SHIFT), t); 283662306a36Sopenharmony_ci t += ic->tag_size; 283762306a36Sopenharmony_ci } 283862306a36Sopenharmony_ci 283962306a36Sopenharmony_ci metadata_block = get_metadata_sector_and_offset(ic, area, offset, &metadata_offset); 284062306a36Sopenharmony_ci 284162306a36Sopenharmony_ci r = dm_integrity_rw_tag(ic, recalc_tags, &metadata_block, &metadata_offset, t - recalc_tags, TAG_WRITE); 284262306a36Sopenharmony_ci if (unlikely(r)) { 284362306a36Sopenharmony_ci dm_integrity_io_error(ic, "writing tags", r); 284462306a36Sopenharmony_ci goto err; 284562306a36Sopenharmony_ci } 284662306a36Sopenharmony_ci 284762306a36Sopenharmony_ci if (ic->mode == 'B') { 284862306a36Sopenharmony_ci sector_t start, end; 284962306a36Sopenharmony_ci 285062306a36Sopenharmony_ci start = (range.logical_sector >> 285162306a36Sopenharmony_ci (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit)) << 285262306a36Sopenharmony_ci (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit); 285362306a36Sopenharmony_ci end = ((range.logical_sector + range.n_sectors) >> 285462306a36Sopenharmony_ci (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit)) << 285562306a36Sopenharmony_ci (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit); 285662306a36Sopenharmony_ci block_bitmap_op(ic, ic->recalc_bitmap, start, end - start, BITMAP_OP_CLEAR); 285762306a36Sopenharmony_ci } 285862306a36Sopenharmony_ci 285962306a36Sopenharmony_ciadvance_and_next: 286062306a36Sopenharmony_ci cond_resched(); 286162306a36Sopenharmony_ci 286262306a36Sopenharmony_ci spin_lock_irq(&ic->endio_wait.lock); 286362306a36Sopenharmony_ci remove_range_unlocked(ic, &range); 286462306a36Sopenharmony_ci ic->sb->recalc_sector = cpu_to_le64(range.logical_sector + range.n_sectors); 286562306a36Sopenharmony_ci goto next_chunk; 286662306a36Sopenharmony_ci 286762306a36Sopenharmony_cierr: 286862306a36Sopenharmony_ci remove_range(ic, &range); 286962306a36Sopenharmony_ci goto free_ret; 287062306a36Sopenharmony_ci 287162306a36Sopenharmony_ciunlock_ret: 287262306a36Sopenharmony_ci spin_unlock_irq(&ic->endio_wait.lock); 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_ci recalc_write_super(ic); 287562306a36Sopenharmony_ci 287662306a36Sopenharmony_cifree_ret: 287762306a36Sopenharmony_ci vfree(recalc_buffer); 287862306a36Sopenharmony_ci kvfree(recalc_tags); 287962306a36Sopenharmony_ci} 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_cistatic void bitmap_block_work(struct work_struct *w) 288262306a36Sopenharmony_ci{ 288362306a36Sopenharmony_ci struct bitmap_block_status *bbs = container_of(w, struct bitmap_block_status, work); 288462306a36Sopenharmony_ci struct dm_integrity_c *ic = bbs->ic; 288562306a36Sopenharmony_ci struct bio *bio; 288662306a36Sopenharmony_ci struct bio_list bio_queue; 288762306a36Sopenharmony_ci struct bio_list waiting; 288862306a36Sopenharmony_ci 288962306a36Sopenharmony_ci bio_list_init(&waiting); 289062306a36Sopenharmony_ci 289162306a36Sopenharmony_ci spin_lock(&bbs->bio_queue_lock); 289262306a36Sopenharmony_ci bio_queue = bbs->bio_queue; 289362306a36Sopenharmony_ci bio_list_init(&bbs->bio_queue); 289462306a36Sopenharmony_ci spin_unlock(&bbs->bio_queue_lock); 289562306a36Sopenharmony_ci 289662306a36Sopenharmony_ci while ((bio = bio_list_pop(&bio_queue))) { 289762306a36Sopenharmony_ci struct dm_integrity_io *dio; 289862306a36Sopenharmony_ci 289962306a36Sopenharmony_ci dio = dm_per_bio_data(bio, sizeof(struct dm_integrity_io)); 290062306a36Sopenharmony_ci 290162306a36Sopenharmony_ci if (block_bitmap_op(ic, ic->may_write_bitmap, dio->range.logical_sector, 290262306a36Sopenharmony_ci dio->range.n_sectors, BITMAP_OP_TEST_ALL_SET)) { 290362306a36Sopenharmony_ci remove_range(ic, &dio->range); 290462306a36Sopenharmony_ci INIT_WORK(&dio->work, integrity_bio_wait); 290562306a36Sopenharmony_ci queue_work(ic->offload_wq, &dio->work); 290662306a36Sopenharmony_ci } else { 290762306a36Sopenharmony_ci block_bitmap_op(ic, ic->journal, dio->range.logical_sector, 290862306a36Sopenharmony_ci dio->range.n_sectors, BITMAP_OP_SET); 290962306a36Sopenharmony_ci bio_list_add(&waiting, bio); 291062306a36Sopenharmony_ci } 291162306a36Sopenharmony_ci } 291262306a36Sopenharmony_ci 291362306a36Sopenharmony_ci if (bio_list_empty(&waiting)) 291462306a36Sopenharmony_ci return; 291562306a36Sopenharmony_ci 291662306a36Sopenharmony_ci rw_journal_sectors(ic, REQ_OP_WRITE | REQ_FUA | REQ_SYNC, 291762306a36Sopenharmony_ci bbs->idx * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), 291862306a36Sopenharmony_ci BITMAP_BLOCK_SIZE >> SECTOR_SHIFT, NULL); 291962306a36Sopenharmony_ci 292062306a36Sopenharmony_ci while ((bio = bio_list_pop(&waiting))) { 292162306a36Sopenharmony_ci struct dm_integrity_io *dio = dm_per_bio_data(bio, sizeof(struct dm_integrity_io)); 292262306a36Sopenharmony_ci 292362306a36Sopenharmony_ci block_bitmap_op(ic, ic->may_write_bitmap, dio->range.logical_sector, 292462306a36Sopenharmony_ci dio->range.n_sectors, BITMAP_OP_SET); 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_ci remove_range(ic, &dio->range); 292762306a36Sopenharmony_ci INIT_WORK(&dio->work, integrity_bio_wait); 292862306a36Sopenharmony_ci queue_work(ic->offload_wq, &dio->work); 292962306a36Sopenharmony_ci } 293062306a36Sopenharmony_ci 293162306a36Sopenharmony_ci queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, ic->bitmap_flush_interval); 293262306a36Sopenharmony_ci} 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_cistatic void bitmap_flush_work(struct work_struct *work) 293562306a36Sopenharmony_ci{ 293662306a36Sopenharmony_ci struct dm_integrity_c *ic = container_of(work, struct dm_integrity_c, bitmap_flush_work.work); 293762306a36Sopenharmony_ci struct dm_integrity_range range; 293862306a36Sopenharmony_ci unsigned long limit; 293962306a36Sopenharmony_ci struct bio *bio; 294062306a36Sopenharmony_ci 294162306a36Sopenharmony_ci dm_integrity_flush_buffers(ic, false); 294262306a36Sopenharmony_ci 294362306a36Sopenharmony_ci range.logical_sector = 0; 294462306a36Sopenharmony_ci range.n_sectors = ic->provided_data_sectors; 294562306a36Sopenharmony_ci 294662306a36Sopenharmony_ci spin_lock_irq(&ic->endio_wait.lock); 294762306a36Sopenharmony_ci add_new_range_and_wait(ic, &range); 294862306a36Sopenharmony_ci spin_unlock_irq(&ic->endio_wait.lock); 294962306a36Sopenharmony_ci 295062306a36Sopenharmony_ci dm_integrity_flush_buffers(ic, true); 295162306a36Sopenharmony_ci 295262306a36Sopenharmony_ci limit = ic->provided_data_sectors; 295362306a36Sopenharmony_ci if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) { 295462306a36Sopenharmony_ci limit = le64_to_cpu(ic->sb->recalc_sector) 295562306a36Sopenharmony_ci >> (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit) 295662306a36Sopenharmony_ci << (ic->sb->log2_sectors_per_block + ic->log2_blocks_per_bitmap_bit); 295762306a36Sopenharmony_ci } 295862306a36Sopenharmony_ci /*DEBUG_print("zeroing journal\n");*/ 295962306a36Sopenharmony_ci block_bitmap_op(ic, ic->journal, 0, limit, BITMAP_OP_CLEAR); 296062306a36Sopenharmony_ci block_bitmap_op(ic, ic->may_write_bitmap, 0, limit, BITMAP_OP_CLEAR); 296162306a36Sopenharmony_ci 296262306a36Sopenharmony_ci rw_journal_sectors(ic, REQ_OP_WRITE | REQ_FUA | REQ_SYNC, 0, 296362306a36Sopenharmony_ci ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL); 296462306a36Sopenharmony_ci 296562306a36Sopenharmony_ci spin_lock_irq(&ic->endio_wait.lock); 296662306a36Sopenharmony_ci remove_range_unlocked(ic, &range); 296762306a36Sopenharmony_ci while (unlikely((bio = bio_list_pop(&ic->synchronous_bios)) != NULL)) { 296862306a36Sopenharmony_ci bio_endio(bio); 296962306a36Sopenharmony_ci spin_unlock_irq(&ic->endio_wait.lock); 297062306a36Sopenharmony_ci spin_lock_irq(&ic->endio_wait.lock); 297162306a36Sopenharmony_ci } 297262306a36Sopenharmony_ci spin_unlock_irq(&ic->endio_wait.lock); 297362306a36Sopenharmony_ci} 297462306a36Sopenharmony_ci 297562306a36Sopenharmony_ci 297662306a36Sopenharmony_cistatic void init_journal(struct dm_integrity_c *ic, unsigned int start_section, 297762306a36Sopenharmony_ci unsigned int n_sections, unsigned char commit_seq) 297862306a36Sopenharmony_ci{ 297962306a36Sopenharmony_ci unsigned int i, j, n; 298062306a36Sopenharmony_ci 298162306a36Sopenharmony_ci if (!n_sections) 298262306a36Sopenharmony_ci return; 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_ci for (n = 0; n < n_sections; n++) { 298562306a36Sopenharmony_ci i = start_section + n; 298662306a36Sopenharmony_ci wraparound_section(ic, &i); 298762306a36Sopenharmony_ci for (j = 0; j < ic->journal_section_sectors; j++) { 298862306a36Sopenharmony_ci struct journal_sector *js = access_journal(ic, i, j); 298962306a36Sopenharmony_ci 299062306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(js->sectors) != JOURNAL_SECTOR_DATA); 299162306a36Sopenharmony_ci memset(&js->sectors, 0, sizeof(js->sectors)); 299262306a36Sopenharmony_ci js->commit_id = dm_integrity_commit_id(ic, i, j, commit_seq); 299362306a36Sopenharmony_ci } 299462306a36Sopenharmony_ci for (j = 0; j < ic->journal_section_entries; j++) { 299562306a36Sopenharmony_ci struct journal_entry *je = access_journal_entry(ic, i, j); 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ci journal_entry_set_unused(je); 299862306a36Sopenharmony_ci } 299962306a36Sopenharmony_ci } 300062306a36Sopenharmony_ci 300162306a36Sopenharmony_ci write_journal(ic, start_section, n_sections); 300262306a36Sopenharmony_ci} 300362306a36Sopenharmony_ci 300462306a36Sopenharmony_cistatic int find_commit_seq(struct dm_integrity_c *ic, unsigned int i, unsigned int j, commit_id_t id) 300562306a36Sopenharmony_ci{ 300662306a36Sopenharmony_ci unsigned char k; 300762306a36Sopenharmony_ci 300862306a36Sopenharmony_ci for (k = 0; k < N_COMMIT_IDS; k++) { 300962306a36Sopenharmony_ci if (dm_integrity_commit_id(ic, i, j, k) == id) 301062306a36Sopenharmony_ci return k; 301162306a36Sopenharmony_ci } 301262306a36Sopenharmony_ci dm_integrity_io_error(ic, "journal commit id", -EIO); 301362306a36Sopenharmony_ci return -EIO; 301462306a36Sopenharmony_ci} 301562306a36Sopenharmony_ci 301662306a36Sopenharmony_cistatic void replay_journal(struct dm_integrity_c *ic) 301762306a36Sopenharmony_ci{ 301862306a36Sopenharmony_ci unsigned int i, j; 301962306a36Sopenharmony_ci bool used_commit_ids[N_COMMIT_IDS]; 302062306a36Sopenharmony_ci unsigned int max_commit_id_sections[N_COMMIT_IDS]; 302162306a36Sopenharmony_ci unsigned int write_start, write_sections; 302262306a36Sopenharmony_ci unsigned int continue_section; 302362306a36Sopenharmony_ci bool journal_empty; 302462306a36Sopenharmony_ci unsigned char unused, last_used, want_commit_seq; 302562306a36Sopenharmony_ci 302662306a36Sopenharmony_ci if (ic->mode == 'R') 302762306a36Sopenharmony_ci return; 302862306a36Sopenharmony_ci 302962306a36Sopenharmony_ci if (ic->journal_uptodate) 303062306a36Sopenharmony_ci return; 303162306a36Sopenharmony_ci 303262306a36Sopenharmony_ci last_used = 0; 303362306a36Sopenharmony_ci write_start = 0; 303462306a36Sopenharmony_ci 303562306a36Sopenharmony_ci if (!ic->just_formatted) { 303662306a36Sopenharmony_ci DEBUG_print("reading journal\n"); 303762306a36Sopenharmony_ci rw_journal(ic, REQ_OP_READ, 0, ic->journal_sections, NULL); 303862306a36Sopenharmony_ci if (ic->journal_io) 303962306a36Sopenharmony_ci DEBUG_bytes(lowmem_page_address(ic->journal_io[0].page), 64, "read journal"); 304062306a36Sopenharmony_ci if (ic->journal_io) { 304162306a36Sopenharmony_ci struct journal_completion crypt_comp; 304262306a36Sopenharmony_ci 304362306a36Sopenharmony_ci crypt_comp.ic = ic; 304462306a36Sopenharmony_ci init_completion(&crypt_comp.comp); 304562306a36Sopenharmony_ci crypt_comp.in_flight = (atomic_t)ATOMIC_INIT(0); 304662306a36Sopenharmony_ci encrypt_journal(ic, false, 0, ic->journal_sections, &crypt_comp); 304762306a36Sopenharmony_ci wait_for_completion(&crypt_comp.comp); 304862306a36Sopenharmony_ci } 304962306a36Sopenharmony_ci DEBUG_bytes(lowmem_page_address(ic->journal[0].page), 64, "decrypted journal"); 305062306a36Sopenharmony_ci } 305162306a36Sopenharmony_ci 305262306a36Sopenharmony_ci if (dm_integrity_failed(ic)) 305362306a36Sopenharmony_ci goto clear_journal; 305462306a36Sopenharmony_ci 305562306a36Sopenharmony_ci journal_empty = true; 305662306a36Sopenharmony_ci memset(used_commit_ids, 0, sizeof(used_commit_ids)); 305762306a36Sopenharmony_ci memset(max_commit_id_sections, 0, sizeof(max_commit_id_sections)); 305862306a36Sopenharmony_ci for (i = 0; i < ic->journal_sections; i++) { 305962306a36Sopenharmony_ci for (j = 0; j < ic->journal_section_sectors; j++) { 306062306a36Sopenharmony_ci int k; 306162306a36Sopenharmony_ci struct journal_sector *js = access_journal(ic, i, j); 306262306a36Sopenharmony_ci 306362306a36Sopenharmony_ci k = find_commit_seq(ic, i, j, js->commit_id); 306462306a36Sopenharmony_ci if (k < 0) 306562306a36Sopenharmony_ci goto clear_journal; 306662306a36Sopenharmony_ci used_commit_ids[k] = true; 306762306a36Sopenharmony_ci max_commit_id_sections[k] = i; 306862306a36Sopenharmony_ci } 306962306a36Sopenharmony_ci if (journal_empty) { 307062306a36Sopenharmony_ci for (j = 0; j < ic->journal_section_entries; j++) { 307162306a36Sopenharmony_ci struct journal_entry *je = access_journal_entry(ic, i, j); 307262306a36Sopenharmony_ci 307362306a36Sopenharmony_ci if (!journal_entry_is_unused(je)) { 307462306a36Sopenharmony_ci journal_empty = false; 307562306a36Sopenharmony_ci break; 307662306a36Sopenharmony_ci } 307762306a36Sopenharmony_ci } 307862306a36Sopenharmony_ci } 307962306a36Sopenharmony_ci } 308062306a36Sopenharmony_ci 308162306a36Sopenharmony_ci if (!used_commit_ids[N_COMMIT_IDS - 1]) { 308262306a36Sopenharmony_ci unused = N_COMMIT_IDS - 1; 308362306a36Sopenharmony_ci while (unused && !used_commit_ids[unused - 1]) 308462306a36Sopenharmony_ci unused--; 308562306a36Sopenharmony_ci } else { 308662306a36Sopenharmony_ci for (unused = 0; unused < N_COMMIT_IDS; unused++) 308762306a36Sopenharmony_ci if (!used_commit_ids[unused]) 308862306a36Sopenharmony_ci break; 308962306a36Sopenharmony_ci if (unused == N_COMMIT_IDS) { 309062306a36Sopenharmony_ci dm_integrity_io_error(ic, "journal commit ids", -EIO); 309162306a36Sopenharmony_ci goto clear_journal; 309262306a36Sopenharmony_ci } 309362306a36Sopenharmony_ci } 309462306a36Sopenharmony_ci DEBUG_print("first unused commit seq %d [%d,%d,%d,%d]\n", 309562306a36Sopenharmony_ci unused, used_commit_ids[0], used_commit_ids[1], 309662306a36Sopenharmony_ci used_commit_ids[2], used_commit_ids[3]); 309762306a36Sopenharmony_ci 309862306a36Sopenharmony_ci last_used = prev_commit_seq(unused); 309962306a36Sopenharmony_ci want_commit_seq = prev_commit_seq(last_used); 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_ci if (!used_commit_ids[want_commit_seq] && used_commit_ids[prev_commit_seq(want_commit_seq)]) 310262306a36Sopenharmony_ci journal_empty = true; 310362306a36Sopenharmony_ci 310462306a36Sopenharmony_ci write_start = max_commit_id_sections[last_used] + 1; 310562306a36Sopenharmony_ci if (unlikely(write_start >= ic->journal_sections)) 310662306a36Sopenharmony_ci want_commit_seq = next_commit_seq(want_commit_seq); 310762306a36Sopenharmony_ci wraparound_section(ic, &write_start); 310862306a36Sopenharmony_ci 310962306a36Sopenharmony_ci i = write_start; 311062306a36Sopenharmony_ci for (write_sections = 0; write_sections < ic->journal_sections; write_sections++) { 311162306a36Sopenharmony_ci for (j = 0; j < ic->journal_section_sectors; j++) { 311262306a36Sopenharmony_ci struct journal_sector *js = access_journal(ic, i, j); 311362306a36Sopenharmony_ci 311462306a36Sopenharmony_ci if (js->commit_id != dm_integrity_commit_id(ic, i, j, want_commit_seq)) { 311562306a36Sopenharmony_ci /* 311662306a36Sopenharmony_ci * This could be caused by crash during writing. 311762306a36Sopenharmony_ci * We won't replay the inconsistent part of the 311862306a36Sopenharmony_ci * journal. 311962306a36Sopenharmony_ci */ 312062306a36Sopenharmony_ci DEBUG_print("commit id mismatch at position (%u, %u): %d != %d\n", 312162306a36Sopenharmony_ci i, j, find_commit_seq(ic, i, j, js->commit_id), want_commit_seq); 312262306a36Sopenharmony_ci goto brk; 312362306a36Sopenharmony_ci } 312462306a36Sopenharmony_ci } 312562306a36Sopenharmony_ci i++; 312662306a36Sopenharmony_ci if (unlikely(i >= ic->journal_sections)) 312762306a36Sopenharmony_ci want_commit_seq = next_commit_seq(want_commit_seq); 312862306a36Sopenharmony_ci wraparound_section(ic, &i); 312962306a36Sopenharmony_ci } 313062306a36Sopenharmony_cibrk: 313162306a36Sopenharmony_ci 313262306a36Sopenharmony_ci if (!journal_empty) { 313362306a36Sopenharmony_ci DEBUG_print("replaying %u sections, starting at %u, commit seq %d\n", 313462306a36Sopenharmony_ci write_sections, write_start, want_commit_seq); 313562306a36Sopenharmony_ci do_journal_write(ic, write_start, write_sections, true); 313662306a36Sopenharmony_ci } 313762306a36Sopenharmony_ci 313862306a36Sopenharmony_ci if (write_sections == ic->journal_sections && (ic->mode == 'J' || journal_empty)) { 313962306a36Sopenharmony_ci continue_section = write_start; 314062306a36Sopenharmony_ci ic->commit_seq = want_commit_seq; 314162306a36Sopenharmony_ci DEBUG_print("continuing from section %u, commit seq %d\n", write_start, ic->commit_seq); 314262306a36Sopenharmony_ci } else { 314362306a36Sopenharmony_ci unsigned int s; 314462306a36Sopenharmony_ci unsigned char erase_seq; 314562306a36Sopenharmony_ci 314662306a36Sopenharmony_ciclear_journal: 314762306a36Sopenharmony_ci DEBUG_print("clearing journal\n"); 314862306a36Sopenharmony_ci 314962306a36Sopenharmony_ci erase_seq = prev_commit_seq(prev_commit_seq(last_used)); 315062306a36Sopenharmony_ci s = write_start; 315162306a36Sopenharmony_ci init_journal(ic, s, 1, erase_seq); 315262306a36Sopenharmony_ci s++; 315362306a36Sopenharmony_ci wraparound_section(ic, &s); 315462306a36Sopenharmony_ci if (ic->journal_sections >= 2) { 315562306a36Sopenharmony_ci init_journal(ic, s, ic->journal_sections - 2, erase_seq); 315662306a36Sopenharmony_ci s += ic->journal_sections - 2; 315762306a36Sopenharmony_ci wraparound_section(ic, &s); 315862306a36Sopenharmony_ci init_journal(ic, s, 1, erase_seq); 315962306a36Sopenharmony_ci } 316062306a36Sopenharmony_ci 316162306a36Sopenharmony_ci continue_section = 0; 316262306a36Sopenharmony_ci ic->commit_seq = next_commit_seq(erase_seq); 316362306a36Sopenharmony_ci } 316462306a36Sopenharmony_ci 316562306a36Sopenharmony_ci ic->committed_section = continue_section; 316662306a36Sopenharmony_ci ic->n_committed_sections = 0; 316762306a36Sopenharmony_ci 316862306a36Sopenharmony_ci ic->uncommitted_section = continue_section; 316962306a36Sopenharmony_ci ic->n_uncommitted_sections = 0; 317062306a36Sopenharmony_ci 317162306a36Sopenharmony_ci ic->free_section = continue_section; 317262306a36Sopenharmony_ci ic->free_section_entry = 0; 317362306a36Sopenharmony_ci ic->free_sectors = ic->journal_entries; 317462306a36Sopenharmony_ci 317562306a36Sopenharmony_ci ic->journal_tree_root = RB_ROOT; 317662306a36Sopenharmony_ci for (i = 0; i < ic->journal_entries; i++) 317762306a36Sopenharmony_ci init_journal_node(&ic->journal_tree[i]); 317862306a36Sopenharmony_ci} 317962306a36Sopenharmony_ci 318062306a36Sopenharmony_cistatic void dm_integrity_enter_synchronous_mode(struct dm_integrity_c *ic) 318162306a36Sopenharmony_ci{ 318262306a36Sopenharmony_ci DEBUG_print("%s\n", __func__); 318362306a36Sopenharmony_ci 318462306a36Sopenharmony_ci if (ic->mode == 'B') { 318562306a36Sopenharmony_ci ic->bitmap_flush_interval = msecs_to_jiffies(10) + 1; 318662306a36Sopenharmony_ci ic->synchronous_mode = 1; 318762306a36Sopenharmony_ci 318862306a36Sopenharmony_ci cancel_delayed_work_sync(&ic->bitmap_flush_work); 318962306a36Sopenharmony_ci queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, 0); 319062306a36Sopenharmony_ci flush_workqueue(ic->commit_wq); 319162306a36Sopenharmony_ci } 319262306a36Sopenharmony_ci} 319362306a36Sopenharmony_ci 319462306a36Sopenharmony_cistatic int dm_integrity_reboot(struct notifier_block *n, unsigned long code, void *x) 319562306a36Sopenharmony_ci{ 319662306a36Sopenharmony_ci struct dm_integrity_c *ic = container_of(n, struct dm_integrity_c, reboot_notifier); 319762306a36Sopenharmony_ci 319862306a36Sopenharmony_ci DEBUG_print("%s\n", __func__); 319962306a36Sopenharmony_ci 320062306a36Sopenharmony_ci dm_integrity_enter_synchronous_mode(ic); 320162306a36Sopenharmony_ci 320262306a36Sopenharmony_ci return NOTIFY_DONE; 320362306a36Sopenharmony_ci} 320462306a36Sopenharmony_ci 320562306a36Sopenharmony_cistatic void dm_integrity_postsuspend(struct dm_target *ti) 320662306a36Sopenharmony_ci{ 320762306a36Sopenharmony_ci struct dm_integrity_c *ic = ti->private; 320862306a36Sopenharmony_ci int r; 320962306a36Sopenharmony_ci 321062306a36Sopenharmony_ci WARN_ON(unregister_reboot_notifier(&ic->reboot_notifier)); 321162306a36Sopenharmony_ci 321262306a36Sopenharmony_ci del_timer_sync(&ic->autocommit_timer); 321362306a36Sopenharmony_ci 321462306a36Sopenharmony_ci if (ic->recalc_wq) 321562306a36Sopenharmony_ci drain_workqueue(ic->recalc_wq); 321662306a36Sopenharmony_ci 321762306a36Sopenharmony_ci if (ic->mode == 'B') 321862306a36Sopenharmony_ci cancel_delayed_work_sync(&ic->bitmap_flush_work); 321962306a36Sopenharmony_ci 322062306a36Sopenharmony_ci queue_work(ic->commit_wq, &ic->commit_work); 322162306a36Sopenharmony_ci drain_workqueue(ic->commit_wq); 322262306a36Sopenharmony_ci 322362306a36Sopenharmony_ci if (ic->mode == 'J') { 322462306a36Sopenharmony_ci queue_work(ic->writer_wq, &ic->writer_work); 322562306a36Sopenharmony_ci drain_workqueue(ic->writer_wq); 322662306a36Sopenharmony_ci dm_integrity_flush_buffers(ic, true); 322762306a36Sopenharmony_ci if (ic->wrote_to_journal) { 322862306a36Sopenharmony_ci init_journal(ic, ic->free_section, 322962306a36Sopenharmony_ci ic->journal_sections - ic->free_section, ic->commit_seq); 323062306a36Sopenharmony_ci if (ic->free_section) { 323162306a36Sopenharmony_ci init_journal(ic, 0, ic->free_section, 323262306a36Sopenharmony_ci next_commit_seq(ic->commit_seq)); 323362306a36Sopenharmony_ci } 323462306a36Sopenharmony_ci } 323562306a36Sopenharmony_ci } 323662306a36Sopenharmony_ci 323762306a36Sopenharmony_ci if (ic->mode == 'B') { 323862306a36Sopenharmony_ci dm_integrity_flush_buffers(ic, true); 323962306a36Sopenharmony_ci#if 1 324062306a36Sopenharmony_ci /* set to 0 to test bitmap replay code */ 324162306a36Sopenharmony_ci init_journal(ic, 0, ic->journal_sections, 0); 324262306a36Sopenharmony_ci ic->sb->flags &= ~cpu_to_le32(SB_FLAG_DIRTY_BITMAP); 324362306a36Sopenharmony_ci r = sync_rw_sb(ic, REQ_OP_WRITE | REQ_FUA); 324462306a36Sopenharmony_ci if (unlikely(r)) 324562306a36Sopenharmony_ci dm_integrity_io_error(ic, "writing superblock", r); 324662306a36Sopenharmony_ci#endif 324762306a36Sopenharmony_ci } 324862306a36Sopenharmony_ci 324962306a36Sopenharmony_ci BUG_ON(!RB_EMPTY_ROOT(&ic->in_progress)); 325062306a36Sopenharmony_ci 325162306a36Sopenharmony_ci ic->journal_uptodate = true; 325262306a36Sopenharmony_ci} 325362306a36Sopenharmony_ci 325462306a36Sopenharmony_cistatic void dm_integrity_resume(struct dm_target *ti) 325562306a36Sopenharmony_ci{ 325662306a36Sopenharmony_ci struct dm_integrity_c *ic = ti->private; 325762306a36Sopenharmony_ci __u64 old_provided_data_sectors = le64_to_cpu(ic->sb->provided_data_sectors); 325862306a36Sopenharmony_ci int r; 325962306a36Sopenharmony_ci 326062306a36Sopenharmony_ci DEBUG_print("resume\n"); 326162306a36Sopenharmony_ci 326262306a36Sopenharmony_ci ic->wrote_to_journal = false; 326362306a36Sopenharmony_ci 326462306a36Sopenharmony_ci if (ic->provided_data_sectors != old_provided_data_sectors) { 326562306a36Sopenharmony_ci if (ic->provided_data_sectors > old_provided_data_sectors && 326662306a36Sopenharmony_ci ic->mode == 'B' && 326762306a36Sopenharmony_ci ic->sb->log2_blocks_per_bitmap_bit == ic->log2_blocks_per_bitmap_bit) { 326862306a36Sopenharmony_ci rw_journal_sectors(ic, REQ_OP_READ, 0, 326962306a36Sopenharmony_ci ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL); 327062306a36Sopenharmony_ci block_bitmap_op(ic, ic->journal, old_provided_data_sectors, 327162306a36Sopenharmony_ci ic->provided_data_sectors - old_provided_data_sectors, BITMAP_OP_SET); 327262306a36Sopenharmony_ci rw_journal_sectors(ic, REQ_OP_WRITE | REQ_FUA | REQ_SYNC, 0, 327362306a36Sopenharmony_ci ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL); 327462306a36Sopenharmony_ci } 327562306a36Sopenharmony_ci 327662306a36Sopenharmony_ci ic->sb->provided_data_sectors = cpu_to_le64(ic->provided_data_sectors); 327762306a36Sopenharmony_ci r = sync_rw_sb(ic, REQ_OP_WRITE | REQ_FUA); 327862306a36Sopenharmony_ci if (unlikely(r)) 327962306a36Sopenharmony_ci dm_integrity_io_error(ic, "writing superblock", r); 328062306a36Sopenharmony_ci } 328162306a36Sopenharmony_ci 328262306a36Sopenharmony_ci if (ic->sb->flags & cpu_to_le32(SB_FLAG_DIRTY_BITMAP)) { 328362306a36Sopenharmony_ci DEBUG_print("resume dirty_bitmap\n"); 328462306a36Sopenharmony_ci rw_journal_sectors(ic, REQ_OP_READ, 0, 328562306a36Sopenharmony_ci ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL); 328662306a36Sopenharmony_ci if (ic->mode == 'B') { 328762306a36Sopenharmony_ci if (ic->sb->log2_blocks_per_bitmap_bit == ic->log2_blocks_per_bitmap_bit && 328862306a36Sopenharmony_ci !ic->reset_recalculate_flag) { 328962306a36Sopenharmony_ci block_bitmap_copy(ic, ic->recalc_bitmap, ic->journal); 329062306a36Sopenharmony_ci block_bitmap_copy(ic, ic->may_write_bitmap, ic->journal); 329162306a36Sopenharmony_ci if (!block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, 329262306a36Sopenharmony_ci BITMAP_OP_TEST_ALL_CLEAR)) { 329362306a36Sopenharmony_ci ic->sb->flags |= cpu_to_le32(SB_FLAG_RECALCULATING); 329462306a36Sopenharmony_ci ic->sb->recalc_sector = cpu_to_le64(0); 329562306a36Sopenharmony_ci } 329662306a36Sopenharmony_ci } else { 329762306a36Sopenharmony_ci DEBUG_print("non-matching blocks_per_bitmap_bit: %u, %u\n", 329862306a36Sopenharmony_ci ic->sb->log2_blocks_per_bitmap_bit, ic->log2_blocks_per_bitmap_bit); 329962306a36Sopenharmony_ci ic->sb->log2_blocks_per_bitmap_bit = ic->log2_blocks_per_bitmap_bit; 330062306a36Sopenharmony_ci block_bitmap_op(ic, ic->recalc_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_SET); 330162306a36Sopenharmony_ci block_bitmap_op(ic, ic->may_write_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_SET); 330262306a36Sopenharmony_ci block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, BITMAP_OP_SET); 330362306a36Sopenharmony_ci rw_journal_sectors(ic, REQ_OP_WRITE | REQ_FUA | REQ_SYNC, 0, 330462306a36Sopenharmony_ci ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL); 330562306a36Sopenharmony_ci ic->sb->flags |= cpu_to_le32(SB_FLAG_RECALCULATING); 330662306a36Sopenharmony_ci ic->sb->recalc_sector = cpu_to_le64(0); 330762306a36Sopenharmony_ci } 330862306a36Sopenharmony_ci } else { 330962306a36Sopenharmony_ci if (!(ic->sb->log2_blocks_per_bitmap_bit == ic->log2_blocks_per_bitmap_bit && 331062306a36Sopenharmony_ci block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, BITMAP_OP_TEST_ALL_CLEAR)) || 331162306a36Sopenharmony_ci ic->reset_recalculate_flag) { 331262306a36Sopenharmony_ci ic->sb->flags |= cpu_to_le32(SB_FLAG_RECALCULATING); 331362306a36Sopenharmony_ci ic->sb->recalc_sector = cpu_to_le64(0); 331462306a36Sopenharmony_ci } 331562306a36Sopenharmony_ci init_journal(ic, 0, ic->journal_sections, 0); 331662306a36Sopenharmony_ci replay_journal(ic); 331762306a36Sopenharmony_ci ic->sb->flags &= ~cpu_to_le32(SB_FLAG_DIRTY_BITMAP); 331862306a36Sopenharmony_ci } 331962306a36Sopenharmony_ci r = sync_rw_sb(ic, REQ_OP_WRITE | REQ_FUA); 332062306a36Sopenharmony_ci if (unlikely(r)) 332162306a36Sopenharmony_ci dm_integrity_io_error(ic, "writing superblock", r); 332262306a36Sopenharmony_ci } else { 332362306a36Sopenharmony_ci replay_journal(ic); 332462306a36Sopenharmony_ci if (ic->reset_recalculate_flag) { 332562306a36Sopenharmony_ci ic->sb->flags |= cpu_to_le32(SB_FLAG_RECALCULATING); 332662306a36Sopenharmony_ci ic->sb->recalc_sector = cpu_to_le64(0); 332762306a36Sopenharmony_ci } 332862306a36Sopenharmony_ci if (ic->mode == 'B') { 332962306a36Sopenharmony_ci ic->sb->flags |= cpu_to_le32(SB_FLAG_DIRTY_BITMAP); 333062306a36Sopenharmony_ci ic->sb->log2_blocks_per_bitmap_bit = ic->log2_blocks_per_bitmap_bit; 333162306a36Sopenharmony_ci r = sync_rw_sb(ic, REQ_OP_WRITE | REQ_FUA); 333262306a36Sopenharmony_ci if (unlikely(r)) 333362306a36Sopenharmony_ci dm_integrity_io_error(ic, "writing superblock", r); 333462306a36Sopenharmony_ci 333562306a36Sopenharmony_ci block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR); 333662306a36Sopenharmony_ci block_bitmap_op(ic, ic->recalc_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR); 333762306a36Sopenharmony_ci block_bitmap_op(ic, ic->may_write_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR); 333862306a36Sopenharmony_ci if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING) && 333962306a36Sopenharmony_ci le64_to_cpu(ic->sb->recalc_sector) < ic->provided_data_sectors) { 334062306a36Sopenharmony_ci block_bitmap_op(ic, ic->journal, le64_to_cpu(ic->sb->recalc_sector), 334162306a36Sopenharmony_ci ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET); 334262306a36Sopenharmony_ci block_bitmap_op(ic, ic->recalc_bitmap, le64_to_cpu(ic->sb->recalc_sector), 334362306a36Sopenharmony_ci ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET); 334462306a36Sopenharmony_ci block_bitmap_op(ic, ic->may_write_bitmap, le64_to_cpu(ic->sb->recalc_sector), 334562306a36Sopenharmony_ci ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET); 334662306a36Sopenharmony_ci } 334762306a36Sopenharmony_ci rw_journal_sectors(ic, REQ_OP_WRITE | REQ_FUA | REQ_SYNC, 0, 334862306a36Sopenharmony_ci ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL); 334962306a36Sopenharmony_ci } 335062306a36Sopenharmony_ci } 335162306a36Sopenharmony_ci 335262306a36Sopenharmony_ci DEBUG_print("testing recalc: %x\n", ic->sb->flags); 335362306a36Sopenharmony_ci if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) { 335462306a36Sopenharmony_ci __u64 recalc_pos = le64_to_cpu(ic->sb->recalc_sector); 335562306a36Sopenharmony_ci 335662306a36Sopenharmony_ci DEBUG_print("recalc pos: %llx / %llx\n", recalc_pos, ic->provided_data_sectors); 335762306a36Sopenharmony_ci if (recalc_pos < ic->provided_data_sectors) { 335862306a36Sopenharmony_ci queue_work(ic->recalc_wq, &ic->recalc_work); 335962306a36Sopenharmony_ci } else if (recalc_pos > ic->provided_data_sectors) { 336062306a36Sopenharmony_ci ic->sb->recalc_sector = cpu_to_le64(ic->provided_data_sectors); 336162306a36Sopenharmony_ci recalc_write_super(ic); 336262306a36Sopenharmony_ci } 336362306a36Sopenharmony_ci } 336462306a36Sopenharmony_ci 336562306a36Sopenharmony_ci ic->reboot_notifier.notifier_call = dm_integrity_reboot; 336662306a36Sopenharmony_ci ic->reboot_notifier.next = NULL; 336762306a36Sopenharmony_ci ic->reboot_notifier.priority = INT_MAX - 1; /* be notified after md and before hardware drivers */ 336862306a36Sopenharmony_ci WARN_ON(register_reboot_notifier(&ic->reboot_notifier)); 336962306a36Sopenharmony_ci 337062306a36Sopenharmony_ci#if 0 337162306a36Sopenharmony_ci /* set to 1 to stress test synchronous mode */ 337262306a36Sopenharmony_ci dm_integrity_enter_synchronous_mode(ic); 337362306a36Sopenharmony_ci#endif 337462306a36Sopenharmony_ci} 337562306a36Sopenharmony_ci 337662306a36Sopenharmony_cistatic void dm_integrity_status(struct dm_target *ti, status_type_t type, 337762306a36Sopenharmony_ci unsigned int status_flags, char *result, unsigned int maxlen) 337862306a36Sopenharmony_ci{ 337962306a36Sopenharmony_ci struct dm_integrity_c *ic = ti->private; 338062306a36Sopenharmony_ci unsigned int arg_count; 338162306a36Sopenharmony_ci size_t sz = 0; 338262306a36Sopenharmony_ci 338362306a36Sopenharmony_ci switch (type) { 338462306a36Sopenharmony_ci case STATUSTYPE_INFO: 338562306a36Sopenharmony_ci DMEMIT("%llu %llu", 338662306a36Sopenharmony_ci (unsigned long long)atomic64_read(&ic->number_of_mismatches), 338762306a36Sopenharmony_ci ic->provided_data_sectors); 338862306a36Sopenharmony_ci if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) 338962306a36Sopenharmony_ci DMEMIT(" %llu", le64_to_cpu(ic->sb->recalc_sector)); 339062306a36Sopenharmony_ci else 339162306a36Sopenharmony_ci DMEMIT(" -"); 339262306a36Sopenharmony_ci break; 339362306a36Sopenharmony_ci 339462306a36Sopenharmony_ci case STATUSTYPE_TABLE: { 339562306a36Sopenharmony_ci __u64 watermark_percentage = (__u64)(ic->journal_entries - ic->free_sectors_threshold) * 100; 339662306a36Sopenharmony_ci 339762306a36Sopenharmony_ci watermark_percentage += ic->journal_entries / 2; 339862306a36Sopenharmony_ci do_div(watermark_percentage, ic->journal_entries); 339962306a36Sopenharmony_ci arg_count = 3; 340062306a36Sopenharmony_ci arg_count += !!ic->meta_dev; 340162306a36Sopenharmony_ci arg_count += ic->sectors_per_block != 1; 340262306a36Sopenharmony_ci arg_count += !!(ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)); 340362306a36Sopenharmony_ci arg_count += ic->reset_recalculate_flag; 340462306a36Sopenharmony_ci arg_count += ic->discard; 340562306a36Sopenharmony_ci arg_count += ic->mode == 'J'; 340662306a36Sopenharmony_ci arg_count += ic->mode == 'J'; 340762306a36Sopenharmony_ci arg_count += ic->mode == 'B'; 340862306a36Sopenharmony_ci arg_count += ic->mode == 'B'; 340962306a36Sopenharmony_ci arg_count += !!ic->internal_hash_alg.alg_string; 341062306a36Sopenharmony_ci arg_count += !!ic->journal_crypt_alg.alg_string; 341162306a36Sopenharmony_ci arg_count += !!ic->journal_mac_alg.alg_string; 341262306a36Sopenharmony_ci arg_count += (ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_PADDING)) != 0; 341362306a36Sopenharmony_ci arg_count += (ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_HMAC)) != 0; 341462306a36Sopenharmony_ci arg_count += ic->legacy_recalculate; 341562306a36Sopenharmony_ci DMEMIT("%s %llu %u %c %u", ic->dev->name, ic->start, 341662306a36Sopenharmony_ci ic->tag_size, ic->mode, arg_count); 341762306a36Sopenharmony_ci if (ic->meta_dev) 341862306a36Sopenharmony_ci DMEMIT(" meta_device:%s", ic->meta_dev->name); 341962306a36Sopenharmony_ci if (ic->sectors_per_block != 1) 342062306a36Sopenharmony_ci DMEMIT(" block_size:%u", ic->sectors_per_block << SECTOR_SHIFT); 342162306a36Sopenharmony_ci if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) 342262306a36Sopenharmony_ci DMEMIT(" recalculate"); 342362306a36Sopenharmony_ci if (ic->reset_recalculate_flag) 342462306a36Sopenharmony_ci DMEMIT(" reset_recalculate"); 342562306a36Sopenharmony_ci if (ic->discard) 342662306a36Sopenharmony_ci DMEMIT(" allow_discards"); 342762306a36Sopenharmony_ci DMEMIT(" journal_sectors:%u", ic->initial_sectors - SB_SECTORS); 342862306a36Sopenharmony_ci DMEMIT(" interleave_sectors:%u", 1U << ic->sb->log2_interleave_sectors); 342962306a36Sopenharmony_ci DMEMIT(" buffer_sectors:%u", 1U << ic->log2_buffer_sectors); 343062306a36Sopenharmony_ci if (ic->mode == 'J') { 343162306a36Sopenharmony_ci DMEMIT(" journal_watermark:%u", (unsigned int)watermark_percentage); 343262306a36Sopenharmony_ci DMEMIT(" commit_time:%u", ic->autocommit_msec); 343362306a36Sopenharmony_ci } 343462306a36Sopenharmony_ci if (ic->mode == 'B') { 343562306a36Sopenharmony_ci DMEMIT(" sectors_per_bit:%llu", (sector_t)ic->sectors_per_block << ic->log2_blocks_per_bitmap_bit); 343662306a36Sopenharmony_ci DMEMIT(" bitmap_flush_interval:%u", jiffies_to_msecs(ic->bitmap_flush_interval)); 343762306a36Sopenharmony_ci } 343862306a36Sopenharmony_ci if ((ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_PADDING)) != 0) 343962306a36Sopenharmony_ci DMEMIT(" fix_padding"); 344062306a36Sopenharmony_ci if ((ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_HMAC)) != 0) 344162306a36Sopenharmony_ci DMEMIT(" fix_hmac"); 344262306a36Sopenharmony_ci if (ic->legacy_recalculate) 344362306a36Sopenharmony_ci DMEMIT(" legacy_recalculate"); 344462306a36Sopenharmony_ci 344562306a36Sopenharmony_ci#define EMIT_ALG(a, n) \ 344662306a36Sopenharmony_ci do { \ 344762306a36Sopenharmony_ci if (ic->a.alg_string) { \ 344862306a36Sopenharmony_ci DMEMIT(" %s:%s", n, ic->a.alg_string); \ 344962306a36Sopenharmony_ci if (ic->a.key_string) \ 345062306a36Sopenharmony_ci DMEMIT(":%s", ic->a.key_string);\ 345162306a36Sopenharmony_ci } \ 345262306a36Sopenharmony_ci } while (0) 345362306a36Sopenharmony_ci EMIT_ALG(internal_hash_alg, "internal_hash"); 345462306a36Sopenharmony_ci EMIT_ALG(journal_crypt_alg, "journal_crypt"); 345562306a36Sopenharmony_ci EMIT_ALG(journal_mac_alg, "journal_mac"); 345662306a36Sopenharmony_ci break; 345762306a36Sopenharmony_ci } 345862306a36Sopenharmony_ci case STATUSTYPE_IMA: 345962306a36Sopenharmony_ci DMEMIT_TARGET_NAME_VERSION(ti->type); 346062306a36Sopenharmony_ci DMEMIT(",dev_name=%s,start=%llu,tag_size=%u,mode=%c", 346162306a36Sopenharmony_ci ic->dev->name, ic->start, ic->tag_size, ic->mode); 346262306a36Sopenharmony_ci 346362306a36Sopenharmony_ci if (ic->meta_dev) 346462306a36Sopenharmony_ci DMEMIT(",meta_device=%s", ic->meta_dev->name); 346562306a36Sopenharmony_ci if (ic->sectors_per_block != 1) 346662306a36Sopenharmony_ci DMEMIT(",block_size=%u", ic->sectors_per_block << SECTOR_SHIFT); 346762306a36Sopenharmony_ci 346862306a36Sopenharmony_ci DMEMIT(",recalculate=%c", (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) ? 346962306a36Sopenharmony_ci 'y' : 'n'); 347062306a36Sopenharmony_ci DMEMIT(",allow_discards=%c", ic->discard ? 'y' : 'n'); 347162306a36Sopenharmony_ci DMEMIT(",fix_padding=%c", 347262306a36Sopenharmony_ci ((ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_PADDING)) != 0) ? 'y' : 'n'); 347362306a36Sopenharmony_ci DMEMIT(",fix_hmac=%c", 347462306a36Sopenharmony_ci ((ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_HMAC)) != 0) ? 'y' : 'n'); 347562306a36Sopenharmony_ci DMEMIT(",legacy_recalculate=%c", ic->legacy_recalculate ? 'y' : 'n'); 347662306a36Sopenharmony_ci 347762306a36Sopenharmony_ci DMEMIT(",journal_sectors=%u", ic->initial_sectors - SB_SECTORS); 347862306a36Sopenharmony_ci DMEMIT(",interleave_sectors=%u", 1U << ic->sb->log2_interleave_sectors); 347962306a36Sopenharmony_ci DMEMIT(",buffer_sectors=%u", 1U << ic->log2_buffer_sectors); 348062306a36Sopenharmony_ci DMEMIT(";"); 348162306a36Sopenharmony_ci break; 348262306a36Sopenharmony_ci } 348362306a36Sopenharmony_ci} 348462306a36Sopenharmony_ci 348562306a36Sopenharmony_cistatic int dm_integrity_iterate_devices(struct dm_target *ti, 348662306a36Sopenharmony_ci iterate_devices_callout_fn fn, void *data) 348762306a36Sopenharmony_ci{ 348862306a36Sopenharmony_ci struct dm_integrity_c *ic = ti->private; 348962306a36Sopenharmony_ci 349062306a36Sopenharmony_ci if (!ic->meta_dev) 349162306a36Sopenharmony_ci return fn(ti, ic->dev, ic->start + ic->initial_sectors + ic->metadata_run, ti->len, data); 349262306a36Sopenharmony_ci else 349362306a36Sopenharmony_ci return fn(ti, ic->dev, 0, ti->len, data); 349462306a36Sopenharmony_ci} 349562306a36Sopenharmony_ci 349662306a36Sopenharmony_cistatic void dm_integrity_io_hints(struct dm_target *ti, struct queue_limits *limits) 349762306a36Sopenharmony_ci{ 349862306a36Sopenharmony_ci struct dm_integrity_c *ic = ti->private; 349962306a36Sopenharmony_ci 350062306a36Sopenharmony_ci if (ic->sectors_per_block > 1) { 350162306a36Sopenharmony_ci limits->logical_block_size = ic->sectors_per_block << SECTOR_SHIFT; 350262306a36Sopenharmony_ci limits->physical_block_size = ic->sectors_per_block << SECTOR_SHIFT; 350362306a36Sopenharmony_ci blk_limits_io_min(limits, ic->sectors_per_block << SECTOR_SHIFT); 350462306a36Sopenharmony_ci limits->dma_alignment = limits->logical_block_size - 1; 350562306a36Sopenharmony_ci } 350662306a36Sopenharmony_ci} 350762306a36Sopenharmony_ci 350862306a36Sopenharmony_cistatic void calculate_journal_section_size(struct dm_integrity_c *ic) 350962306a36Sopenharmony_ci{ 351062306a36Sopenharmony_ci unsigned int sector_space = JOURNAL_SECTOR_DATA; 351162306a36Sopenharmony_ci 351262306a36Sopenharmony_ci ic->journal_sections = le32_to_cpu(ic->sb->journal_sections); 351362306a36Sopenharmony_ci ic->journal_entry_size = roundup(offsetof(struct journal_entry, last_bytes[ic->sectors_per_block]) + ic->tag_size, 351462306a36Sopenharmony_ci JOURNAL_ENTRY_ROUNDUP); 351562306a36Sopenharmony_ci 351662306a36Sopenharmony_ci if (ic->sb->flags & cpu_to_le32(SB_FLAG_HAVE_JOURNAL_MAC)) 351762306a36Sopenharmony_ci sector_space -= JOURNAL_MAC_PER_SECTOR; 351862306a36Sopenharmony_ci ic->journal_entries_per_sector = sector_space / ic->journal_entry_size; 351962306a36Sopenharmony_ci ic->journal_section_entries = ic->journal_entries_per_sector * JOURNAL_BLOCK_SECTORS; 352062306a36Sopenharmony_ci ic->journal_section_sectors = (ic->journal_section_entries << ic->sb->log2_sectors_per_block) + JOURNAL_BLOCK_SECTORS; 352162306a36Sopenharmony_ci ic->journal_entries = ic->journal_section_entries * ic->journal_sections; 352262306a36Sopenharmony_ci} 352362306a36Sopenharmony_ci 352462306a36Sopenharmony_cistatic int calculate_device_limits(struct dm_integrity_c *ic) 352562306a36Sopenharmony_ci{ 352662306a36Sopenharmony_ci __u64 initial_sectors; 352762306a36Sopenharmony_ci 352862306a36Sopenharmony_ci calculate_journal_section_size(ic); 352962306a36Sopenharmony_ci initial_sectors = SB_SECTORS + (__u64)ic->journal_section_sectors * ic->journal_sections; 353062306a36Sopenharmony_ci if (initial_sectors + METADATA_PADDING_SECTORS >= ic->meta_device_sectors || initial_sectors > UINT_MAX) 353162306a36Sopenharmony_ci return -EINVAL; 353262306a36Sopenharmony_ci ic->initial_sectors = initial_sectors; 353362306a36Sopenharmony_ci 353462306a36Sopenharmony_ci if (!ic->meta_dev) { 353562306a36Sopenharmony_ci sector_t last_sector, last_area, last_offset; 353662306a36Sopenharmony_ci 353762306a36Sopenharmony_ci /* we have to maintain excessive padding for compatibility with existing volumes */ 353862306a36Sopenharmony_ci __u64 metadata_run_padding = 353962306a36Sopenharmony_ci ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_PADDING) ? 354062306a36Sopenharmony_ci (__u64)(METADATA_PADDING_SECTORS << SECTOR_SHIFT) : 354162306a36Sopenharmony_ci (__u64)(1 << SECTOR_SHIFT << METADATA_PADDING_SECTORS); 354262306a36Sopenharmony_ci 354362306a36Sopenharmony_ci ic->metadata_run = round_up((__u64)ic->tag_size << (ic->sb->log2_interleave_sectors - ic->sb->log2_sectors_per_block), 354462306a36Sopenharmony_ci metadata_run_padding) >> SECTOR_SHIFT; 354562306a36Sopenharmony_ci if (!(ic->metadata_run & (ic->metadata_run - 1))) 354662306a36Sopenharmony_ci ic->log2_metadata_run = __ffs(ic->metadata_run); 354762306a36Sopenharmony_ci else 354862306a36Sopenharmony_ci ic->log2_metadata_run = -1; 354962306a36Sopenharmony_ci 355062306a36Sopenharmony_ci get_area_and_offset(ic, ic->provided_data_sectors - 1, &last_area, &last_offset); 355162306a36Sopenharmony_ci last_sector = get_data_sector(ic, last_area, last_offset); 355262306a36Sopenharmony_ci if (last_sector < ic->start || last_sector >= ic->meta_device_sectors) 355362306a36Sopenharmony_ci return -EINVAL; 355462306a36Sopenharmony_ci } else { 355562306a36Sopenharmony_ci __u64 meta_size = (ic->provided_data_sectors >> ic->sb->log2_sectors_per_block) * ic->tag_size; 355662306a36Sopenharmony_ci 355762306a36Sopenharmony_ci meta_size = (meta_size + ((1U << (ic->log2_buffer_sectors + SECTOR_SHIFT)) - 1)) 355862306a36Sopenharmony_ci >> (ic->log2_buffer_sectors + SECTOR_SHIFT); 355962306a36Sopenharmony_ci meta_size <<= ic->log2_buffer_sectors; 356062306a36Sopenharmony_ci if (ic->initial_sectors + meta_size < ic->initial_sectors || 356162306a36Sopenharmony_ci ic->initial_sectors + meta_size > ic->meta_device_sectors) 356262306a36Sopenharmony_ci return -EINVAL; 356362306a36Sopenharmony_ci ic->metadata_run = 1; 356462306a36Sopenharmony_ci ic->log2_metadata_run = 0; 356562306a36Sopenharmony_ci } 356662306a36Sopenharmony_ci 356762306a36Sopenharmony_ci return 0; 356862306a36Sopenharmony_ci} 356962306a36Sopenharmony_ci 357062306a36Sopenharmony_cistatic void get_provided_data_sectors(struct dm_integrity_c *ic) 357162306a36Sopenharmony_ci{ 357262306a36Sopenharmony_ci if (!ic->meta_dev) { 357362306a36Sopenharmony_ci int test_bit; 357462306a36Sopenharmony_ci 357562306a36Sopenharmony_ci ic->provided_data_sectors = 0; 357662306a36Sopenharmony_ci for (test_bit = fls64(ic->meta_device_sectors) - 1; test_bit >= 3; test_bit--) { 357762306a36Sopenharmony_ci __u64 prev_data_sectors = ic->provided_data_sectors; 357862306a36Sopenharmony_ci 357962306a36Sopenharmony_ci ic->provided_data_sectors |= (sector_t)1 << test_bit; 358062306a36Sopenharmony_ci if (calculate_device_limits(ic)) 358162306a36Sopenharmony_ci ic->provided_data_sectors = prev_data_sectors; 358262306a36Sopenharmony_ci } 358362306a36Sopenharmony_ci } else { 358462306a36Sopenharmony_ci ic->provided_data_sectors = ic->data_device_sectors; 358562306a36Sopenharmony_ci ic->provided_data_sectors &= ~(sector_t)(ic->sectors_per_block - 1); 358662306a36Sopenharmony_ci } 358762306a36Sopenharmony_ci} 358862306a36Sopenharmony_ci 358962306a36Sopenharmony_cistatic int initialize_superblock(struct dm_integrity_c *ic, 359062306a36Sopenharmony_ci unsigned int journal_sectors, unsigned int interleave_sectors) 359162306a36Sopenharmony_ci{ 359262306a36Sopenharmony_ci unsigned int journal_sections; 359362306a36Sopenharmony_ci int test_bit; 359462306a36Sopenharmony_ci 359562306a36Sopenharmony_ci memset(ic->sb, 0, SB_SECTORS << SECTOR_SHIFT); 359662306a36Sopenharmony_ci memcpy(ic->sb->magic, SB_MAGIC, 8); 359762306a36Sopenharmony_ci ic->sb->integrity_tag_size = cpu_to_le16(ic->tag_size); 359862306a36Sopenharmony_ci ic->sb->log2_sectors_per_block = __ffs(ic->sectors_per_block); 359962306a36Sopenharmony_ci if (ic->journal_mac_alg.alg_string) 360062306a36Sopenharmony_ci ic->sb->flags |= cpu_to_le32(SB_FLAG_HAVE_JOURNAL_MAC); 360162306a36Sopenharmony_ci 360262306a36Sopenharmony_ci calculate_journal_section_size(ic); 360362306a36Sopenharmony_ci journal_sections = journal_sectors / ic->journal_section_sectors; 360462306a36Sopenharmony_ci if (!journal_sections) 360562306a36Sopenharmony_ci journal_sections = 1; 360662306a36Sopenharmony_ci 360762306a36Sopenharmony_ci if (ic->fix_hmac && (ic->internal_hash_alg.alg_string || ic->journal_mac_alg.alg_string)) { 360862306a36Sopenharmony_ci ic->sb->flags |= cpu_to_le32(SB_FLAG_FIXED_HMAC); 360962306a36Sopenharmony_ci get_random_bytes(ic->sb->salt, SALT_SIZE); 361062306a36Sopenharmony_ci } 361162306a36Sopenharmony_ci 361262306a36Sopenharmony_ci if (!ic->meta_dev) { 361362306a36Sopenharmony_ci if (ic->fix_padding) 361462306a36Sopenharmony_ci ic->sb->flags |= cpu_to_le32(SB_FLAG_FIXED_PADDING); 361562306a36Sopenharmony_ci ic->sb->journal_sections = cpu_to_le32(journal_sections); 361662306a36Sopenharmony_ci if (!interleave_sectors) 361762306a36Sopenharmony_ci interleave_sectors = DEFAULT_INTERLEAVE_SECTORS; 361862306a36Sopenharmony_ci ic->sb->log2_interleave_sectors = __fls(interleave_sectors); 361962306a36Sopenharmony_ci ic->sb->log2_interleave_sectors = max_t(__u8, MIN_LOG2_INTERLEAVE_SECTORS, ic->sb->log2_interleave_sectors); 362062306a36Sopenharmony_ci ic->sb->log2_interleave_sectors = min_t(__u8, MAX_LOG2_INTERLEAVE_SECTORS, ic->sb->log2_interleave_sectors); 362162306a36Sopenharmony_ci 362262306a36Sopenharmony_ci get_provided_data_sectors(ic); 362362306a36Sopenharmony_ci if (!ic->provided_data_sectors) 362462306a36Sopenharmony_ci return -EINVAL; 362562306a36Sopenharmony_ci } else { 362662306a36Sopenharmony_ci ic->sb->log2_interleave_sectors = 0; 362762306a36Sopenharmony_ci 362862306a36Sopenharmony_ci get_provided_data_sectors(ic); 362962306a36Sopenharmony_ci if (!ic->provided_data_sectors) 363062306a36Sopenharmony_ci return -EINVAL; 363162306a36Sopenharmony_ci 363262306a36Sopenharmony_citry_smaller_buffer: 363362306a36Sopenharmony_ci ic->sb->journal_sections = cpu_to_le32(0); 363462306a36Sopenharmony_ci for (test_bit = fls(journal_sections) - 1; test_bit >= 0; test_bit--) { 363562306a36Sopenharmony_ci __u32 prev_journal_sections = le32_to_cpu(ic->sb->journal_sections); 363662306a36Sopenharmony_ci __u32 test_journal_sections = prev_journal_sections | (1U << test_bit); 363762306a36Sopenharmony_ci 363862306a36Sopenharmony_ci if (test_journal_sections > journal_sections) 363962306a36Sopenharmony_ci continue; 364062306a36Sopenharmony_ci ic->sb->journal_sections = cpu_to_le32(test_journal_sections); 364162306a36Sopenharmony_ci if (calculate_device_limits(ic)) 364262306a36Sopenharmony_ci ic->sb->journal_sections = cpu_to_le32(prev_journal_sections); 364362306a36Sopenharmony_ci 364462306a36Sopenharmony_ci } 364562306a36Sopenharmony_ci if (!le32_to_cpu(ic->sb->journal_sections)) { 364662306a36Sopenharmony_ci if (ic->log2_buffer_sectors > 3) { 364762306a36Sopenharmony_ci ic->log2_buffer_sectors--; 364862306a36Sopenharmony_ci goto try_smaller_buffer; 364962306a36Sopenharmony_ci } 365062306a36Sopenharmony_ci return -EINVAL; 365162306a36Sopenharmony_ci } 365262306a36Sopenharmony_ci } 365362306a36Sopenharmony_ci 365462306a36Sopenharmony_ci ic->sb->provided_data_sectors = cpu_to_le64(ic->provided_data_sectors); 365562306a36Sopenharmony_ci 365662306a36Sopenharmony_ci sb_set_version(ic); 365762306a36Sopenharmony_ci 365862306a36Sopenharmony_ci return 0; 365962306a36Sopenharmony_ci} 366062306a36Sopenharmony_ci 366162306a36Sopenharmony_cistatic void dm_integrity_set(struct dm_target *ti, struct dm_integrity_c *ic) 366262306a36Sopenharmony_ci{ 366362306a36Sopenharmony_ci struct gendisk *disk = dm_disk(dm_table_get_md(ti->table)); 366462306a36Sopenharmony_ci struct blk_integrity bi; 366562306a36Sopenharmony_ci 366662306a36Sopenharmony_ci memset(&bi, 0, sizeof(bi)); 366762306a36Sopenharmony_ci bi.profile = &dm_integrity_profile; 366862306a36Sopenharmony_ci bi.tuple_size = ic->tag_size; 366962306a36Sopenharmony_ci bi.tag_size = bi.tuple_size; 367062306a36Sopenharmony_ci bi.interval_exp = ic->sb->log2_sectors_per_block + SECTOR_SHIFT; 367162306a36Sopenharmony_ci 367262306a36Sopenharmony_ci blk_integrity_register(disk, &bi); 367362306a36Sopenharmony_ci blk_queue_max_integrity_segments(disk->queue, UINT_MAX); 367462306a36Sopenharmony_ci} 367562306a36Sopenharmony_ci 367662306a36Sopenharmony_cistatic void dm_integrity_free_page_list(struct page_list *pl) 367762306a36Sopenharmony_ci{ 367862306a36Sopenharmony_ci unsigned int i; 367962306a36Sopenharmony_ci 368062306a36Sopenharmony_ci if (!pl) 368162306a36Sopenharmony_ci return; 368262306a36Sopenharmony_ci for (i = 0; pl[i].page; i++) 368362306a36Sopenharmony_ci __free_page(pl[i].page); 368462306a36Sopenharmony_ci kvfree(pl); 368562306a36Sopenharmony_ci} 368662306a36Sopenharmony_ci 368762306a36Sopenharmony_cistatic struct page_list *dm_integrity_alloc_page_list(unsigned int n_pages) 368862306a36Sopenharmony_ci{ 368962306a36Sopenharmony_ci struct page_list *pl; 369062306a36Sopenharmony_ci unsigned int i; 369162306a36Sopenharmony_ci 369262306a36Sopenharmony_ci pl = kvmalloc_array(n_pages + 1, sizeof(struct page_list), GFP_KERNEL | __GFP_ZERO); 369362306a36Sopenharmony_ci if (!pl) 369462306a36Sopenharmony_ci return NULL; 369562306a36Sopenharmony_ci 369662306a36Sopenharmony_ci for (i = 0; i < n_pages; i++) { 369762306a36Sopenharmony_ci pl[i].page = alloc_page(GFP_KERNEL); 369862306a36Sopenharmony_ci if (!pl[i].page) { 369962306a36Sopenharmony_ci dm_integrity_free_page_list(pl); 370062306a36Sopenharmony_ci return NULL; 370162306a36Sopenharmony_ci } 370262306a36Sopenharmony_ci if (i) 370362306a36Sopenharmony_ci pl[i - 1].next = &pl[i]; 370462306a36Sopenharmony_ci } 370562306a36Sopenharmony_ci pl[i].page = NULL; 370662306a36Sopenharmony_ci pl[i].next = NULL; 370762306a36Sopenharmony_ci 370862306a36Sopenharmony_ci return pl; 370962306a36Sopenharmony_ci} 371062306a36Sopenharmony_ci 371162306a36Sopenharmony_cistatic void dm_integrity_free_journal_scatterlist(struct dm_integrity_c *ic, struct scatterlist **sl) 371262306a36Sopenharmony_ci{ 371362306a36Sopenharmony_ci unsigned int i; 371462306a36Sopenharmony_ci 371562306a36Sopenharmony_ci for (i = 0; i < ic->journal_sections; i++) 371662306a36Sopenharmony_ci kvfree(sl[i]); 371762306a36Sopenharmony_ci kvfree(sl); 371862306a36Sopenharmony_ci} 371962306a36Sopenharmony_ci 372062306a36Sopenharmony_cistatic struct scatterlist **dm_integrity_alloc_journal_scatterlist(struct dm_integrity_c *ic, 372162306a36Sopenharmony_ci struct page_list *pl) 372262306a36Sopenharmony_ci{ 372362306a36Sopenharmony_ci struct scatterlist **sl; 372462306a36Sopenharmony_ci unsigned int i; 372562306a36Sopenharmony_ci 372662306a36Sopenharmony_ci sl = kvmalloc_array(ic->journal_sections, 372762306a36Sopenharmony_ci sizeof(struct scatterlist *), 372862306a36Sopenharmony_ci GFP_KERNEL | __GFP_ZERO); 372962306a36Sopenharmony_ci if (!sl) 373062306a36Sopenharmony_ci return NULL; 373162306a36Sopenharmony_ci 373262306a36Sopenharmony_ci for (i = 0; i < ic->journal_sections; i++) { 373362306a36Sopenharmony_ci struct scatterlist *s; 373462306a36Sopenharmony_ci unsigned int start_index, start_offset; 373562306a36Sopenharmony_ci unsigned int end_index, end_offset; 373662306a36Sopenharmony_ci unsigned int n_pages; 373762306a36Sopenharmony_ci unsigned int idx; 373862306a36Sopenharmony_ci 373962306a36Sopenharmony_ci page_list_location(ic, i, 0, &start_index, &start_offset); 374062306a36Sopenharmony_ci page_list_location(ic, i, ic->journal_section_sectors - 1, 374162306a36Sopenharmony_ci &end_index, &end_offset); 374262306a36Sopenharmony_ci 374362306a36Sopenharmony_ci n_pages = (end_index - start_index + 1); 374462306a36Sopenharmony_ci 374562306a36Sopenharmony_ci s = kvmalloc_array(n_pages, sizeof(struct scatterlist), 374662306a36Sopenharmony_ci GFP_KERNEL); 374762306a36Sopenharmony_ci if (!s) { 374862306a36Sopenharmony_ci dm_integrity_free_journal_scatterlist(ic, sl); 374962306a36Sopenharmony_ci return NULL; 375062306a36Sopenharmony_ci } 375162306a36Sopenharmony_ci 375262306a36Sopenharmony_ci sg_init_table(s, n_pages); 375362306a36Sopenharmony_ci for (idx = start_index; idx <= end_index; idx++) { 375462306a36Sopenharmony_ci char *va = lowmem_page_address(pl[idx].page); 375562306a36Sopenharmony_ci unsigned int start = 0, end = PAGE_SIZE; 375662306a36Sopenharmony_ci 375762306a36Sopenharmony_ci if (idx == start_index) 375862306a36Sopenharmony_ci start = start_offset; 375962306a36Sopenharmony_ci if (idx == end_index) 376062306a36Sopenharmony_ci end = end_offset + (1 << SECTOR_SHIFT); 376162306a36Sopenharmony_ci sg_set_buf(&s[idx - start_index], va + start, end - start); 376262306a36Sopenharmony_ci } 376362306a36Sopenharmony_ci 376462306a36Sopenharmony_ci sl[i] = s; 376562306a36Sopenharmony_ci } 376662306a36Sopenharmony_ci 376762306a36Sopenharmony_ci return sl; 376862306a36Sopenharmony_ci} 376962306a36Sopenharmony_ci 377062306a36Sopenharmony_cistatic void free_alg(struct alg_spec *a) 377162306a36Sopenharmony_ci{ 377262306a36Sopenharmony_ci kfree_sensitive(a->alg_string); 377362306a36Sopenharmony_ci kfree_sensitive(a->key); 377462306a36Sopenharmony_ci memset(a, 0, sizeof(*a)); 377562306a36Sopenharmony_ci} 377662306a36Sopenharmony_ci 377762306a36Sopenharmony_cistatic int get_alg_and_key(const char *arg, struct alg_spec *a, char **error, char *error_inval) 377862306a36Sopenharmony_ci{ 377962306a36Sopenharmony_ci char *k; 378062306a36Sopenharmony_ci 378162306a36Sopenharmony_ci free_alg(a); 378262306a36Sopenharmony_ci 378362306a36Sopenharmony_ci a->alg_string = kstrdup(strchr(arg, ':') + 1, GFP_KERNEL); 378462306a36Sopenharmony_ci if (!a->alg_string) 378562306a36Sopenharmony_ci goto nomem; 378662306a36Sopenharmony_ci 378762306a36Sopenharmony_ci k = strchr(a->alg_string, ':'); 378862306a36Sopenharmony_ci if (k) { 378962306a36Sopenharmony_ci *k = 0; 379062306a36Sopenharmony_ci a->key_string = k + 1; 379162306a36Sopenharmony_ci if (strlen(a->key_string) & 1) 379262306a36Sopenharmony_ci goto inval; 379362306a36Sopenharmony_ci 379462306a36Sopenharmony_ci a->key_size = strlen(a->key_string) / 2; 379562306a36Sopenharmony_ci a->key = kmalloc(a->key_size, GFP_KERNEL); 379662306a36Sopenharmony_ci if (!a->key) 379762306a36Sopenharmony_ci goto nomem; 379862306a36Sopenharmony_ci if (hex2bin(a->key, a->key_string, a->key_size)) 379962306a36Sopenharmony_ci goto inval; 380062306a36Sopenharmony_ci } 380162306a36Sopenharmony_ci 380262306a36Sopenharmony_ci return 0; 380362306a36Sopenharmony_ciinval: 380462306a36Sopenharmony_ci *error = error_inval; 380562306a36Sopenharmony_ci return -EINVAL; 380662306a36Sopenharmony_cinomem: 380762306a36Sopenharmony_ci *error = "Out of memory for an argument"; 380862306a36Sopenharmony_ci return -ENOMEM; 380962306a36Sopenharmony_ci} 381062306a36Sopenharmony_ci 381162306a36Sopenharmony_cistatic int get_mac(struct crypto_shash **hash, struct alg_spec *a, char **error, 381262306a36Sopenharmony_ci char *error_alg, char *error_key) 381362306a36Sopenharmony_ci{ 381462306a36Sopenharmony_ci int r; 381562306a36Sopenharmony_ci 381662306a36Sopenharmony_ci if (a->alg_string) { 381762306a36Sopenharmony_ci *hash = crypto_alloc_shash(a->alg_string, 0, CRYPTO_ALG_ALLOCATES_MEMORY); 381862306a36Sopenharmony_ci if (IS_ERR(*hash)) { 381962306a36Sopenharmony_ci *error = error_alg; 382062306a36Sopenharmony_ci r = PTR_ERR(*hash); 382162306a36Sopenharmony_ci *hash = NULL; 382262306a36Sopenharmony_ci return r; 382362306a36Sopenharmony_ci } 382462306a36Sopenharmony_ci 382562306a36Sopenharmony_ci if (a->key) { 382662306a36Sopenharmony_ci r = crypto_shash_setkey(*hash, a->key, a->key_size); 382762306a36Sopenharmony_ci if (r) { 382862306a36Sopenharmony_ci *error = error_key; 382962306a36Sopenharmony_ci return r; 383062306a36Sopenharmony_ci } 383162306a36Sopenharmony_ci } else if (crypto_shash_get_flags(*hash) & CRYPTO_TFM_NEED_KEY) { 383262306a36Sopenharmony_ci *error = error_key; 383362306a36Sopenharmony_ci return -ENOKEY; 383462306a36Sopenharmony_ci } 383562306a36Sopenharmony_ci } 383662306a36Sopenharmony_ci 383762306a36Sopenharmony_ci return 0; 383862306a36Sopenharmony_ci} 383962306a36Sopenharmony_ci 384062306a36Sopenharmony_cistatic int create_journal(struct dm_integrity_c *ic, char **error) 384162306a36Sopenharmony_ci{ 384262306a36Sopenharmony_ci int r = 0; 384362306a36Sopenharmony_ci unsigned int i; 384462306a36Sopenharmony_ci __u64 journal_pages, journal_desc_size, journal_tree_size; 384562306a36Sopenharmony_ci unsigned char *crypt_data = NULL, *crypt_iv = NULL; 384662306a36Sopenharmony_ci struct skcipher_request *req = NULL; 384762306a36Sopenharmony_ci 384862306a36Sopenharmony_ci ic->commit_ids[0] = cpu_to_le64(0x1111111111111111ULL); 384962306a36Sopenharmony_ci ic->commit_ids[1] = cpu_to_le64(0x2222222222222222ULL); 385062306a36Sopenharmony_ci ic->commit_ids[2] = cpu_to_le64(0x3333333333333333ULL); 385162306a36Sopenharmony_ci ic->commit_ids[3] = cpu_to_le64(0x4444444444444444ULL); 385262306a36Sopenharmony_ci 385362306a36Sopenharmony_ci journal_pages = roundup((__u64)ic->journal_sections * ic->journal_section_sectors, 385462306a36Sopenharmony_ci PAGE_SIZE >> SECTOR_SHIFT) >> (PAGE_SHIFT - SECTOR_SHIFT); 385562306a36Sopenharmony_ci journal_desc_size = journal_pages * sizeof(struct page_list); 385662306a36Sopenharmony_ci if (journal_pages >= totalram_pages() - totalhigh_pages() || journal_desc_size > ULONG_MAX) { 385762306a36Sopenharmony_ci *error = "Journal doesn't fit into memory"; 385862306a36Sopenharmony_ci r = -ENOMEM; 385962306a36Sopenharmony_ci goto bad; 386062306a36Sopenharmony_ci } 386162306a36Sopenharmony_ci ic->journal_pages = journal_pages; 386262306a36Sopenharmony_ci 386362306a36Sopenharmony_ci ic->journal = dm_integrity_alloc_page_list(ic->journal_pages); 386462306a36Sopenharmony_ci if (!ic->journal) { 386562306a36Sopenharmony_ci *error = "Could not allocate memory for journal"; 386662306a36Sopenharmony_ci r = -ENOMEM; 386762306a36Sopenharmony_ci goto bad; 386862306a36Sopenharmony_ci } 386962306a36Sopenharmony_ci if (ic->journal_crypt_alg.alg_string) { 387062306a36Sopenharmony_ci unsigned int ivsize, blocksize; 387162306a36Sopenharmony_ci struct journal_completion comp; 387262306a36Sopenharmony_ci 387362306a36Sopenharmony_ci comp.ic = ic; 387462306a36Sopenharmony_ci ic->journal_crypt = crypto_alloc_skcipher(ic->journal_crypt_alg.alg_string, 0, CRYPTO_ALG_ALLOCATES_MEMORY); 387562306a36Sopenharmony_ci if (IS_ERR(ic->journal_crypt)) { 387662306a36Sopenharmony_ci *error = "Invalid journal cipher"; 387762306a36Sopenharmony_ci r = PTR_ERR(ic->journal_crypt); 387862306a36Sopenharmony_ci ic->journal_crypt = NULL; 387962306a36Sopenharmony_ci goto bad; 388062306a36Sopenharmony_ci } 388162306a36Sopenharmony_ci ivsize = crypto_skcipher_ivsize(ic->journal_crypt); 388262306a36Sopenharmony_ci blocksize = crypto_skcipher_blocksize(ic->journal_crypt); 388362306a36Sopenharmony_ci 388462306a36Sopenharmony_ci if (ic->journal_crypt_alg.key) { 388562306a36Sopenharmony_ci r = crypto_skcipher_setkey(ic->journal_crypt, ic->journal_crypt_alg.key, 388662306a36Sopenharmony_ci ic->journal_crypt_alg.key_size); 388762306a36Sopenharmony_ci if (r) { 388862306a36Sopenharmony_ci *error = "Error setting encryption key"; 388962306a36Sopenharmony_ci goto bad; 389062306a36Sopenharmony_ci } 389162306a36Sopenharmony_ci } 389262306a36Sopenharmony_ci DEBUG_print("cipher %s, block size %u iv size %u\n", 389362306a36Sopenharmony_ci ic->journal_crypt_alg.alg_string, blocksize, ivsize); 389462306a36Sopenharmony_ci 389562306a36Sopenharmony_ci ic->journal_io = dm_integrity_alloc_page_list(ic->journal_pages); 389662306a36Sopenharmony_ci if (!ic->journal_io) { 389762306a36Sopenharmony_ci *error = "Could not allocate memory for journal io"; 389862306a36Sopenharmony_ci r = -ENOMEM; 389962306a36Sopenharmony_ci goto bad; 390062306a36Sopenharmony_ci } 390162306a36Sopenharmony_ci 390262306a36Sopenharmony_ci if (blocksize == 1) { 390362306a36Sopenharmony_ci struct scatterlist *sg; 390462306a36Sopenharmony_ci 390562306a36Sopenharmony_ci req = skcipher_request_alloc(ic->journal_crypt, GFP_KERNEL); 390662306a36Sopenharmony_ci if (!req) { 390762306a36Sopenharmony_ci *error = "Could not allocate crypt request"; 390862306a36Sopenharmony_ci r = -ENOMEM; 390962306a36Sopenharmony_ci goto bad; 391062306a36Sopenharmony_ci } 391162306a36Sopenharmony_ci 391262306a36Sopenharmony_ci crypt_iv = kzalloc(ivsize, GFP_KERNEL); 391362306a36Sopenharmony_ci if (!crypt_iv) { 391462306a36Sopenharmony_ci *error = "Could not allocate iv"; 391562306a36Sopenharmony_ci r = -ENOMEM; 391662306a36Sopenharmony_ci goto bad; 391762306a36Sopenharmony_ci } 391862306a36Sopenharmony_ci 391962306a36Sopenharmony_ci ic->journal_xor = dm_integrity_alloc_page_list(ic->journal_pages); 392062306a36Sopenharmony_ci if (!ic->journal_xor) { 392162306a36Sopenharmony_ci *error = "Could not allocate memory for journal xor"; 392262306a36Sopenharmony_ci r = -ENOMEM; 392362306a36Sopenharmony_ci goto bad; 392462306a36Sopenharmony_ci } 392562306a36Sopenharmony_ci 392662306a36Sopenharmony_ci sg = kvmalloc_array(ic->journal_pages + 1, 392762306a36Sopenharmony_ci sizeof(struct scatterlist), 392862306a36Sopenharmony_ci GFP_KERNEL); 392962306a36Sopenharmony_ci if (!sg) { 393062306a36Sopenharmony_ci *error = "Unable to allocate sg list"; 393162306a36Sopenharmony_ci r = -ENOMEM; 393262306a36Sopenharmony_ci goto bad; 393362306a36Sopenharmony_ci } 393462306a36Sopenharmony_ci sg_init_table(sg, ic->journal_pages + 1); 393562306a36Sopenharmony_ci for (i = 0; i < ic->journal_pages; i++) { 393662306a36Sopenharmony_ci char *va = lowmem_page_address(ic->journal_xor[i].page); 393762306a36Sopenharmony_ci 393862306a36Sopenharmony_ci clear_page(va); 393962306a36Sopenharmony_ci sg_set_buf(&sg[i], va, PAGE_SIZE); 394062306a36Sopenharmony_ci } 394162306a36Sopenharmony_ci sg_set_buf(&sg[i], &ic->commit_ids, sizeof(ic->commit_ids)); 394262306a36Sopenharmony_ci 394362306a36Sopenharmony_ci skcipher_request_set_crypt(req, sg, sg, 394462306a36Sopenharmony_ci PAGE_SIZE * ic->journal_pages + sizeof(ic->commit_ids), crypt_iv); 394562306a36Sopenharmony_ci init_completion(&comp.comp); 394662306a36Sopenharmony_ci comp.in_flight = (atomic_t)ATOMIC_INIT(1); 394762306a36Sopenharmony_ci if (do_crypt(true, req, &comp)) 394862306a36Sopenharmony_ci wait_for_completion(&comp.comp); 394962306a36Sopenharmony_ci kvfree(sg); 395062306a36Sopenharmony_ci r = dm_integrity_failed(ic); 395162306a36Sopenharmony_ci if (r) { 395262306a36Sopenharmony_ci *error = "Unable to encrypt journal"; 395362306a36Sopenharmony_ci goto bad; 395462306a36Sopenharmony_ci } 395562306a36Sopenharmony_ci DEBUG_bytes(lowmem_page_address(ic->journal_xor[0].page), 64, "xor data"); 395662306a36Sopenharmony_ci 395762306a36Sopenharmony_ci crypto_free_skcipher(ic->journal_crypt); 395862306a36Sopenharmony_ci ic->journal_crypt = NULL; 395962306a36Sopenharmony_ci } else { 396062306a36Sopenharmony_ci unsigned int crypt_len = roundup(ivsize, blocksize); 396162306a36Sopenharmony_ci 396262306a36Sopenharmony_ci req = skcipher_request_alloc(ic->journal_crypt, GFP_KERNEL); 396362306a36Sopenharmony_ci if (!req) { 396462306a36Sopenharmony_ci *error = "Could not allocate crypt request"; 396562306a36Sopenharmony_ci r = -ENOMEM; 396662306a36Sopenharmony_ci goto bad; 396762306a36Sopenharmony_ci } 396862306a36Sopenharmony_ci 396962306a36Sopenharmony_ci crypt_iv = kmalloc(ivsize, GFP_KERNEL); 397062306a36Sopenharmony_ci if (!crypt_iv) { 397162306a36Sopenharmony_ci *error = "Could not allocate iv"; 397262306a36Sopenharmony_ci r = -ENOMEM; 397362306a36Sopenharmony_ci goto bad; 397462306a36Sopenharmony_ci } 397562306a36Sopenharmony_ci 397662306a36Sopenharmony_ci crypt_data = kmalloc(crypt_len, GFP_KERNEL); 397762306a36Sopenharmony_ci if (!crypt_data) { 397862306a36Sopenharmony_ci *error = "Unable to allocate crypt data"; 397962306a36Sopenharmony_ci r = -ENOMEM; 398062306a36Sopenharmony_ci goto bad; 398162306a36Sopenharmony_ci } 398262306a36Sopenharmony_ci 398362306a36Sopenharmony_ci ic->journal_scatterlist = dm_integrity_alloc_journal_scatterlist(ic, ic->journal); 398462306a36Sopenharmony_ci if (!ic->journal_scatterlist) { 398562306a36Sopenharmony_ci *error = "Unable to allocate sg list"; 398662306a36Sopenharmony_ci r = -ENOMEM; 398762306a36Sopenharmony_ci goto bad; 398862306a36Sopenharmony_ci } 398962306a36Sopenharmony_ci ic->journal_io_scatterlist = dm_integrity_alloc_journal_scatterlist(ic, ic->journal_io); 399062306a36Sopenharmony_ci if (!ic->journal_io_scatterlist) { 399162306a36Sopenharmony_ci *error = "Unable to allocate sg list"; 399262306a36Sopenharmony_ci r = -ENOMEM; 399362306a36Sopenharmony_ci goto bad; 399462306a36Sopenharmony_ci } 399562306a36Sopenharmony_ci ic->sk_requests = kvmalloc_array(ic->journal_sections, 399662306a36Sopenharmony_ci sizeof(struct skcipher_request *), 399762306a36Sopenharmony_ci GFP_KERNEL | __GFP_ZERO); 399862306a36Sopenharmony_ci if (!ic->sk_requests) { 399962306a36Sopenharmony_ci *error = "Unable to allocate sk requests"; 400062306a36Sopenharmony_ci r = -ENOMEM; 400162306a36Sopenharmony_ci goto bad; 400262306a36Sopenharmony_ci } 400362306a36Sopenharmony_ci for (i = 0; i < ic->journal_sections; i++) { 400462306a36Sopenharmony_ci struct scatterlist sg; 400562306a36Sopenharmony_ci struct skcipher_request *section_req; 400662306a36Sopenharmony_ci __le32 section_le = cpu_to_le32(i); 400762306a36Sopenharmony_ci 400862306a36Sopenharmony_ci memset(crypt_iv, 0x00, ivsize); 400962306a36Sopenharmony_ci memset(crypt_data, 0x00, crypt_len); 401062306a36Sopenharmony_ci memcpy(crypt_data, §ion_le, min_t(size_t, crypt_len, sizeof(section_le))); 401162306a36Sopenharmony_ci 401262306a36Sopenharmony_ci sg_init_one(&sg, crypt_data, crypt_len); 401362306a36Sopenharmony_ci skcipher_request_set_crypt(req, &sg, &sg, crypt_len, crypt_iv); 401462306a36Sopenharmony_ci init_completion(&comp.comp); 401562306a36Sopenharmony_ci comp.in_flight = (atomic_t)ATOMIC_INIT(1); 401662306a36Sopenharmony_ci if (do_crypt(true, req, &comp)) 401762306a36Sopenharmony_ci wait_for_completion(&comp.comp); 401862306a36Sopenharmony_ci 401962306a36Sopenharmony_ci r = dm_integrity_failed(ic); 402062306a36Sopenharmony_ci if (r) { 402162306a36Sopenharmony_ci *error = "Unable to generate iv"; 402262306a36Sopenharmony_ci goto bad; 402362306a36Sopenharmony_ci } 402462306a36Sopenharmony_ci 402562306a36Sopenharmony_ci section_req = skcipher_request_alloc(ic->journal_crypt, GFP_KERNEL); 402662306a36Sopenharmony_ci if (!section_req) { 402762306a36Sopenharmony_ci *error = "Unable to allocate crypt request"; 402862306a36Sopenharmony_ci r = -ENOMEM; 402962306a36Sopenharmony_ci goto bad; 403062306a36Sopenharmony_ci } 403162306a36Sopenharmony_ci section_req->iv = kmalloc_array(ivsize, 2, 403262306a36Sopenharmony_ci GFP_KERNEL); 403362306a36Sopenharmony_ci if (!section_req->iv) { 403462306a36Sopenharmony_ci skcipher_request_free(section_req); 403562306a36Sopenharmony_ci *error = "Unable to allocate iv"; 403662306a36Sopenharmony_ci r = -ENOMEM; 403762306a36Sopenharmony_ci goto bad; 403862306a36Sopenharmony_ci } 403962306a36Sopenharmony_ci memcpy(section_req->iv + ivsize, crypt_data, ivsize); 404062306a36Sopenharmony_ci section_req->cryptlen = (size_t)ic->journal_section_sectors << SECTOR_SHIFT; 404162306a36Sopenharmony_ci ic->sk_requests[i] = section_req; 404262306a36Sopenharmony_ci DEBUG_bytes(crypt_data, ivsize, "iv(%u)", i); 404362306a36Sopenharmony_ci } 404462306a36Sopenharmony_ci } 404562306a36Sopenharmony_ci } 404662306a36Sopenharmony_ci 404762306a36Sopenharmony_ci for (i = 0; i < N_COMMIT_IDS; i++) { 404862306a36Sopenharmony_ci unsigned int j; 404962306a36Sopenharmony_ci 405062306a36Sopenharmony_ciretest_commit_id: 405162306a36Sopenharmony_ci for (j = 0; j < i; j++) { 405262306a36Sopenharmony_ci if (ic->commit_ids[j] == ic->commit_ids[i]) { 405362306a36Sopenharmony_ci ic->commit_ids[i] = cpu_to_le64(le64_to_cpu(ic->commit_ids[i]) + 1); 405462306a36Sopenharmony_ci goto retest_commit_id; 405562306a36Sopenharmony_ci } 405662306a36Sopenharmony_ci } 405762306a36Sopenharmony_ci DEBUG_print("commit id %u: %016llx\n", i, ic->commit_ids[i]); 405862306a36Sopenharmony_ci } 405962306a36Sopenharmony_ci 406062306a36Sopenharmony_ci journal_tree_size = (__u64)ic->journal_entries * sizeof(struct journal_node); 406162306a36Sopenharmony_ci if (journal_tree_size > ULONG_MAX) { 406262306a36Sopenharmony_ci *error = "Journal doesn't fit into memory"; 406362306a36Sopenharmony_ci r = -ENOMEM; 406462306a36Sopenharmony_ci goto bad; 406562306a36Sopenharmony_ci } 406662306a36Sopenharmony_ci ic->journal_tree = kvmalloc(journal_tree_size, GFP_KERNEL); 406762306a36Sopenharmony_ci if (!ic->journal_tree) { 406862306a36Sopenharmony_ci *error = "Could not allocate memory for journal tree"; 406962306a36Sopenharmony_ci r = -ENOMEM; 407062306a36Sopenharmony_ci } 407162306a36Sopenharmony_cibad: 407262306a36Sopenharmony_ci kfree(crypt_data); 407362306a36Sopenharmony_ci kfree(crypt_iv); 407462306a36Sopenharmony_ci skcipher_request_free(req); 407562306a36Sopenharmony_ci 407662306a36Sopenharmony_ci return r; 407762306a36Sopenharmony_ci} 407862306a36Sopenharmony_ci 407962306a36Sopenharmony_ci/* 408062306a36Sopenharmony_ci * Construct a integrity mapping 408162306a36Sopenharmony_ci * 408262306a36Sopenharmony_ci * Arguments: 408362306a36Sopenharmony_ci * device 408462306a36Sopenharmony_ci * offset from the start of the device 408562306a36Sopenharmony_ci * tag size 408662306a36Sopenharmony_ci * D - direct writes, J - journal writes, B - bitmap mode, R - recovery mode 408762306a36Sopenharmony_ci * number of optional arguments 408862306a36Sopenharmony_ci * optional arguments: 408962306a36Sopenharmony_ci * journal_sectors 409062306a36Sopenharmony_ci * interleave_sectors 409162306a36Sopenharmony_ci * buffer_sectors 409262306a36Sopenharmony_ci * journal_watermark 409362306a36Sopenharmony_ci * commit_time 409462306a36Sopenharmony_ci * meta_device 409562306a36Sopenharmony_ci * block_size 409662306a36Sopenharmony_ci * sectors_per_bit 409762306a36Sopenharmony_ci * bitmap_flush_interval 409862306a36Sopenharmony_ci * internal_hash 409962306a36Sopenharmony_ci * journal_crypt 410062306a36Sopenharmony_ci * journal_mac 410162306a36Sopenharmony_ci * recalculate 410262306a36Sopenharmony_ci */ 410362306a36Sopenharmony_cistatic int dm_integrity_ctr(struct dm_target *ti, unsigned int argc, char **argv) 410462306a36Sopenharmony_ci{ 410562306a36Sopenharmony_ci struct dm_integrity_c *ic; 410662306a36Sopenharmony_ci char dummy; 410762306a36Sopenharmony_ci int r; 410862306a36Sopenharmony_ci unsigned int extra_args; 410962306a36Sopenharmony_ci struct dm_arg_set as; 411062306a36Sopenharmony_ci static const struct dm_arg _args[] = { 411162306a36Sopenharmony_ci {0, 18, "Invalid number of feature args"}, 411262306a36Sopenharmony_ci }; 411362306a36Sopenharmony_ci unsigned int journal_sectors, interleave_sectors, buffer_sectors, journal_watermark, sync_msec; 411462306a36Sopenharmony_ci bool should_write_sb; 411562306a36Sopenharmony_ci __u64 threshold; 411662306a36Sopenharmony_ci unsigned long long start; 411762306a36Sopenharmony_ci __s8 log2_sectors_per_bitmap_bit = -1; 411862306a36Sopenharmony_ci __s8 log2_blocks_per_bitmap_bit; 411962306a36Sopenharmony_ci __u64 bits_in_journal; 412062306a36Sopenharmony_ci __u64 n_bitmap_bits; 412162306a36Sopenharmony_ci 412262306a36Sopenharmony_ci#define DIRECT_ARGUMENTS 4 412362306a36Sopenharmony_ci 412462306a36Sopenharmony_ci if (argc <= DIRECT_ARGUMENTS) { 412562306a36Sopenharmony_ci ti->error = "Invalid argument count"; 412662306a36Sopenharmony_ci return -EINVAL; 412762306a36Sopenharmony_ci } 412862306a36Sopenharmony_ci 412962306a36Sopenharmony_ci ic = kzalloc(sizeof(struct dm_integrity_c), GFP_KERNEL); 413062306a36Sopenharmony_ci if (!ic) { 413162306a36Sopenharmony_ci ti->error = "Cannot allocate integrity context"; 413262306a36Sopenharmony_ci return -ENOMEM; 413362306a36Sopenharmony_ci } 413462306a36Sopenharmony_ci ti->private = ic; 413562306a36Sopenharmony_ci ti->per_io_data_size = sizeof(struct dm_integrity_io); 413662306a36Sopenharmony_ci ic->ti = ti; 413762306a36Sopenharmony_ci 413862306a36Sopenharmony_ci ic->in_progress = RB_ROOT; 413962306a36Sopenharmony_ci INIT_LIST_HEAD(&ic->wait_list); 414062306a36Sopenharmony_ci init_waitqueue_head(&ic->endio_wait); 414162306a36Sopenharmony_ci bio_list_init(&ic->flush_bio_list); 414262306a36Sopenharmony_ci init_waitqueue_head(&ic->copy_to_journal_wait); 414362306a36Sopenharmony_ci init_completion(&ic->crypto_backoff); 414462306a36Sopenharmony_ci atomic64_set(&ic->number_of_mismatches, 0); 414562306a36Sopenharmony_ci ic->bitmap_flush_interval = BITMAP_FLUSH_INTERVAL; 414662306a36Sopenharmony_ci 414762306a36Sopenharmony_ci r = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &ic->dev); 414862306a36Sopenharmony_ci if (r) { 414962306a36Sopenharmony_ci ti->error = "Device lookup failed"; 415062306a36Sopenharmony_ci goto bad; 415162306a36Sopenharmony_ci } 415262306a36Sopenharmony_ci 415362306a36Sopenharmony_ci if (sscanf(argv[1], "%llu%c", &start, &dummy) != 1 || start != (sector_t)start) { 415462306a36Sopenharmony_ci ti->error = "Invalid starting offset"; 415562306a36Sopenharmony_ci r = -EINVAL; 415662306a36Sopenharmony_ci goto bad; 415762306a36Sopenharmony_ci } 415862306a36Sopenharmony_ci ic->start = start; 415962306a36Sopenharmony_ci 416062306a36Sopenharmony_ci if (strcmp(argv[2], "-")) { 416162306a36Sopenharmony_ci if (sscanf(argv[2], "%u%c", &ic->tag_size, &dummy) != 1 || !ic->tag_size) { 416262306a36Sopenharmony_ci ti->error = "Invalid tag size"; 416362306a36Sopenharmony_ci r = -EINVAL; 416462306a36Sopenharmony_ci goto bad; 416562306a36Sopenharmony_ci } 416662306a36Sopenharmony_ci } 416762306a36Sopenharmony_ci 416862306a36Sopenharmony_ci if (!strcmp(argv[3], "J") || !strcmp(argv[3], "B") || 416962306a36Sopenharmony_ci !strcmp(argv[3], "D") || !strcmp(argv[3], "R")) { 417062306a36Sopenharmony_ci ic->mode = argv[3][0]; 417162306a36Sopenharmony_ci } else { 417262306a36Sopenharmony_ci ti->error = "Invalid mode (expecting J, B, D, R)"; 417362306a36Sopenharmony_ci r = -EINVAL; 417462306a36Sopenharmony_ci goto bad; 417562306a36Sopenharmony_ci } 417662306a36Sopenharmony_ci 417762306a36Sopenharmony_ci journal_sectors = 0; 417862306a36Sopenharmony_ci interleave_sectors = DEFAULT_INTERLEAVE_SECTORS; 417962306a36Sopenharmony_ci buffer_sectors = DEFAULT_BUFFER_SECTORS; 418062306a36Sopenharmony_ci journal_watermark = DEFAULT_JOURNAL_WATERMARK; 418162306a36Sopenharmony_ci sync_msec = DEFAULT_SYNC_MSEC; 418262306a36Sopenharmony_ci ic->sectors_per_block = 1; 418362306a36Sopenharmony_ci 418462306a36Sopenharmony_ci as.argc = argc - DIRECT_ARGUMENTS; 418562306a36Sopenharmony_ci as.argv = argv + DIRECT_ARGUMENTS; 418662306a36Sopenharmony_ci r = dm_read_arg_group(_args, &as, &extra_args, &ti->error); 418762306a36Sopenharmony_ci if (r) 418862306a36Sopenharmony_ci goto bad; 418962306a36Sopenharmony_ci 419062306a36Sopenharmony_ci while (extra_args--) { 419162306a36Sopenharmony_ci const char *opt_string; 419262306a36Sopenharmony_ci unsigned int val; 419362306a36Sopenharmony_ci unsigned long long llval; 419462306a36Sopenharmony_ci 419562306a36Sopenharmony_ci opt_string = dm_shift_arg(&as); 419662306a36Sopenharmony_ci if (!opt_string) { 419762306a36Sopenharmony_ci r = -EINVAL; 419862306a36Sopenharmony_ci ti->error = "Not enough feature arguments"; 419962306a36Sopenharmony_ci goto bad; 420062306a36Sopenharmony_ci } 420162306a36Sopenharmony_ci if (sscanf(opt_string, "journal_sectors:%u%c", &val, &dummy) == 1) 420262306a36Sopenharmony_ci journal_sectors = val ? val : 1; 420362306a36Sopenharmony_ci else if (sscanf(opt_string, "interleave_sectors:%u%c", &val, &dummy) == 1) 420462306a36Sopenharmony_ci interleave_sectors = val; 420562306a36Sopenharmony_ci else if (sscanf(opt_string, "buffer_sectors:%u%c", &val, &dummy) == 1) 420662306a36Sopenharmony_ci buffer_sectors = val; 420762306a36Sopenharmony_ci else if (sscanf(opt_string, "journal_watermark:%u%c", &val, &dummy) == 1 && val <= 100) 420862306a36Sopenharmony_ci journal_watermark = val; 420962306a36Sopenharmony_ci else if (sscanf(opt_string, "commit_time:%u%c", &val, &dummy) == 1) 421062306a36Sopenharmony_ci sync_msec = val; 421162306a36Sopenharmony_ci else if (!strncmp(opt_string, "meta_device:", strlen("meta_device:"))) { 421262306a36Sopenharmony_ci if (ic->meta_dev) { 421362306a36Sopenharmony_ci dm_put_device(ti, ic->meta_dev); 421462306a36Sopenharmony_ci ic->meta_dev = NULL; 421562306a36Sopenharmony_ci } 421662306a36Sopenharmony_ci r = dm_get_device(ti, strchr(opt_string, ':') + 1, 421762306a36Sopenharmony_ci dm_table_get_mode(ti->table), &ic->meta_dev); 421862306a36Sopenharmony_ci if (r) { 421962306a36Sopenharmony_ci ti->error = "Device lookup failed"; 422062306a36Sopenharmony_ci goto bad; 422162306a36Sopenharmony_ci } 422262306a36Sopenharmony_ci } else if (sscanf(opt_string, "block_size:%u%c", &val, &dummy) == 1) { 422362306a36Sopenharmony_ci if (val < 1 << SECTOR_SHIFT || 422462306a36Sopenharmony_ci val > MAX_SECTORS_PER_BLOCK << SECTOR_SHIFT || 422562306a36Sopenharmony_ci (val & (val - 1))) { 422662306a36Sopenharmony_ci r = -EINVAL; 422762306a36Sopenharmony_ci ti->error = "Invalid block_size argument"; 422862306a36Sopenharmony_ci goto bad; 422962306a36Sopenharmony_ci } 423062306a36Sopenharmony_ci ic->sectors_per_block = val >> SECTOR_SHIFT; 423162306a36Sopenharmony_ci } else if (sscanf(opt_string, "sectors_per_bit:%llu%c", &llval, &dummy) == 1) { 423262306a36Sopenharmony_ci log2_sectors_per_bitmap_bit = !llval ? 0 : __ilog2_u64(llval); 423362306a36Sopenharmony_ci } else if (sscanf(opt_string, "bitmap_flush_interval:%u%c", &val, &dummy) == 1) { 423462306a36Sopenharmony_ci if (val >= (uint64_t)UINT_MAX * 1000 / HZ) { 423562306a36Sopenharmony_ci r = -EINVAL; 423662306a36Sopenharmony_ci ti->error = "Invalid bitmap_flush_interval argument"; 423762306a36Sopenharmony_ci goto bad; 423862306a36Sopenharmony_ci } 423962306a36Sopenharmony_ci ic->bitmap_flush_interval = msecs_to_jiffies(val); 424062306a36Sopenharmony_ci } else if (!strncmp(opt_string, "internal_hash:", strlen("internal_hash:"))) { 424162306a36Sopenharmony_ci r = get_alg_and_key(opt_string, &ic->internal_hash_alg, &ti->error, 424262306a36Sopenharmony_ci "Invalid internal_hash argument"); 424362306a36Sopenharmony_ci if (r) 424462306a36Sopenharmony_ci goto bad; 424562306a36Sopenharmony_ci } else if (!strncmp(opt_string, "journal_crypt:", strlen("journal_crypt:"))) { 424662306a36Sopenharmony_ci r = get_alg_and_key(opt_string, &ic->journal_crypt_alg, &ti->error, 424762306a36Sopenharmony_ci "Invalid journal_crypt argument"); 424862306a36Sopenharmony_ci if (r) 424962306a36Sopenharmony_ci goto bad; 425062306a36Sopenharmony_ci } else if (!strncmp(opt_string, "journal_mac:", strlen("journal_mac:"))) { 425162306a36Sopenharmony_ci r = get_alg_and_key(opt_string, &ic->journal_mac_alg, &ti->error, 425262306a36Sopenharmony_ci "Invalid journal_mac argument"); 425362306a36Sopenharmony_ci if (r) 425462306a36Sopenharmony_ci goto bad; 425562306a36Sopenharmony_ci } else if (!strcmp(opt_string, "recalculate")) { 425662306a36Sopenharmony_ci ic->recalculate_flag = true; 425762306a36Sopenharmony_ci } else if (!strcmp(opt_string, "reset_recalculate")) { 425862306a36Sopenharmony_ci ic->recalculate_flag = true; 425962306a36Sopenharmony_ci ic->reset_recalculate_flag = true; 426062306a36Sopenharmony_ci } else if (!strcmp(opt_string, "allow_discards")) { 426162306a36Sopenharmony_ci ic->discard = true; 426262306a36Sopenharmony_ci } else if (!strcmp(opt_string, "fix_padding")) { 426362306a36Sopenharmony_ci ic->fix_padding = true; 426462306a36Sopenharmony_ci } else if (!strcmp(opt_string, "fix_hmac")) { 426562306a36Sopenharmony_ci ic->fix_hmac = true; 426662306a36Sopenharmony_ci } else if (!strcmp(opt_string, "legacy_recalculate")) { 426762306a36Sopenharmony_ci ic->legacy_recalculate = true; 426862306a36Sopenharmony_ci } else { 426962306a36Sopenharmony_ci r = -EINVAL; 427062306a36Sopenharmony_ci ti->error = "Invalid argument"; 427162306a36Sopenharmony_ci goto bad; 427262306a36Sopenharmony_ci } 427362306a36Sopenharmony_ci } 427462306a36Sopenharmony_ci 427562306a36Sopenharmony_ci ic->data_device_sectors = bdev_nr_sectors(ic->dev->bdev); 427662306a36Sopenharmony_ci if (!ic->meta_dev) 427762306a36Sopenharmony_ci ic->meta_device_sectors = ic->data_device_sectors; 427862306a36Sopenharmony_ci else 427962306a36Sopenharmony_ci ic->meta_device_sectors = bdev_nr_sectors(ic->meta_dev->bdev); 428062306a36Sopenharmony_ci 428162306a36Sopenharmony_ci if (!journal_sectors) { 428262306a36Sopenharmony_ci journal_sectors = min((sector_t)DEFAULT_MAX_JOURNAL_SECTORS, 428362306a36Sopenharmony_ci ic->data_device_sectors >> DEFAULT_JOURNAL_SIZE_FACTOR); 428462306a36Sopenharmony_ci } 428562306a36Sopenharmony_ci 428662306a36Sopenharmony_ci if (!buffer_sectors) 428762306a36Sopenharmony_ci buffer_sectors = 1; 428862306a36Sopenharmony_ci ic->log2_buffer_sectors = min((int)__fls(buffer_sectors), 31 - SECTOR_SHIFT); 428962306a36Sopenharmony_ci 429062306a36Sopenharmony_ci r = get_mac(&ic->internal_hash, &ic->internal_hash_alg, &ti->error, 429162306a36Sopenharmony_ci "Invalid internal hash", "Error setting internal hash key"); 429262306a36Sopenharmony_ci if (r) 429362306a36Sopenharmony_ci goto bad; 429462306a36Sopenharmony_ci 429562306a36Sopenharmony_ci r = get_mac(&ic->journal_mac, &ic->journal_mac_alg, &ti->error, 429662306a36Sopenharmony_ci "Invalid journal mac", "Error setting journal mac key"); 429762306a36Sopenharmony_ci if (r) 429862306a36Sopenharmony_ci goto bad; 429962306a36Sopenharmony_ci 430062306a36Sopenharmony_ci if (!ic->tag_size) { 430162306a36Sopenharmony_ci if (!ic->internal_hash) { 430262306a36Sopenharmony_ci ti->error = "Unknown tag size"; 430362306a36Sopenharmony_ci r = -EINVAL; 430462306a36Sopenharmony_ci goto bad; 430562306a36Sopenharmony_ci } 430662306a36Sopenharmony_ci ic->tag_size = crypto_shash_digestsize(ic->internal_hash); 430762306a36Sopenharmony_ci } 430862306a36Sopenharmony_ci if (ic->tag_size > MAX_TAG_SIZE) { 430962306a36Sopenharmony_ci ti->error = "Too big tag size"; 431062306a36Sopenharmony_ci r = -EINVAL; 431162306a36Sopenharmony_ci goto bad; 431262306a36Sopenharmony_ci } 431362306a36Sopenharmony_ci if (!(ic->tag_size & (ic->tag_size - 1))) 431462306a36Sopenharmony_ci ic->log2_tag_size = __ffs(ic->tag_size); 431562306a36Sopenharmony_ci else 431662306a36Sopenharmony_ci ic->log2_tag_size = -1; 431762306a36Sopenharmony_ci 431862306a36Sopenharmony_ci if (ic->mode == 'B' && !ic->internal_hash) { 431962306a36Sopenharmony_ci r = -EINVAL; 432062306a36Sopenharmony_ci ti->error = "Bitmap mode can be only used with internal hash"; 432162306a36Sopenharmony_ci goto bad; 432262306a36Sopenharmony_ci } 432362306a36Sopenharmony_ci 432462306a36Sopenharmony_ci if (ic->discard && !ic->internal_hash) { 432562306a36Sopenharmony_ci r = -EINVAL; 432662306a36Sopenharmony_ci ti->error = "Discard can be only used with internal hash"; 432762306a36Sopenharmony_ci goto bad; 432862306a36Sopenharmony_ci } 432962306a36Sopenharmony_ci 433062306a36Sopenharmony_ci ic->autocommit_jiffies = msecs_to_jiffies(sync_msec); 433162306a36Sopenharmony_ci ic->autocommit_msec = sync_msec; 433262306a36Sopenharmony_ci timer_setup(&ic->autocommit_timer, autocommit_fn, 0); 433362306a36Sopenharmony_ci 433462306a36Sopenharmony_ci ic->io = dm_io_client_create(); 433562306a36Sopenharmony_ci if (IS_ERR(ic->io)) { 433662306a36Sopenharmony_ci r = PTR_ERR(ic->io); 433762306a36Sopenharmony_ci ic->io = NULL; 433862306a36Sopenharmony_ci ti->error = "Cannot allocate dm io"; 433962306a36Sopenharmony_ci goto bad; 434062306a36Sopenharmony_ci } 434162306a36Sopenharmony_ci 434262306a36Sopenharmony_ci r = mempool_init_slab_pool(&ic->journal_io_mempool, JOURNAL_IO_MEMPOOL, journal_io_cache); 434362306a36Sopenharmony_ci if (r) { 434462306a36Sopenharmony_ci ti->error = "Cannot allocate mempool"; 434562306a36Sopenharmony_ci goto bad; 434662306a36Sopenharmony_ci } 434762306a36Sopenharmony_ci 434862306a36Sopenharmony_ci r = mempool_init_page_pool(&ic->recheck_pool, 1, 0); 434962306a36Sopenharmony_ci if (r) { 435062306a36Sopenharmony_ci ti->error = "Cannot allocate mempool"; 435162306a36Sopenharmony_ci goto bad; 435262306a36Sopenharmony_ci } 435362306a36Sopenharmony_ci 435462306a36Sopenharmony_ci ic->metadata_wq = alloc_workqueue("dm-integrity-metadata", 435562306a36Sopenharmony_ci WQ_MEM_RECLAIM, METADATA_WORKQUEUE_MAX_ACTIVE); 435662306a36Sopenharmony_ci if (!ic->metadata_wq) { 435762306a36Sopenharmony_ci ti->error = "Cannot allocate workqueue"; 435862306a36Sopenharmony_ci r = -ENOMEM; 435962306a36Sopenharmony_ci goto bad; 436062306a36Sopenharmony_ci } 436162306a36Sopenharmony_ci 436262306a36Sopenharmony_ci /* 436362306a36Sopenharmony_ci * If this workqueue weren't ordered, it would cause bio reordering 436462306a36Sopenharmony_ci * and reduced performance. 436562306a36Sopenharmony_ci */ 436662306a36Sopenharmony_ci ic->wait_wq = alloc_ordered_workqueue("dm-integrity-wait", WQ_MEM_RECLAIM); 436762306a36Sopenharmony_ci if (!ic->wait_wq) { 436862306a36Sopenharmony_ci ti->error = "Cannot allocate workqueue"; 436962306a36Sopenharmony_ci r = -ENOMEM; 437062306a36Sopenharmony_ci goto bad; 437162306a36Sopenharmony_ci } 437262306a36Sopenharmony_ci 437362306a36Sopenharmony_ci ic->offload_wq = alloc_workqueue("dm-integrity-offload", WQ_MEM_RECLAIM, 437462306a36Sopenharmony_ci METADATA_WORKQUEUE_MAX_ACTIVE); 437562306a36Sopenharmony_ci if (!ic->offload_wq) { 437662306a36Sopenharmony_ci ti->error = "Cannot allocate workqueue"; 437762306a36Sopenharmony_ci r = -ENOMEM; 437862306a36Sopenharmony_ci goto bad; 437962306a36Sopenharmony_ci } 438062306a36Sopenharmony_ci 438162306a36Sopenharmony_ci ic->commit_wq = alloc_workqueue("dm-integrity-commit", WQ_MEM_RECLAIM, 1); 438262306a36Sopenharmony_ci if (!ic->commit_wq) { 438362306a36Sopenharmony_ci ti->error = "Cannot allocate workqueue"; 438462306a36Sopenharmony_ci r = -ENOMEM; 438562306a36Sopenharmony_ci goto bad; 438662306a36Sopenharmony_ci } 438762306a36Sopenharmony_ci INIT_WORK(&ic->commit_work, integrity_commit); 438862306a36Sopenharmony_ci 438962306a36Sopenharmony_ci if (ic->mode == 'J' || ic->mode == 'B') { 439062306a36Sopenharmony_ci ic->writer_wq = alloc_workqueue("dm-integrity-writer", WQ_MEM_RECLAIM, 1); 439162306a36Sopenharmony_ci if (!ic->writer_wq) { 439262306a36Sopenharmony_ci ti->error = "Cannot allocate workqueue"; 439362306a36Sopenharmony_ci r = -ENOMEM; 439462306a36Sopenharmony_ci goto bad; 439562306a36Sopenharmony_ci } 439662306a36Sopenharmony_ci INIT_WORK(&ic->writer_work, integrity_writer); 439762306a36Sopenharmony_ci } 439862306a36Sopenharmony_ci 439962306a36Sopenharmony_ci ic->sb = alloc_pages_exact(SB_SECTORS << SECTOR_SHIFT, GFP_KERNEL); 440062306a36Sopenharmony_ci if (!ic->sb) { 440162306a36Sopenharmony_ci r = -ENOMEM; 440262306a36Sopenharmony_ci ti->error = "Cannot allocate superblock area"; 440362306a36Sopenharmony_ci goto bad; 440462306a36Sopenharmony_ci } 440562306a36Sopenharmony_ci 440662306a36Sopenharmony_ci r = sync_rw_sb(ic, REQ_OP_READ); 440762306a36Sopenharmony_ci if (r) { 440862306a36Sopenharmony_ci ti->error = "Error reading superblock"; 440962306a36Sopenharmony_ci goto bad; 441062306a36Sopenharmony_ci } 441162306a36Sopenharmony_ci should_write_sb = false; 441262306a36Sopenharmony_ci if (memcmp(ic->sb->magic, SB_MAGIC, 8)) { 441362306a36Sopenharmony_ci if (ic->mode != 'R') { 441462306a36Sopenharmony_ci if (memchr_inv(ic->sb, 0, SB_SECTORS << SECTOR_SHIFT)) { 441562306a36Sopenharmony_ci r = -EINVAL; 441662306a36Sopenharmony_ci ti->error = "The device is not initialized"; 441762306a36Sopenharmony_ci goto bad; 441862306a36Sopenharmony_ci } 441962306a36Sopenharmony_ci } 442062306a36Sopenharmony_ci 442162306a36Sopenharmony_ci r = initialize_superblock(ic, journal_sectors, interleave_sectors); 442262306a36Sopenharmony_ci if (r) { 442362306a36Sopenharmony_ci ti->error = "Could not initialize superblock"; 442462306a36Sopenharmony_ci goto bad; 442562306a36Sopenharmony_ci } 442662306a36Sopenharmony_ci if (ic->mode != 'R') 442762306a36Sopenharmony_ci should_write_sb = true; 442862306a36Sopenharmony_ci } 442962306a36Sopenharmony_ci 443062306a36Sopenharmony_ci if (!ic->sb->version || ic->sb->version > SB_VERSION_5) { 443162306a36Sopenharmony_ci r = -EINVAL; 443262306a36Sopenharmony_ci ti->error = "Unknown version"; 443362306a36Sopenharmony_ci goto bad; 443462306a36Sopenharmony_ci } 443562306a36Sopenharmony_ci if (le16_to_cpu(ic->sb->integrity_tag_size) != ic->tag_size) { 443662306a36Sopenharmony_ci r = -EINVAL; 443762306a36Sopenharmony_ci ti->error = "Tag size doesn't match the information in superblock"; 443862306a36Sopenharmony_ci goto bad; 443962306a36Sopenharmony_ci } 444062306a36Sopenharmony_ci if (ic->sb->log2_sectors_per_block != __ffs(ic->sectors_per_block)) { 444162306a36Sopenharmony_ci r = -EINVAL; 444262306a36Sopenharmony_ci ti->error = "Block size doesn't match the information in superblock"; 444362306a36Sopenharmony_ci goto bad; 444462306a36Sopenharmony_ci } 444562306a36Sopenharmony_ci if (!le32_to_cpu(ic->sb->journal_sections)) { 444662306a36Sopenharmony_ci r = -EINVAL; 444762306a36Sopenharmony_ci ti->error = "Corrupted superblock, journal_sections is 0"; 444862306a36Sopenharmony_ci goto bad; 444962306a36Sopenharmony_ci } 445062306a36Sopenharmony_ci /* make sure that ti->max_io_len doesn't overflow */ 445162306a36Sopenharmony_ci if (!ic->meta_dev) { 445262306a36Sopenharmony_ci if (ic->sb->log2_interleave_sectors < MIN_LOG2_INTERLEAVE_SECTORS || 445362306a36Sopenharmony_ci ic->sb->log2_interleave_sectors > MAX_LOG2_INTERLEAVE_SECTORS) { 445462306a36Sopenharmony_ci r = -EINVAL; 445562306a36Sopenharmony_ci ti->error = "Invalid interleave_sectors in the superblock"; 445662306a36Sopenharmony_ci goto bad; 445762306a36Sopenharmony_ci } 445862306a36Sopenharmony_ci } else { 445962306a36Sopenharmony_ci if (ic->sb->log2_interleave_sectors) { 446062306a36Sopenharmony_ci r = -EINVAL; 446162306a36Sopenharmony_ci ti->error = "Invalid interleave_sectors in the superblock"; 446262306a36Sopenharmony_ci goto bad; 446362306a36Sopenharmony_ci } 446462306a36Sopenharmony_ci } 446562306a36Sopenharmony_ci if (!!(ic->sb->flags & cpu_to_le32(SB_FLAG_HAVE_JOURNAL_MAC)) != !!ic->journal_mac_alg.alg_string) { 446662306a36Sopenharmony_ci r = -EINVAL; 446762306a36Sopenharmony_ci ti->error = "Journal mac mismatch"; 446862306a36Sopenharmony_ci goto bad; 446962306a36Sopenharmony_ci } 447062306a36Sopenharmony_ci 447162306a36Sopenharmony_ci get_provided_data_sectors(ic); 447262306a36Sopenharmony_ci if (!ic->provided_data_sectors) { 447362306a36Sopenharmony_ci r = -EINVAL; 447462306a36Sopenharmony_ci ti->error = "The device is too small"; 447562306a36Sopenharmony_ci goto bad; 447662306a36Sopenharmony_ci } 447762306a36Sopenharmony_ci 447862306a36Sopenharmony_citry_smaller_buffer: 447962306a36Sopenharmony_ci r = calculate_device_limits(ic); 448062306a36Sopenharmony_ci if (r) { 448162306a36Sopenharmony_ci if (ic->meta_dev) { 448262306a36Sopenharmony_ci if (ic->log2_buffer_sectors > 3) { 448362306a36Sopenharmony_ci ic->log2_buffer_sectors--; 448462306a36Sopenharmony_ci goto try_smaller_buffer; 448562306a36Sopenharmony_ci } 448662306a36Sopenharmony_ci } 448762306a36Sopenharmony_ci ti->error = "The device is too small"; 448862306a36Sopenharmony_ci goto bad; 448962306a36Sopenharmony_ci } 449062306a36Sopenharmony_ci 449162306a36Sopenharmony_ci if (log2_sectors_per_bitmap_bit < 0) 449262306a36Sopenharmony_ci log2_sectors_per_bitmap_bit = __fls(DEFAULT_SECTORS_PER_BITMAP_BIT); 449362306a36Sopenharmony_ci if (log2_sectors_per_bitmap_bit < ic->sb->log2_sectors_per_block) 449462306a36Sopenharmony_ci log2_sectors_per_bitmap_bit = ic->sb->log2_sectors_per_block; 449562306a36Sopenharmony_ci 449662306a36Sopenharmony_ci bits_in_journal = ((__u64)ic->journal_section_sectors * ic->journal_sections) << (SECTOR_SHIFT + 3); 449762306a36Sopenharmony_ci if (bits_in_journal > UINT_MAX) 449862306a36Sopenharmony_ci bits_in_journal = UINT_MAX; 449962306a36Sopenharmony_ci while (bits_in_journal < (ic->provided_data_sectors + ((sector_t)1 << log2_sectors_per_bitmap_bit) - 1) >> log2_sectors_per_bitmap_bit) 450062306a36Sopenharmony_ci log2_sectors_per_bitmap_bit++; 450162306a36Sopenharmony_ci 450262306a36Sopenharmony_ci log2_blocks_per_bitmap_bit = log2_sectors_per_bitmap_bit - ic->sb->log2_sectors_per_block; 450362306a36Sopenharmony_ci ic->log2_blocks_per_bitmap_bit = log2_blocks_per_bitmap_bit; 450462306a36Sopenharmony_ci if (should_write_sb) 450562306a36Sopenharmony_ci ic->sb->log2_blocks_per_bitmap_bit = log2_blocks_per_bitmap_bit; 450662306a36Sopenharmony_ci 450762306a36Sopenharmony_ci n_bitmap_bits = ((ic->provided_data_sectors >> ic->sb->log2_sectors_per_block) 450862306a36Sopenharmony_ci + (((sector_t)1 << log2_blocks_per_bitmap_bit) - 1)) >> log2_blocks_per_bitmap_bit; 450962306a36Sopenharmony_ci ic->n_bitmap_blocks = DIV_ROUND_UP(n_bitmap_bits, BITMAP_BLOCK_SIZE * 8); 451062306a36Sopenharmony_ci 451162306a36Sopenharmony_ci if (!ic->meta_dev) 451262306a36Sopenharmony_ci ic->log2_buffer_sectors = min(ic->log2_buffer_sectors, (__u8)__ffs(ic->metadata_run)); 451362306a36Sopenharmony_ci 451462306a36Sopenharmony_ci if (ti->len > ic->provided_data_sectors) { 451562306a36Sopenharmony_ci r = -EINVAL; 451662306a36Sopenharmony_ci ti->error = "Not enough provided sectors for requested mapping size"; 451762306a36Sopenharmony_ci goto bad; 451862306a36Sopenharmony_ci } 451962306a36Sopenharmony_ci 452062306a36Sopenharmony_ci 452162306a36Sopenharmony_ci threshold = (__u64)ic->journal_entries * (100 - journal_watermark); 452262306a36Sopenharmony_ci threshold += 50; 452362306a36Sopenharmony_ci do_div(threshold, 100); 452462306a36Sopenharmony_ci ic->free_sectors_threshold = threshold; 452562306a36Sopenharmony_ci 452662306a36Sopenharmony_ci DEBUG_print("initialized:\n"); 452762306a36Sopenharmony_ci DEBUG_print(" integrity_tag_size %u\n", le16_to_cpu(ic->sb->integrity_tag_size)); 452862306a36Sopenharmony_ci DEBUG_print(" journal_entry_size %u\n", ic->journal_entry_size); 452962306a36Sopenharmony_ci DEBUG_print(" journal_entries_per_sector %u\n", ic->journal_entries_per_sector); 453062306a36Sopenharmony_ci DEBUG_print(" journal_section_entries %u\n", ic->journal_section_entries); 453162306a36Sopenharmony_ci DEBUG_print(" journal_section_sectors %u\n", ic->journal_section_sectors); 453262306a36Sopenharmony_ci DEBUG_print(" journal_sections %u\n", (unsigned int)le32_to_cpu(ic->sb->journal_sections)); 453362306a36Sopenharmony_ci DEBUG_print(" journal_entries %u\n", ic->journal_entries); 453462306a36Sopenharmony_ci DEBUG_print(" log2_interleave_sectors %d\n", ic->sb->log2_interleave_sectors); 453562306a36Sopenharmony_ci DEBUG_print(" data_device_sectors 0x%llx\n", bdev_nr_sectors(ic->dev->bdev)); 453662306a36Sopenharmony_ci DEBUG_print(" initial_sectors 0x%x\n", ic->initial_sectors); 453762306a36Sopenharmony_ci DEBUG_print(" metadata_run 0x%x\n", ic->metadata_run); 453862306a36Sopenharmony_ci DEBUG_print(" log2_metadata_run %d\n", ic->log2_metadata_run); 453962306a36Sopenharmony_ci DEBUG_print(" provided_data_sectors 0x%llx (%llu)\n", ic->provided_data_sectors, ic->provided_data_sectors); 454062306a36Sopenharmony_ci DEBUG_print(" log2_buffer_sectors %u\n", ic->log2_buffer_sectors); 454162306a36Sopenharmony_ci DEBUG_print(" bits_in_journal %llu\n", bits_in_journal); 454262306a36Sopenharmony_ci 454362306a36Sopenharmony_ci if (ic->recalculate_flag && !(ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING))) { 454462306a36Sopenharmony_ci ic->sb->flags |= cpu_to_le32(SB_FLAG_RECALCULATING); 454562306a36Sopenharmony_ci ic->sb->recalc_sector = cpu_to_le64(0); 454662306a36Sopenharmony_ci } 454762306a36Sopenharmony_ci 454862306a36Sopenharmony_ci if (ic->internal_hash) { 454962306a36Sopenharmony_ci ic->recalc_wq = alloc_workqueue("dm-integrity-recalc", WQ_MEM_RECLAIM, 1); 455062306a36Sopenharmony_ci if (!ic->recalc_wq) { 455162306a36Sopenharmony_ci ti->error = "Cannot allocate workqueue"; 455262306a36Sopenharmony_ci r = -ENOMEM; 455362306a36Sopenharmony_ci goto bad; 455462306a36Sopenharmony_ci } 455562306a36Sopenharmony_ci INIT_WORK(&ic->recalc_work, integrity_recalc); 455662306a36Sopenharmony_ci } else { 455762306a36Sopenharmony_ci if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) { 455862306a36Sopenharmony_ci ti->error = "Recalculate can only be specified with internal_hash"; 455962306a36Sopenharmony_ci r = -EINVAL; 456062306a36Sopenharmony_ci goto bad; 456162306a36Sopenharmony_ci } 456262306a36Sopenharmony_ci } 456362306a36Sopenharmony_ci 456462306a36Sopenharmony_ci if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING) && 456562306a36Sopenharmony_ci le64_to_cpu(ic->sb->recalc_sector) < ic->provided_data_sectors && 456662306a36Sopenharmony_ci dm_integrity_disable_recalculate(ic)) { 456762306a36Sopenharmony_ci ti->error = "Recalculating with HMAC is disabled for security reasons - if you really need it, use the argument \"legacy_recalculate\""; 456862306a36Sopenharmony_ci r = -EOPNOTSUPP; 456962306a36Sopenharmony_ci goto bad; 457062306a36Sopenharmony_ci } 457162306a36Sopenharmony_ci 457262306a36Sopenharmony_ci ic->bufio = dm_bufio_client_create(ic->meta_dev ? ic->meta_dev->bdev : ic->dev->bdev, 457362306a36Sopenharmony_ci 1U << (SECTOR_SHIFT + ic->log2_buffer_sectors), 1, 0, NULL, NULL, 0); 457462306a36Sopenharmony_ci if (IS_ERR(ic->bufio)) { 457562306a36Sopenharmony_ci r = PTR_ERR(ic->bufio); 457662306a36Sopenharmony_ci ti->error = "Cannot initialize dm-bufio"; 457762306a36Sopenharmony_ci ic->bufio = NULL; 457862306a36Sopenharmony_ci goto bad; 457962306a36Sopenharmony_ci } 458062306a36Sopenharmony_ci dm_bufio_set_sector_offset(ic->bufio, ic->start + ic->initial_sectors); 458162306a36Sopenharmony_ci 458262306a36Sopenharmony_ci if (ic->mode != 'R') { 458362306a36Sopenharmony_ci r = create_journal(ic, &ti->error); 458462306a36Sopenharmony_ci if (r) 458562306a36Sopenharmony_ci goto bad; 458662306a36Sopenharmony_ci 458762306a36Sopenharmony_ci } 458862306a36Sopenharmony_ci 458962306a36Sopenharmony_ci if (ic->mode == 'B') { 459062306a36Sopenharmony_ci unsigned int i; 459162306a36Sopenharmony_ci unsigned int n_bitmap_pages = DIV_ROUND_UP(ic->n_bitmap_blocks, PAGE_SIZE / BITMAP_BLOCK_SIZE); 459262306a36Sopenharmony_ci 459362306a36Sopenharmony_ci ic->recalc_bitmap = dm_integrity_alloc_page_list(n_bitmap_pages); 459462306a36Sopenharmony_ci if (!ic->recalc_bitmap) { 459562306a36Sopenharmony_ci r = -ENOMEM; 459662306a36Sopenharmony_ci goto bad; 459762306a36Sopenharmony_ci } 459862306a36Sopenharmony_ci ic->may_write_bitmap = dm_integrity_alloc_page_list(n_bitmap_pages); 459962306a36Sopenharmony_ci if (!ic->may_write_bitmap) { 460062306a36Sopenharmony_ci r = -ENOMEM; 460162306a36Sopenharmony_ci goto bad; 460262306a36Sopenharmony_ci } 460362306a36Sopenharmony_ci ic->bbs = kvmalloc_array(ic->n_bitmap_blocks, sizeof(struct bitmap_block_status), GFP_KERNEL); 460462306a36Sopenharmony_ci if (!ic->bbs) { 460562306a36Sopenharmony_ci r = -ENOMEM; 460662306a36Sopenharmony_ci goto bad; 460762306a36Sopenharmony_ci } 460862306a36Sopenharmony_ci INIT_DELAYED_WORK(&ic->bitmap_flush_work, bitmap_flush_work); 460962306a36Sopenharmony_ci for (i = 0; i < ic->n_bitmap_blocks; i++) { 461062306a36Sopenharmony_ci struct bitmap_block_status *bbs = &ic->bbs[i]; 461162306a36Sopenharmony_ci unsigned int sector, pl_index, pl_offset; 461262306a36Sopenharmony_ci 461362306a36Sopenharmony_ci INIT_WORK(&bbs->work, bitmap_block_work); 461462306a36Sopenharmony_ci bbs->ic = ic; 461562306a36Sopenharmony_ci bbs->idx = i; 461662306a36Sopenharmony_ci bio_list_init(&bbs->bio_queue); 461762306a36Sopenharmony_ci spin_lock_init(&bbs->bio_queue_lock); 461862306a36Sopenharmony_ci 461962306a36Sopenharmony_ci sector = i * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT); 462062306a36Sopenharmony_ci pl_index = sector >> (PAGE_SHIFT - SECTOR_SHIFT); 462162306a36Sopenharmony_ci pl_offset = (sector << SECTOR_SHIFT) & (PAGE_SIZE - 1); 462262306a36Sopenharmony_ci 462362306a36Sopenharmony_ci bbs->bitmap = lowmem_page_address(ic->journal[pl_index].page) + pl_offset; 462462306a36Sopenharmony_ci } 462562306a36Sopenharmony_ci } 462662306a36Sopenharmony_ci 462762306a36Sopenharmony_ci if (should_write_sb) { 462862306a36Sopenharmony_ci init_journal(ic, 0, ic->journal_sections, 0); 462962306a36Sopenharmony_ci r = dm_integrity_failed(ic); 463062306a36Sopenharmony_ci if (unlikely(r)) { 463162306a36Sopenharmony_ci ti->error = "Error initializing journal"; 463262306a36Sopenharmony_ci goto bad; 463362306a36Sopenharmony_ci } 463462306a36Sopenharmony_ci r = sync_rw_sb(ic, REQ_OP_WRITE | REQ_FUA); 463562306a36Sopenharmony_ci if (r) { 463662306a36Sopenharmony_ci ti->error = "Error initializing superblock"; 463762306a36Sopenharmony_ci goto bad; 463862306a36Sopenharmony_ci } 463962306a36Sopenharmony_ci ic->just_formatted = true; 464062306a36Sopenharmony_ci } 464162306a36Sopenharmony_ci 464262306a36Sopenharmony_ci if (!ic->meta_dev) { 464362306a36Sopenharmony_ci r = dm_set_target_max_io_len(ti, 1U << ic->sb->log2_interleave_sectors); 464462306a36Sopenharmony_ci if (r) 464562306a36Sopenharmony_ci goto bad; 464662306a36Sopenharmony_ci } 464762306a36Sopenharmony_ci if (ic->mode == 'B') { 464862306a36Sopenharmony_ci unsigned int max_io_len; 464962306a36Sopenharmony_ci 465062306a36Sopenharmony_ci max_io_len = ((sector_t)ic->sectors_per_block << ic->log2_blocks_per_bitmap_bit) * (BITMAP_BLOCK_SIZE * 8); 465162306a36Sopenharmony_ci if (!max_io_len) 465262306a36Sopenharmony_ci max_io_len = 1U << 31; 465362306a36Sopenharmony_ci DEBUG_print("max_io_len: old %u, new %u\n", ti->max_io_len, max_io_len); 465462306a36Sopenharmony_ci if (!ti->max_io_len || ti->max_io_len > max_io_len) { 465562306a36Sopenharmony_ci r = dm_set_target_max_io_len(ti, max_io_len); 465662306a36Sopenharmony_ci if (r) 465762306a36Sopenharmony_ci goto bad; 465862306a36Sopenharmony_ci } 465962306a36Sopenharmony_ci } 466062306a36Sopenharmony_ci 466162306a36Sopenharmony_ci if (!ic->internal_hash) 466262306a36Sopenharmony_ci dm_integrity_set(ti, ic); 466362306a36Sopenharmony_ci 466462306a36Sopenharmony_ci ti->num_flush_bios = 1; 466562306a36Sopenharmony_ci ti->flush_supported = true; 466662306a36Sopenharmony_ci if (ic->discard) 466762306a36Sopenharmony_ci ti->num_discard_bios = 1; 466862306a36Sopenharmony_ci 466962306a36Sopenharmony_ci dm_audit_log_ctr(DM_MSG_PREFIX, ti, 1); 467062306a36Sopenharmony_ci return 0; 467162306a36Sopenharmony_ci 467262306a36Sopenharmony_cibad: 467362306a36Sopenharmony_ci dm_audit_log_ctr(DM_MSG_PREFIX, ti, 0); 467462306a36Sopenharmony_ci dm_integrity_dtr(ti); 467562306a36Sopenharmony_ci return r; 467662306a36Sopenharmony_ci} 467762306a36Sopenharmony_ci 467862306a36Sopenharmony_cistatic void dm_integrity_dtr(struct dm_target *ti) 467962306a36Sopenharmony_ci{ 468062306a36Sopenharmony_ci struct dm_integrity_c *ic = ti->private; 468162306a36Sopenharmony_ci 468262306a36Sopenharmony_ci BUG_ON(!RB_EMPTY_ROOT(&ic->in_progress)); 468362306a36Sopenharmony_ci BUG_ON(!list_empty(&ic->wait_list)); 468462306a36Sopenharmony_ci 468562306a36Sopenharmony_ci if (ic->mode == 'B') 468662306a36Sopenharmony_ci cancel_delayed_work_sync(&ic->bitmap_flush_work); 468762306a36Sopenharmony_ci if (ic->metadata_wq) 468862306a36Sopenharmony_ci destroy_workqueue(ic->metadata_wq); 468962306a36Sopenharmony_ci if (ic->wait_wq) 469062306a36Sopenharmony_ci destroy_workqueue(ic->wait_wq); 469162306a36Sopenharmony_ci if (ic->offload_wq) 469262306a36Sopenharmony_ci destroy_workqueue(ic->offload_wq); 469362306a36Sopenharmony_ci if (ic->commit_wq) 469462306a36Sopenharmony_ci destroy_workqueue(ic->commit_wq); 469562306a36Sopenharmony_ci if (ic->writer_wq) 469662306a36Sopenharmony_ci destroy_workqueue(ic->writer_wq); 469762306a36Sopenharmony_ci if (ic->recalc_wq) 469862306a36Sopenharmony_ci destroy_workqueue(ic->recalc_wq); 469962306a36Sopenharmony_ci kvfree(ic->bbs); 470062306a36Sopenharmony_ci if (ic->bufio) 470162306a36Sopenharmony_ci dm_bufio_client_destroy(ic->bufio); 470262306a36Sopenharmony_ci mempool_exit(&ic->recheck_pool); 470362306a36Sopenharmony_ci mempool_exit(&ic->journal_io_mempool); 470462306a36Sopenharmony_ci if (ic->io) 470562306a36Sopenharmony_ci dm_io_client_destroy(ic->io); 470662306a36Sopenharmony_ci if (ic->dev) 470762306a36Sopenharmony_ci dm_put_device(ti, ic->dev); 470862306a36Sopenharmony_ci if (ic->meta_dev) 470962306a36Sopenharmony_ci dm_put_device(ti, ic->meta_dev); 471062306a36Sopenharmony_ci dm_integrity_free_page_list(ic->journal); 471162306a36Sopenharmony_ci dm_integrity_free_page_list(ic->journal_io); 471262306a36Sopenharmony_ci dm_integrity_free_page_list(ic->journal_xor); 471362306a36Sopenharmony_ci dm_integrity_free_page_list(ic->recalc_bitmap); 471462306a36Sopenharmony_ci dm_integrity_free_page_list(ic->may_write_bitmap); 471562306a36Sopenharmony_ci if (ic->journal_scatterlist) 471662306a36Sopenharmony_ci dm_integrity_free_journal_scatterlist(ic, ic->journal_scatterlist); 471762306a36Sopenharmony_ci if (ic->journal_io_scatterlist) 471862306a36Sopenharmony_ci dm_integrity_free_journal_scatterlist(ic, ic->journal_io_scatterlist); 471962306a36Sopenharmony_ci if (ic->sk_requests) { 472062306a36Sopenharmony_ci unsigned int i; 472162306a36Sopenharmony_ci 472262306a36Sopenharmony_ci for (i = 0; i < ic->journal_sections; i++) { 472362306a36Sopenharmony_ci struct skcipher_request *req; 472462306a36Sopenharmony_ci 472562306a36Sopenharmony_ci req = ic->sk_requests[i]; 472662306a36Sopenharmony_ci if (req) { 472762306a36Sopenharmony_ci kfree_sensitive(req->iv); 472862306a36Sopenharmony_ci skcipher_request_free(req); 472962306a36Sopenharmony_ci } 473062306a36Sopenharmony_ci } 473162306a36Sopenharmony_ci kvfree(ic->sk_requests); 473262306a36Sopenharmony_ci } 473362306a36Sopenharmony_ci kvfree(ic->journal_tree); 473462306a36Sopenharmony_ci if (ic->sb) 473562306a36Sopenharmony_ci free_pages_exact(ic->sb, SB_SECTORS << SECTOR_SHIFT); 473662306a36Sopenharmony_ci 473762306a36Sopenharmony_ci if (ic->internal_hash) 473862306a36Sopenharmony_ci crypto_free_shash(ic->internal_hash); 473962306a36Sopenharmony_ci free_alg(&ic->internal_hash_alg); 474062306a36Sopenharmony_ci 474162306a36Sopenharmony_ci if (ic->journal_crypt) 474262306a36Sopenharmony_ci crypto_free_skcipher(ic->journal_crypt); 474362306a36Sopenharmony_ci free_alg(&ic->journal_crypt_alg); 474462306a36Sopenharmony_ci 474562306a36Sopenharmony_ci if (ic->journal_mac) 474662306a36Sopenharmony_ci crypto_free_shash(ic->journal_mac); 474762306a36Sopenharmony_ci free_alg(&ic->journal_mac_alg); 474862306a36Sopenharmony_ci 474962306a36Sopenharmony_ci kfree(ic); 475062306a36Sopenharmony_ci dm_audit_log_dtr(DM_MSG_PREFIX, ti, 1); 475162306a36Sopenharmony_ci} 475262306a36Sopenharmony_ci 475362306a36Sopenharmony_cistatic struct target_type integrity_target = { 475462306a36Sopenharmony_ci .name = "integrity", 475562306a36Sopenharmony_ci .version = {1, 10, 0}, 475662306a36Sopenharmony_ci .module = THIS_MODULE, 475762306a36Sopenharmony_ci .features = DM_TARGET_SINGLETON | DM_TARGET_INTEGRITY, 475862306a36Sopenharmony_ci .ctr = dm_integrity_ctr, 475962306a36Sopenharmony_ci .dtr = dm_integrity_dtr, 476062306a36Sopenharmony_ci .map = dm_integrity_map, 476162306a36Sopenharmony_ci .postsuspend = dm_integrity_postsuspend, 476262306a36Sopenharmony_ci .resume = dm_integrity_resume, 476362306a36Sopenharmony_ci .status = dm_integrity_status, 476462306a36Sopenharmony_ci .iterate_devices = dm_integrity_iterate_devices, 476562306a36Sopenharmony_ci .io_hints = dm_integrity_io_hints, 476662306a36Sopenharmony_ci}; 476762306a36Sopenharmony_ci 476862306a36Sopenharmony_cistatic int __init dm_integrity_init(void) 476962306a36Sopenharmony_ci{ 477062306a36Sopenharmony_ci int r; 477162306a36Sopenharmony_ci 477262306a36Sopenharmony_ci journal_io_cache = kmem_cache_create("integrity_journal_io", 477362306a36Sopenharmony_ci sizeof(struct journal_io), 0, 0, NULL); 477462306a36Sopenharmony_ci if (!journal_io_cache) { 477562306a36Sopenharmony_ci DMERR("can't allocate journal io cache"); 477662306a36Sopenharmony_ci return -ENOMEM; 477762306a36Sopenharmony_ci } 477862306a36Sopenharmony_ci 477962306a36Sopenharmony_ci r = dm_register_target(&integrity_target); 478062306a36Sopenharmony_ci if (r < 0) { 478162306a36Sopenharmony_ci kmem_cache_destroy(journal_io_cache); 478262306a36Sopenharmony_ci return r; 478362306a36Sopenharmony_ci } 478462306a36Sopenharmony_ci 478562306a36Sopenharmony_ci return 0; 478662306a36Sopenharmony_ci} 478762306a36Sopenharmony_ci 478862306a36Sopenharmony_cistatic void __exit dm_integrity_exit(void) 478962306a36Sopenharmony_ci{ 479062306a36Sopenharmony_ci dm_unregister_target(&integrity_target); 479162306a36Sopenharmony_ci kmem_cache_destroy(journal_io_cache); 479262306a36Sopenharmony_ci} 479362306a36Sopenharmony_ci 479462306a36Sopenharmony_cimodule_init(dm_integrity_init); 479562306a36Sopenharmony_cimodule_exit(dm_integrity_exit); 479662306a36Sopenharmony_ci 479762306a36Sopenharmony_ciMODULE_AUTHOR("Milan Broz"); 479862306a36Sopenharmony_ciMODULE_AUTHOR("Mikulas Patocka"); 479962306a36Sopenharmony_ciMODULE_DESCRIPTION(DM_NAME " target for integrity tags extension"); 480062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 4801