forked from Minki/linux
3 stable@ fixes:
- DM core AB-BA deadlock fix in the device destruction path (vs device creation's DM table swap). - DM raid fix to properly round up the region_size to the next power-of-2. - DM cache fix for a NULL pointer seen while switching from the "cleaner" cache policy. 2 fixes for regressions introduced during the 4.3 merge: - request-based DM error propagation regressed due to incorrect changes introduced when adding the bi_error field to bio. - DM snapshot fix to only support snapshots that overflow if the client (e.g. lvm2) is prepared to deal with the associated snapshot status interface change. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJWGC/jAAoJEMUj8QotnQNaTgYIAJz1AG5IcHz8D3zi8+MBWXFL WAYrXfXSxexsymVKFsqi6z9fYiW5fRZ41/+Kl8/dYnhBIS8uUzWlad2qw/JFg+zC l/EzdHWjakzuGm9/quK2h/CBC/3pmRH9UeKgzOPODOpAzkJfrKoO4/J7JPIi3JyP esE/2F2TBwERL4oC74UB7/nuM/xckS/DRjbd3B82/IsfM5n+MARvuSSrqWcPEu8h Hh5k42KyA+Tq7uElLnXF8phFOCJCn9IyI+QLdxj33PfDxwrtXMvV6Sxw7FS8b7oF /gw3Dod4sEv+EJZ1A+O9mxGBk3ajCpMvUYbcY6owIHyB1mKWiSKyvyBPyIY6RiQ= =2z9t -----END PGP SIGNATURE----- Merge tag 'dm-4.3-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm Pull dm fixes from Mike Snitzer: "Three stable fixes: - DM core AB-BA deadlock fix in the device destruction path (vs device creation's DM table swap). - DM raid fix to properly round up the region_size to the next power-of-2. - DM cache fix for a NULL pointer seen while switching from the "cleaner" cache policy. Two fixes for regressions introduced during the 4.3 merge: - request-based DM error propagation regressed due to incorrect changes introduced when adding the bi_error field to bio. - DM snapshot fix to only support snapshots that overflow if the client (e.g. lvm2) is prepared to deal with the associated snapshot status interface change" * tag 'dm-4.3-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm: dm snapshot: add new persistent store option to support overflow dm cache: fix NULL pointer when switching from cleaner policy dm: fix request-based dm error reporting dm raid: fix round up of default region size dm: fix AB-BA deadlock in __dm_destroy()
This commit is contained in:
commit
0444555670
@ -41,9 +41,13 @@ useless and be disabled, returning errors. So it is important to monitor
|
||||
the amount of free space and expand the <COW device> before it fills up.
|
||||
|
||||
<persistent?> is P (Persistent) or N (Not persistent - will not survive
|
||||
after reboot).
|
||||
The difference is that for transient snapshots less metadata must be
|
||||
saved on disk - they can be kept in memory by the kernel.
|
||||
after reboot). O (Overflow) can be added as a persistent store option
|
||||
to allow userspace to advertise its support for seeing "Overflow" in the
|
||||
snapshot status. So supported store types are "P", "PO" and "N".
|
||||
|
||||
The difference between persistent and transient is with transient
|
||||
snapshots less metadata must be saved on disk - they can be kept in
|
||||
memory by the kernel.
|
||||
|
||||
|
||||
* snapshot-merge <origin> <COW device> <persistent> <chunksize>
|
||||
|
@ -436,7 +436,7 @@ static struct dm_cache_policy *wb_create(dm_cblock_t cache_size,
|
||||
static struct dm_cache_policy_type wb_policy_type = {
|
||||
.name = "cleaner",
|
||||
.version = {1, 0, 0},
|
||||
.hint_size = 0,
|
||||
.hint_size = 4,
|
||||
.owner = THIS_MODULE,
|
||||
.create = wb_create
|
||||
};
|
||||
|
@ -203,7 +203,7 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tmp_store = kmalloc(sizeof(*tmp_store), GFP_KERNEL);
|
||||
tmp_store = kzalloc(sizeof(*tmp_store), GFP_KERNEL);
|
||||
if (!tmp_store) {
|
||||
ti->error = "Exception store allocation failed";
|
||||
return -ENOMEM;
|
||||
@ -215,7 +215,7 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
|
||||
else if (persistent == 'N')
|
||||
type = get_type("N");
|
||||
else {
|
||||
ti->error = "Persistent flag is not P or N";
|
||||
ti->error = "Exception store type is not P or N";
|
||||
r = -EINVAL;
|
||||
goto bad_type;
|
||||
}
|
||||
@ -233,7 +233,7 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
|
||||
if (r)
|
||||
goto bad;
|
||||
|
||||
r = type->ctr(tmp_store, 0, NULL);
|
||||
r = type->ctr(tmp_store, (strlen(argv[0]) > 1 ? &argv[0][1] : NULL));
|
||||
if (r) {
|
||||
ti->error = "Exception store type constructor failed";
|
||||
goto bad;
|
||||
|
@ -42,8 +42,7 @@ struct dm_exception_store_type {
|
||||
const char *name;
|
||||
struct module *module;
|
||||
|
||||
int (*ctr) (struct dm_exception_store *store,
|
||||
unsigned argc, char **argv);
|
||||
int (*ctr) (struct dm_exception_store *store, char *options);
|
||||
|
||||
/*
|
||||
* Destroys this object when you've finished with it.
|
||||
@ -123,6 +122,8 @@ struct dm_exception_store {
|
||||
unsigned chunk_shift;
|
||||
|
||||
void *context;
|
||||
|
||||
bool userspace_supports_overflow;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -329,8 +329,7 @@ static int validate_region_size(struct raid_set *rs, unsigned long region_size)
|
||||
*/
|
||||
if (min_region_size > (1 << 13)) {
|
||||
/* If not a power of 2, make it the next power of 2 */
|
||||
if (min_region_size & (min_region_size - 1))
|
||||
region_size = 1 << fls(region_size);
|
||||
region_size = roundup_pow_of_two(min_region_size);
|
||||
DMINFO("Choosing default region size of %lu sectors",
|
||||
region_size);
|
||||
} else {
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "dm-exception-store.h"
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/vmalloc.h>
|
||||
@ -843,8 +844,7 @@ static void persistent_drop_snapshot(struct dm_exception_store *store)
|
||||
DMWARN("write header failed");
|
||||
}
|
||||
|
||||
static int persistent_ctr(struct dm_exception_store *store,
|
||||
unsigned argc, char **argv)
|
||||
static int persistent_ctr(struct dm_exception_store *store, char *options)
|
||||
{
|
||||
struct pstore *ps;
|
||||
|
||||
@ -873,6 +873,16 @@ static int persistent_ctr(struct dm_exception_store *store,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (options) {
|
||||
char overflow = toupper(options[0]);
|
||||
if (overflow == 'O')
|
||||
store->userspace_supports_overflow = true;
|
||||
else {
|
||||
DMERR("Unsupported persistent store option: %s", options);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
store->context = ps;
|
||||
|
||||
return 0;
|
||||
@ -888,7 +898,8 @@ static unsigned persistent_status(struct dm_exception_store *store,
|
||||
case STATUSTYPE_INFO:
|
||||
break;
|
||||
case STATUSTYPE_TABLE:
|
||||
DMEMIT(" P %llu", (unsigned long long)store->chunk_size);
|
||||
DMEMIT(" %s %llu", store->userspace_supports_overflow ? "PO" : "P",
|
||||
(unsigned long long)store->chunk_size);
|
||||
}
|
||||
|
||||
return sz;
|
||||
|
@ -70,8 +70,7 @@ static void transient_usage(struct dm_exception_store *store,
|
||||
*metadata_sectors = 0;
|
||||
}
|
||||
|
||||
static int transient_ctr(struct dm_exception_store *store,
|
||||
unsigned argc, char **argv)
|
||||
static int transient_ctr(struct dm_exception_store *store, char *options)
|
||||
{
|
||||
struct transient_c *tc;
|
||||
|
||||
|
@ -1098,7 +1098,7 @@ static void stop_merge(struct dm_snapshot *s)
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct a snapshot mapping: <origin_dev> <COW-dev> <p/n> <chunk-size>
|
||||
* Construct a snapshot mapping: <origin_dev> <COW-dev> <p|po|n> <chunk-size>
|
||||
*/
|
||||
static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
{
|
||||
@ -1302,6 +1302,7 @@ static void __handover_exceptions(struct dm_snapshot *snap_src,
|
||||
|
||||
u.store_swap = snap_dest->store;
|
||||
snap_dest->store = snap_src->store;
|
||||
snap_dest->store->userspace_supports_overflow = u.store_swap->userspace_supports_overflow;
|
||||
snap_src->store = u.store_swap;
|
||||
|
||||
snap_dest->store->snap = snap_dest;
|
||||
@ -1739,8 +1740,11 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
|
||||
|
||||
pe = __find_pending_exception(s, pe, chunk);
|
||||
if (!pe) {
|
||||
s->snapshot_overflowed = 1;
|
||||
DMERR("Snapshot overflowed: Unable to allocate exception.");
|
||||
if (s->store->userspace_supports_overflow) {
|
||||
s->snapshot_overflowed = 1;
|
||||
DMERR("Snapshot overflowed: Unable to allocate exception.");
|
||||
} else
|
||||
__invalidate_snapshot(s, -ENOMEM);
|
||||
r = -EIO;
|
||||
goto out_unlock;
|
||||
}
|
||||
@ -2365,7 +2369,7 @@ static struct target_type origin_target = {
|
||||
|
||||
static struct target_type snapshot_target = {
|
||||
.name = "snapshot",
|
||||
.version = {1, 14, 0},
|
||||
.version = {1, 15, 0},
|
||||
.module = THIS_MODULE,
|
||||
.ctr = snapshot_ctr,
|
||||
.dtr = snapshot_dtr,
|
||||
@ -2379,7 +2383,7 @@ static struct target_type snapshot_target = {
|
||||
|
||||
static struct target_type merge_target = {
|
||||
.name = dm_snapshot_merge_target_name,
|
||||
.version = {1, 3, 0},
|
||||
.version = {1, 4, 0},
|
||||
.module = THIS_MODULE,
|
||||
.ctr = snapshot_ctr,
|
||||
.dtr = snapshot_dtr,
|
||||
|
@ -1001,6 +1001,7 @@ static void end_clone_bio(struct bio *clone)
|
||||
struct dm_rq_target_io *tio = info->tio;
|
||||
struct bio *bio = info->orig;
|
||||
unsigned int nr_bytes = info->orig->bi_iter.bi_size;
|
||||
int error = clone->bi_error;
|
||||
|
||||
bio_put(clone);
|
||||
|
||||
@ -1011,13 +1012,13 @@ static void end_clone_bio(struct bio *clone)
|
||||
* the remainder.
|
||||
*/
|
||||
return;
|
||||
else if (bio->bi_error) {
|
||||
else if (error) {
|
||||
/*
|
||||
* Don't notice the error to the upper layer yet.
|
||||
* The error handling decision is made by the target driver,
|
||||
* when the request is completed.
|
||||
*/
|
||||
tio->error = bio->bi_error;
|
||||
tio->error = error;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2837,8 +2838,6 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
|
||||
|
||||
might_sleep();
|
||||
|
||||
map = dm_get_live_table(md, &srcu_idx);
|
||||
|
||||
spin_lock(&_minor_lock);
|
||||
idr_replace(&_minor_idr, MINOR_ALLOCED, MINOR(disk_devt(dm_disk(md))));
|
||||
set_bit(DMF_FREEING, &md->flags);
|
||||
@ -2852,14 +2851,14 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
|
||||
* do not race with internal suspend.
|
||||
*/
|
||||
mutex_lock(&md->suspend_lock);
|
||||
map = dm_get_live_table(md, &srcu_idx);
|
||||
if (!dm_suspended_md(md)) {
|
||||
dm_table_presuspend_targets(map);
|
||||
dm_table_postsuspend_targets(map);
|
||||
}
|
||||
mutex_unlock(&md->suspend_lock);
|
||||
|
||||
/* dm_put_live_table must be before msleep, otherwise deadlock is possible */
|
||||
dm_put_live_table(md, srcu_idx);
|
||||
mutex_unlock(&md->suspend_lock);
|
||||
|
||||
/*
|
||||
* Rare, but there may be I/O requests still going to complete,
|
||||
|
Loading…
Reference in New Issue
Block a user