dm snapshot: add new persistent store option to support overflow
Commit76c44f6d80
introduced the possibly for "Overflow" to be reported by the snapshot device's status. Older userspace (e.g. lvm2) does not handle the "Overflow" status response. Fix this incompatibility by requiring newer userspace code, that can cope with "Overflow", request the persistent store with overflow support by using "PO" (Persistent with Overflow) for the snapshot store type. Reported-by: Zdenek Kabelac <zkabelac@redhat.com> Fixes:76c44f6d80
("dm snapshot: don't invalidate on-disk image on snapshot write overflow") Reviewed-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
This commit is contained in:
parent
2bffa1503c
commit
b0d3cc011e
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue
Block a user