You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'for-4.17/dm-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm
Pull device mapper updates from Mike Snitzer: - DM core passthrough ioctl fix to retain reference to DM table, and that table's block devices, while issuing the ioctl to one of those block devices. - DM core passthrough ioctl fix to _not_ override the fmode_t used to issue the ioctl. Overriding by using the fmode_t that the block device was originally open with during DM table load is a liability. - Add DM core support for secure erase forwarding and update the DM linear and DM striped targets to support them. - A DM core 4.16 stable fix to allow abnormal IO (e.g. discard, write same, write zeroes) for targets that make use of the non-splitting IO variant (as is done for multipath or thinp when layered directly on NVMe). - Allow DM targets to return a payload in response to a DM message that they are sent. This is useful for DM targets that would like to provide statistics data in response to DM messages. - Update DM bufio to support non-power-of-2 block sizes. Numerous other related changes prepare the DM bufio code for this support. - Fix DM crypt to use a bounded amount of memory across the entire system. This is to avoid OOM that can otherwise occur in response to certain pathological IO workloads (e.g. discarding a large DM crypt device). - Add a 'check_at_most_once' feature to the DM verity target to allow verity to be used on mobile devices that have very limited resources. - Fix the DM integrity target to fail early if a keyed algorithm (e.g. HMAC) is to be used but the key isn't set. - Add non-power-of-2 support to the DM unstripe target. - Eliminate the use of a Variable Length Array in the DM stripe target. - Update the DM log-writes target to record metadata (REQ_META flag). - DM raid fixes for its nosync status and some variable range issues. * tag 'for-4.17/dm-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm: (28 commits) dm: remove fmode_t argument from .prepare_ioctl hook dm: hold DM table for duration of ioctl rather than use blkdev_get dm raid: fix parse_raid_params() variable range issue dm verity: make verity_for_io_block static dm verity: add 'check_at_most_once' option to only validate hashes once dm bufio: don't embed a bio in the dm_buffer structure dm bufio: support non-power-of-two block sizes dm bufio: use slab cache for dm_buffer structure allocations dm bufio: reorder fields in dm_buffer structure dm bufio: relax alignment constraint on slab cache dm bufio: remove code that merges slab caches dm bufio: get rid of slab cache name allocations dm bufio: move dm-bufio.h to include/linux/ dm bufio: delete outdated comment dm: add support for secure erase forwarding dm: backfill abnormal IO support to non-splitting IO submission dm raid: fix nosync status dm mpath: use DM_MAPIO_SUBMITTED instead of magic number 0 in process_queued_bios() dm stripe: get rid of a Variable Length Array (VLA) dm log writes: record metadata flag for better flags record ...
This commit is contained in:
@@ -109,6 +109,17 @@ fec_start <offset>
|
||||
This is the offset, in <data_block_size> blocks, from the start of the
|
||||
FEC device to the beginning of the encoding data.
|
||||
|
||||
check_at_most_once
|
||||
Verify data blocks only the first time they are read from the data device,
|
||||
rather than every time. This reduces the overhead of dm-verity so that it
|
||||
can be used on systems that are memory and/or CPU constrained. However, it
|
||||
provides a reduced level of security because only offline tampering of the
|
||||
data device's content will be detected, not online tampering.
|
||||
|
||||
Hash blocks are still verified each time they are read from the hash device,
|
||||
since verification of hash blocks is less performance critical than data
|
||||
blocks, and a hash block will not be verified any more after all the data
|
||||
blocks it covers have been verified anyway.
|
||||
|
||||
Theory of operation
|
||||
===================
|
||||
|
||||
+122
-157
File diff suppressed because it is too large
Load Diff
@@ -3387,7 +3387,8 @@ static int process_invalidate_cblocks_message(struct cache *cache, unsigned coun
|
||||
*
|
||||
* The key migration_threshold is supported by the cache target core.
|
||||
*/
|
||||
static int cache_message(struct dm_target *ti, unsigned argc, char **argv)
|
||||
static int cache_message(struct dm_target *ti, unsigned argc, char **argv,
|
||||
char *result, unsigned maxlen)
|
||||
{
|
||||
struct cache *cache = ti->private;
|
||||
|
||||
|
||||
+67
-2
@@ -148,6 +148,8 @@ struct crypt_config {
|
||||
mempool_t *tag_pool;
|
||||
unsigned tag_pool_max_sectors;
|
||||
|
||||
struct percpu_counter n_allocated_pages;
|
||||
|
||||
struct bio_set *bs;
|
||||
struct mutex bio_alloc_lock;
|
||||
|
||||
@@ -219,6 +221,12 @@ struct crypt_config {
|
||||
#define MAX_TAG_SIZE 480
|
||||
#define POOL_ENTRY_SIZE 512
|
||||
|
||||
static DEFINE_SPINLOCK(dm_crypt_clients_lock);
|
||||
static unsigned dm_crypt_clients_n = 0;
|
||||
static volatile unsigned long dm_crypt_pages_per_client;
|
||||
#define DM_CRYPT_MEMORY_PERCENT 2
|
||||
#define DM_CRYPT_MIN_PAGES_PER_CLIENT (BIO_MAX_PAGES * 16)
|
||||
|
||||
static void clone_init(struct dm_crypt_io *, struct bio *);
|
||||
static void kcryptd_queue_crypt(struct dm_crypt_io *io);
|
||||
static struct scatterlist *crypt_get_sg_data(struct crypt_config *cc,
|
||||
@@ -2155,6 +2163,43 @@ static int crypt_wipe_key(struct crypt_config *cc)
|
||||
return r;
|
||||
}
|
||||
|
||||
static void crypt_calculate_pages_per_client(void)
|
||||
{
|
||||
unsigned long pages = (totalram_pages - totalhigh_pages) * DM_CRYPT_MEMORY_PERCENT / 100;
|
||||
|
||||
if (!dm_crypt_clients_n)
|
||||
return;
|
||||
|
||||
pages /= dm_crypt_clients_n;
|
||||
if (pages < DM_CRYPT_MIN_PAGES_PER_CLIENT)
|
||||
pages = DM_CRYPT_MIN_PAGES_PER_CLIENT;
|
||||
dm_crypt_pages_per_client = pages;
|
||||
}
|
||||
|
||||
static void *crypt_page_alloc(gfp_t gfp_mask, void *pool_data)
|
||||
{
|
||||
struct crypt_config *cc = pool_data;
|
||||
struct page *page;
|
||||
|
||||
if (unlikely(percpu_counter_compare(&cc->n_allocated_pages, dm_crypt_pages_per_client) >= 0) &&
|
||||
likely(gfp_mask & __GFP_NORETRY))
|
||||
return NULL;
|
||||
|
||||
page = alloc_page(gfp_mask);
|
||||
if (likely(page != NULL))
|
||||
percpu_counter_add(&cc->n_allocated_pages, 1);
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
static void crypt_page_free(void *page, void *pool_data)
|
||||
{
|
||||
struct crypt_config *cc = pool_data;
|
||||
|
||||
__free_page(page);
|
||||
percpu_counter_sub(&cc->n_allocated_pages, 1);
|
||||
}
|
||||
|
||||
static void crypt_dtr(struct dm_target *ti)
|
||||
{
|
||||
struct crypt_config *cc = ti->private;
|
||||
@@ -2181,6 +2226,10 @@ static void crypt_dtr(struct dm_target *ti)
|
||||
mempool_destroy(cc->req_pool);
|
||||
mempool_destroy(cc->tag_pool);
|
||||
|
||||
if (cc->page_pool)
|
||||
WARN_ON(percpu_counter_sum(&cc->n_allocated_pages) != 0);
|
||||
percpu_counter_destroy(&cc->n_allocated_pages);
|
||||
|
||||
if (cc->iv_gen_ops && cc->iv_gen_ops->dtr)
|
||||
cc->iv_gen_ops->dtr(cc);
|
||||
|
||||
@@ -2197,6 +2246,12 @@ static void crypt_dtr(struct dm_target *ti)
|
||||
|
||||
/* Must zero key material before freeing */
|
||||
kzfree(cc);
|
||||
|
||||
spin_lock(&dm_crypt_clients_lock);
|
||||
WARN_ON(!dm_crypt_clients_n);
|
||||
dm_crypt_clients_n--;
|
||||
crypt_calculate_pages_per_client();
|
||||
spin_unlock(&dm_crypt_clients_lock);
|
||||
}
|
||||
|
||||
static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode)
|
||||
@@ -2644,6 +2699,15 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
|
||||
ti->private = cc;
|
||||
|
||||
spin_lock(&dm_crypt_clients_lock);
|
||||
dm_crypt_clients_n++;
|
||||
crypt_calculate_pages_per_client();
|
||||
spin_unlock(&dm_crypt_clients_lock);
|
||||
|
||||
ret = percpu_counter_init(&cc->n_allocated_pages, 0, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
goto bad;
|
||||
|
||||
/* Optional parameters need to be read before cipher constructor */
|
||||
if (argc > 5) {
|
||||
ret = crypt_ctr_optional(ti, argc - 5, &argv[5]);
|
||||
@@ -2698,7 +2762,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
ALIGN(sizeof(struct dm_crypt_io) + cc->dmreq_start + additional_req_size,
|
||||
ARCH_KMALLOC_MINALIGN);
|
||||
|
||||
cc->page_pool = mempool_create_page_pool(BIO_MAX_PAGES, 0);
|
||||
cc->page_pool = mempool_create(BIO_MAX_PAGES, crypt_page_alloc, crypt_page_free, cc);
|
||||
if (!cc->page_pool) {
|
||||
ti->error = "Cannot allocate page mempool";
|
||||
goto bad;
|
||||
@@ -2942,7 +3006,8 @@ static void crypt_resume(struct dm_target *ti)
|
||||
* key set <key>
|
||||
* key wipe
|
||||
*/
|
||||
static int crypt_message(struct dm_target *ti, unsigned argc, char **argv)
|
||||
static int crypt_message(struct dm_target *ti, unsigned argc, char **argv,
|
||||
char *result, unsigned maxlen)
|
||||
{
|
||||
struct crypt_config *cc = ti->private;
|
||||
int key_size, ret = -EINVAL;
|
||||
|
||||
@@ -1635,7 +1635,8 @@ err:
|
||||
DMEMIT("Error");
|
||||
}
|
||||
|
||||
static int era_message(struct dm_target *ti, unsigned argc, char **argv)
|
||||
static int era_message(struct dm_target *ti, unsigned argc, char **argv,
|
||||
char *result, unsigned maxlen)
|
||||
{
|
||||
struct era *era = ti->private;
|
||||
|
||||
|
||||
@@ -442,8 +442,7 @@ static void flakey_status(struct dm_target *ti, status_type_t type,
|
||||
}
|
||||
}
|
||||
|
||||
static int flakey_prepare_ioctl(struct dm_target *ti,
|
||||
struct block_device **bdev, fmode_t *mode)
|
||||
static int flakey_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
|
||||
{
|
||||
struct flakey_c *fc = ti->private;
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <crypto/hash.h>
|
||||
#include <crypto/skcipher.h>
|
||||
#include <linux/async_tx.h>
|
||||
#include "dm-bufio.h"
|
||||
#include <linux/dm-bufio.h>
|
||||
|
||||
#define DM_MSG_PREFIX "integrity"
|
||||
|
||||
@@ -2548,6 +2548,9 @@ static int get_mac(struct crypto_shash **hash, struct alg_spec *a, char **error,
|
||||
*error = error_key;
|
||||
return r;
|
||||
}
|
||||
} else if (crypto_shash_get_flags(*hash) & CRYPTO_TFM_NEED_KEY) {
|
||||
*error = error_key;
|
||||
return -ENOKEY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1595,7 +1595,7 @@ static int target_message(struct file *filp, struct dm_ioctl *param, size_t para
|
||||
DMWARN("Target message sector outside device.");
|
||||
r = -EINVAL;
|
||||
} else if (ti->type->message)
|
||||
r = ti->type->message(ti, argc, argv);
|
||||
r = ti->type->message(ti, argc, argv, result, maxlen);
|
||||
else {
|
||||
DMWARN("Target type does not support messages");
|
||||
r = -EINVAL;
|
||||
|
||||
@@ -59,6 +59,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
|
||||
ti->num_flush_bios = 1;
|
||||
ti->num_discard_bios = 1;
|
||||
ti->num_secure_erase_bios = 1;
|
||||
ti->num_write_same_bios = 1;
|
||||
ti->num_write_zeroes_bios = 1;
|
||||
ti->private = lc;
|
||||
@@ -129,8 +130,7 @@ static void linear_status(struct dm_target *ti, status_type_t type,
|
||||
}
|
||||
}
|
||||
|
||||
static int linear_prepare_ioctl(struct dm_target *ti,
|
||||
struct block_device **bdev, fmode_t *mode)
|
||||
static int linear_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
|
||||
{
|
||||
struct linear_c *lc = (struct linear_c *) ti->private;
|
||||
struct dm_dev *dev = lc->dev;
|
||||
|
||||
@@ -52,10 +52,11 @@
|
||||
* in fact we want to do the data and the discard in the order that they
|
||||
* completed.
|
||||
*/
|
||||
#define LOG_FLUSH_FLAG (1 << 0)
|
||||
#define LOG_FUA_FLAG (1 << 1)
|
||||
#define LOG_DISCARD_FLAG (1 << 2)
|
||||
#define LOG_MARK_FLAG (1 << 3)
|
||||
#define LOG_FLUSH_FLAG (1 << 0)
|
||||
#define LOG_FUA_FLAG (1 << 1)
|
||||
#define LOG_DISCARD_FLAG (1 << 2)
|
||||
#define LOG_MARK_FLAG (1 << 3)
|
||||
#define LOG_METADATA_FLAG (1 << 4)
|
||||
|
||||
#define WRITE_LOG_VERSION 1ULL
|
||||
#define WRITE_LOG_MAGIC 0x6a736677736872ULL
|
||||
@@ -699,6 +700,7 @@ static int log_writes_map(struct dm_target *ti, struct bio *bio)
|
||||
bool flush_bio = (bio->bi_opf & REQ_PREFLUSH);
|
||||
bool fua_bio = (bio->bi_opf & REQ_FUA);
|
||||
bool discard_bio = (bio_op(bio) == REQ_OP_DISCARD);
|
||||
bool meta_bio = (bio->bi_opf & REQ_META);
|
||||
|
||||
pb->block = NULL;
|
||||
|
||||
@@ -743,6 +745,8 @@ static int log_writes_map(struct dm_target *ti, struct bio *bio)
|
||||
block->flags |= LOG_FUA_FLAG;
|
||||
if (discard_bio)
|
||||
block->flags |= LOG_DISCARD_FLAG;
|
||||
if (meta_bio)
|
||||
block->flags |= LOG_METADATA_FLAG;
|
||||
|
||||
block->sector = bio_to_dev_sectors(lc, bio->bi_iter.bi_sector);
|
||||
block->nr_sectors = bio_to_dev_sectors(lc, bio_sectors(bio));
|
||||
@@ -860,7 +864,7 @@ static void log_writes_status(struct dm_target *ti, status_type_t type,
|
||||
}
|
||||
|
||||
static int log_writes_prepare_ioctl(struct dm_target *ti,
|
||||
struct block_device **bdev, fmode_t *mode)
|
||||
struct block_device **bdev)
|
||||
{
|
||||
struct log_writes_c *lc = ti->private;
|
||||
struct dm_dev *dev = lc->dev;
|
||||
@@ -887,7 +891,8 @@ static int log_writes_iterate_devices(struct dm_target *ti,
|
||||
* Messages supported:
|
||||
* mark <mark data> - specify the marked data.
|
||||
*/
|
||||
static int log_writes_message(struct dm_target *ti, unsigned argc, char **argv)
|
||||
static int log_writes_message(struct dm_target *ti, unsigned argc, char **argv,
|
||||
char *result, unsigned maxlen)
|
||||
{
|
||||
int r = -EINVAL;
|
||||
struct log_writes_c *lc = ti->private;
|
||||
|
||||
@@ -714,7 +714,7 @@ static void process_queued_bios(struct work_struct *work)
|
||||
case DM_MAPIO_REMAPPED:
|
||||
generic_make_request(bio);
|
||||
break;
|
||||
case 0:
|
||||
case DM_MAPIO_SUBMITTED:
|
||||
break;
|
||||
default:
|
||||
WARN_ONCE(true, "__multipath_map_bio() returned %d\n", r);
|
||||
@@ -1811,7 +1811,8 @@ static void multipath_status(struct dm_target *ti, status_type_t type,
|
||||
spin_unlock_irqrestore(&m->lock, flags);
|
||||
}
|
||||
|
||||
static int multipath_message(struct dm_target *ti, unsigned argc, char **argv)
|
||||
static int multipath_message(struct dm_target *ti, unsigned argc, char **argv,
|
||||
char *result, unsigned maxlen)
|
||||
{
|
||||
int r = -EINVAL;
|
||||
struct dm_dev *dev;
|
||||
@@ -1875,7 +1876,7 @@ out:
|
||||
}
|
||||
|
||||
static int multipath_prepare_ioctl(struct dm_target *ti,
|
||||
struct block_device **bdev, fmode_t *mode)
|
||||
struct block_device **bdev)
|
||||
{
|
||||
struct multipath *m = ti->private;
|
||||
struct pgpath *current_pgpath;
|
||||
@@ -1888,7 +1889,6 @@ static int multipath_prepare_ioctl(struct dm_target *ti,
|
||||
if (current_pgpath) {
|
||||
if (!test_bit(MPATHF_QUEUE_IO, &m->flags)) {
|
||||
*bdev = current_pgpath->path.dev->bdev;
|
||||
*mode = current_pgpath->path.dev->mode;
|
||||
r = 0;
|
||||
} else {
|
||||
/* pg_init has not started or completed */
|
||||
|
||||
+23
-10
@@ -1370,19 +1370,18 @@ static int parse_raid_params(struct raid_set *rs, struct dm_arg_set *as,
|
||||
* In device-mapper, we specify things in sectors, but
|
||||
* MD records this value in kB
|
||||
*/
|
||||
value /= 2;
|
||||
if (value > COUNTER_MAX) {
|
||||
if (value < 0 || value / 2 > COUNTER_MAX) {
|
||||
rs->ti->error = "Max write-behind limit out of range";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rs->md.bitmap_info.max_write_behind = value;
|
||||
rs->md.bitmap_info.max_write_behind = value / 2;
|
||||
} else if (!strcasecmp(key, dm_raid_arg_name_by_flag(CTR_FLAG_DAEMON_SLEEP))) {
|
||||
if (test_and_set_bit(__CTR_FLAG_DAEMON_SLEEP, &rs->ctr_flags)) {
|
||||
rs->ti->error = "Only one daemon_sleep argument pair allowed";
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!value || (value > MAX_SCHEDULE_TIMEOUT)) {
|
||||
if (value < 0) {
|
||||
rs->ti->error = "daemon sleep period out of range";
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1424,27 +1423,33 @@ static int parse_raid_params(struct raid_set *rs, struct dm_arg_set *as,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (value < 0) {
|
||||
rs->ti->error = "Bogus stripe cache entries value";
|
||||
return -EINVAL;
|
||||
}
|
||||
rs->stripe_cache_entries = value;
|
||||
} else if (!strcasecmp(key, dm_raid_arg_name_by_flag(CTR_FLAG_MIN_RECOVERY_RATE))) {
|
||||
if (test_and_set_bit(__CTR_FLAG_MIN_RECOVERY_RATE, &rs->ctr_flags)) {
|
||||
rs->ti->error = "Only one min_recovery_rate argument pair allowed";
|
||||
return -EINVAL;
|
||||
}
|
||||
if (value > INT_MAX) {
|
||||
|
||||
if (value < 0) {
|
||||
rs->ti->error = "min_recovery_rate out of range";
|
||||
return -EINVAL;
|
||||
}
|
||||
rs->md.sync_speed_min = (int)value;
|
||||
rs->md.sync_speed_min = value;
|
||||
} else if (!strcasecmp(key, dm_raid_arg_name_by_flag(CTR_FLAG_MAX_RECOVERY_RATE))) {
|
||||
if (test_and_set_bit(__CTR_FLAG_MAX_RECOVERY_RATE, &rs->ctr_flags)) {
|
||||
rs->ti->error = "Only one max_recovery_rate argument pair allowed";
|
||||
return -EINVAL;
|
||||
}
|
||||
if (value > INT_MAX) {
|
||||
|
||||
if (value < 0) {
|
||||
rs->ti->error = "max_recovery_rate out of range";
|
||||
return -EINVAL;
|
||||
}
|
||||
rs->md.sync_speed_max = (int)value;
|
||||
rs->md.sync_speed_max = value;
|
||||
} else if (!strcasecmp(key, dm_raid_arg_name_by_flag(CTR_FLAG_REGION_SIZE))) {
|
||||
if (test_and_set_bit(__CTR_FLAG_REGION_SIZE, &rs->ctr_flags)) {
|
||||
rs->ti->error = "Only one region_size argument pair allowed";
|
||||
@@ -1490,6 +1495,12 @@ static int parse_raid_params(struct raid_set *rs, struct dm_arg_set *as,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (rs->md.sync_speed_max &&
|
||||
rs->md.sync_speed_min > rs->md.sync_speed_max) {
|
||||
rs->ti->error = "Bogus recovery rates";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (validate_region_size(rs, region_size))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -3408,7 +3419,8 @@ static sector_t rs_get_progress(struct raid_set *rs, unsigned long recovery,
|
||||
set_bit(RT_FLAG_RS_IN_SYNC, &rs->runtime_flags);
|
||||
|
||||
} else {
|
||||
if (!test_bit(MD_RECOVERY_INTR, &recovery) &&
|
||||
if (!test_bit(__CTR_FLAG_NOSYNC, &rs->ctr_flags) &&
|
||||
!test_bit(MD_RECOVERY_INTR, &recovery) &&
|
||||
(test_bit(MD_RECOVERY_NEEDED, &recovery) ||
|
||||
test_bit(MD_RECOVERY_RESHAPE, &recovery) ||
|
||||
test_bit(MD_RECOVERY_RUNNING, &recovery)))
|
||||
@@ -3663,7 +3675,8 @@ static void raid_status(struct dm_target *ti, status_type_t type,
|
||||
}
|
||||
}
|
||||
|
||||
static int raid_message(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
static int raid_message(struct dm_target *ti, unsigned int argc, char **argv,
|
||||
char *result, unsigned maxlen)
|
||||
{
|
||||
struct raid_set *rs = ti->private;
|
||||
struct mddev *mddev = &rs->md;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dm-io.h>
|
||||
#include "dm-bufio.h"
|
||||
#include <linux/dm-bufio.h>
|
||||
|
||||
#define DM_MSG_PREFIX "persistent snapshot"
|
||||
#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32 /* 16KB */
|
||||
|
||||
@@ -169,6 +169,7 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
|
||||
ti->num_flush_bios = stripes;
|
||||
ti->num_discard_bios = stripes;
|
||||
ti->num_secure_erase_bios = stripes;
|
||||
ti->num_write_same_bios = stripes;
|
||||
ti->num_write_zeroes_bios = stripes;
|
||||
|
||||
@@ -295,6 +296,7 @@ static int stripe_map(struct dm_target *ti, struct bio *bio)
|
||||
return DM_MAPIO_REMAPPED;
|
||||
}
|
||||
if (unlikely(bio_op(bio) == REQ_OP_DISCARD) ||
|
||||
unlikely(bio_op(bio) == REQ_OP_SECURE_ERASE) ||
|
||||
unlikely(bio_op(bio) == REQ_OP_WRITE_ZEROES) ||
|
||||
unlikely(bio_op(bio) == REQ_OP_WRITE_SAME)) {
|
||||
target_bio_nr = dm_bio_get_target_bio_nr(bio);
|
||||
@@ -368,7 +370,6 @@ static void stripe_status(struct dm_target *ti, status_type_t type,
|
||||
unsigned status_flags, char *result, unsigned maxlen)
|
||||
{
|
||||
struct stripe_c *sc = (struct stripe_c *) ti->private;
|
||||
char buffer[sc->stripes + 1];
|
||||
unsigned int sz = 0;
|
||||
unsigned int i;
|
||||
|
||||
@@ -377,11 +378,12 @@ static void stripe_status(struct dm_target *ti, status_type_t type,
|
||||
DMEMIT("%d ", sc->stripes);
|
||||
for (i = 0; i < sc->stripes; i++) {
|
||||
DMEMIT("%s ", sc->stripe[i].dev->name);
|
||||
buffer[i] = atomic_read(&(sc->stripe[i].error_count)) ?
|
||||
'D' : 'A';
|
||||
}
|
||||
buffer[i] = '\0';
|
||||
DMEMIT("1 %s", buffer);
|
||||
DMEMIT("1 ");
|
||||
for (i = 0; i < sc->stripes; i++) {
|
||||
DMEMIT("%c", atomic_read(&(sc->stripe[i].error_count)) ?
|
||||
'D' : 'A');
|
||||
}
|
||||
break;
|
||||
|
||||
case STATUSTYPE_TABLE:
|
||||
|
||||
@@ -466,7 +466,8 @@ static int process_set_region_mappings(struct switch_ctx *sctx,
|
||||
*
|
||||
* Only set_region_mappings is supported.
|
||||
*/
|
||||
static int switch_message(struct dm_target *ti, unsigned argc, char **argv)
|
||||
static int switch_message(struct dm_target *ti, unsigned argc, char **argv,
|
||||
char *result, unsigned maxlen)
|
||||
{
|
||||
static DEFINE_MUTEX(message_mutex);
|
||||
|
||||
@@ -511,8 +512,7 @@ static void switch_status(struct dm_target *ti, status_type_t type,
|
||||
*
|
||||
* Passthrough all ioctls to the path for sector 0
|
||||
*/
|
||||
static int switch_prepare_ioctl(struct dm_target *ti,
|
||||
struct block_device **bdev, fmode_t *mode)
|
||||
static int switch_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
|
||||
{
|
||||
struct switch_ctx *sctx = ti->private;
|
||||
unsigned path_nr;
|
||||
@@ -520,7 +520,6 @@ static int switch_prepare_ioctl(struct dm_target *ti,
|
||||
path_nr = switch_get_path_nr(sctx, 0);
|
||||
|
||||
*bdev = sctx->path_list[path_nr].dmdev->bdev;
|
||||
*mode = sctx->path_list[path_nr].dmdev->mode;
|
||||
|
||||
/*
|
||||
* Only pass ioctls through if the device sizes match exactly.
|
||||
|
||||
@@ -1846,6 +1846,34 @@ static bool dm_table_supports_discards(struct dm_table *t)
|
||||
return true;
|
||||
}
|
||||
|
||||
static int device_not_secure_erase_capable(struct dm_target *ti,
|
||||
struct dm_dev *dev, sector_t start,
|
||||
sector_t len, void *data)
|
||||
{
|
||||
struct request_queue *q = bdev_get_queue(dev->bdev);
|
||||
|
||||
return q && !blk_queue_secure_erase(q);
|
||||
}
|
||||
|
||||
static bool dm_table_supports_secure_erase(struct dm_table *t)
|
||||
{
|
||||
struct dm_target *ti;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < dm_table_get_num_targets(t); i++) {
|
||||
ti = dm_table_get_target(t, i);
|
||||
|
||||
if (!ti->num_secure_erase_bios)
|
||||
return false;
|
||||
|
||||
if (!ti->type->iterate_devices ||
|
||||
ti->type->iterate_devices(ti, device_not_secure_erase_capable, NULL))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
|
||||
struct queue_limits *limits)
|
||||
{
|
||||
@@ -1867,6 +1895,9 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
|
||||
} else
|
||||
blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
|
||||
|
||||
if (dm_table_supports_secure_erase(t))
|
||||
blk_queue_flag_set(QUEUE_FLAG_SECERASE, q);
|
||||
|
||||
if (dm_table_supports_flush(t, (1UL << QUEUE_FLAG_WC))) {
|
||||
wc = true;
|
||||
if (dm_table_supports_flush(t, (1UL << QUEUE_FLAG_FUA)))
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
static LIST_HEAD(_targets);
|
||||
static DECLARE_RWSEM(_lock);
|
||||
|
||||
#define DM_MOD_NAME_SIZE 32
|
||||
|
||||
static inline struct target_type *__find_target_type(const char *name)
|
||||
{
|
||||
struct target_type *tt;
|
||||
|
||||
@@ -3705,7 +3705,8 @@ static int process_release_metadata_snap_mesg(unsigned argc, char **argv, struct
|
||||
* reserve_metadata_snap
|
||||
* release_metadata_snap
|
||||
*/
|
||||
static int pool_message(struct dm_target *ti, unsigned argc, char **argv)
|
||||
static int pool_message(struct dm_target *ti, unsigned argc, char **argv,
|
||||
char *result, unsigned maxlen)
|
||||
{
|
||||
int r = -EINVAL;
|
||||
struct pool_c *pt = ti->private;
|
||||
|
||||
+12
-25
@@ -7,12 +7,6 @@
|
||||
#include "dm.h"
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/bio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device-mapper.h>
|
||||
|
||||
struct unstripe_c {
|
||||
struct dm_dev *dev;
|
||||
@@ -69,12 +63,6 @@ static int unstripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
goto err;
|
||||
}
|
||||
|
||||
// FIXME: must support non power of 2 chunk_size, dm-stripe.c does
|
||||
if (!is_power_of_2(uc->chunk_size)) {
|
||||
ti->error = "Non power of 2 chunk_size is not supported yet";
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (kstrtouint(argv[2], 10, &uc->unstripe)) {
|
||||
ti->error = "Invalid stripe number";
|
||||
goto err;
|
||||
@@ -98,7 +86,7 @@ static int unstripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
|
||||
uc->unstripe_offset = uc->unstripe * uc->chunk_size;
|
||||
uc->unstripe_width = (uc->stripes - 1) * uc->chunk_size;
|
||||
uc->chunk_shift = fls(uc->chunk_size) - 1;
|
||||
uc->chunk_shift = is_power_of_2(uc->chunk_size) ? fls(uc->chunk_size) - 1 : 0;
|
||||
|
||||
tmp_len = ti->len;
|
||||
if (sector_div(tmp_len, uc->chunk_size)) {
|
||||
@@ -129,14 +117,18 @@ static sector_t map_to_core(struct dm_target *ti, struct bio *bio)
|
||||
{
|
||||
struct unstripe_c *uc = ti->private;
|
||||
sector_t sector = bio->bi_iter.bi_sector;
|
||||
sector_t tmp_sector = sector;
|
||||
|
||||
/* Shift us up to the right "row" on the stripe */
|
||||
sector += uc->unstripe_width * (sector >> uc->chunk_shift);
|
||||
if (uc->chunk_shift)
|
||||
tmp_sector >>= uc->chunk_shift;
|
||||
else
|
||||
sector_div(tmp_sector, uc->chunk_size);
|
||||
|
||||
sector += uc->unstripe_width * tmp_sector;
|
||||
|
||||
/* Account for what stripe we're operating on */
|
||||
sector += uc->unstripe_offset;
|
||||
|
||||
return sector;
|
||||
return sector + uc->unstripe_offset;
|
||||
}
|
||||
|
||||
static int unstripe_map(struct dm_target *ti, struct bio *bio)
|
||||
@@ -185,7 +177,7 @@ static void unstripe_io_hints(struct dm_target *ti,
|
||||
|
||||
static struct target_type unstripe_target = {
|
||||
.name = "unstriped",
|
||||
.version = {1, 0, 0},
|
||||
.version = {1, 1, 0},
|
||||
.module = THIS_MODULE,
|
||||
.ctr = unstripe_ctr,
|
||||
.dtr = unstripe_dtr,
|
||||
@@ -197,13 +189,7 @@ static struct target_type unstripe_target = {
|
||||
|
||||
static int __init dm_unstripe_init(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = dm_register_target(&unstripe_target);
|
||||
if (r < 0)
|
||||
DMERR("target registration failed");
|
||||
|
||||
return r;
|
||||
return dm_register_target(&unstripe_target);
|
||||
}
|
||||
|
||||
static void __exit dm_unstripe_exit(void)
|
||||
@@ -215,5 +201,6 @@ module_init(dm_unstripe_init);
|
||||
module_exit(dm_unstripe_exit);
|
||||
|
||||
MODULE_DESCRIPTION(DM_NAME " unstriped target");
|
||||
MODULE_ALIAS("dm-unstriped");
|
||||
MODULE_AUTHOR("Scott Bauer <scott.bauer@intel.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#define DM_VERITY_OPT_LOGGING "ignore_corruption"
|
||||
#define DM_VERITY_OPT_RESTART "restart_on_corruption"
|
||||
#define DM_VERITY_OPT_IGN_ZEROES "ignore_zero_blocks"
|
||||
#define DM_VERITY_OPT_AT_MOST_ONCE "check_at_most_once"
|
||||
|
||||
#define DM_VERITY_OPTS_MAX (2 + DM_VERITY_OPTS_FEC)
|
||||
|
||||
@@ -347,8 +348,8 @@ out:
|
||||
/*
|
||||
* Calculates the digest for the given bio
|
||||
*/
|
||||
int verity_for_io_block(struct dm_verity *v, struct dm_verity_io *io,
|
||||
struct bvec_iter *iter, struct crypto_wait *wait)
|
||||
static int verity_for_io_block(struct dm_verity *v, struct dm_verity_io *io,
|
||||
struct bvec_iter *iter, struct crypto_wait *wait)
|
||||
{
|
||||
unsigned int todo = 1 << v->data_dev_block_bits;
|
||||
struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size);
|
||||
@@ -432,6 +433,18 @@ static int verity_bv_zero(struct dm_verity *v, struct dm_verity_io *io,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Moves the bio iter one data block forward.
|
||||
*/
|
||||
static inline void verity_bv_skip_block(struct dm_verity *v,
|
||||
struct dm_verity_io *io,
|
||||
struct bvec_iter *iter)
|
||||
{
|
||||
struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size);
|
||||
|
||||
bio_advance_iter(bio, iter, 1 << v->data_dev_block_bits);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify one "dm_verity_io" structure.
|
||||
*/
|
||||
@@ -445,9 +458,16 @@ static int verity_verify_io(struct dm_verity_io *io)
|
||||
|
||||
for (b = 0; b < io->n_blocks; b++) {
|
||||
int r;
|
||||
sector_t cur_block = io->block + b;
|
||||
struct ahash_request *req = verity_io_hash_req(v, io);
|
||||
|
||||
r = verity_hash_for_block(v, io, io->block + b,
|
||||
if (v->validated_blocks &&
|
||||
likely(test_bit(cur_block, v->validated_blocks))) {
|
||||
verity_bv_skip_block(v, io, &io->iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = verity_hash_for_block(v, io, cur_block,
|
||||
verity_io_want_digest(v, io),
|
||||
&is_zero);
|
||||
if (unlikely(r < 0))
|
||||
@@ -481,13 +501,16 @@ static int verity_verify_io(struct dm_verity_io *io)
|
||||
return r;
|
||||
|
||||
if (likely(memcmp(verity_io_real_digest(v, io),
|
||||
verity_io_want_digest(v, io), v->digest_size) == 0))
|
||||
verity_io_want_digest(v, io), v->digest_size) == 0)) {
|
||||
if (v->validated_blocks)
|
||||
set_bit(cur_block, v->validated_blocks);
|
||||
continue;
|
||||
}
|
||||
else if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_DATA,
|
||||
io->block + b, NULL, &start) == 0)
|
||||
cur_block, NULL, &start) == 0)
|
||||
continue;
|
||||
else if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA,
|
||||
io->block + b))
|
||||
cur_block))
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -673,6 +696,8 @@ static void verity_status(struct dm_target *ti, status_type_t type,
|
||||
args += DM_VERITY_OPTS_FEC;
|
||||
if (v->zero_digest)
|
||||
args++;
|
||||
if (v->validated_blocks)
|
||||
args++;
|
||||
if (!args)
|
||||
return;
|
||||
DMEMIT(" %u", args);
|
||||
@@ -691,13 +716,14 @@ static void verity_status(struct dm_target *ti, status_type_t type,
|
||||
}
|
||||
if (v->zero_digest)
|
||||
DMEMIT(" " DM_VERITY_OPT_IGN_ZEROES);
|
||||
if (v->validated_blocks)
|
||||
DMEMIT(" " DM_VERITY_OPT_AT_MOST_ONCE);
|
||||
sz = verity_fec_status_table(v, sz, result, maxlen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int verity_prepare_ioctl(struct dm_target *ti,
|
||||
struct block_device **bdev, fmode_t *mode)
|
||||
static int verity_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
|
||||
{
|
||||
struct dm_verity *v = ti->private;
|
||||
|
||||
@@ -740,6 +766,7 @@ static void verity_dtr(struct dm_target *ti)
|
||||
if (v->bufio)
|
||||
dm_bufio_client_destroy(v->bufio);
|
||||
|
||||
kvfree(v->validated_blocks);
|
||||
kfree(v->salt);
|
||||
kfree(v->root_digest);
|
||||
kfree(v->zero_digest);
|
||||
@@ -760,6 +787,26 @@ static void verity_dtr(struct dm_target *ti)
|
||||
kfree(v);
|
||||
}
|
||||
|
||||
static int verity_alloc_most_once(struct dm_verity *v)
|
||||
{
|
||||
struct dm_target *ti = v->ti;
|
||||
|
||||
/* the bitset can only handle INT_MAX blocks */
|
||||
if (v->data_blocks > INT_MAX) {
|
||||
ti->error = "device too large to use check_at_most_once";
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
v->validated_blocks = kvzalloc(BITS_TO_LONGS(v->data_blocks) *
|
||||
sizeof(unsigned long), GFP_KERNEL);
|
||||
if (!v->validated_blocks) {
|
||||
ti->error = "failed to allocate bitset for check_at_most_once";
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verity_alloc_zero_digest(struct dm_verity *v)
|
||||
{
|
||||
int r = -ENOMEM;
|
||||
@@ -829,6 +876,12 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v)
|
||||
}
|
||||
continue;
|
||||
|
||||
} else if (!strcasecmp(arg_name, DM_VERITY_OPT_AT_MOST_ONCE)) {
|
||||
r = verity_alloc_most_once(v);
|
||||
if (r)
|
||||
return r;
|
||||
continue;
|
||||
|
||||
} else if (verity_is_fec_opt_arg(arg_name)) {
|
||||
r = verity_fec_parse_opt_args(as, v, &argc, arg_name);
|
||||
if (r)
|
||||
@@ -1096,7 +1149,7 @@ bad:
|
||||
|
||||
static struct target_type verity_target = {
|
||||
.name = "verity",
|
||||
.version = {1, 3, 0},
|
||||
.version = {1, 4, 0},
|
||||
.module = THIS_MODULE,
|
||||
.ctr = verity_ctr,
|
||||
.dtr = verity_dtr,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user