mirror of
git://sourceware.org/git/lvm2.git
synced 2025-12-25 20:23:49 +03:00
Compare commits
23 Commits
dm_v1_01_0
...
dm_v1_01_0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
196b8eaad3 | ||
|
|
8e526ba1bf | ||
|
|
19225828d9 | ||
|
|
7e594126be | ||
|
|
d2529e6334 | ||
|
|
97344f18e2 | ||
|
|
33934db629 | ||
|
|
6c6165c9f5 | ||
|
|
853460b20d | ||
|
|
cc4d9676c5 | ||
|
|
1cf1b819f4 | ||
|
|
f916c66d2b | ||
|
|
550aa86b45 | ||
|
|
014e764758 | ||
|
|
d1fc28432b | ||
|
|
879576f0a2 | ||
|
|
69098210be | ||
|
|
99df4f892d | ||
|
|
7bc04fbad3 | ||
|
|
8a74ce578d | ||
|
|
0805e4e5de | ||
|
|
f1060fc88e | ||
|
|
7d3d3d0a3a |
23
WHATS_NEW
23
WHATS_NEW
@@ -1,5 +1,27 @@
|
||||
Version 2.01.11 -
|
||||
==============================
|
||||
Remove hard-coded 64k text metadata writing restriction.
|
||||
Make VG name restrictions consistent.
|
||||
Introduce lvconvert. So far only removes mirror images.
|
||||
Allow mirror images to be resized.
|
||||
Allow mirror images to have more than one segment.
|
||||
Centralise restrictions on LV names.
|
||||
Always insert an intermediate layer for mirrors.
|
||||
Suppress hidden LVs from reports unless --all is given.
|
||||
Use square brackets for hidden LVs in reports.
|
||||
Allow the creation of mirrors with contiguous extents.
|
||||
Always perform sanity checks against metadata before committing it to disk.
|
||||
Split lv_extend into two steps: choosing extents + allocation to LV(s).
|
||||
Add mirror log region size to metadata.
|
||||
Use list_iterate_items throughout and add list*back macros.
|
||||
Introduce seg_ macros to access areas.
|
||||
Add segtype_is_ macros.
|
||||
Support tiny metadata areas for pool conversions.
|
||||
Mirror activation handles disk log as well as core.
|
||||
Activation code recognises mirror log dependency.
|
||||
Add mirror_log and regionsize fields to report.
|
||||
Fix non-orphan pvchange -u.
|
||||
Fix vgmerge to handle duplicate LVIDs.
|
||||
Move archiver code from tools into library.
|
||||
vgscan/change/display/vgs automatically create metadata backups if needed.
|
||||
Merge cloned allocation functions.
|
||||
@@ -14,6 +36,7 @@ Version 2.01.11 -
|
||||
lv_reduce tidying.
|
||||
Remove some unnecessary parameters.
|
||||
Introduce seg_is macros.
|
||||
Don't defer closing dead FDs in clvmd.
|
||||
|
||||
Version 2.01.10 - 3rd May 2005
|
||||
==============================
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
Version 1.01.03 - 13 Jun 2005
|
||||
=============================
|
||||
Use matchpathcon mode parameter.
|
||||
Fix configure script to re-enable selinux.
|
||||
|
||||
Version 1.01.02 - 17 May 2005
|
||||
=============================
|
||||
Call dm_lib_exit() and dm_lib_release() automatically now.
|
||||
|
||||
@@ -578,6 +578,7 @@ static void main_loop(int local_sock, int cmd_timeout)
|
||||
lastfd->next = thisfd->next;
|
||||
free_fd = thisfd;
|
||||
thisfd = lastfd;
|
||||
close(free_fd->fd);
|
||||
|
||||
/* Queue cleanup, this also frees the client struct */
|
||||
add_to_lvmqueue(free_fd, NULL, 0, NULL);
|
||||
@@ -1610,7 +1611,6 @@ static int process_work_item(struct lvm_thread_cmd *cmd)
|
||||
/* If msg is NULL then this is a cleanup request */
|
||||
if (cmd->msg == NULL) {
|
||||
DEBUGLOG("process_work_item: free fd %d\n", cmd->client->fd);
|
||||
close(cmd->client->fd);
|
||||
cmd_client_cleanup(cmd->client);
|
||||
free(cmd->client);
|
||||
return 0;
|
||||
|
||||
@@ -106,6 +106,7 @@ void tcp_remove_client(char *csid)
|
||||
{
|
||||
hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
|
||||
client->removeme = 1;
|
||||
close(client->fd);
|
||||
}
|
||||
|
||||
/* Look for a mangled one too */
|
||||
@@ -116,6 +117,7 @@ void tcp_remove_client(char *csid)
|
||||
{
|
||||
hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
|
||||
client->removeme = 1;
|
||||
close(client->fd);
|
||||
}
|
||||
|
||||
/* Put it back as we found it */
|
||||
@@ -228,6 +230,25 @@ int cluster_fd_gulm_callback(struct local_client *fd, char *buf, int len, char *
|
||||
return newfd;
|
||||
}
|
||||
|
||||
/* Try to get at least 'len' bytes from the socket */
|
||||
static int really_read(int fd, char *buf, int len)
|
||||
{
|
||||
int got, offset;
|
||||
|
||||
got = offset = 0;
|
||||
|
||||
do {
|
||||
got = read(fd, buf+offset, len-offset);
|
||||
DEBUGLOG("really_read. got %d bytes\n", got);
|
||||
offset += got;
|
||||
} while (got > 0 && offset < len);
|
||||
|
||||
if (got < 0)
|
||||
return got;
|
||||
else
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
static int read_from_tcpsock(struct local_client *client, char *buf, int len, char *csid,
|
||||
struct local_client **new_client)
|
||||
@@ -248,7 +269,7 @@ static int read_from_tcpsock(struct local_client *client, char *buf, int len, ch
|
||||
/* Read just the header first, then get the rest if there is any.
|
||||
* Stream sockets, sigh.
|
||||
*/
|
||||
status = read(client->fd, buf, sizeof(struct clvm_header));
|
||||
status = really_read(client->fd, buf, sizeof(struct clvm_header));
|
||||
if (status > 0)
|
||||
{
|
||||
int status2;
|
||||
@@ -258,7 +279,7 @@ static int read_from_tcpsock(struct local_client *client, char *buf, int len, ch
|
||||
/* Get the rest */
|
||||
if (arglen && arglen < GULM_MAX_CLUSTER_MESSAGE)
|
||||
{
|
||||
status2 = read(client->fd, buf+status, arglen);
|
||||
status2 = really_read(client->fd, buf+status, arglen);
|
||||
if (status2 > 0)
|
||||
status += status2;
|
||||
else
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
static enum event_type events = ALL_ERRORS; /* All until we can distinguish. */
|
||||
static char default_dso_name[] = "noop"; /* default DSO is noop */
|
||||
static int default_reg = 1; /* default action is register */
|
||||
static uint32_t timeout;
|
||||
|
||||
/* Display help. */
|
||||
static void print_usage(char *name)
|
||||
@@ -45,6 +46,7 @@ static void print_usage(char *name)
|
||||
" -h Print this usage.\n"
|
||||
" -l List registered devices.\n"
|
||||
" -r Register for event (default).\n"
|
||||
" -t <timeout> (un)register for timeout event.\n"
|
||||
" -u Unregister for event.\n"
|
||||
"\n", cmd);
|
||||
}
|
||||
@@ -54,7 +56,7 @@ static int parse_argv(int argc, char **argv, char **dso_name_arg,
|
||||
char **device_arg, int *reg, int *list)
|
||||
{
|
||||
int c;
|
||||
const char *options = "d:hlru";
|
||||
const char *options = "d:hlrt:u";
|
||||
|
||||
while ((c = getopt(argc, argv, options)) != -1) {
|
||||
switch (c) {
|
||||
@@ -70,6 +72,14 @@ static int parse_argv(int argc, char **argv, char **dso_name_arg,
|
||||
case 'r':
|
||||
*reg = 1;
|
||||
break;
|
||||
case 't':
|
||||
events = TIMEOUT;
|
||||
if (sscanf(optarg, "%"SCNu32, &timeout) != 1){
|
||||
fprintf(stderr, "invalid timeout '%s'\n",
|
||||
optarg);
|
||||
timeout = 0;
|
||||
}
|
||||
break;
|
||||
case 'u':
|
||||
*reg = 0;
|
||||
break;
|
||||
@@ -100,13 +110,13 @@ int main(int argc, char **argv)
|
||||
if (!parse_argv(argc, argv, &dso_name_arg, &device_arg, ®, &list))
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (device_arg){
|
||||
if (device_arg) {
|
||||
if (!(device = strdup(device_arg)))
|
||||
exit(EXIT_FAILURE);
|
||||
} else
|
||||
device = NULL;
|
||||
|
||||
if (dso_name_arg){
|
||||
if (dso_name_arg) {
|
||||
if (!(dso_name = strdup(dso_name_arg)))
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
@@ -119,19 +129,25 @@ int main(int argc, char **argv)
|
||||
multilog_init_verbose(standard, _LOG_DEBUG);
|
||||
|
||||
if (list) {
|
||||
do {
|
||||
if (!(ret= dm_get_registered_device(&dso_name,
|
||||
&device,
|
||||
&events, next))) {
|
||||
printf("%s %s 0x%x\n",
|
||||
dso_name, device, events);
|
||||
while (1) {
|
||||
if ((ret= dm_get_registered_device(&dso_name, &device,
|
||||
&events, next)))
|
||||
break;
|
||||
printf("%s %s 0x%x", dso_name, device, events);
|
||||
if (events & TIMEOUT){
|
||||
if ((ret = dm_get_event_timeout(device,
|
||||
&timeout))) {
|
||||
ret = EXIT_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
printf(" %"PRIu32"\n", timeout);
|
||||
} else
|
||||
printf("\n");
|
||||
if (device_arg)
|
||||
break;
|
||||
|
||||
if (device_arg)
|
||||
break;
|
||||
|
||||
next = 1;
|
||||
}
|
||||
} while (!ret);
|
||||
next = 1;
|
||||
}
|
||||
|
||||
ret = (ret && device_arg) ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
goto out;
|
||||
@@ -143,9 +159,16 @@ int main(int argc, char **argv)
|
||||
reg ? "": "un", device, strerror(-ret));
|
||||
ret = EXIT_FAILURE;
|
||||
} else {
|
||||
printf("%s %sregistered successfully.\n",
|
||||
device, reg ? "" : "un");
|
||||
ret = EXIT_SUCCESS;
|
||||
if (reg && (events & TIMEOUT) &&
|
||||
((ret = dm_set_event_timeout(device, timeout)))){
|
||||
fprintf(stderr, "Failed to set timeout for %s: %s\n",
|
||||
device, strerror(-ret));
|
||||
ret = EXIT_FAILURE;
|
||||
} else {
|
||||
printf("%s %sregistered successfully.\n",
|
||||
device, reg ? "" : "un");
|
||||
ret = EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
@@ -56,6 +57,7 @@
|
||||
#define UNLINK_DSO(x) UNLINK(x)
|
||||
#define UNLINK_THREAD(x) UNLINK(x)
|
||||
|
||||
#define DAEMON_NAME "dmeventd"
|
||||
|
||||
/* Global mutex for list accesses. */
|
||||
static pthread_mutex_t mutex;
|
||||
@@ -321,14 +323,9 @@ static void unlock(void)
|
||||
/* Check, if a device exists. */
|
||||
static int device_exists(char *device)
|
||||
{
|
||||
int f;
|
||||
struct stat st_buf;
|
||||
|
||||
if ((f = open(device, O_RDONLY)) == -1)
|
||||
return 0;
|
||||
|
||||
close(f);
|
||||
|
||||
return 1;
|
||||
return !stat(device, &st_buf) && S_ISBLK(st_buf.st_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -963,9 +960,10 @@ static void comm_thread(struct fifos *fifos)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Loop forever and handle client requests sequentially. */
|
||||
while (1)
|
||||
/* Exit after last unregister. */
|
||||
do {
|
||||
process_request(fifos, &msg);
|
||||
} while (!list_empty(&thread_registry));
|
||||
}
|
||||
|
||||
/* Fork into the background and detach from our parent process. */
|
||||
@@ -1020,7 +1018,7 @@ static void init_thread_signals(int hup)
|
||||
int main(void)
|
||||
{
|
||||
struct fifos fifos;
|
||||
|
||||
struct sys_log logdata = {DAEMON_NAME, LOG_DAEMON};
|
||||
/* Make sure, parent accepts HANGUP signal. */
|
||||
init_thread_signals(1);
|
||||
|
||||
@@ -1036,8 +1034,9 @@ int main(void)
|
||||
kill(getppid(), HANGUP);
|
||||
|
||||
multilog_clear_logging();
|
||||
multilog_add_type(threaded_syslog, NULL);
|
||||
multilog_init_verbose(threaded_syslog, _LOG_DEBUG);
|
||||
multilog_add_type(std_syslog, &logdata);
|
||||
multilog_init_verbose(std_syslog, _LOG_DEBUG);
|
||||
multilog_async(1);
|
||||
|
||||
init_fifos(&fifos);
|
||||
pthread_mutex_init(&mutex, NULL);
|
||||
|
||||
@@ -517,17 +517,15 @@ static int _lv_suspend_lv(struct logical_volume *lv)
|
||||
*/
|
||||
int lvs_in_vg_activated(struct volume_group *vg)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
int count = 0;
|
||||
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
if (lv->status & VISIBLE_LV)
|
||||
count += (_lv_active(lv) == 1);
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
if (lvl->lv->status & VISIBLE_LV)
|
||||
count += (_lv_active(lvl->lv) == 1);
|
||||
}
|
||||
|
||||
return count;
|
||||
@@ -535,17 +533,15 @@ int lvs_in_vg_activated(struct volume_group *vg)
|
||||
|
||||
int lvs_in_vg_opened(struct volume_group *vg)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
int count = 0;
|
||||
|
||||
if (!activation())
|
||||
return 0;
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
if (lv->status & VISIBLE_LV)
|
||||
count += (_lv_open_count(lv) > 0);
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
if (lvl->lv->status & VISIBLE_LV)
|
||||
count += (_lv_open_count(lvl->lv) > 0);
|
||||
}
|
||||
|
||||
return count;
|
||||
|
||||
@@ -732,9 +732,38 @@ int compose_log_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
uint32_t region_size)
|
||||
{
|
||||
int tw;
|
||||
char devbuf[10];
|
||||
char *name;
|
||||
struct dev_layer *dl;
|
||||
|
||||
tw = lvm_snprintf(params, paramsize, "core 1 %u %u ",
|
||||
region_size, areas);
|
||||
if (!seg->log_lv)
|
||||
tw = lvm_snprintf(params, paramsize, "core 1 %u %u ",
|
||||
region_size, areas);
|
||||
else {
|
||||
if (!(name = build_dm_name(dm->mem, seg->log_lv->vg->name,
|
||||
seg->log_lv->name, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(dl = hash_lookup(dm->layers, seg->log_lv->lvid.s))) {
|
||||
log_error("device layer %s missing from hash",
|
||||
seg->log_lv->lvid.s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dm_format_dev(devbuf, sizeof(devbuf), dl->info.major,
|
||||
dl->info.minor)) {
|
||||
log_error("Failed to format device number as dm "
|
||||
"target (%u,%u)",
|
||||
dl->info.major, dl->info.minor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME add sync parm? */
|
||||
tw = lvm_snprintf(params, paramsize, "disk 2 %s %u %u ",
|
||||
devbuf, region_size, areas);
|
||||
}
|
||||
|
||||
if (tw < 0) {
|
||||
stack;
|
||||
@@ -759,29 +788,26 @@ int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
|
||||
for (s = start_area; s < areas; s++, *pos += tw) {
|
||||
trailing_space = (areas - s - 1) ? " " : "";
|
||||
if ((seg->area[s].type == AREA_PV &&
|
||||
(!seg->area[s].u.pv.pvseg ||
|
||||
!seg->area[s].u.pv.pvseg->pv ||
|
||||
!seg->area[s].u.pv.pvseg->pv->dev)) ||
|
||||
(seg->area[s].type == AREA_LV && !seg->area[s].u.lv.lv))
|
||||
if ((seg_type(seg, s) == AREA_PV &&
|
||||
(!seg_pvseg(seg, s) ||
|
||||
!seg_pv(seg, s) ||
|
||||
!seg_dev(seg, s))) ||
|
||||
(seg_type(seg, s) == AREA_LV && !seg_lv(seg, s)))
|
||||
tw = lvm_snprintf(params + *pos, paramsize - *pos,
|
||||
"%s 0%s", dm->stripe_filler,
|
||||
trailing_space);
|
||||
else if (seg->area[s].type == AREA_PV)
|
||||
else if (seg_type(seg, s) == AREA_PV)
|
||||
tw = lvm_snprintf(params + *pos, paramsize - *pos,
|
||||
"%s %" PRIu64 "%s",
|
||||
dev_name(seg->area[s].u.pv.pvseg->
|
||||
pv->dev),
|
||||
(seg->area[s].u.pv.pvseg->pv->
|
||||
pe_start +
|
||||
(esize * seg->area[s].u.pv.pvseg->
|
||||
pe)),
|
||||
dev_name(seg_dev(seg, s)),
|
||||
(seg_pv(seg, s)->pe_start +
|
||||
(esize * seg_pe(seg, s))),
|
||||
trailing_space);
|
||||
else {
|
||||
if (!(dl = hash_lookup(dm->layers,
|
||||
seg->area[s].u.lv.lv->lvid.s))) {
|
||||
seg_lv(seg, s)->lvid.s))) {
|
||||
log_error("device layer %s missing from hash",
|
||||
seg->area[s].u.lv.lv->lvid.s);
|
||||
seg_lv(seg, s)->lvid.s);
|
||||
return 0;
|
||||
}
|
||||
if (!dm_format_dev
|
||||
@@ -794,7 +820,7 @@ int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||
}
|
||||
tw = lvm_snprintf(params + *pos, paramsize - *pos,
|
||||
"%s %" PRIu64 "%s", devbuf,
|
||||
esize * seg->area[s].u.lv.le,
|
||||
esize * seg_le(seg, s),
|
||||
trailing_space);
|
||||
}
|
||||
|
||||
@@ -842,14 +868,12 @@ static int _emit_target(struct dev_manager *dm, struct dm_task *dmt,
|
||||
static int _populate_vanilla(struct dev_manager *dm,
|
||||
struct dm_task *dmt, struct dev_layer *dl)
|
||||
{
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
struct logical_volume *lv = dl->lv;
|
||||
|
||||
dm->pvmove_mirror_count = 0u;
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
if (!_emit_target(dm, dmt, seg)) {
|
||||
log_error("Unable to build table for '%s'", lv->name);
|
||||
return 0;
|
||||
@@ -1201,7 +1225,6 @@ static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv,
|
||||
* only one layer.
|
||||
*/
|
||||
struct dev_layer *dl, *dlr;
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
uint32_t s;
|
||||
|
||||
@@ -1219,14 +1242,22 @@ static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv,
|
||||
_set_flag(dl, TOPLEVEL);
|
||||
|
||||
/* Add dependencies for any LVs that segments refer to */
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
if (seg->log_lv &&
|
||||
!str_list_add(dm->mem, &dl->pre_create,
|
||||
_build_dlid(dm->mem, seg->log_lv->lvid.s,
|
||||
NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
// FIXME Check we don't want NOPROPAGATE here
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg->area[s].type != AREA_LV)
|
||||
if (seg_type(seg, s) != AREA_LV)
|
||||
continue;
|
||||
if (!str_list_add(dm->mem, &dl->pre_create,
|
||||
_build_dlid(dm->mem,
|
||||
seg->area[s].u.lv.lv->
|
||||
seg_lv(seg, s)->
|
||||
lvid.s, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
@@ -1300,14 +1331,14 @@ static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv)
|
||||
{
|
||||
struct logical_volume *active;
|
||||
struct lv_segment *snap_seg;
|
||||
struct list *sh;
|
||||
struct lv_list *lvl;
|
||||
|
||||
/*
|
||||
* We only need to create an origin layer if one of our
|
||||
* snapshots is in the active list
|
||||
*/
|
||||
list_iterate(sh, &dm->active_list) {
|
||||
active = list_item(sh, struct lv_list)->lv;
|
||||
list_iterate_items(lvl, &dm->active_list) {
|
||||
active = lvl->lv;
|
||||
if ((snap_seg = find_cow(active)) && (snap_seg->origin == lv))
|
||||
return _expand_origin_real(dm, lv);
|
||||
}
|
||||
@@ -1411,12 +1442,12 @@ static void _clear_marks(struct dev_manager *dm, int flag)
|
||||
static int _trace_layer_marks(struct dev_manager *dm, struct dev_layer *dl,
|
||||
int flag)
|
||||
{
|
||||
struct list *sh;
|
||||
struct str_list *strl;
|
||||
const char *dlid;
|
||||
struct dev_layer *dep;
|
||||
|
||||
list_iterate(sh, &dl->pre_create) {
|
||||
dlid = list_item(sh, struct str_list)->str;
|
||||
list_iterate_items(strl, &dl->pre_create) {
|
||||
dlid = strl->str;
|
||||
|
||||
if (!(dep = hash_lookup(dm->layers, dlid))) {
|
||||
log_error("Couldn't find device layer '%s'.", dlid);
|
||||
@@ -1466,16 +1497,14 @@ static int _trace_all_marks(struct dev_manager *dm, int flag)
|
||||
*/
|
||||
static int _mark_lvs(struct dev_manager *dm, struct list *lvs, int flag)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
struct dev_layer *dl;
|
||||
|
||||
list_iterate(lvh, lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
if (lv->status & SNAPSHOT)
|
||||
list_iterate_items(lvl, lvs) {
|
||||
if (lvl->lv->status & SNAPSHOT)
|
||||
continue;
|
||||
|
||||
if (!(dl = _lookup(dm, lv->lvid.s, NULL))) {
|
||||
if (!(dl = _lookup(dm, lvl->lv->lvid.s, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1493,12 +1522,12 @@ static int _mark_lvs(struct dev_manager *dm, struct list *lvs, int flag)
|
||||
|
||||
static int _suspend_parents(struct dev_manager *dm, struct dev_layer *dl)
|
||||
{
|
||||
struct list *sh;
|
||||
struct str_list *strl;
|
||||
struct dev_layer *dep;
|
||||
const char *dlid;
|
||||
|
||||
list_iterate(sh, &dl->pre_suspend) {
|
||||
dlid = list_item(sh, struct str_list)->str;
|
||||
list_iterate_items(strl, &dl->pre_suspend) {
|
||||
dlid = strl->str;
|
||||
|
||||
if (!(dep = hash_lookup(dm->layers, dlid))) {
|
||||
log_debug("_suspend_parents couldn't find device "
|
||||
@@ -1527,12 +1556,12 @@ static int _suspend_parents(struct dev_manager *dm, struct dev_layer *dl)
|
||||
|
||||
static int _resume_with_deps(struct dev_manager *dm, struct dev_layer *dl)
|
||||
{
|
||||
struct list *sh;
|
||||
struct str_list *strl;
|
||||
struct dev_layer *dep;
|
||||
const char *dlid;
|
||||
|
||||
list_iterate(sh, &dl->pre_create) {
|
||||
dlid = list_item(sh, struct str_list)->str;
|
||||
list_iterate_items(strl, &dl->pre_create) {
|
||||
dlid = strl->str;
|
||||
|
||||
if (!(dep = hash_lookup(dm->layers, dlid))) {
|
||||
log_debug("_resume_with_deps couldn't find device "
|
||||
@@ -1565,7 +1594,7 @@ static int _resume_with_deps(struct dev_manager *dm, struct dev_layer *dl)
|
||||
*/
|
||||
static int _create_rec(struct dev_manager *dm, struct dev_layer *dl)
|
||||
{
|
||||
struct list *sh;
|
||||
struct str_list *strl;
|
||||
struct dev_layer *dep;
|
||||
const char *dlid;
|
||||
char *newname, *suffix;
|
||||
@@ -1577,8 +1606,8 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate(sh, &dl->pre_create) {
|
||||
dlid = list_item(sh, struct str_list)->str;
|
||||
list_iterate_items(strl, &dl->pre_create) {
|
||||
dlid = strl->str;
|
||||
|
||||
if (!(dep = hash_lookup(dm->layers, dlid))) {
|
||||
log_error("Couldn't find device layer '%s'.", dlid);
|
||||
@@ -1634,17 +1663,15 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl)
|
||||
|
||||
static int _build_all_layers(struct dev_manager *dm, struct volume_group *vg)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
|
||||
/*
|
||||
* Build layers for complete vg.
|
||||
*/
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
if (lv->status & SNAPSHOT)
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
if (lvl->lv->status & SNAPSHOT)
|
||||
continue;
|
||||
if (!_expand_lv(dm, lv)) {
|
||||
if (!_expand_lv(dm, lvl->lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1684,15 +1711,15 @@ static int _populate_pre_suspend_lists(struct dev_manager *dm)
|
||||
{
|
||||
struct hash_node *hn;
|
||||
struct dev_layer *dl;
|
||||
struct list *sh;
|
||||
struct str_list *strl;
|
||||
const char *dlid;
|
||||
struct dev_layer *dep;
|
||||
|
||||
hash_iterate(hn, dm->layers) {
|
||||
dl = hash_get_data(dm->layers, hn);
|
||||
|
||||
list_iterate(sh, &dl->pre_suspend) {
|
||||
dlid = list_item(sh, struct str_list)->str;
|
||||
list_iterate_items(strl, &dl->pre_suspend) {
|
||||
dlid = strl->str;
|
||||
|
||||
if (!(dep = hash_lookup(dm->layers, dlid))) {
|
||||
log_debug("_populate_pre_suspend_lists: "
|
||||
@@ -1707,8 +1734,8 @@ static int _populate_pre_suspend_lists(struct dev_manager *dm)
|
||||
}
|
||||
}
|
||||
|
||||
list_iterate(sh, &dl->pre_create) {
|
||||
dlid = list_item(sh, struct str_list)->str;
|
||||
list_iterate_items(strl, &dl->pre_create) {
|
||||
dlid = strl->str;
|
||||
|
||||
if (!(dep = hash_lookup(dm->layers, dlid))) {
|
||||
log_debug("_populate_pre_suspend_lists: "
|
||||
@@ -1733,6 +1760,7 @@ static int _populate_pre_suspend_lists(struct dev_manager *dm)
|
||||
static int _remove_old_layers(struct dev_manager *dm)
|
||||
{
|
||||
int change;
|
||||
struct dl_list *dll;
|
||||
struct list *rh, *n;
|
||||
struct dev_layer *dl;
|
||||
|
||||
@@ -1755,10 +1783,8 @@ static int _remove_old_layers(struct dev_manager *dm)
|
||||
} while (change);
|
||||
|
||||
if (!list_empty(&dm->remove_list)) {
|
||||
list_iterate(rh, &dm->remove_list) {
|
||||
dl = list_item(rh, struct dl_list)->dl;
|
||||
log_error("Couldn't deactivate device %s", dl->name);
|
||||
}
|
||||
list_iterate_items(dll, &dm->remove_list)
|
||||
log_error("Couldn't deactivate device %s", dll->dl->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1945,16 +1971,14 @@ static int _add_lv(struct pool *mem,
|
||||
static int _add_lvs(struct pool *mem,
|
||||
struct list *head, struct logical_volume *origin)
|
||||
{
|
||||
struct logical_volume *lv;
|
||||
struct lv_segment *snap_seg;
|
||||
struct list *lvh;
|
||||
struct lv_list *lvl;
|
||||
|
||||
list_iterate(lvh, &origin->vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
if (lv->status & SNAPSHOT)
|
||||
list_iterate_items(lvl, &origin->vg->lvs) {
|
||||
if (lvl->lv->status & SNAPSHOT)
|
||||
continue;
|
||||
if ((snap_seg = find_cow(lv)) && snap_seg->origin == origin)
|
||||
if (!_add_lv(mem, head, lv))
|
||||
if ((snap_seg = find_cow(lvl->lv)) && snap_seg->origin == origin)
|
||||
if (!_add_lv(mem, head, lvl->lv))
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1963,13 +1987,11 @@ static int _add_lvs(struct pool *mem,
|
||||
|
||||
static void _remove_lv(struct list *head, struct logical_volume *lv)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct lv_list *lvl;
|
||||
|
||||
list_iterate(lvh, head) {
|
||||
lvl = list_item(lvh, struct lv_list);
|
||||
list_iterate_items(lvl, head) {
|
||||
if (lvl->lv == lv) {
|
||||
list_del(lvh);
|
||||
list_del(&lvl->list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1979,13 +2001,14 @@ static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv)
|
||||
{
|
||||
struct logical_volume *active, *old_origin;
|
||||
struct lv_segment *snap_seg;
|
||||
struct list *sh, *active_head;
|
||||
struct list *active_head;
|
||||
struct lv_list *lvl;
|
||||
|
||||
active_head = &dm->active_list;
|
||||
|
||||
/* Remove any snapshots with given origin */
|
||||
list_iterate(sh, active_head) {
|
||||
active = list_item(sh, struct lv_list)->lv;
|
||||
list_iterate_items(lvl, active_head) {
|
||||
active = lvl->lv;
|
||||
if ((snap_seg = find_cow(active)) && snap_seg->origin == lv) {
|
||||
_remove_lv(active_head, active);
|
||||
}
|
||||
@@ -1999,8 +2022,8 @@ static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv)
|
||||
old_origin = snap_seg->origin;
|
||||
|
||||
/* Was this the last active snapshot with this origin? */
|
||||
list_iterate(sh, active_head) {
|
||||
active = list_item(sh, struct lv_list)->lv;
|
||||
list_iterate_items(lvl, active_head) {
|
||||
active = lvl->lv;
|
||||
if ((snap_seg = find_cow(active)) &&
|
||||
snap_seg->origin == old_origin) {
|
||||
return 1;
|
||||
@@ -2015,13 +2038,14 @@ static int _remove_suspended_lvs(struct dev_manager *dm,
|
||||
{
|
||||
struct logical_volume *suspended;
|
||||
struct lv_segment *snap_seg;
|
||||
struct list *sh, *suspend_head;
|
||||
struct list *suspend_head;
|
||||
struct lv_list *lvl;
|
||||
|
||||
suspend_head = &dm->suspend_list;
|
||||
|
||||
/* Remove from list any snapshots with given origin */
|
||||
list_iterate(sh, suspend_head) {
|
||||
suspended = list_item(sh, struct lv_list)->lv;
|
||||
list_iterate_items(lvl, suspend_head) {
|
||||
suspended = lvl->lv;
|
||||
if ((snap_seg = find_cow(suspended)) &&
|
||||
snap_seg->origin == lv) {
|
||||
_remove_lv(suspend_head, suspended);
|
||||
@@ -2036,13 +2060,13 @@ static int _remove_suspended_lvs(struct dev_manager *dm,
|
||||
static int _targets_present(struct dev_manager *dm, struct list *lvs)
|
||||
{
|
||||
struct logical_volume *lv;
|
||||
struct list *lvh, *segh;
|
||||
struct lv_list *lvl;
|
||||
struct segment_type *segtype;
|
||||
struct lv_segment *seg;
|
||||
int snapshots = 0, mirrors = 0;
|
||||
|
||||
list_iterate(lvh, lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
list_iterate_items(lvl, lvs) {
|
||||
lv = lvl->lv;
|
||||
|
||||
if (!snapshots)
|
||||
if (lv_is_cow(lv) || lv_is_origin(lv))
|
||||
@@ -2053,8 +2077,7 @@ static int _targets_present(struct dev_manager *dm, struct list *lvs)
|
||||
mirrors = 1;
|
||||
|
||||
if (lv->status & VIRTUAL) {
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
if (seg->segtype->ops->target_present &&
|
||||
!seg->segtype->ops->target_present()) {
|
||||
log_error("Can't expand LV: %s target "
|
||||
@@ -2103,16 +2126,14 @@ static int _targets_present(struct dev_manager *dm, struct list *lvs)
|
||||
static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg)
|
||||
{
|
||||
char *dlid;
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
struct dev_layer *dl;
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
if (lv->status & SNAPSHOT)
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
if (lvl->lv->status & SNAPSHOT)
|
||||
continue;
|
||||
|
||||
if (!(dlid = _build_dlid(dm->mem, lv->lvid.s, NULL))) {
|
||||
if (!(dlid = _build_dlid(dm->mem, lvl->lv->lvid.s, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -2121,16 +2142,16 @@ static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg)
|
||||
pool_free(dm->mem, dlid);
|
||||
|
||||
if (dl) {
|
||||
log_debug("Found active lv %s%s", lv->name,
|
||||
log_debug("Found active lv %s%s", lvl->lv->name,
|
||||
dl->info.suspended ? " (suspended)" : "");
|
||||
|
||||
if (!_add_lv(dm->mem, &dm->active_list, lv)) {
|
||||
if (!_add_lv(dm->mem, &dm->active_list, lvl->lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dl->info.suspended) {
|
||||
if (!_add_lv(dm->mem, &dm->suspend_list, lv)) {
|
||||
if (!_add_lv(dm->mem, &dm->suspend_list, lvl->lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
25
lib/cache/lvmcache.c
vendored
25
lib/cache/lvmcache.c
vendored
@@ -104,8 +104,9 @@ struct lvmcache_vginfo *vginfo_from_vgname(const char *vgname)
|
||||
const struct format_type *fmt_from_vgname(const char *vgname)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct lvmcache_info *info;
|
||||
struct label *label;
|
||||
struct list *ih, *devh, *tmp;
|
||||
struct list *devh, *tmp;
|
||||
struct list devs;
|
||||
struct device_list *devl;
|
||||
|
||||
@@ -115,9 +116,9 @@ const struct format_type *fmt_from_vgname(const char *vgname)
|
||||
/* This function is normally called before reading metadata so
|
||||
* we check cached labels here. Unfortunately vginfo is volatile. */
|
||||
list_init(&devs);
|
||||
list_iterate(ih, &vginfo->infos) {
|
||||
devl = malloc(sizeof(*devl));
|
||||
devl->dev = list_item(ih, struct lvmcache_info)->dev;
|
||||
list_iterate_items(info, &vginfo->infos) {
|
||||
devl = dbg_malloc(sizeof(*devl));
|
||||
devl->dev = info->dev;
|
||||
list_add(&devs, &devl->list);
|
||||
}
|
||||
|
||||
@@ -125,7 +126,7 @@ const struct format_type *fmt_from_vgname(const char *vgname)
|
||||
devl = list_item(devh, struct device_list);
|
||||
label_read(devl->dev, &label);
|
||||
list_del(&devl->list);
|
||||
free(devl);
|
||||
dbg_free(devl);
|
||||
}
|
||||
|
||||
return vginfo->fmt;
|
||||
@@ -186,7 +187,6 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
|
||||
struct label *label;
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
struct list *fmth;
|
||||
struct format_type *fmt;
|
||||
|
||||
static int _scanning_in_progress = 0;
|
||||
@@ -221,8 +221,7 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
|
||||
_has_scanned = 1;
|
||||
|
||||
/* Perform any format-specific scanning e.g. text files */
|
||||
list_iterate(fmth, &cmd->formats) {
|
||||
fmt = list_item(fmth, struct format_type);
|
||||
list_iterate_items(fmt, &cmd->formats) {
|
||||
if (fmt->ops->scan && !fmt->ops->scan(fmt))
|
||||
goto out;
|
||||
}
|
||||
@@ -431,18 +430,16 @@ int lvmcache_update_vgname(struct lvmcache_info *info, const char *vgname)
|
||||
|
||||
int lvmcache_update_vg(struct volume_group *vg)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct physical_volume *pv;
|
||||
struct pv_list *pvl;
|
||||
struct lvmcache_info *info;
|
||||
char pvid_s[ID_LEN + 1];
|
||||
int vgid_updated = 0;
|
||||
|
||||
pvid_s[sizeof(pvid_s) - 1] = '\0';
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
strncpy(pvid_s, (char *) &pv->id, sizeof(pvid_s) - 1);
|
||||
/* FIXME Could pv->dev->pvid ever be different? */
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
strncpy(pvid_s, (char *) &pvl->pv->id, sizeof(pvid_s) - 1);
|
||||
/* FIXME Could pvl->pv->dev->pvid ever be different? */
|
||||
if ((info = info_from_pvid(pvid_s))) {
|
||||
lvmcache_update_vgname(info, vg->name);
|
||||
if (!vgid_updated) {
|
||||
|
||||
@@ -622,7 +622,6 @@ static int _init_formats(struct cmd_context *cmd)
|
||||
const char *format;
|
||||
|
||||
struct format_type *fmt;
|
||||
struct list *fmth;
|
||||
|
||||
#ifdef HAVE_LIBDL
|
||||
const struct config_node *cn;
|
||||
@@ -689,8 +688,7 @@ static int _init_formats(struct cmd_context *cmd)
|
||||
format = find_config_str(cmd->cft->root, "global/format",
|
||||
DEFAULT_FORMAT);
|
||||
|
||||
list_iterate(fmth, &cmd->formats) {
|
||||
fmt = list_item(fmth, struct format_type);
|
||||
list_iterate_items(fmt, &cmd->formats) {
|
||||
if (!strcasecmp(fmt->name, format) ||
|
||||
(fmt->alias && !strcasecmp(fmt->alias, format))) {
|
||||
cmd->default_settings.fmt = fmt;
|
||||
|
||||
@@ -91,13 +91,13 @@
|
||||
#define DEFAULT_REP_HEADINGS 1
|
||||
#define DEFAULT_REP_SEPARATOR " "
|
||||
|
||||
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,copy_percent"
|
||||
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,mirror_log,copy_percent"
|
||||
#define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
|
||||
#define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free"
|
||||
#define DEFAULT_SEGS_COLS "lv_name,vg_name,lv_attr,stripes,segtype,seg_size"
|
||||
#define DEFAULT_PVSEGS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"
|
||||
|
||||
#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,origin,snap_percent,move_pv,copy_percent,lv_uuid"
|
||||
#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,origin,snap_percent,move_pv,copy_percent,mirror_log,lv_uuid"
|
||||
#define DEFAULT_VGS_COLS_VERB "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid"
|
||||
#define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,dev_size,pv_uuid"
|
||||
#define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize"
|
||||
|
||||
@@ -103,6 +103,14 @@ static inline int list_end(struct list *head, struct list *elem)
|
||||
return elem->n == head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return first element of the list or NULL if empty
|
||||
*/
|
||||
static inline struct list *list_first(struct list *head)
|
||||
{
|
||||
return (list_empty(head) ? NULL : head->n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return last element of the list or NULL if empty
|
||||
*/
|
||||
@@ -194,6 +202,25 @@ static inline struct list *list_next(struct list *head, struct list *elem)
|
||||
*/
|
||||
#define list_iterate_items(v, head) list_iterate_items_gen(v, (head), list)
|
||||
|
||||
/*
|
||||
* Walk a list backwards, setting 'v' in turn to the containing structure
|
||||
* of each item.
|
||||
* The containing structure should be the same type as 'v'.
|
||||
* The 'struct list' variable within the containing structure is 'field'.
|
||||
*/
|
||||
#define list_iterate_back_items_gen(v, head, field) \
|
||||
for (v = list_struct_base((head)->p, typeof(*v), field); \
|
||||
&v->field != (head); \
|
||||
v = list_struct_base(v->field.p, typeof(*v), field))
|
||||
|
||||
/*
|
||||
* Walk a list backwards, setting 'v' in turn to the containing structure
|
||||
* of each item.
|
||||
* The containing structure should be the same type as 'v'.
|
||||
* The list should be 'struct list list' within the containing structure.
|
||||
*/
|
||||
#define list_iterate_back_items(v, head) list_iterate_back_items_gen(v, (head), list)
|
||||
|
||||
/*
|
||||
* Return the number of elements in a list by walking it.
|
||||
*/
|
||||
|
||||
@@ -196,7 +196,7 @@ static int _compare_paths(const char *path0, const char *path1)
|
||||
static int _add_alias(struct device *dev, const char *path)
|
||||
{
|
||||
struct str_list *sl = _alloc(sizeof(*sl));
|
||||
struct list *ah;
|
||||
struct str_list *strl;
|
||||
const char *oldpath;
|
||||
int prefer_old = 1;
|
||||
|
||||
@@ -206,8 +206,8 @@ static int _add_alias(struct device *dev, const char *path)
|
||||
}
|
||||
|
||||
/* Is name already there? */
|
||||
list_iterate(ah, &dev->aliases) {
|
||||
if (!strcmp(list_item(ah, struct str_list)->str, path)) {
|
||||
list_iterate_items(strl, &dev->aliases) {
|
||||
if (!strcmp(strl->str, path)) {
|
||||
log_debug("%s: Already in device cache", path);
|
||||
return 1;
|
||||
}
|
||||
@@ -414,20 +414,16 @@ static int _insert(const char *path, int rec)
|
||||
|
||||
static void _full_scan(int dev_scan)
|
||||
{
|
||||
struct list *dh;
|
||||
struct dir_list *dl;
|
||||
|
||||
if (_cache.has_scanned && !dev_scan)
|
||||
return;
|
||||
|
||||
list_iterate(dh, &_cache.dirs) {
|
||||
struct dir_list *dl = list_item(dh, struct dir_list);
|
||||
list_iterate_items(dl, &_cache.dirs)
|
||||
_insert_dir(dl->dir);
|
||||
};
|
||||
|
||||
list_iterate(dh, &_cache.files) {
|
||||
struct dir_list *dl = list_item(dh, struct dir_list);
|
||||
list_iterate_items(dl, &_cache.files)
|
||||
_insert_file(dl->dir);
|
||||
};
|
||||
|
||||
_cache.has_scanned = 1;
|
||||
init_full_scan_done(1);
|
||||
|
||||
@@ -449,29 +449,28 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
|
||||
void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre)
|
||||
{
|
||||
switch (seg->area[s].type) {
|
||||
switch (seg_type(seg, s)) {
|
||||
case AREA_PV:
|
||||
/* FIXME Re-check the conditions for 'Missing' */
|
||||
log_print("%sPhysical volume\t%s", pre,
|
||||
seg->area[s].u.pv.pvseg->pv ?
|
||||
dev_name(seg->area[s].u.pv.pvseg->pv->dev) :
|
||||
seg_pv(seg, s) ?
|
||||
dev_name(seg_dev(seg, s)) :
|
||||
"Missing");
|
||||
|
||||
if (seg->area[s].u.pv.pvseg->pv)
|
||||
if (seg_pv(seg, s))
|
||||
log_print("%sPhysical extents\t%d to %d", pre,
|
||||
seg->area[s].u.pv.pvseg->pe,
|
||||
seg->area[s].u.pv.pvseg->pe +
|
||||
seg->area_len - 1);
|
||||
seg_pe(seg, s),
|
||||
seg_pe(seg, s) + seg->area_len - 1);
|
||||
break;
|
||||
case AREA_LV:
|
||||
log_print("%sLogical volume\t%s", pre,
|
||||
seg->area[s].u.lv.lv ?
|
||||
seg->area[s].u.lv.lv->name : "Missing");
|
||||
seg_lv(seg, s) ?
|
||||
seg_lv(seg, s)->name : "Missing");
|
||||
|
||||
if (seg->area[s].u.lv.lv)
|
||||
if (seg_lv(seg, s))
|
||||
log_print("%sLogical extents\t%d to %d", pre,
|
||||
seg->area[s].u.lv.le,
|
||||
seg->area[s].u.lv.le + seg->area_len - 1);
|
||||
seg_le(seg, s),
|
||||
seg_le(seg, s) + seg->area_len - 1);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,16 +204,14 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
|
||||
struct pfilter *pf = (struct pfilter *) f->private;
|
||||
void *l = hash_lookup(pf->devices, dev_name(dev));
|
||||
struct str_list *sl;
|
||||
struct list *ah;
|
||||
|
||||
if (!l) {
|
||||
l = pf->real->passes_filter(pf->real, dev) ?
|
||||
PF_GOOD_DEVICE : PF_BAD_DEVICE;
|
||||
|
||||
list_iterate(ah, &dev->aliases) {
|
||||
sl = list_item(ah, struct str_list);
|
||||
list_iterate_items(sl, &dev->aliases)
|
||||
hash_insert(pf->devices, sl->str, l);
|
||||
}
|
||||
|
||||
} else if (l == PF_BAD_DEVICE)
|
||||
log_debug("%s: Skipping (cached)", dev_name(dev));
|
||||
|
||||
|
||||
@@ -158,13 +158,11 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
|
||||
|
||||
static int _accept_p(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
struct list *ah;
|
||||
int m, first = 1, rejected = 0;
|
||||
struct rfilter *rf = (struct rfilter *) f->private;
|
||||
struct str_list *sl;
|
||||
|
||||
list_iterate(ah, &dev->aliases) {
|
||||
sl = list_item(ah, struct str_list);
|
||||
list_iterate_items(sl, &dev->aliases) {
|
||||
m = matcher_run(rf->engine, sl->str);
|
||||
|
||||
if (m >= 0) {
|
||||
|
||||
@@ -424,11 +424,11 @@ struct disk_list *read_disk(const struct format_type *fmt, struct device *dev,
|
||||
|
||||
static void _add_pv_to_list(struct list *head, struct disk_list *data)
|
||||
{
|
||||
struct list *pvdh;
|
||||
struct pv_disk *pvd;
|
||||
struct disk_list *diskl;
|
||||
|
||||
list_iterate(pvdh, head) {
|
||||
pvd = &list_item(pvdh, struct disk_list)->pvd;
|
||||
list_iterate_items(diskl, head) {
|
||||
pvd = &diskl->pvd;
|
||||
if (!strncmp(data->pvd.pv_uuid, pvd->pv_uuid,
|
||||
sizeof(pvd->pv_uuid))) {
|
||||
if (MAJOR(data->dev->dev) != md_major()) {
|
||||
@@ -439,7 +439,7 @@ static void _add_pv_to_list(struct list *head, struct disk_list *data)
|
||||
}
|
||||
log_very_verbose("Duplicate PV %s - using md %s",
|
||||
pvd->pv_uuid, dev_name(data->dev));
|
||||
list_del(pvdh);
|
||||
list_del(&diskl->list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -458,14 +458,14 @@ int read_pvs_in_vg(const struct format_type *fmt, const char *vg_name,
|
||||
struct dev_iter *iter;
|
||||
struct device *dev;
|
||||
struct disk_list *data = NULL;
|
||||
struct list *vgih;
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct lvmcache_info *info;
|
||||
|
||||
/* Fast path if we already saw this VG and cached the list of PVs */
|
||||
if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) &&
|
||||
vginfo->infos.n) {
|
||||
list_iterate(vgih, &vginfo->infos) {
|
||||
dev = list_item(vgih, struct lvmcache_info)->dev;
|
||||
list_iterate_items(info, &vginfo->infos) {
|
||||
dev = info->dev;
|
||||
if (dev && !(data = read_disk(fmt, dev, mem, vg_name)))
|
||||
break;
|
||||
_add_pv_to_list(head, data);
|
||||
@@ -518,18 +518,16 @@ static int _write_vgd(struct disk_list *data)
|
||||
static int _write_uuids(struct disk_list *data)
|
||||
{
|
||||
struct uuid_list *ul;
|
||||
struct list *uh;
|
||||
uint64_t pos = data->pvd.pv_uuidlist_on_disk.base;
|
||||
uint64_t end = pos + data->pvd.pv_uuidlist_on_disk.size;
|
||||
|
||||
list_iterate(uh, &data->uuids) {
|
||||
list_iterate_items(ul, &data->uuids) {
|
||||
if (pos >= end) {
|
||||
log_error("Too many uuids to fit on %s",
|
||||
dev_name(data->dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ul = list_item(uh, struct uuid_list);
|
||||
if (!dev_write(data->dev, pos, NAME_LEN, ul->uuid))
|
||||
fail;
|
||||
|
||||
@@ -552,7 +550,7 @@ static int _write_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
|
||||
|
||||
static int _write_lvs(struct disk_list *data)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct lvd_list *ll;
|
||||
uint64_t pos, offset;
|
||||
|
||||
pos = data->pvd.lv_on_disk.base;
|
||||
@@ -563,9 +561,7 @@ static int _write_lvs(struct disk_list *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate(lvh, &data->lvds) {
|
||||
struct lvd_list *ll = list_item(lvh, struct lvd_list);
|
||||
|
||||
list_iterate_items(ll, &data->lvds) {
|
||||
offset = sizeof(struct lv_disk) * ll->lvd.lv_number;
|
||||
if (offset + sizeof(struct lv_disk) > data->pvd.lv_on_disk.size) {
|
||||
log_error("lv_number %d too large", ll->lvd.lv_number);
|
||||
@@ -704,11 +700,9 @@ static int _write_all_pvd(const struct format_type *fmt, struct disk_list *data)
|
||||
*/
|
||||
int write_disks(const struct format_type *fmt, struct list *pvs)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct disk_list *dl;
|
||||
|
||||
list_iterate(pvh, pvs) {
|
||||
dl = list_item(pvh, struct disk_list);
|
||||
list_iterate_items(dl, pvs) {
|
||||
if (!(_write_all_pvd(fmt, dl)))
|
||||
fail;
|
||||
|
||||
|
||||
@@ -46,9 +46,7 @@ static int _check_vgs(struct list *pvs, int *partial)
|
||||
* This means an active VG won't be affected if disks are inserted
|
||||
* bearing an exported VG with the same name.
|
||||
*/
|
||||
list_iterate(pvh, pvs) {
|
||||
dl = list_item(pvh, struct disk_list);
|
||||
|
||||
list_iterate_items(dl, pvs) {
|
||||
if (first_time) {
|
||||
exported = dl->pvd.pv_status & VG_EXPORTED;
|
||||
first_time = 0;
|
||||
@@ -246,13 +244,10 @@ static int _flatten_vg(struct format_instance *fid, struct pool *mem,
|
||||
struct list *pvds, const char *dev_dir,
|
||||
struct dev_filter *filter)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
struct disk_list *data;
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pvl = list_item(pvh, struct pv_list);
|
||||
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (!(data = _flatten_pv(fid, mem, vg, pvl->pv, dev_dir))) {
|
||||
stack;
|
||||
return 0;
|
||||
|
||||
@@ -87,7 +87,7 @@ int import_pv(struct pool *mem, struct device *dev,
|
||||
pv->pe_size = pvd->pe_size;
|
||||
pv->pe_start = pvd->pe_start;
|
||||
pv->pe_count = pvd->pe_total;
|
||||
pv->pe_alloc_count = pvd->pe_allocated;
|
||||
pv->pe_alloc_count = 0;
|
||||
|
||||
list_init(&pv->tags);
|
||||
list_init(&pv->segments);
|
||||
@@ -382,14 +382,11 @@ static void _export_lv(struct lv_disk *lvd, struct volume_group *vg,
|
||||
int export_extents(struct disk_list *dl, uint32_t lv_num,
|
||||
struct logical_volume *lv, struct physical_volume *pv)
|
||||
{
|
||||
struct list *segh;
|
||||
struct pe_disk *ped;
|
||||
struct lv_segment *seg;
|
||||
uint32_t pe, s;
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (!(seg->segtype->flags & SEG_FORMAT1_SUPPORT)) {
|
||||
log_error("Segment type %s in LV %s: "
|
||||
@@ -397,17 +394,16 @@ int export_extents(struct disk_list *dl, uint32_t lv_num,
|
||||
seg->segtype->name, lv->name);
|
||||
return 0;
|
||||
}
|
||||
if (seg->area[s].type != AREA_PV) {
|
||||
if (seg_type(seg, s) != AREA_PV) {
|
||||
log_error("LV stripe found in LV %s: "
|
||||
"unsupported by format1", lv->name);
|
||||
return 0;
|
||||
}
|
||||
if (seg->area[s].u.pv.pvseg->pv != pv)
|
||||
if (seg_pv(seg, s) != pv)
|
||||
continue; /* not our pv */
|
||||
|
||||
for (pe = 0; pe < (seg->len / seg->area_count); pe++) {
|
||||
ped = &dl->extents[pe +
|
||||
seg->area[s].u.pv.pvseg->pe];
|
||||
ped = &dl->extents[pe + seg_pe(seg, s)];
|
||||
ped->lv_num = lv_num;
|
||||
ped->le_num = (seg->le / seg->area_count) + pe +
|
||||
s * (lv->le_count / seg->area_count);
|
||||
@@ -422,15 +418,11 @@ int import_pvs(const struct format_type *fmt, struct pool *mem,
|
||||
struct volume_group *vg,
|
||||
struct list *pvds, struct list *results, int *count)
|
||||
{
|
||||
struct list *pvdh;
|
||||
struct disk_list *dl;
|
||||
struct pv_list *pvl;
|
||||
|
||||
*count = 0;
|
||||
list_iterate(pvdh, pvds) {
|
||||
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
|
||||
list_iterate_items(dl, pvds) {
|
||||
if (!(pvl = pool_zalloc(mem, sizeof(*pvl))) ||
|
||||
!(pvl->pv = pool_alloc(mem, sizeof(*pvl->pv)))) {
|
||||
stack;
|
||||
@@ -481,12 +473,9 @@ int import_lvs(struct pool *mem, struct volume_group *vg, struct list *pvds)
|
||||
struct disk_list *dl;
|
||||
struct lvd_list *ll;
|
||||
struct lv_disk *lvd;
|
||||
struct list *pvdh, *lvdh;
|
||||
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
list_iterate(lvdh, &dl->lvds) {
|
||||
ll = list_item(lvdh, struct lvd_list);
|
||||
list_iterate_items(dl, pvds) {
|
||||
list_iterate_items(ll, &dl->lvds) {
|
||||
lvd = &ll->lvd;
|
||||
|
||||
if (!find_lv(vg, lvd->lv_name) &&
|
||||
@@ -505,7 +494,6 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||
struct physical_volume *pv, const char *dev_dir)
|
||||
{
|
||||
int r = 0;
|
||||
struct list *lvh;
|
||||
struct lv_list *ll;
|
||||
struct lvd_list *lvdl;
|
||||
size_t len;
|
||||
@@ -532,8 +520,7 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
|
||||
}
|
||||
memset(dl->extents, 0, len);
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
ll = list_item(lvh, struct lv_list);
|
||||
list_iterate_items(ll, &vg->lvs) {
|
||||
if (ll->lv->status & SNAPSHOT)
|
||||
continue;
|
||||
|
||||
@@ -585,19 +572,17 @@ int import_snapshots(struct pool *mem, struct volume_group *vg,
|
||||
struct list *pvds)
|
||||
{
|
||||
struct logical_volume *lvs[MAX_LV];
|
||||
struct list *pvdh, *lvdh;
|
||||
struct disk_list *dl;
|
||||
struct lvd_list *ll;
|
||||
struct lv_disk *lvd;
|
||||
int lvnum;
|
||||
struct logical_volume *org, *cow;
|
||||
|
||||
/* build an index of lv numbers */
|
||||
memset(lvs, 0, sizeof(lvs));
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
|
||||
list_iterate(lvdh, &dl->lvds) {
|
||||
lvd = &(list_item(lvdh, struct lvd_list)->lvd);
|
||||
list_iterate_items(dl, pvds) {
|
||||
list_iterate_items(ll, &dl->lvds) {
|
||||
lvd = &ll->lvd;
|
||||
|
||||
lvnum = lvd->lv_number;
|
||||
|
||||
@@ -619,11 +604,9 @@ int import_snapshots(struct pool *mem, struct volume_group *vg,
|
||||
/*
|
||||
* Now iterate through yet again adding the snapshots.
|
||||
*/
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
|
||||
list_iterate(lvdh, &dl->lvds) {
|
||||
lvd = &(list_item(lvdh, struct lvd_list)->lvd);
|
||||
list_iterate_items(dl, pvds) {
|
||||
list_iterate_items(ll, &dl->lvds) {
|
||||
lvd = &ll->lvd;
|
||||
|
||||
if (!(lvd->lv_access & LV_SNAPSHOT))
|
||||
continue;
|
||||
@@ -657,10 +640,8 @@ int export_uuids(struct disk_list *dl, struct volume_group *vg)
|
||||
{
|
||||
struct uuid_list *ul;
|
||||
struct pv_list *pvl;
|
||||
struct list *pvh;
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pvl = list_item(pvh, struct pv_list);
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (!(ul = pool_alloc(dl->mem, sizeof(*ul)))) {
|
||||
stack;
|
||||
return 0;
|
||||
@@ -680,14 +661,11 @@ int export_uuids(struct disk_list *dl, struct volume_group *vg)
|
||||
*/
|
||||
void export_numbers(struct list *pvds, struct volume_group *vg)
|
||||
{
|
||||
struct list *pvdh;
|
||||
struct disk_list *dl;
|
||||
int pv_num = 1;
|
||||
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
list_iterate_items(dl, pvds)
|
||||
dl->pvd.pv_number = pv_num++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -695,26 +673,20 @@ void export_numbers(struct list *pvds, struct volume_group *vg)
|
||||
*/
|
||||
void export_pv_act(struct list *pvds)
|
||||
{
|
||||
struct list *pvdh;
|
||||
struct disk_list *dl;
|
||||
int act = 0;
|
||||
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
list_iterate_items(dl, pvds)
|
||||
if (dl->pvd.pv_status & PV_ACTIVE)
|
||||
act++;
|
||||
}
|
||||
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
list_iterate_items(dl, pvds)
|
||||
dl->vgd.pv_act = act;
|
||||
}
|
||||
}
|
||||
|
||||
int export_vg_number(struct format_instance *fid, struct list *pvds,
|
||||
const char *vg_name, struct dev_filter *filter)
|
||||
{
|
||||
struct list *pvdh;
|
||||
struct disk_list *dl;
|
||||
int vg_num;
|
||||
|
||||
@@ -723,10 +695,8 @@ int export_vg_number(struct format_instance *fid, struct list *pvds,
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
list_iterate_items(dl, pvds)
|
||||
dl->vgd.vg_number = vg_num;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ static struct hash_table *_create_lv_maps(struct pool *mem,
|
||||
struct volume_group *vg)
|
||||
{
|
||||
struct hash_table *maps = hash_create(32);
|
||||
struct list *llh;
|
||||
struct lv_list *ll;
|
||||
struct lv_map *lvm;
|
||||
|
||||
@@ -58,8 +57,7 @@ static struct hash_table *_create_lv_maps(struct pool *mem,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_iterate(llh, &vg->lvs) {
|
||||
ll = list_item(llh, struct lv_list);
|
||||
list_iterate_items(ll, &vg->lvs) {
|
||||
if (ll->lv->status & SNAPSHOT)
|
||||
continue;
|
||||
|
||||
@@ -91,13 +89,12 @@ static struct hash_table *_create_lv_maps(struct pool *mem,
|
||||
static int _fill_lv_array(struct lv_map **lvs,
|
||||
struct hash_table *maps, struct disk_list *dl)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct lvd_list *ll;
|
||||
struct lv_map *lvm;
|
||||
|
||||
memset(lvs, 0, sizeof(*lvs) * MAX_LV);
|
||||
list_iterate(lvh, &dl->lvds) {
|
||||
struct lvd_list *ll = list_item(lvh, struct lvd_list);
|
||||
|
||||
list_iterate_items(ll, &dl->lvds) {
|
||||
if (!(lvm = hash_lookup(maps, strrchr(ll->lvd.lv_name, '/')
|
||||
+ 1))) {
|
||||
log_err("Physical volume (%s) contains an "
|
||||
@@ -118,15 +115,13 @@ static int _fill_lv_array(struct lv_map **lvs,
|
||||
static int _fill_maps(struct hash_table *maps, struct volume_group *vg,
|
||||
struct list *pvds)
|
||||
{
|
||||
struct list *pvdh;
|
||||
struct disk_list *dl;
|
||||
struct physical_volume *pv;
|
||||
struct lv_map *lvms[MAX_LV], *lvm;
|
||||
struct pe_disk *e;
|
||||
uint32_t i, lv_num, le;
|
||||
|
||||
list_iterate(pvdh, pvds) {
|
||||
dl = list_item(pvdh, struct disk_list);
|
||||
list_iterate_items(dl, pvds) {
|
||||
pv = find_pv(vg, dl->dev);
|
||||
e = dl->extents;
|
||||
|
||||
@@ -226,7 +221,7 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
lvm->map[le + len].pe == lvm->map[le].pe + len));
|
||||
|
||||
if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv, le,
|
||||
len, 0, 0, 1, len, 0, 0))) {
|
||||
len, 0, 0, NULL, 1, len, 0, 0, 0))) {
|
||||
log_error("Failed to allocate linear segment.");
|
||||
return 0;
|
||||
}
|
||||
@@ -300,8 +295,9 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
|
||||
if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv,
|
||||
lvm->stripes * le,
|
||||
lvm->stripes * area_len,
|
||||
0, lvm->stripe_size, lvm->stripes,
|
||||
area_len, 0, 0))) {
|
||||
0, lvm->stripe_size, NULL,
|
||||
lvm->stripes,
|
||||
area_len, 0, 0, 0))) {
|
||||
log_error("Failed to allocate striped segment.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
|
||||
const char *candidate_vg, int *result)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct list all_pvs;
|
||||
struct disk_list *dl;
|
||||
struct pool *mem = pool_create("lvm1 vg_number", 10 * 1024);
|
||||
@@ -47,8 +46,7 @@ int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
|
||||
|
||||
memset(numbers, 0, sizeof(numbers));
|
||||
|
||||
list_iterate(pvh, &all_pvs) {
|
||||
dl = list_item(pvh, struct disk_list);
|
||||
list_iterate_items(dl, &all_pvs) {
|
||||
if (!*dl->pvd.vg_name || !strcmp(dl->pvd.vg_name, candidate_vg))
|
||||
continue;
|
||||
|
||||
|
||||
@@ -57,12 +57,9 @@ static int __read_pool_disk(const struct format_type *fmt, struct device *dev,
|
||||
|
||||
static void _add_pl_to_list(struct list *head, struct pool_list *data)
|
||||
{
|
||||
struct list *pvdh;
|
||||
struct pool_list *pl;
|
||||
|
||||
list_iterate(pvdh, head) {
|
||||
pl = list_item(pvdh, struct pool_list);
|
||||
|
||||
list_iterate_items(pl, head) {
|
||||
if (id_equal(&data->pv_uuid, &pl->pv_uuid)) {
|
||||
char uuid[ID_LEN + 7];
|
||||
|
||||
@@ -76,7 +73,7 @@ static void _add_pl_to_list(struct list *head, struct pool_list *data)
|
||||
}
|
||||
log_very_verbose("Duplicate PV %s - using md %s",
|
||||
uuid, dev_name(data->dev));
|
||||
list_del(pvdh);
|
||||
list_del(&pl->list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -247,11 +244,9 @@ static int _read_vg_pds(const struct format_type *fmt, struct pool *mem,
|
||||
struct lvmcache_vginfo *vginfo, struct list *head,
|
||||
uint32_t *devcount)
|
||||
{
|
||||
|
||||
struct list *vgih = NULL;
|
||||
struct device *dev;
|
||||
struct pool_list *pl = NULL;
|
||||
struct pool *tmpmem = NULL;
|
||||
struct lvmcache_info *info;
|
||||
struct pool_list *pl;
|
||||
struct pool *tmpmem;
|
||||
|
||||
uint32_t sp_count = 0;
|
||||
uint32_t *sp_devs = NULL;
|
||||
@@ -264,16 +259,16 @@ static int _read_vg_pds(const struct format_type *fmt, struct pool *mem,
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate(vgih, &vginfo->infos) {
|
||||
dev = list_item(vgih, struct lvmcache_info)->dev;
|
||||
if (dev &&
|
||||
!(pl = read_pool_disk(fmt, dev, mem, vginfo->vgname)))
|
||||
list_iterate_items(info, &vginfo->infos) {
|
||||
if (info->dev &&
|
||||
!(pl = read_pool_disk(fmt, info->dev, mem, vginfo->vgname)))
|
||||
break;
|
||||
/*
|
||||
* We need to keep track of the total expected number
|
||||
* of devices per subpool
|
||||
*/
|
||||
if (!sp_count) {
|
||||
/* FIXME pl left uninitialised if !info->dev */
|
||||
sp_count = pl->pd.pl_subpools;
|
||||
if (!(sp_devs =
|
||||
pool_zalloc(tmpmem,
|
||||
@@ -298,9 +293,8 @@ static int _read_vg_pds(const struct format_type *fmt, struct pool *mem,
|
||||
}
|
||||
|
||||
*devcount = 0;
|
||||
for (i = 0; i < sp_count; i++) {
|
||||
for (i = 0; i < sp_count; i++)
|
||||
*devcount += sp_devs[i];
|
||||
}
|
||||
|
||||
pool_destroy(tmpmem);
|
||||
|
||||
|
||||
@@ -33,8 +33,6 @@
|
||||
static struct user_subpool *_build_usp(struct list *pls, struct pool *mem,
|
||||
int *sps)
|
||||
{
|
||||
|
||||
struct list *plhs;
|
||||
struct pool_list *pl;
|
||||
struct user_subpool *usp = NULL, *cur_sp = NULL;
|
||||
struct user_device *cur_dev = NULL;
|
||||
@@ -43,9 +41,7 @@ static struct user_subpool *_build_usp(struct list *pls, struct pool *mem,
|
||||
* FIXME: Need to do some checks here - I'm tempted to add a
|
||||
* user_pool structure and build the entire thing to check against.
|
||||
*/
|
||||
list_iterate(plhs, pls) {
|
||||
pl = list_item(plhs, struct pool_list);
|
||||
|
||||
list_iterate_items(pl, pls) {
|
||||
*sps = pl->pd.pl_subpools;
|
||||
if (!usp && (!(usp = pool_zalloc(mem, sizeof(*usp) * (*sps))))) {
|
||||
log_error("Unable to allocate %d subpool structures",
|
||||
@@ -72,13 +68,13 @@ static struct user_subpool *_build_usp(struct list *pls, struct pool *mem,
|
||||
"structures", pl->pd.pl_sp_devs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cur_dev = &cur_sp->devs[pl->pd.pl_sp_devid];
|
||||
cur_dev->sp_id = cur_sp->id;
|
||||
cur_dev->devid = pl->pd.pl_sp_id;
|
||||
cur_dev->blocks = pl->pd.pl_blocks;
|
||||
cur_dev->pv = pl->pv;
|
||||
cur_dev->initialized = 1;
|
||||
|
||||
}
|
||||
|
||||
return usp;
|
||||
|
||||
@@ -30,12 +30,9 @@
|
||||
|
||||
int import_pool_vg(struct volume_group *vg, struct pool *mem, struct list *pls)
|
||||
{
|
||||
struct list *plhs;
|
||||
struct pool_list *pl;
|
||||
|
||||
list_iterate(plhs, pls) {
|
||||
pl = list_item(plhs, struct pool_list);
|
||||
|
||||
list_iterate_items(pl, pls) {
|
||||
vg->extent_count +=
|
||||
((pl->pd.pl_blocks) / POOL_PE_SIZE);
|
||||
|
||||
@@ -61,7 +58,6 @@ int import_pool_vg(struct volume_group *vg, struct pool *mem, struct list *pls)
|
||||
int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls)
|
||||
{
|
||||
struct pool_list *pl;
|
||||
struct list *plhs;
|
||||
struct lv_list *lvl = pool_zalloc(mem, sizeof(*lvl));
|
||||
struct logical_volume *lv;
|
||||
|
||||
@@ -88,9 +84,7 @@ int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls)
|
||||
list_init(&lv->segments);
|
||||
list_init(&lv->tags);
|
||||
|
||||
list_iterate(plhs, pls) {
|
||||
pl = list_item(plhs, struct pool_list);
|
||||
|
||||
list_iterate_items(pl, pls) {
|
||||
lv->size += pl->pd.pl_blocks;
|
||||
|
||||
if (lv->name)
|
||||
@@ -134,11 +128,8 @@ int import_pool_pvs(const struct format_type *fmt, struct volume_group *vg,
|
||||
{
|
||||
struct pv_list *pvl;
|
||||
struct pool_list *pl;
|
||||
struct list *plhs;
|
||||
|
||||
list_iterate(plhs, pls) {
|
||||
pl = list_item(plhs, struct pool_list);
|
||||
|
||||
list_iterate_items(pl, pls) {
|
||||
if (!(pvl = pool_zalloc(mem, sizeof(*pvl)))) {
|
||||
log_error("Unable to allocate pv list structure");
|
||||
return 0;
|
||||
@@ -180,7 +171,7 @@ int import_pool_pv(const struct format_type *fmt, struct pool *mem,
|
||||
pv->pe_size = POOL_PE_SIZE;
|
||||
pv->pe_start = POOL_PE_START;
|
||||
pv->pe_count = pv->size / POOL_PE_SIZE;
|
||||
pv->pe_alloc_count = pv->pe_count;
|
||||
pv->pe_alloc_count = 0;
|
||||
|
||||
list_init(&pv->tags);
|
||||
list_init(&pv->segments);
|
||||
@@ -230,8 +221,8 @@ static int _add_stripe_seg(struct pool *mem,
|
||||
|
||||
if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur,
|
||||
area_len * usp->num_devs, 0,
|
||||
usp->striping, usp->num_devs, area_len,
|
||||
0, 0))) {
|
||||
usp->striping, NULL, usp->num_devs,
|
||||
area_len, 0, 0, 0))) {
|
||||
log_error("Unable to allocate striped lv_segment structure");
|
||||
return 0;
|
||||
}
|
||||
@@ -271,7 +262,8 @@ static int _add_linear_seg(struct pool *mem,
|
||||
|
||||
if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur,
|
||||
area_len, 0, usp->striping,
|
||||
1, area_len, POOL_PE_SIZE, 0))) {
|
||||
NULL, 1, area_len,
|
||||
POOL_PE_SIZE, 0, 0))) {
|
||||
log_error("Unable to allocate linear lv_segment "
|
||||
"structure");
|
||||
return 0;
|
||||
@@ -295,15 +287,12 @@ static int _add_linear_seg(struct pool *mem,
|
||||
int import_pool_segments(struct list *lvs, struct pool *mem,
|
||||
struct user_subpool *usp, int subpools)
|
||||
{
|
||||
|
||||
struct list *lvhs;
|
||||
struct lv_list *lvl;
|
||||
struct logical_volume *lv;
|
||||
uint32_t le_cur = 0;
|
||||
int i;
|
||||
|
||||
list_iterate(lvhs, lvs) {
|
||||
lvl = list_item(lvhs, struct lv_list);
|
||||
list_iterate_items(lvl, lvs) {
|
||||
lv = lvl->lv;
|
||||
|
||||
if (lv->status & SNAPSHOT)
|
||||
@@ -325,5 +314,4 @@ int import_pool_segments(struct list *lvs, struct pool *mem,
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
@@ -91,7 +91,6 @@ static int _split_vg(const char *filename, char *vgname, size_t vg_size,
|
||||
|
||||
static void _insert_file(struct list *head, struct archive_file *b)
|
||||
{
|
||||
struct list *bh;
|
||||
struct archive_file *bf = NULL;
|
||||
|
||||
if (list_empty(head)) {
|
||||
@@ -99,11 +98,9 @@ static void _insert_file(struct list *head, struct archive_file *b)
|
||||
return;
|
||||
}
|
||||
|
||||
/* index increases through list */
|
||||
list_iterate(bh, head) {
|
||||
bf = list_item(bh, struct archive_file);
|
||||
|
||||
if (bf->index > b->index) {
|
||||
/* index reduces through list */
|
||||
list_iterate_items(bf, head) {
|
||||
if (b->index > bf->index) {
|
||||
list_add(&bf->list, &b->list);
|
||||
return;
|
||||
}
|
||||
@@ -153,8 +150,8 @@ static struct list *_scan_archive(struct pool *mem,
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
/* ignore dot files */
|
||||
if (dirent[i]->d_name[0] == '.')
|
||||
if (!strcmp(dirent[i]->d_name, ".") ||
|
||||
!strcmp(dirent[i]->d_name, ".."))
|
||||
continue;
|
||||
|
||||
/* check the name is the correct format */
|
||||
@@ -200,7 +197,6 @@ static struct list *_scan_archive(struct pool *mem,
|
||||
static void _remove_expired(struct list *archives, uint32_t archives_size,
|
||||
uint32_t retain_days, uint32_t min_archive)
|
||||
{
|
||||
struct list *bh;
|
||||
struct archive_file *bf;
|
||||
struct stat sb;
|
||||
time_t retain_time;
|
||||
@@ -214,9 +210,7 @@ static void _remove_expired(struct list *archives, uint32_t archives_size,
|
||||
retain_time = time(NULL) - (time_t) retain_days *SECS_PER_DAY;
|
||||
|
||||
/* Assume list is ordered oldest first (by index) */
|
||||
list_iterate(bh, archives) {
|
||||
bf = list_item(bh, struct archive_file);
|
||||
|
||||
list_iterate_items(bf, archives) {
|
||||
/* Get the mtime of the file and unlink if too old */
|
||||
if (stat(bf->path, &sb)) {
|
||||
log_sys_error("stat", bf->path);
|
||||
@@ -280,7 +274,7 @@ int archive_vg(struct volume_group *vg,
|
||||
if (list_empty(archives))
|
||||
ix = 0;
|
||||
else {
|
||||
last = list_item(archives->p, struct archive_file);
|
||||
last = list_item(list_first(archives), struct archive_file);
|
||||
ix = last->index + 1;
|
||||
}
|
||||
|
||||
@@ -345,7 +339,7 @@ static void _display_archive(struct cmd_context *cmd, struct archive_file *af)
|
||||
|
||||
int archive_list(struct cmd_context *cmd, const char *dir, const char *vgname)
|
||||
{
|
||||
struct list *archives, *ah;
|
||||
struct list *archives;
|
||||
struct archive_file *af;
|
||||
|
||||
if (!(archives = _scan_archive(cmd->mem, vgname, dir))) {
|
||||
@@ -356,11 +350,8 @@ int archive_list(struct cmd_context *cmd, const char *dir, const char *vgname)
|
||||
if (list_empty(archives))
|
||||
log_print("No archives found in %s.", dir);
|
||||
|
||||
list_iterate(ah, archives) {
|
||||
af = list_item(ah, struct archive_file);
|
||||
|
||||
list_iterate_back_items(af, archives)
|
||||
_display_archive(cmd, af);
|
||||
}
|
||||
|
||||
pool_free(cmd->mem, archives);
|
||||
|
||||
|
||||
@@ -38,7 +38,8 @@ struct backup_params {
|
||||
int archive_init(struct cmd_context *cmd, const char *dir,
|
||||
unsigned int keep_days, unsigned int keep_min)
|
||||
{
|
||||
if (!(cmd->archive_params = pool_zalloc(cmd->mem, sizeof(*cmd->archive_params)))) {
|
||||
if (!(cmd->archive_params = pool_zalloc(cmd->libmem,
|
||||
sizeof(*cmd->archive_params)))) {
|
||||
log_error("archive_params alloc failed");
|
||||
return 0;
|
||||
}
|
||||
@@ -149,7 +150,8 @@ int archive_display(struct cmd_context *cmd, const char *vg_name)
|
||||
|
||||
int backup_init(struct cmd_context *cmd, const char *dir)
|
||||
{
|
||||
if (!(cmd->backup_params = pool_zalloc(cmd->mem, sizeof(*cmd->archive_params)))) {
|
||||
if (!(cmd->backup_params = pool_zalloc(cmd->libmem,
|
||||
sizeof(*cmd->archive_params)))) {
|
||||
log_error("archive_params alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
struct formatter;
|
||||
typedef int (*out_with_comment_fn) (struct formatter * f, const char *comment,
|
||||
const char *fmt, va_list ap);
|
||||
typedef void (*nl_fn) (struct formatter * f);
|
||||
typedef int (*nl_fn) (struct formatter * f);
|
||||
/*
|
||||
* The first half of this file deals with
|
||||
* exporting the vg, ie. writing it to a file.
|
||||
@@ -42,7 +42,7 @@ struct formatter {
|
||||
union {
|
||||
FILE *fp; /* where we're writing to */
|
||||
struct {
|
||||
char *buf;
|
||||
char *start;
|
||||
uint32_t size;
|
||||
uint32_t used;
|
||||
} buf;
|
||||
@@ -95,22 +95,34 @@ static void _dec_indent(struct formatter *f)
|
||||
/*
|
||||
* Newline function for prettier layout.
|
||||
*/
|
||||
static void _nl_file(struct formatter *f)
|
||||
static int _nl_file(struct formatter *f)
|
||||
{
|
||||
fprintf(f->data.fp, "\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _nl_raw(struct formatter *f)
|
||||
static int _nl_raw(struct formatter *f)
|
||||
{
|
||||
if (f->data.buf.used >= f->data.buf.size - 1)
|
||||
return;
|
||||
char *newbuf;
|
||||
|
||||
*f->data.buf.buf = '\n';
|
||||
f->data.buf.buf += 1;
|
||||
/* If metadata doesn't fit, double the buffer size */
|
||||
if (f->data.buf.used + 2 > f->data.buf.size) {
|
||||
if (!(newbuf = dbg_realloc(f->data.buf.start,
|
||||
f->data.buf.size * 2))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
f->data.buf.start = newbuf;
|
||||
f->data.buf.size *= 2;
|
||||
}
|
||||
|
||||
*(f->data.buf.start + f->data.buf.used) = '\n';
|
||||
f->data.buf.used += 1;
|
||||
*f->data.buf.buf = '\0';
|
||||
|
||||
return;
|
||||
*(f->data.buf.start + f->data.buf.used) = '\0';
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define COMMENT_TAB 6
|
||||
@@ -153,17 +165,27 @@ static int _out_with_comment_raw(struct formatter *f, const char *comment,
|
||||
const char *fmt, va_list ap)
|
||||
{
|
||||
int n;
|
||||
char *newbuf;
|
||||
|
||||
n = vsnprintf(f->data.buf.buf, f->data.buf.size - f->data.buf.used,
|
||||
fmt, ap);
|
||||
retry:
|
||||
n = vsnprintf(f->data.buf.start + f->data.buf.used,
|
||||
f->data.buf.size - f->data.buf.used, fmt, ap);
|
||||
|
||||
if (n < 0 || (n > f->data.buf.size - f->data.buf.used - 1))
|
||||
return 0;
|
||||
/* If metadata doesn't fit, double the buffer size */
|
||||
if (n < 0 || (n + f->data.buf.used + 2 > f->data.buf.size)) {
|
||||
if (!(newbuf = dbg_realloc(f->data.buf.start,
|
||||
f->data.buf.size * 2))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
f->data.buf.start = newbuf;
|
||||
f->data.buf.size *= 2;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
f->data.buf.buf += n;
|
||||
f->data.buf.used += n;
|
||||
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -257,10 +279,10 @@ static int _print_header(struct formatter *f,
|
||||
outf(f, "# Generated by LVM2: %s", ctime(&t));
|
||||
outf(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\"");
|
||||
outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE);
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
|
||||
outf(f, "description = \"%s\"", desc);
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
|
||||
_utsname.sysname, _utsname.nodename, _utsname.release,
|
||||
_utsname.version, _utsname.machine);
|
||||
@@ -309,7 +331,7 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
|
||||
|
||||
/* Default policy is NORMAL; INHERIT is meaningless */
|
||||
if (vg->alloc != ALLOC_NORMAL && vg->alloc != ALLOC_INHERIT) {
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
outf(f, "allocation_policy = \"%s\"",
|
||||
get_alloc_string(vg->alloc));
|
||||
}
|
||||
@@ -330,7 +352,7 @@ static inline const char *_get_pv_name(struct formatter *f,
|
||||
|
||||
static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
struct physical_volume *pv;
|
||||
char buffer[4096];
|
||||
const char *name;
|
||||
@@ -338,15 +360,15 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
||||
outf(f, "physical_volumes {");
|
||||
_inc_indent(f);
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
pv = pvl->pv;
|
||||
|
||||
if (!(name = _get_pv_name(f, pv))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
outf(f, "%s {", name);
|
||||
_inc_indent(f);
|
||||
|
||||
@@ -360,7 +382,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
|
||||
if (!print_flags(pv->status, PV_FLAGS, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
@@ -407,7 +429,7 @@ static int _print_segment(struct formatter *f, struct volume_group *vg,
|
||||
return 0;
|
||||
}
|
||||
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
outf(f, "type = \"%s\"", seg->segtype->name);
|
||||
|
||||
if (!list_empty(&seg->tags)) {
|
||||
@@ -436,28 +458,27 @@ int out_areas(struct formatter *f, const struct lv_segment *seg,
|
||||
const char *name;
|
||||
unsigned int s;
|
||||
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
|
||||
outf(f, "%ss = [", type);
|
||||
_inc_indent(f);
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
switch (seg->area[s].type) {
|
||||
switch (seg_type(seg, s)) {
|
||||
case AREA_PV:
|
||||
if (!(name = _get_pv_name(f, seg->area[s].u.pv.pvseg->
|
||||
pv))) {
|
||||
if (!(name = _get_pv_name(f, seg_pv(seg, s)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
outf(f, "\"%s\", %u%s", name,
|
||||
seg->area[s].u.pv.pvseg->pe,
|
||||
seg_pe(seg, s),
|
||||
(s == seg->area_count - 1) ? "" : ",");
|
||||
break;
|
||||
case AREA_LV:
|
||||
outf(f, "\"%s\", %u%s",
|
||||
seg->area[s].u.lv.lv->name,
|
||||
seg->area[s].u.lv.le,
|
||||
seg_lv(seg, s)->name,
|
||||
seg_le(seg, s),
|
||||
(s == seg->area_count - 1) ? "" : ",");
|
||||
}
|
||||
}
|
||||
@@ -467,24 +488,68 @@ int out_areas(struct formatter *f, const struct lv_segment *seg,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _count_segments(struct logical_volume *lv)
|
||||
static int _print_lv(struct formatter *f, struct logical_volume *lv)
|
||||
{
|
||||
int r = 0;
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
char buffer[4096];
|
||||
int seg_count;
|
||||
|
||||
list_iterate(segh, &lv->segments)
|
||||
r++;
|
||||
outnl(f);
|
||||
outf(f, "%s {", lv->name);
|
||||
_inc_indent(f);
|
||||
|
||||
return r;
|
||||
/* FIXME: Write full lvid */
|
||||
if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
outf(f, "id = \"%s\"", buffer);
|
||||
|
||||
if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
outf(f, "status = %s", buffer);
|
||||
|
||||
if (!list_empty(&lv->tags)) {
|
||||
if (!print_tags(&lv->tags, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
outf(f, "tags = %s", buffer);
|
||||
}
|
||||
|
||||
if (lv->alloc != ALLOC_INHERIT)
|
||||
outf(f, "allocation_policy = \"%s\"",
|
||||
get_alloc_string(lv->alloc));
|
||||
|
||||
if (lv->read_ahead)
|
||||
outf(f, "read_ahead = %u", lv->read_ahead);
|
||||
if (lv->major >= 0)
|
||||
outf(f, "major = %d", lv->major);
|
||||
if (lv->minor >= 0)
|
||||
outf(f, "minor = %d", lv->minor);
|
||||
outf(f, "segment_count = %u", list_size(&lv->segments));
|
||||
outnl(f);
|
||||
|
||||
seg_count = 1;
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
if (!_print_segment(f, lv->vg, seg_count++, seg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_dec_indent(f);
|
||||
outf(f, "}");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
struct lv_segment *seg;
|
||||
char buffer[4096];
|
||||
int seg_count;
|
||||
struct lv_list *lvl;
|
||||
|
||||
/*
|
||||
* Don't bother with an lv section if there are no lvs.
|
||||
@@ -495,58 +560,25 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
||||
outf(f, "logical_volumes {");
|
||||
_inc_indent(f);
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
|
||||
f->nl(f);
|
||||
outf(f, "%s {", lv->name);
|
||||
_inc_indent(f);
|
||||
|
||||
/* FIXME: Write full lvid */
|
||||
if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) {
|
||||
/*
|
||||
* Write visible LVs first
|
||||
*/
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
if (!(lvl->lv->status & VISIBLE_LV))
|
||||
continue;
|
||||
if (!_print_lv(f, lvl->lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
outf(f, "id = \"%s\"", buffer);
|
||||
|
||||
if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
if ((lvl->lv->status & VISIBLE_LV))
|
||||
continue;
|
||||
if (!_print_lv(f, lvl->lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
outf(f, "status = %s", buffer);
|
||||
|
||||
if (!list_empty(&lv->tags)) {
|
||||
if (!print_tags(&lv->tags, buffer, sizeof(buffer))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
outf(f, "tags = %s", buffer);
|
||||
}
|
||||
|
||||
if (lv->alloc != ALLOC_INHERIT)
|
||||
outf(f, "allocation_policy = \"%s\"",
|
||||
get_alloc_string(lv->alloc));
|
||||
|
||||
if (lv->read_ahead)
|
||||
outf(f, "read_ahead = %u", lv->read_ahead);
|
||||
if (lv->major >= 0)
|
||||
outf(f, "major = %d", lv->major);
|
||||
if (lv->minor >= 0)
|
||||
outf(f, "minor = %d", lv->minor);
|
||||
outf(f, "segment_count = %u", _count_segments(lv));
|
||||
f->nl(f);
|
||||
|
||||
seg_count = 1;
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
if (!_print_segment(f, vg, seg_count++, seg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
_dec_indent(f);
|
||||
outf(f, "}");
|
||||
}
|
||||
|
||||
_dec_indent(f);
|
||||
@@ -563,7 +595,7 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
||||
static int _build_pv_names(struct formatter *f, struct volume_group *vg)
|
||||
{
|
||||
int count = 0;
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
struct physical_volume *pv;
|
||||
char buffer[32], *name;
|
||||
|
||||
@@ -577,8 +609,8 @@ static int _build_pv_names(struct formatter *f, struct volume_group *vg)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
pv = pvl->pv;
|
||||
|
||||
/* FIXME But skip if there's already an LV called pv%d ! */
|
||||
if (lvm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0) {
|
||||
@@ -631,11 +663,11 @@ static int _text_vg_export(struct formatter *f,
|
||||
if (!_print_vg(f, vg))
|
||||
fail;
|
||||
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
if (!_print_pvs(f, vg))
|
||||
fail;
|
||||
|
||||
f->nl(f);
|
||||
outnl(f);
|
||||
if (!_print_lvs(f, vg))
|
||||
fail;
|
||||
|
||||
@@ -686,11 +718,10 @@ int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp)
|
||||
}
|
||||
|
||||
/* Returns amount of buffer used incl. terminating NUL */
|
||||
int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
|
||||
uint32_t size)
|
||||
int text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf)
|
||||
{
|
||||
struct formatter *f;
|
||||
int r;
|
||||
int r = 0;
|
||||
|
||||
_init();
|
||||
|
||||
@@ -700,8 +731,13 @@ int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
|
||||
}
|
||||
|
||||
memset(f, 0, sizeof(*f));
|
||||
f->data.buf.buf = buf;
|
||||
f->data.buf.size = size;
|
||||
|
||||
f->data.buf.size = 65536; /* Initial metadata limit */
|
||||
if (!(f->data.buf.start = dbg_malloc(f->data.buf.size))) {
|
||||
log_error("text_export buffer allocation failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
f->indent = 0;
|
||||
f->header = 0;
|
||||
f->out_with_comment = &_out_with_comment_raw;
|
||||
@@ -709,11 +745,12 @@ int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
|
||||
|
||||
if (!_text_vg_export(f, vg, desc)) {
|
||||
stack;
|
||||
r = 0;
|
||||
dbg_free(f->data.buf.start);
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = f->data.buf.used + 1;
|
||||
*buf = f->data.buf.start;
|
||||
|
||||
out:
|
||||
dbg_free(f);
|
||||
@@ -721,3 +758,4 @@ int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
|
||||
}
|
||||
|
||||
#undef outf
|
||||
#undef outnl
|
||||
|
||||
@@ -52,6 +52,8 @@ static struct flag _lv_flags[] = {
|
||||
{VISIBLE_LV, "VISIBLE"},
|
||||
{PVMOVE, "PVMOVE"},
|
||||
{LOCKED, "LOCKED"},
|
||||
{MIRROR_IMAGE, NULL},
|
||||
{MIRROR_LOG, NULL},
|
||||
{MIRRORED, NULL},
|
||||
{VIRTUAL, NULL},
|
||||
{SNAPSHOT, NULL},
|
||||
|
||||
@@ -341,19 +341,15 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
struct raw_locn *rlocn;
|
||||
struct mda_header *mdah;
|
||||
struct physical_volume *pv;
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
int r = 0;
|
||||
uint32_t new_wrap = 0, old_wrap = 0;
|
||||
|
||||
/* FIXME Essential fix! Make dynamic (realloc? pool?) */
|
||||
char buf[65536];
|
||||
char *buf = NULL;
|
||||
int found = 0;
|
||||
|
||||
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
if (pv->dev == mdac->area.dev) {
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (pvl->pv->dev == mdac->area.dev) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
@@ -375,7 +371,7 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, 0);
|
||||
mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah);
|
||||
|
||||
if (!(mdac->rlocn.size = text_vg_export_raw(vg, "", buf, sizeof(buf)))) {
|
||||
if (!(mdac->rlocn.size = text_vg_export_raw(vg, "", &buf))) {
|
||||
log_error("VG %s metadata writing failed", vg->name);
|
||||
goto out;
|
||||
}
|
||||
@@ -435,6 +431,8 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
if (!r && !dev_close(mdac->area.dev))
|
||||
stack;
|
||||
|
||||
if (buf)
|
||||
dbg_free(buf);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -446,15 +444,13 @@ static int _vg_commit_raw_rlocn(struct format_instance *fid,
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
struct mda_header *mdah;
|
||||
struct raw_locn *rlocn;
|
||||
struct physical_volume *pv;
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
int r = 0;
|
||||
int found = 0;
|
||||
|
||||
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
if (pv->dev == mdac->area.dev) {
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (pvl->pv->dev == mdac->area.dev) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
@@ -518,14 +514,12 @@ static int _vg_revert_raw(struct format_instance *fid, struct volume_group *vg,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
struct physical_volume *pv;
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
int found = 0;
|
||||
|
||||
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
if (pv->dev == mdac->area.dev) {
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (pvl->pv->dev == mdac->area.dev) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
@@ -784,7 +778,7 @@ static int _scan_file(const struct format_type *fmt)
|
||||
{
|
||||
struct dirent *dirent;
|
||||
struct dir_list *dl;
|
||||
struct list *dlh, *dir_list;
|
||||
struct list *dir_list;
|
||||
char *tmp;
|
||||
DIR *d;
|
||||
struct volume_group *vg;
|
||||
@@ -794,8 +788,7 @@ static int _scan_file(const struct format_type *fmt)
|
||||
|
||||
dir_list = &((struct mda_lists *) fmt->private)->dirs;
|
||||
|
||||
list_iterate(dlh, dir_list) {
|
||||
dl = list_item(dlh, struct dir_list);
|
||||
list_iterate_items(dl, dir_list) {
|
||||
if (!(d = opendir(dl->dir))) {
|
||||
log_sys_error("opendir", dl->dir);
|
||||
continue;
|
||||
@@ -883,7 +876,7 @@ int vgname_from_mda(const struct format_type *fmt, struct device_area *dev_area,
|
||||
static int _scan_raw(const struct format_type *fmt)
|
||||
{
|
||||
struct raw_list *rl;
|
||||
struct list *rlh, *raw_list;
|
||||
struct list *raw_list;
|
||||
char vgnamebuf[NAME_LEN + 2];
|
||||
struct volume_group *vg;
|
||||
struct format_instance fid;
|
||||
@@ -893,9 +886,7 @@ static int _scan_raw(const struct format_type *fmt)
|
||||
fid.fmt = fmt;
|
||||
list_init(&fid.metadata_areas);
|
||||
|
||||
list_iterate(rlh, raw_list) {
|
||||
rl = list_item(rlh, struct raw_list);
|
||||
|
||||
list_iterate_items(rl, raw_list) {
|
||||
/* FIXME We're reading mdah twice here... */
|
||||
if (vgname_from_mda(fmt, &rl->dev_area, vgnamebuf,
|
||||
sizeof(vgnamebuf))) {
|
||||
@@ -925,6 +916,7 @@ static int _mda_setup(const struct format_type *fmt,
|
||||
uint64_t start1, mda_size1; /* First area - start of disk */
|
||||
uint64_t start2, mda_size2; /* Second area - end of disk */
|
||||
uint64_t wipe_size = 8 << SECTOR_SHIFT;
|
||||
size_t pagesize = getpagesize();
|
||||
|
||||
if (!pvmetadatacopies) {
|
||||
/* Space available for PEs */
|
||||
@@ -952,10 +944,21 @@ static int _mda_setup(const struct format_type *fmt,
|
||||
/* Place mda straight after label area at start of disk */
|
||||
start1 = LABEL_SCAN_SIZE;
|
||||
|
||||
/* Unless the space available is tiny, round to PAGE_SIZE boundary */
|
||||
if ((!pe_start && !pe_end) ||
|
||||
((pe_start > start1) && (pe_start - start1 >= MDA_SIZE_MIN))) {
|
||||
mda_adjustment = start1 % pagesize;
|
||||
if (mda_adjustment) {
|
||||
start1 += (pagesize - mda_adjustment);
|
||||
pv->size -= ((pagesize - mda_adjustment) >>
|
||||
SECTOR_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure it's not going to be bigger than the disk! */
|
||||
if (mda_size1 > disk_size) {
|
||||
log_print("Warning: metadata area fills disk %s",
|
||||
dev_name(pv->dev));
|
||||
if (start1 + mda_size1 > disk_size) {
|
||||
log_print("Warning: metadata area fills disk leaving no "
|
||||
"space for data on %s.", dev_name(pv->dev));
|
||||
/* Leave some free space for rounding */
|
||||
/* Avoid empty data area as could cause tools problems */
|
||||
mda_size1 = disk_size - start1 - alignment * 2;
|
||||
@@ -1048,7 +1051,6 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
struct label *label;
|
||||
struct lvmcache_info *info;
|
||||
struct mda_context *mdac;
|
||||
struct list *mdash;
|
||||
struct metadata_area *mda;
|
||||
char buf[MDA_HEADER_SIZE];
|
||||
struct mda_header *mdah = (struct mda_header *) buf;
|
||||
@@ -1076,8 +1078,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
del_mdas(&info->mdas);
|
||||
else
|
||||
list_init(&info->mdas);
|
||||
list_iterate(mdash, mdas) {
|
||||
mda = list_item(mdash, struct metadata_area);
|
||||
list_iterate_items(mda, mdas) {
|
||||
mdac = mda->metadata_locn;
|
||||
log_debug("Creating metadata area on %s at sector %"
|
||||
PRIu64 " size %" PRIu64 " sectors",
|
||||
@@ -1100,8 +1101,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
/* Set pe_start to first aligned sector after any metadata
|
||||
* areas that begin before pe_start */
|
||||
pv->pe_start = PE_ALIGN;
|
||||
list_iterate(mdash, &info->mdas) {
|
||||
mda = list_item(mdash, struct metadata_area);
|
||||
list_iterate_items(mda, &info->mdas) {
|
||||
mdac = (struct mda_context *) mda->metadata_locn;
|
||||
if (pv->dev == mdac->area.dev &&
|
||||
(mdac->area.start < (pv->pe_start << SECTOR_SHIFT)) &&
|
||||
@@ -1125,8 +1125,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate(mdash, &info->mdas) {
|
||||
mda = list_item(mdash, struct metadata_area);
|
||||
list_iterate_items(mda, &info->mdas) {
|
||||
mdac = mda->metadata_locn;
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
mdah->size = mdac->area.size;
|
||||
@@ -1152,14 +1151,13 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
||||
static int _add_raw(struct list *raw_list, struct device_area *dev_area)
|
||||
{
|
||||
struct raw_list *rl;
|
||||
struct list *rlh;
|
||||
|
||||
/* Already present? */
|
||||
list_iterate(rlh, raw_list) {
|
||||
rl = list_item(rlh, struct raw_list);
|
||||
list_iterate_items(rl, raw_list) {
|
||||
/* FIXME Check size/overlap consistency too */
|
||||
if (rl->dev_area.dev == dev_area->dev &&
|
||||
rl->dev_area.start == dev_area->start) return 1;
|
||||
rl->dev_area.start == dev_area->start)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(rl = dbg_malloc(sizeof(struct raw_list)))) {
|
||||
@@ -1180,7 +1178,6 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
struct lvmcache_info *info;
|
||||
struct metadata_area *mda, *mda_new;
|
||||
struct mda_context *mdac, *mdac_new;
|
||||
struct list *mdah, *dah;
|
||||
struct data_area_list *da;
|
||||
|
||||
if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) {
|
||||
@@ -1227,17 +1224,15 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
list_size(&info->das), dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
list_iterate(dah, &info->das) {
|
||||
da = list_item(dah, struct data_area_list);
|
||||
|
||||
list_iterate_items(da, &info->das)
|
||||
pv->pe_start = da->disk_locn.offset >> SECTOR_SHIFT;
|
||||
}
|
||||
|
||||
if (!mdas)
|
||||
return 1;
|
||||
|
||||
/* Add copy of mdas to supplied list */
|
||||
list_iterate(mdah, &info->mdas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
list_iterate_items(mda, &info->mdas) {
|
||||
mdac = (struct mda_context *) mda->metadata_locn;
|
||||
if (!(mda_new = pool_alloc(fmt->cmd->mem, sizeof(*mda_new)))) {
|
||||
log_error("metadata_area allocation failed");
|
||||
@@ -1327,7 +1322,7 @@ static int _pv_setup(const struct format_type *fmt,
|
||||
{
|
||||
struct metadata_area *mda, *mda_new, *mda2;
|
||||
struct mda_context *mdac, *mdac_new, *mdac2;
|
||||
struct list *pvmdas, *pvmdash, *mdash;
|
||||
struct list *pvmdas;
|
||||
struct lvmcache_info *info;
|
||||
int found;
|
||||
uint64_t pe_end = 0;
|
||||
@@ -1342,8 +1337,7 @@ static int _pv_setup(const struct format_type *fmt,
|
||||
/* Iterate through all mdas on this PV */
|
||||
if ((info = info_from_pvid(pv->dev->pvid))) {
|
||||
pvmdas = &info->mdas;
|
||||
list_iterate(pvmdash, pvmdas) {
|
||||
mda = list_item(pvmdash, struct metadata_area);
|
||||
list_iterate_items(mda, pvmdas) {
|
||||
mdac =
|
||||
(struct mda_context *) mda->metadata_locn;
|
||||
|
||||
@@ -1351,10 +1345,7 @@ static int _pv_setup(const struct format_type *fmt,
|
||||
|
||||
/* Ensure it isn't already on list */
|
||||
found = 0;
|
||||
list_iterate(mdash, mdas) {
|
||||
mda2 =
|
||||
list_item(mdash,
|
||||
struct metadata_area);
|
||||
list_iterate_items(mda2, mdas) {
|
||||
if (mda2->ops !=
|
||||
&_metadata_text_raw_ops) continue;
|
||||
mdac2 =
|
||||
@@ -1416,9 +1407,10 @@ static struct format_instance *_create_text_instance(const struct format_type
|
||||
struct mda_context *mdac, *mdac_new;
|
||||
struct dir_list *dl;
|
||||
struct raw_list *rl;
|
||||
struct list *dlh, *dir_list, *rlh, *raw_list, *mdas, *mdash, *infoh;
|
||||
struct list *dir_list, *raw_list, *mdas;
|
||||
char path[PATH_MAX];
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct lvmcache_info *info;
|
||||
|
||||
if (!(fid = pool_alloc(fmt->cmd->mem, sizeof(*fid)))) {
|
||||
log_error("Couldn't allocate format instance object.");
|
||||
@@ -1440,8 +1432,7 @@ static struct format_instance *_create_text_instance(const struct format_type
|
||||
} else {
|
||||
dir_list = &((struct mda_lists *) fmt->private)->dirs;
|
||||
|
||||
list_iterate(dlh, dir_list) {
|
||||
dl = list_item(dlh, struct dir_list);
|
||||
list_iterate_items(dl, dir_list) {
|
||||
if (lvm_snprintf(path, PATH_MAX, "%s/%s",
|
||||
dl->dir, vgname) < 0) {
|
||||
log_error("Name too long %s/%s", dl->dir,
|
||||
@@ -1461,9 +1452,7 @@ static struct format_instance *_create_text_instance(const struct format_type
|
||||
|
||||
raw_list = &((struct mda_lists *) fmt->private)->raws;
|
||||
|
||||
list_iterate(rlh, raw_list) {
|
||||
rl = list_item(rlh, struct raw_list);
|
||||
|
||||
list_iterate_items(rl, raw_list) {
|
||||
/* FIXME Cache this; rescan below if some missing */
|
||||
if (!_raw_holds_vgname(fid, &rl->dev_area, vgname))
|
||||
continue;
|
||||
@@ -1491,10 +1480,9 @@ static struct format_instance *_create_text_instance(const struct format_type
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
list_iterate(infoh, &vginfo->infos) {
|
||||
mdas = &(list_item(infoh, struct lvmcache_info)->mdas);
|
||||
list_iterate(mdash, mdas) {
|
||||
mda = list_item(mdash, struct metadata_area);
|
||||
list_iterate_items(info, &vginfo->infos) {
|
||||
mdas = &info->mdas;
|
||||
list_iterate_items(mda, mdas) {
|
||||
mdac =
|
||||
(struct mda_context *) mda->metadata_locn;
|
||||
|
||||
|
||||
@@ -59,8 +59,7 @@ int print_tags(struct list *tags, char *buffer, size_t size);
|
||||
int read_tags(struct pool *mem, struct list *tags, struct config_value *cv);
|
||||
|
||||
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
|
||||
int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
|
||||
uint32_t size);
|
||||
int text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf);
|
||||
struct volume_group *text_vg_import_file(struct format_instance *fid,
|
||||
const char *file,
|
||||
time_t *when, char **desc);
|
||||
|
||||
@@ -223,12 +223,9 @@ static int _read_pv(struct format_instance *fid, struct pool *mem,
|
||||
|
||||
static void _insert_segment(struct logical_volume *lv, struct lv_segment *seg)
|
||||
{
|
||||
struct list *segh;
|
||||
struct lv_segment *comp;
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
comp = list_item(segh, struct lv_segment);
|
||||
|
||||
list_iterate_items(comp, &lv->segments) {
|
||||
if (comp->le > seg->le) {
|
||||
list_add(&comp->list, &seg->list);
|
||||
return;
|
||||
@@ -291,8 +288,8 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
|
||||
}
|
||||
|
||||
if (!(seg = alloc_lv_segment(mem, segtype, lv, start_extent,
|
||||
extent_count, 0, 0, area_count,
|
||||
extent_count, 0, 0))) {
|
||||
extent_count, 0, 0, NULL, area_count,
|
||||
extent_count, 0, 0, 0))) {
|
||||
log_error("Segment allocation failed");
|
||||
return 0;
|
||||
}
|
||||
@@ -326,7 +323,8 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
|
||||
}
|
||||
|
||||
int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
|
||||
const struct config_node *cn, struct hash_table *pv_hash)
|
||||
const struct config_node *cn, struct hash_table *pv_hash,
|
||||
uint32_t flags)
|
||||
{
|
||||
unsigned int s;
|
||||
struct config_value *cv;
|
||||
@@ -369,10 +367,10 @@ int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
|
||||
/*
|
||||
* Adjust extent counts in the pv and vg.
|
||||
*/
|
||||
pv->pe_alloc_count += seg->area_len;
|
||||
seg->lv->vg->free_count -= seg->area_len;
|
||||
} else if ((lv1 = find_lv(seg->lv->vg, cv->v.str))) {
|
||||
set_lv_segment_area_lv(seg, s, lv1, cv->next->v.i);
|
||||
set_lv_segment_area_lv(seg, s, lv1, cv->next->v.i,
|
||||
flags);
|
||||
} else {
|
||||
log_error("Couldn't find volume '%s' "
|
||||
"for segment '%s'.",
|
||||
@@ -436,7 +434,7 @@ static int _read_segments(struct pool *mem, struct volume_group *vg,
|
||||
/*
|
||||
* Check there are no gaps or overlaps in the lv.
|
||||
*/
|
||||
if (!lv_check_segments(lv)) {
|
||||
if (!check_lv_segments(lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -81,5 +81,6 @@ struct mda_context {
|
||||
#define FMTT_VERSION 1
|
||||
#define MDA_HEADER_SIZE 512
|
||||
#define LVM2_LABEL "LVM2 001"
|
||||
#define MDA_SIZE_MIN (8 * getpagesize())
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#define _LVM_TEXT_EXPORT_H
|
||||
|
||||
#define outf(args...) do {if (!out_text(args)) {stack; return 0;}} while (0)
|
||||
#define outnl(f) do {if (!f->nl(f)) {stack; return 0;}} while (0)
|
||||
|
||||
struct formatter;
|
||||
struct lv_segment;
|
||||
|
||||
@@ -20,6 +20,7 @@ struct lv_segment;
|
||||
struct config_node;
|
||||
|
||||
int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
|
||||
const struct config_node *cn, struct hash_table *pv_hash);
|
||||
const struct config_node *cn, struct hash_table *pv_hash,
|
||||
uint32_t flags);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -39,7 +39,6 @@ static int _write(struct label *label, char *buf)
|
||||
struct pv_header *pvhdr;
|
||||
struct lvmcache_info *info;
|
||||
struct disk_locn *pvh_dlocn_xl;
|
||||
struct list *mdash, *dash;
|
||||
struct metadata_area *mda;
|
||||
struct mda_context *mdac;
|
||||
struct data_area_list *da;
|
||||
@@ -57,9 +56,7 @@ static int _write(struct label *label, char *buf)
|
||||
pvh_dlocn_xl = &pvhdr->disk_areas_xl[0];
|
||||
|
||||
/* List of data areas (holding PEs) */
|
||||
list_iterate(dash, &info->das) {
|
||||
da = list_item(dash, struct data_area_list);
|
||||
|
||||
list_iterate_items(da, &info->das) {
|
||||
pvh_dlocn_xl->offset = xlate64(da->disk_locn.offset);
|
||||
pvh_dlocn_xl->size = xlate64(da->disk_locn.size);
|
||||
pvh_dlocn_xl++;
|
||||
@@ -71,8 +68,7 @@ static int _write(struct label *label, char *buf)
|
||||
pvh_dlocn_xl++;
|
||||
|
||||
/* List of metadata area header locations */
|
||||
list_iterate(mdash, &info->mdas) {
|
||||
mda = list_item(mdash, struct metadata_area);
|
||||
list_iterate_items(mda, &info->mdas) {
|
||||
mdac = (struct mda_context *) mda->metadata_locn;
|
||||
|
||||
if (mdac->area.dev != info->dev)
|
||||
@@ -198,7 +194,6 @@ static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||
struct lvmcache_info *info;
|
||||
struct disk_locn *dlocn_xl;
|
||||
uint64_t offset;
|
||||
struct list *mdah;
|
||||
struct metadata_area *mda;
|
||||
char vgnamebuf[NAME_LEN + 2];
|
||||
struct mda_context *mdac;
|
||||
@@ -235,8 +230,7 @@ static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||
dlocn_xl++;
|
||||
}
|
||||
|
||||
list_iterate(mdah, &info->mdas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
list_iterate_items(mda, &info->mdas) {
|
||||
mdac = (struct mda_context *) mda->metadata_locn;
|
||||
if (vgname_from_mda(info->fmt, &mdac->area, vgnamebuf,
|
||||
sizeof(vgnamebuf))) {
|
||||
|
||||
@@ -98,14 +98,11 @@ int label_register_handler(const char *name, struct labeller *handler)
|
||||
|
||||
struct labeller *label_get_handler(const char *name)
|
||||
{
|
||||
struct list *lih;
|
||||
struct labeller_i *li;
|
||||
|
||||
list_iterate(lih, &_labellers) {
|
||||
li = list_item(lih, struct labeller_i);
|
||||
list_iterate_items(li, &_labellers)
|
||||
if (!strcmp(li->name, name))
|
||||
return li->l;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -113,7 +110,6 @@ struct labeller *label_get_handler(const char *name)
|
||||
static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
uint64_t *label_sector)
|
||||
{
|
||||
struct list *lih;
|
||||
struct labeller_i *li;
|
||||
struct labeller *r = NULL;
|
||||
struct label_header *lh;
|
||||
@@ -166,8 +162,7 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
continue;
|
||||
}
|
||||
|
||||
list_iterate(lih, &_labellers) {
|
||||
li = list_item(lih, struct labeller_i);
|
||||
list_iterate_items(li, &_labellers) {
|
||||
if (li->l->ops->can_handle(li->l, (char *) lh, sector)) {
|
||||
log_very_verbose("%s: %s label detected",
|
||||
dev_name(dev), li->name);
|
||||
@@ -208,7 +203,6 @@ int label_remove(struct device *dev)
|
||||
int r = 1;
|
||||
uint64_t sector;
|
||||
int wipe;
|
||||
struct list *lih;
|
||||
struct labeller_i *li;
|
||||
struct label_header *lh;
|
||||
|
||||
@@ -244,8 +238,7 @@ int label_remove(struct device *dev)
|
||||
if (xlate64(lh->sector_xl) == sector)
|
||||
wipe = 1;
|
||||
} else {
|
||||
list_iterate(lih, &_labellers) {
|
||||
li = list_item(lih, struct labeller_i);
|
||||
list_iterate_items(li, &_labellers) {
|
||||
if (li->l->ops->can_handle(li->l, (char *) lh,
|
||||
sector)) {
|
||||
wipe = 1;
|
||||
|
||||
@@ -265,13 +265,10 @@ int lock_vol(struct cmd_context *cmd, const char *vol, int flags)
|
||||
/* Unlock list of LVs */
|
||||
int resume_lvs(struct cmd_context *cmd, struct list *lvs)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
|
||||
list_iterate(lvh, lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
resume_lv(cmd, lv->lvid.s);
|
||||
}
|
||||
list_iterate_items(lvl, lvs)
|
||||
resume_lv(cmd, lvl->lv->lvid.s);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -280,15 +277,14 @@ int resume_lvs(struct cmd_context *cmd, struct list *lvs)
|
||||
int suspend_lvs(struct cmd_context *cmd, struct list *lvs)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
|
||||
list_iterate(lvh, lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
if (!suspend_lv(cmd, lv->lvid.s)) {
|
||||
log_error("Failed to suspend %s", lv->name);
|
||||
list_uniterate(lvh, lvs, lvh) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
resume_lv(cmd, lv->lvid.s);
|
||||
list_iterate_items(lvl, lvs) {
|
||||
if (!suspend_lv(cmd, lvl->lv->lvid.s)) {
|
||||
log_error("Failed to suspend %s", lvl->lv->name);
|
||||
list_uniterate(lvh, lvs, &lvl->list) {
|
||||
lvl = list_item(lvh, struct lv_list);
|
||||
resume_lv(cmd, lvl->lv->lvid.s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -302,15 +298,14 @@ int suspend_lvs(struct cmd_context *cmd, struct list *lvs)
|
||||
int activate_lvs_excl(struct cmd_context *cmd, struct list *lvs)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct logical_volume *lv;
|
||||
struct lv_list *lvl;
|
||||
|
||||
list_iterate(lvh, lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
if (!activate_lv_excl(cmd, lv->lvid.s)) {
|
||||
log_error("Failed to activate %s", lv->name);
|
||||
list_uniterate(lvh, lvs, lvh) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
activate_lv(cmd, lv->lvid.s);
|
||||
list_iterate_items(lvl, lvs) {
|
||||
if (!activate_lv_excl(cmd, lvl->lv->lvid.s)) {
|
||||
log_error("Failed to activate %s", lvl->lv->name);
|
||||
list_uniterate(lvh, lvs, &lvl->list) {
|
||||
lvl = list_item(lvh, struct lv_list);
|
||||
activate_lv(cmd, lvl->lv->lvid.s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -41,4 +41,5 @@ int init_no_locking(struct locking_type *locking, struct config_tree *cf);
|
||||
int init_file_locking(struct locking_type *locking, struct config_tree *cf);
|
||||
|
||||
int init_external_locking(struct locking_type *locking, struct config_tree *cf);
|
||||
|
||||
int init_cluster_locking(struct locking_type *locking, struct config_tree *cf);
|
||||
|
||||
@@ -22,17 +22,58 @@ struct lv_segment *alloc_lv_segment(struct pool *mem,
|
||||
uint32_t le, uint32_t len,
|
||||
uint32_t status,
|
||||
uint32_t stripe_size,
|
||||
struct logical_volume *log_lv,
|
||||
uint32_t area_count,
|
||||
uint32_t area_len,
|
||||
uint32_t chunk_size,
|
||||
uint32_t region_size,
|
||||
uint32_t extents_copied);
|
||||
|
||||
struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv,
|
||||
uint32_t allocated);
|
||||
uint32_t status, uint32_t old_le_count);
|
||||
|
||||
int set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num,
|
||||
struct physical_volume *pv, uint32_t pe);
|
||||
void set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
|
||||
struct logical_volume *lv, uint32_t le);
|
||||
struct logical_volume *lv, uint32_t le,
|
||||
uint32_t flags);
|
||||
|
||||
struct alloc_handle;
|
||||
struct alloc_handle *allocate_extents(struct volume_group *vg,
|
||||
struct logical_volume *lv,
|
||||
struct segment_type *segtype,
|
||||
uint32_t stripes,
|
||||
uint32_t mirrors, uint32_t log_count,
|
||||
uint32_t extents,
|
||||
struct physical_volume *mirrored_pv,
|
||||
uint32_t mirrored_pe,
|
||||
uint32_t status,
|
||||
struct list *allocatable_pvs,
|
||||
alloc_policy_t alloc);
|
||||
|
||||
int lv_add_segment(struct alloc_handle *ah,
|
||||
uint32_t first_area, uint32_t num_areas,
|
||||
struct logical_volume *lv,
|
||||
struct segment_type *segtype,
|
||||
uint32_t stripe_size,
|
||||
struct physical_volume *mirrored_pv,
|
||||
uint32_t mirrored_pe,
|
||||
uint32_t status,
|
||||
uint32_t region_size,
|
||||
struct logical_volume *log_lv);
|
||||
|
||||
int lv_add_log_segment(struct alloc_handle *ah, struct logical_volume *log_lv);
|
||||
int lv_add_virtual_segment(struct logical_volume *lv, uint32_t status,
|
||||
uint32_t extents, struct segment_type *segtype);
|
||||
int lv_add_mirror_segment(struct alloc_handle *ah,
|
||||
struct logical_volume *lv,
|
||||
struct logical_volume **sub_lvs,
|
||||
uint32_t mirrors,
|
||||
struct segment_type *segtype,
|
||||
uint32_t status,
|
||||
uint32_t region_size,
|
||||
struct logical_volume *log_lv);
|
||||
|
||||
void alloc_destroy(struct alloc_handle *ah);
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -58,11 +58,13 @@ int lv_merge_segments(struct logical_volume *lv)
|
||||
/*
|
||||
* Verify that an LV's segments are consecutive, complete and don't overlap.
|
||||
*/
|
||||
int lv_check_segments(struct logical_volume *lv)
|
||||
int check_lv_segments(struct logical_volume *lv)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
uint32_t le = 0;
|
||||
unsigned seg_count = 0;
|
||||
int r = 1;
|
||||
uint32_t area_multiplier, s;
|
||||
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
seg_count++;
|
||||
@@ -70,13 +72,58 @@ int lv_check_segments(struct logical_volume *lv)
|
||||
log_error("LV %s invalid: segment %u should begin at "
|
||||
"LE %" PRIu32 " (found %" PRIu32 ").",
|
||||
lv->name, seg_count, le, seg->le);
|
||||
return 0;
|
||||
r = 0;
|
||||
}
|
||||
|
||||
area_multiplier = segtype_is_striped(seg->segtype) ?
|
||||
seg->area_count : 1;
|
||||
|
||||
if (seg->area_len * area_multiplier != seg->len) {
|
||||
log_error("LV %s: segment %u has inconsistent "
|
||||
"area_len %u",
|
||||
lv->name, seg_count, seg->area_len);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg_type(seg, s) == AREA_PV) {
|
||||
if (!seg_pvseg(seg, s) ||
|
||||
seg_pvseg(seg, s)->lvseg != seg ||
|
||||
seg_pvseg(seg, s)->lv_area != s) {
|
||||
log_error("LV %s: segment %u has "
|
||||
"inconsistent PV area %u",
|
||||
lv->name, seg_count, s);
|
||||
r = 0;
|
||||
}
|
||||
} else {
|
||||
if (!seg_lv(seg, s) ||
|
||||
seg_lv(seg, s)->vg != lv->vg ||
|
||||
seg_lv(seg, s) == lv) {
|
||||
log_error("LV %s: segment %u has "
|
||||
"inconsistent LV area %u",
|
||||
lv->name, seg_count, s);
|
||||
r = 0;
|
||||
}
|
||||
if (seg_le(seg, s) != le) {
|
||||
log_error("LV %s: segment %u has "
|
||||
"inconsistent LV area %u "
|
||||
"size",
|
||||
lv->name, seg_count, s);
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
le += seg->len;
|
||||
}
|
||||
|
||||
return 1;
|
||||
if (le != lv->le_count) {
|
||||
log_error("LV %s: inconsistent LE count %u != %u",
|
||||
lv->name, le, lv->le_count);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -101,8 +148,9 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
|
||||
if (!(split_seg = alloc_lv_segment(lv->vg->cmd->mem, seg->segtype,
|
||||
seg->lv, seg->le, seg->len,
|
||||
seg->status, seg->stripe_size,
|
||||
seg->log_lv,
|
||||
seg->area_count, seg->area_len,
|
||||
seg->chunk_size,
|
||||
seg->chunk_size, seg->region_size,
|
||||
seg->extents_copied))) {
|
||||
log_error("Couldn't allocate cloned LV segment.");
|
||||
return 0;
|
||||
@@ -128,24 +176,24 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
|
||||
|
||||
/* Adjust the PV mapping */
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
split_seg->area[s].type = seg->area[s].type;
|
||||
seg_type(split_seg, s) = seg_type(seg, s);
|
||||
|
||||
/* Split area at the offset */
|
||||
switch (seg->area[s].type) {
|
||||
switch (seg_type(seg, s)) {
|
||||
case AREA_LV:
|
||||
split_seg->area[s].u.lv.lv = seg->area[s].u.lv.lv;
|
||||
split_seg->area[s].u.lv.le =
|
||||
seg->area[s].u.lv.le + seg->area_len;
|
||||
seg_lv(split_seg, s) = seg_lv(seg, s);
|
||||
seg_le(split_seg, s) =
|
||||
seg_le(seg, s) + seg->area_len;
|
||||
log_debug("Split %s:%u[%u] at %u: %s LE %u", lv->name,
|
||||
seg->le, s, le, seg->area[s].u.lv.lv->name,
|
||||
split_seg->area[s].u.lv.le);
|
||||
seg->le, s, le, seg_lv(seg, s)->name,
|
||||
seg_le(split_seg, s));
|
||||
break;
|
||||
|
||||
case AREA_PV:
|
||||
if (!assign_peg_to_lvseg(seg->area[s].u.pv.pvseg->pv,
|
||||
seg->area[s].u.pv.pvseg->pe +
|
||||
if (!assign_peg_to_lvseg(seg_pv(seg, s),
|
||||
seg_pe(seg, s) +
|
||||
seg->area_len,
|
||||
seg->area[s].u.pv.pvseg->len -
|
||||
seg_pvseg(seg, s)->len -
|
||||
seg->area_len,
|
||||
split_seg, s)) {
|
||||
stack;
|
||||
@@ -153,13 +201,13 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
|
||||
}
|
||||
log_debug("Split %s:%u[%u] at %u: %s PE %u", lv->name,
|
||||
seg->le, s, le,
|
||||
dev_name(seg->area[s].u.pv.pvseg->pv->dev),
|
||||
split_seg->area[s].u.pv.pvseg->pe);
|
||||
dev_name(seg_dev(seg, s)),
|
||||
seg_pe(split_seg, s));
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("Unrecognised segment type %u",
|
||||
seg->area[s].type);
|
||||
seg_type(seg, s));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,6 @@ int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
|
||||
const char *id, struct physical_volume *pv)
|
||||
{
|
||||
struct volume_group *vg;
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
int consistent = 0;
|
||||
|
||||
@@ -153,8 +152,7 @@ int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
|
||||
log_error("Warning: Volume group %s is not consistent",
|
||||
vg_name);
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pvl = list_item(pvh, struct pv_list);
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (id_equal(&pvl->pv->id, (const struct id *) id)) {
|
||||
if (!_copy_pv(pv, pvl->pv)) {
|
||||
stack;
|
||||
@@ -171,19 +169,17 @@ int vg_rename(struct cmd_context *cmd, struct volume_group *vg,
|
||||
const char *new_name)
|
||||
{
|
||||
struct pool *mem = cmd->mem;
|
||||
struct physical_volume *pv;
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
|
||||
if (!(vg->name = pool_strdup(mem, new_name))) {
|
||||
log_error("vg->name allocation failed for '%s'", new_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
if (!(pv->vg_name = pool_strdup(mem, new_name))) {
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (!(pvl->pv->vg_name = pool_strdup(mem, new_name))) {
|
||||
log_error("pv->vg_name allocation failed for '%s'",
|
||||
dev_name(pv->dev));
|
||||
dev_name(pvl->pv->dev));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -441,10 +437,10 @@ int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
|
||||
|
||||
/* foreach area */
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
switch (seg->area[s].type) {
|
||||
switch (seg_type(seg, s)) {
|
||||
case AREA_PV:
|
||||
if (!_recalc_extents
|
||||
(&seg->area[s].u.pv.pvseg->pe,
|
||||
(&seg_pe(seg, s),
|
||||
lv->name,
|
||||
" pvseg start", old_size,
|
||||
new_size)) {
|
||||
@@ -452,7 +448,7 @@ int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
|
||||
return 0;
|
||||
}
|
||||
if (!_recalc_extents
|
||||
(&seg->area[s].u.pv.pvseg->len,
|
||||
(&seg_pvseg(seg, s)->len,
|
||||
lv->name,
|
||||
" pvseg length", old_size,
|
||||
new_size)) {
|
||||
@@ -462,7 +458,7 @@ int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
|
||||
break;
|
||||
case AREA_LV:
|
||||
if (!_recalc_extents
|
||||
(&seg->area[s].u.lv.le, lv->name,
|
||||
(&seg_le(seg, s), lv->name,
|
||||
" area start", old_size,
|
||||
new_size)) {
|
||||
stack;
|
||||
@@ -471,7 +467,7 @@ int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
|
||||
break;
|
||||
default:
|
||||
log_error("Unrecognised segment type "
|
||||
"%u", seg->area[s].type);
|
||||
"%u", seg_type(seg, s));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -563,26 +559,22 @@ struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
|
||||
struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pvl = list_item(pvh, struct pv_list);
|
||||
list_iterate_items(pvl, &vg->pvs)
|
||||
if (pvl->pv->dev == dev_cache_get(pv_name, vg->cmd->filter))
|
||||
return pvl;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
if (pv == list_item(pvh, struct pv_list)->pv)
|
||||
list_iterate_items(pvl, &vg->pvs)
|
||||
if (pv == pvl->pv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -590,21 +582,17 @@ int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv)
|
||||
struct physical_volume *find_pv_in_vg_by_uuid(struct volume_group *vg,
|
||||
struct id *id)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct pv_list *pvl;
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pvl = list_item(pvh, struct pv_list);
|
||||
list_iterate_items(pvl, &vg->pvs)
|
||||
if (id_equal(&pvl->pv->id, id))
|
||||
return pvl->pv;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct lv_list *lvl;
|
||||
const char *ptr;
|
||||
|
||||
@@ -614,11 +602,9 @@ struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name)
|
||||
else
|
||||
ptr = lv_name;
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lvl = list_item(lvh, struct lv_list);
|
||||
list_iterate_items(lvl, &vg->lvs)
|
||||
if (!strcmp(lvl->lv->name, ptr))
|
||||
return lvl;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -626,14 +612,11 @@ struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name)
|
||||
struct lv_list *find_lv_in_vg_by_lvid(struct volume_group *vg,
|
||||
const union lvid *lvid)
|
||||
{
|
||||
struct list *lvh;
|
||||
struct lv_list *lvl;
|
||||
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lvl = list_item(lvh, struct lv_list);
|
||||
list_iterate_items(lvl, &vg->lvs)
|
||||
if (!strncmp(lvl->lv->lvid.s, lvid->s, sizeof(*lvid)))
|
||||
return lvl;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -646,15 +629,12 @@ struct logical_volume *find_lv(struct volume_group *vg, const char *lv_name)
|
||||
|
||||
struct physical_volume *find_pv(struct volume_group *vg, struct device *dev)
|
||||
{
|
||||
struct list *pvh;
|
||||
struct physical_volume *pv;
|
||||
struct pv_list *pvl;
|
||||
|
||||
list_iterate(pvh, &vg->pvs) {
|
||||
pv = list_item(pvh, struct pv_list)->pv;
|
||||
list_iterate_items(pvl, &vg->pvs)
|
||||
if (dev == pvl->pv->dev)
|
||||
return pvl->pv;
|
||||
|
||||
if (dev == pv->dev)
|
||||
return pv;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -679,14 +659,11 @@ struct physical_volume *find_pv_by_name(struct cmd_context *cmd,
|
||||
/* Find segment at a given logical extent in an LV */
|
||||
struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le)
|
||||
{
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv->segments)
|
||||
if (le >= seg->le && le < seg->le + seg->len)
|
||||
return seg;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -696,23 +673,20 @@ struct pv_segment *find_peg_by_pe(struct physical_volume *pv, uint32_t pe)
|
||||
{
|
||||
struct pv_segment *peg;
|
||||
|
||||
list_iterate_items(peg, &pv->segments) {
|
||||
list_iterate_items(peg, &pv->segments)
|
||||
if (pe >= peg->pe && pe < peg->pe + peg->len)
|
||||
return peg;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int vg_remove(struct volume_group *vg)
|
||||
{
|
||||
struct list *mdah;
|
||||
struct metadata_area *mda;
|
||||
|
||||
/* FIXME Improve recovery situation? */
|
||||
/* Remove each copy of the metadata */
|
||||
list_iterate(mdah, &vg->fid->metadata_areas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
list_iterate_items(mda, &vg->fid->metadata_areas) {
|
||||
if (mda->ops->vg_remove &&
|
||||
!mda->ops->vg_remove(vg->fid, vg, mda)) {
|
||||
stack;
|
||||
@@ -729,8 +703,9 @@ int vg_remove(struct volume_group *vg)
|
||||
*/
|
||||
int vg_write(struct volume_group *vg)
|
||||
{
|
||||
struct list *mdah, *mdah2;
|
||||
struct list *mdah;
|
||||
struct metadata_area *mda;
|
||||
struct lv_list *lvl;
|
||||
|
||||
if (!check_pv_segments(vg)) {
|
||||
log_error("Internal error: PV segments corrupted in %s.",
|
||||
@@ -738,6 +713,14 @@ int vg_write(struct volume_group *vg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
if (!check_lv_segments(lvl->lv)) {
|
||||
log_error("Internal error: LV segments corrupted in %s.",
|
||||
lvl->lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (vg->status & PARTIAL_VG) {
|
||||
log_error("Cannot change metadata for partial volume group %s",
|
||||
vg->name);
|
||||
@@ -752,14 +735,13 @@ int vg_write(struct volume_group *vg)
|
||||
vg->seqno++;
|
||||
|
||||
/* Write to each copy of the metadata area */
|
||||
list_iterate(mdah, &vg->fid->metadata_areas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
list_iterate_items(mda, &vg->fid->metadata_areas) {
|
||||
if (!mda->ops->vg_write) {
|
||||
log_error("Format does not support writing volume"
|
||||
"group metadata areas");
|
||||
/* Revert */
|
||||
list_uniterate(mdah2, &vg->fid->metadata_areas, mdah) {
|
||||
mda = list_item(mdah2, struct metadata_area);
|
||||
list_uniterate(mdah, &vg->fid->metadata_areas, &mda->list) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
|
||||
if (mda->ops->vg_revert &&
|
||||
!mda->ops->vg_revert(vg->fid, vg, mda)) {
|
||||
@@ -771,8 +753,9 @@ int vg_write(struct volume_group *vg)
|
||||
if (!mda->ops->vg_write(vg->fid, vg, mda)) {
|
||||
stack;
|
||||
/* Revert */
|
||||
list_uniterate(mdah2, &vg->fid->metadata_areas, mdah) {
|
||||
mda = list_item(mdah2, struct metadata_area);
|
||||
list_uniterate(mdah, &vg->fid->metadata_areas, &mda->list) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
|
||||
if (mda->ops->vg_revert &&
|
||||
!mda->ops->vg_revert(vg->fid, vg, mda)) {
|
||||
stack;
|
||||
@@ -783,14 +766,12 @@ int vg_write(struct volume_group *vg)
|
||||
}
|
||||
|
||||
/* Now pre-commit each copy of the new metadata */
|
||||
list_iterate(mdah, &vg->fid->metadata_areas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
list_iterate_items(mda, &vg->fid->metadata_areas) {
|
||||
if (mda->ops->vg_precommit &&
|
||||
!mda->ops->vg_precommit(vg->fid, vg, mda)) {
|
||||
stack;
|
||||
/* Revert */
|
||||
list_iterate(mdah2, &vg->fid->metadata_areas) {
|
||||
mda = list_item(mdah2, struct metadata_area);
|
||||
list_iterate_items(mda, &vg->fid->metadata_areas) {
|
||||
if (mda->ops->vg_revert &&
|
||||
!mda->ops->vg_revert(vg->fid, vg, mda)) {
|
||||
stack;
|
||||
@@ -806,14 +787,12 @@ int vg_write(struct volume_group *vg)
|
||||
/* Commit pending changes */
|
||||
int vg_commit(struct volume_group *vg)
|
||||
{
|
||||
struct list *mdah;
|
||||
struct metadata_area *mda;
|
||||
int cache_updated = 0;
|
||||
int failed = 0;
|
||||
|
||||
/* Commit to each copy of the metadata area */
|
||||
list_iterate(mdah, &vg->fid->metadata_areas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
list_iterate_items(mda, &vg->fid->metadata_areas) {
|
||||
failed = 0;
|
||||
if (mda->ops->vg_commit &&
|
||||
!mda->ops->vg_commit(vg->fid, vg, mda)) {
|
||||
@@ -825,7 +804,6 @@ int vg_commit(struct volume_group *vg)
|
||||
lvmcache_update_vg(vg);
|
||||
cache_updated = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* If at least one mda commit succeeded, it was committed */
|
||||
@@ -835,11 +813,9 @@ int vg_commit(struct volume_group *vg)
|
||||
/* Don't commit any pending changes */
|
||||
int vg_revert(struct volume_group *vg)
|
||||
{
|
||||
struct list *mdah;
|
||||
struct metadata_area *mda;
|
||||
|
||||
list_iterate(mdah, &vg->fid->metadata_areas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
list_iterate_items(mda, &vg->fid->metadata_areas) {
|
||||
if (mda->ops->vg_revert &&
|
||||
!mda->ops->vg_revert(vg->fid, vg, mda)) {
|
||||
stack;
|
||||
@@ -853,8 +829,7 @@ int vg_revert(struct volume_group *vg)
|
||||
static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct list *ih;
|
||||
struct device *dev;
|
||||
struct lvmcache_info *info;
|
||||
struct pv_list *pvl;
|
||||
struct volume_group *vg;
|
||||
struct physical_volume *pv;
|
||||
@@ -877,9 +852,8 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_iterate(ih, &vginfo->infos) {
|
||||
dev = list_item(ih, struct lvmcache_info)->dev;
|
||||
if (!(pv = pv_read(cmd, dev_name(dev), NULL, NULL, 1))) {
|
||||
list_iterate_items(info, &vginfo->infos) {
|
||||
if (!(pv = pv_read(cmd, dev_name(info->dev), NULL, NULL, 1))) {
|
||||
continue;
|
||||
}
|
||||
if (!(pvl = pool_zalloc(cmd->mem, sizeof(*pvl)))) {
|
||||
@@ -908,7 +882,6 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
struct format_instance *fid;
|
||||
const struct format_type *fmt;
|
||||
struct volume_group *vg, *correct_vg = NULL;
|
||||
struct list *mdah;
|
||||
struct metadata_area *mda;
|
||||
int inconsistent = 0;
|
||||
|
||||
@@ -952,8 +925,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
/* Ensure contents of all metadata areas match - else do recovery */
|
||||
list_iterate(mdah, &fid->metadata_areas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
list_iterate_items(mda, &fid->metadata_areas) {
|
||||
if ((precommitted &&
|
||||
!(vg = mda->ops->vg_read_precommit(fid, vgname, mda))) ||
|
||||
(!precommitted &&
|
||||
@@ -996,8 +968,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
/* Ensure contents of all metadata areas match - else recover */
|
||||
list_iterate(mdah, &fid->metadata_areas) {
|
||||
mda = list_item(mdah, struct metadata_area);
|
||||
list_iterate_items(mda, &fid->metadata_areas) {
|
||||
if ((precommitted &&
|
||||
!(vg = mda->ops->vg_read_precommit(fid, vgname,
|
||||
mda))) ||
|
||||
@@ -1091,9 +1062,10 @@ struct volume_group *vg_read_precommitted(struct cmd_context *cmd,
|
||||
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid)
|
||||
{
|
||||
const char *vgname;
|
||||
struct list *vgnames, *slh;
|
||||
struct list *vgnames;
|
||||
struct volume_group *vg;
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct str_list *strl;
|
||||
int consistent = 0;
|
||||
|
||||
/* Is corresponding vgname already cached? */
|
||||
@@ -1124,8 +1096,8 @@ struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_iterate(slh, vgnames) {
|
||||
vgname = list_item(slh, struct str_list)->str;
|
||||
list_iterate_items(strl, vgnames) {
|
||||
vgname = strl->str;
|
||||
if (!vgname || !*vgname)
|
||||
continue; // FIXME Unnecessary?
|
||||
consistent = 0;
|
||||
@@ -1231,10 +1203,11 @@ struct list *get_vgs(struct cmd_context *cmd, int full_scan)
|
||||
|
||||
struct list *get_pvs(struct cmd_context *cmd)
|
||||
{
|
||||
struct str_list *strl;
|
||||
struct list *results;
|
||||
const char *vgname;
|
||||
struct list *pvh, *tmp;
|
||||
struct list *vgnames, *slh;
|
||||
struct list *vgnames;
|
||||
struct volume_group *vg;
|
||||
int consistent = 0;
|
||||
int old_partial;
|
||||
@@ -1261,8 +1234,8 @@ struct list *get_pvs(struct cmd_context *cmd)
|
||||
old_pvmove = pvmove_mode();
|
||||
init_partial(1);
|
||||
init_pvmove(1);
|
||||
list_iterate(slh, vgnames) {
|
||||
vgname = list_item(slh, struct str_list)->str;
|
||||
list_iterate_items(strl, vgnames) {
|
||||
vgname = strl->str;
|
||||
if (!vgname)
|
||||
continue; /* FIXME Unnecessary? */
|
||||
consistent = 0;
|
||||
|
||||
@@ -55,6 +55,8 @@
|
||||
#define LOCKED 0x00004000 /* LV */
|
||||
#define MIRRORED 0x00008000 /* LV - internal use only */
|
||||
#define VIRTUAL 0x00010000 /* LV - internal use only */
|
||||
#define MIRROR_LOG 0x00020000 /* LV */
|
||||
#define MIRROR_IMAGE 0x00040000 /* LV */
|
||||
|
||||
#define LVM_READ 0x00000100 /* LV VG */
|
||||
#define LVM_WRITE 0x00000200 /* LV VG */
|
||||
@@ -228,8 +230,10 @@ struct lv_segment {
|
||||
struct logical_volume *origin;
|
||||
struct logical_volume *cow;
|
||||
struct list origin_list;
|
||||
uint32_t chunk_size; /* In sectors */
|
||||
uint32_t chunk_size; /* For snapshots - in sectors */
|
||||
uint32_t region_size; /* For mirrors - in sectors */
|
||||
uint32_t extents_copied;
|
||||
struct logical_volume *log_lv;
|
||||
|
||||
struct list tags;
|
||||
|
||||
@@ -248,6 +252,14 @@ struct lv_segment {
|
||||
} area[0];
|
||||
};
|
||||
|
||||
#define seg_type(seg, s) (seg)->area[(s)].type
|
||||
#define seg_pvseg(seg, s) (seg)->area[(s)].u.pv.pvseg
|
||||
#define seg_pv(seg, s) (seg)->area[(s)].u.pv.pvseg->pv
|
||||
#define seg_dev(seg, s) (seg)->area[(s)].u.pv.pvseg->pv->dev
|
||||
#define seg_pe(seg, s) (seg)->area[(s)].u.pv.pvseg->pe
|
||||
#define seg_lv(seg, s) (seg)->area[(s)].u.lv.lv
|
||||
#define seg_le(seg, s) (seg)->area[(s)].u.lv.le
|
||||
|
||||
struct logical_volume {
|
||||
union lvid lvid;
|
||||
char *name;
|
||||
@@ -425,7 +437,6 @@ int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
|
||||
/* Manipulate LVs */
|
||||
struct logical_volume *lv_create_empty(struct format_instance *fi,
|
||||
const char *name,
|
||||
const char *name_format,
|
||||
union lvid *lvid,
|
||||
uint32_t status,
|
||||
alloc_policy_t alloc,
|
||||
@@ -492,7 +503,7 @@ const char *strip_dir(const char *vg_name, const char *dir);
|
||||
/*
|
||||
* Checks that an lv has no gaps or overlapping segments.
|
||||
*/
|
||||
int lv_check_segments(struct logical_volume *lv);
|
||||
int check_lv_segments(struct logical_volume *lv);
|
||||
|
||||
/*
|
||||
* Sometimes (eg, after an lvextend), it is possible to merge two
|
||||
@@ -523,9 +534,19 @@ int vg_add_snapshot(struct format_instance *fid, const char *name,
|
||||
|
||||
int vg_remove_snapshot(struct logical_volume *cow);
|
||||
|
||||
|
||||
/*
|
||||
* Mirroring functions
|
||||
*/
|
||||
struct alloc_handle;
|
||||
int create_mirror_layers(struct alloc_handle *ah,
|
||||
uint32_t first_area,
|
||||
uint32_t num_mirrors,
|
||||
struct logical_volume *lv,
|
||||
struct segment_type *segtype,
|
||||
uint32_t status,
|
||||
uint32_t region_size,
|
||||
struct logical_volume *log_lv);
|
||||
int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
struct logical_volume *lv_mirr,
|
||||
struct list *source_pvl,
|
||||
@@ -548,6 +569,8 @@ struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct logical_volume *lv);
|
||||
|
||||
uint32_t find_free_lvnum(struct logical_volume *lv);
|
||||
char *generate_lv_name(struct volume_group *vg, const char *format,
|
||||
char *buffer, size_t len);
|
||||
|
||||
static inline int validate_name(const char *n)
|
||||
{
|
||||
@@ -561,6 +584,9 @@ static inline int validate_name(const char *n)
|
||||
if (*n == '-')
|
||||
return 0;
|
||||
|
||||
if (!strcmp(n, ".") || !strcmp(n, ".."))
|
||||
return 0;
|
||||
|
||||
while ((len++, c = *n++))
|
||||
if (!isalnum(c) && c != '.' && c != '_' && c != '-' && c != '+')
|
||||
return 0;
|
||||
|
||||
@@ -20,6 +20,141 @@
|
||||
#include "display.h"
|
||||
#include "activate.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
/*
|
||||
* Reduce mirrored_seg to num_mirrors images.
|
||||
*/
|
||||
int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors)
|
||||
{
|
||||
uint32_t m;
|
||||
|
||||
for (m = num_mirrors; m < mirrored_seg->area_count; m++) {
|
||||
if (!lv_remove(seg_lv(mirrored_seg, m))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
mirrored_seg->area_count = num_mirrors;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int remove_all_mirror_images(struct logical_volume *lv)
|
||||
{
|
||||
struct lv_segment *first_seg, *seg;
|
||||
struct logical_volume *lv1;
|
||||
|
||||
list_iterate_items(first_seg, &lv->segments)
|
||||
break;
|
||||
|
||||
if (!remove_mirror_images(first_seg, 1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_remove(first_seg->log_lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv1 = seg_lv(first_seg, 0);
|
||||
|
||||
lv->segments = lv1->segments;
|
||||
lv->segments.n->p = &lv->segments;
|
||||
lv->segments.p->n = &lv->segments;
|
||||
|
||||
list_init(&lv1->segments);
|
||||
lv1->le_count = 0;
|
||||
lv1->size = 0;
|
||||
if (!lv_remove(lv1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv->status &= ~MIRRORED;
|
||||
|
||||
list_iterate_items(seg, &lv->segments)
|
||||
seg->lv = lv;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add mirror images to an existing mirror
|
||||
*/
|
||||
/* FIXME
|
||||
int add_mirror_images(struct alloc_handle *ah,
|
||||
uint32_t first_area,
|
||||
uint32_t num_areas,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
}
|
||||
*/
|
||||
|
||||
int create_mirror_layers(struct alloc_handle *ah,
|
||||
uint32_t first_area,
|
||||
uint32_t num_mirrors,
|
||||
struct logical_volume *lv,
|
||||
struct segment_type *segtype,
|
||||
uint32_t status,
|
||||
uint32_t region_size,
|
||||
struct logical_volume *log_lv)
|
||||
{
|
||||
uint32_t m;
|
||||
struct logical_volume **img_lvs;
|
||||
char *img_name;
|
||||
size_t len;
|
||||
|
||||
if (!(img_lvs = alloca(sizeof(*img_lvs) * num_mirrors))) {
|
||||
log_error("img_lvs allocation failed. "
|
||||
"Remove new LV and retry.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = strlen(lv->name) + 32;
|
||||
if (!(img_name = alloca(len))) {
|
||||
log_error("img_name allocation failed. "
|
||||
"Remove new LV and retry.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(img_name, len, "%s_mimage_%%d", lv->name) < 0) {
|
||||
log_error("img_name allocation failed. "
|
||||
"Remove new LV and retry.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (m = 0; m < num_mirrors; m++) {
|
||||
if (!(img_lvs[m] = lv_create_empty(lv->vg->fid, img_name,
|
||||
NULL, LVM_READ | LVM_WRITE,
|
||||
ALLOC_INHERIT, 0, lv->vg))) {\
|
||||
log_error("Aborting. Failed to create submirror LV. "
|
||||
"Remove new LV and retry.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_add_segment(ah, m, 1, img_lvs[m],
|
||||
get_segtype_from_string(lv->vg->cmd,
|
||||
"striped"),
|
||||
0, NULL, 0, 0, 0, NULL)) {
|
||||
log_error("Aborting. Failed to add submirror segment "
|
||||
"to %s. Remove new LV and retry.",
|
||||
img_lvs[m]->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lv_add_mirror_segment(ah, lv, img_lvs, num_mirrors, segtype,
|
||||
0, region_size, log_lv)) {
|
||||
log_error("Aborting. Failed to add mirror segment. "
|
||||
"Remove new LV and retry.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace any LV segments on given PV with temporary mirror.
|
||||
@@ -33,7 +168,6 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
alloc_policy_t alloc,
|
||||
struct list *lvs_changed)
|
||||
{
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
struct lv_list *lvl;
|
||||
struct pv_list *pvl;
|
||||
@@ -59,16 +193,15 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
/* Split LV segments to match PE ranges */
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg->area[s].type != AREA_PV ||
|
||||
seg->area[s].u.pv.pvseg->pv->dev != pvl->pv->dev)
|
||||
if (seg_type(seg, s) != AREA_PV ||
|
||||
seg_dev(seg, s) != pvl->pv->dev)
|
||||
continue;
|
||||
|
||||
/* Do these PEs need moving? */
|
||||
list_iterate_items(per, pvl->pe_ranges) {
|
||||
pe_start = seg->area[s].u.pv.pvseg->pe;
|
||||
pe_start = seg_pe(seg, s);
|
||||
pe_end = pe_start + seg->area_len - 1;
|
||||
per_end = per->start + per->count - 1;
|
||||
|
||||
@@ -104,14 +237,13 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
/* Work through all segments on the supplied PV */
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg->area[s].type != AREA_PV ||
|
||||
seg->area[s].u.pv.pvseg->pv->dev != pvl->pv->dev)
|
||||
if (seg_type(seg, s) != AREA_PV ||
|
||||
seg_dev(seg, s) != pvl->pv->dev)
|
||||
continue;
|
||||
|
||||
pe_start = seg->area[s].u.pv.pvseg->pe;
|
||||
pe_start = seg_pe(seg, s);
|
||||
|
||||
/* Do these PEs need moving? */
|
||||
list_iterate_items(per, pvl->pe_ranges) {
|
||||
@@ -123,9 +255,8 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
|
||||
log_debug("Matched PE range %u-%u against "
|
||||
"%s %u len %u", per->start, per_end,
|
||||
dev_name(seg->area[s].u.pv.pvseg->
|
||||
pv->dev),
|
||||
seg->area[s].u.pv.pvseg->pe,
|
||||
dev_name(seg_dev(seg, s)),
|
||||
seg_pe(seg, s),
|
||||
seg->area_len);
|
||||
|
||||
/* First time, add LV to list of LVs affected */
|
||||
@@ -141,23 +272,23 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
|
||||
log_very_verbose("Moving %s:%u-%u of %s/%s",
|
||||
dev_name(pvl->pv->dev),
|
||||
seg->area[s].u.pv.pvseg->pe,
|
||||
seg->area[s].u.pv.pvseg->pe +
|
||||
seg_pe(seg, s),
|
||||
seg_pe(seg, s) +
|
||||
seg->area_len - 1,
|
||||
lv->vg->name, lv->name);
|
||||
|
||||
start_le = lv_mirr->le_count;
|
||||
if (!lv_extend(lv_mirr, segtype, 1,
|
||||
seg->area_len, 0u, seg->area_len,
|
||||
seg->area[s].u.pv.pvseg->pv,
|
||||
seg->area[s].u.pv.pvseg->pe,
|
||||
seg_pv(seg, s),
|
||||
seg_pe(seg, s),
|
||||
PVMOVE, allocatable_pvs,
|
||||
alloc)) {
|
||||
log_error("Unable to allocate "
|
||||
"temporary LV for pvmove.");
|
||||
return 0;
|
||||
}
|
||||
set_lv_segment_area_lv(seg, s, lv_mirr, start_le);
|
||||
set_lv_segment_area_lv(seg, s, lv_mirr, start_le, 0);
|
||||
|
||||
extent_count += seg->area_len;
|
||||
|
||||
@@ -178,29 +309,27 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
int remove_pvmove_mirrors(struct volume_group *vg,
|
||||
struct logical_volume *lv_mirr)
|
||||
{
|
||||
struct list *lvh, *segh;
|
||||
struct lv_list *lvl;
|
||||
struct logical_volume *lv1;
|
||||
struct lv_segment *seg, *mir_seg;
|
||||
uint32_t s, c;
|
||||
|
||||
/* Loop through all LVs except the temporary mirror */
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv1 = list_item(lvh, struct lv_list)->lv;
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
lv1 = lvl->lv;
|
||||
if (lv1 == lv_mirr)
|
||||
continue;
|
||||
|
||||
/* Find all segments that point at the temporary mirror */
|
||||
list_iterate(segh, &lv1->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv1->segments) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg->area[s].type != AREA_LV ||
|
||||
seg->area[s].u.lv.lv != lv_mirr)
|
||||
if (seg_type(seg, s) != AREA_LV ||
|
||||
seg_lv(seg, s) != lv_mirr)
|
||||
continue;
|
||||
|
||||
/* Find the mirror segment pointed at */
|
||||
if (!(mir_seg = find_seg_by_le(lv_mirr,
|
||||
seg->area[s].
|
||||
u.lv.le))) {
|
||||
seg_le(seg, s)))) {
|
||||
/* FIXME Error message */
|
||||
log_error("No segment found with LE");
|
||||
return 0;
|
||||
@@ -210,7 +339,7 @@ int remove_pvmove_mirrors(struct volume_group *vg,
|
||||
/* FIXME Improve error mesg & remove restrcn */
|
||||
if (!seg_is_mirrored(mir_seg) ||
|
||||
!(mir_seg->status & PVMOVE) ||
|
||||
mir_seg->le != seg->area[s].u.lv.le ||
|
||||
mir_seg->le != seg_le(seg, s) ||
|
||||
mir_seg->area_count != 2 ||
|
||||
mir_seg->area_len != seg->area_len) {
|
||||
log_error("Incompatible segments");
|
||||
@@ -227,8 +356,8 @@ int remove_pvmove_mirrors(struct volume_group *vg,
|
||||
c = 0;
|
||||
|
||||
if (!set_lv_segment_area_pv(seg, s,
|
||||
mir_seg->area[c].u.pv.pvseg->pv,
|
||||
mir_seg->area[c].u.pv.pvseg->pe)) {
|
||||
seg_pv(mir_seg, c),
|
||||
seg_pe(mir_seg, c))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -258,16 +387,14 @@ int remove_pvmove_mirrors(struct volume_group *vg,
|
||||
|
||||
const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr)
|
||||
{
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
|
||||
list_iterate(segh, &lv_mirr->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv_mirr->segments) {
|
||||
if (!seg_is_mirrored(seg))
|
||||
continue;
|
||||
if (seg->area[0].type != AREA_PV)
|
||||
continue;
|
||||
return dev_name(seg->area[0].u.pv.pvseg->pv->dev);
|
||||
return dev_name(seg_dev(seg, 0));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -275,16 +402,14 @@ const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr)
|
||||
|
||||
const char *get_pvmove_pvname_from_lv(struct logical_volume *lv)
|
||||
{
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
uint32_t s;
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg->area[s].type != AREA_LV)
|
||||
if (seg_type(seg, s) != AREA_LV)
|
||||
continue;
|
||||
return get_pvmove_pvname_from_lv_mirr(seg->area[s].u.lv.lv);
|
||||
return get_pvmove_pvname_from_lv_mirr(seg_lv(seg, s));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,23 +420,22 @@ struct logical_volume *find_pvmove_lv(struct volume_group *vg,
|
||||
struct device *dev,
|
||||
uint32_t lv_type)
|
||||
{
|
||||
struct list *lvh, *segh;
|
||||
struct lv_list *lvl;
|
||||
struct logical_volume *lv;
|
||||
struct lv_segment *seg;
|
||||
|
||||
/* Loop through all LVs */
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv = list_item(lvh, struct lv_list)->lv;
|
||||
list_iterate_items(lvl, &vg->lvs) {
|
||||
lv = lvl->lv;
|
||||
|
||||
if (!(lv->status & lv_type))
|
||||
continue;
|
||||
|
||||
/* Check segment origins point to pvname */
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
if (seg->area[0].type != AREA_PV)
|
||||
continue;
|
||||
if (seg->area[0].u.pv.pvseg->pv->dev != dev)
|
||||
if (seg_dev(seg, 0) != dev)
|
||||
continue;
|
||||
return lv;
|
||||
}
|
||||
@@ -338,9 +462,9 @@ struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd,
|
||||
struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
struct list *lvh, *segh, *lvs;
|
||||
struct list *lvs;
|
||||
struct logical_volume *lv1;
|
||||
struct lv_list *lvl;
|
||||
struct lv_list *lvl, *lvl1;
|
||||
struct lv_segment *seg;
|
||||
uint32_t s;
|
||||
|
||||
@@ -352,17 +476,16 @@ struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||
list_init(lvs);
|
||||
|
||||
/* Loop through all LVs except the one supplied */
|
||||
list_iterate(lvh, &vg->lvs) {
|
||||
lv1 = list_item(lvh, struct lv_list)->lv;
|
||||
list_iterate_items(lvl1, &vg->lvs) {
|
||||
lv1 = lvl1->lv;
|
||||
if (lv1 == lv)
|
||||
continue;
|
||||
|
||||
/* Find whether any segment points at the supplied LV */
|
||||
list_iterate(segh, &lv1->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv1->segments) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg->area[s].type != AREA_LV ||
|
||||
seg->area[s].u.lv.lv != lv)
|
||||
if (seg_type(seg, s) != AREA_LV ||
|
||||
seg_lv(seg, s) != lv)
|
||||
continue;
|
||||
if (!(lvl = pool_alloc(cmd->mem, sizeof(*lvl)))) {
|
||||
log_error("lv_list alloc failed");
|
||||
@@ -383,12 +506,9 @@ struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||
float copy_percent(struct logical_volume *lv_mirr)
|
||||
{
|
||||
uint32_t numerator = 0u, denominator = 0u;
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
|
||||
list_iterate(segh, &lv_mirr->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
|
||||
list_iterate_items(seg, &lv_mirr->segments) {
|
||||
denominator += seg->area_len;
|
||||
|
||||
if (seg_is_mirrored(seg))
|
||||
|
||||
@@ -22,7 +22,7 @@ struct pv_segment *assign_peg_to_lvseg(struct physical_volume *pv, uint32_t pe,
|
||||
struct lv_segment *seg,
|
||||
uint32_t area_num);
|
||||
int pv_split_segment(struct physical_volume *pv, uint32_t pe);
|
||||
int release_pv_segment(struct pv_segment *peg, uint32_t new_area_len);
|
||||
int release_pv_segment(struct pv_segment *peg, uint32_t area_reduction);
|
||||
int check_pv_segments(struct volume_group *vg);
|
||||
void merge_pv_segments(struct pv_segment *peg1, struct pv_segment *peg2);
|
||||
|
||||
|
||||
@@ -165,9 +165,11 @@ struct pv_segment *assign_peg_to_lvseg(struct physical_volume *pv,
|
||||
return peg;
|
||||
}
|
||||
|
||||
int release_pv_segment(struct pv_segment *peg, uint32_t new_area_len)
|
||||
int release_pv_segment(struct pv_segment *peg, uint32_t area_reduction)
|
||||
{
|
||||
if (new_area_len == 0) {
|
||||
peg->pv->pe_alloc_count -= area_reduction;
|
||||
|
||||
if (!peg->lvseg->area_len) {
|
||||
peg->lvseg = NULL;
|
||||
peg->lv_area = 0;
|
||||
|
||||
@@ -176,7 +178,7 @@ int release_pv_segment(struct pv_segment *peg, uint32_t new_area_len)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!pv_split_segment(peg->pv, peg->pe + new_area_len)) {
|
||||
if (!pv_split_segment(peg->pv, peg->pe + peg->lvseg->area_len)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -203,13 +205,16 @@ int check_pv_segments(struct volume_group *vg)
|
||||
struct pv_list *pvl;
|
||||
struct pv_segment *peg;
|
||||
unsigned s, segno;
|
||||
uint32_t start_pe;
|
||||
uint32_t start_pe, alloced;
|
||||
uint32_t pv_count = 0, free_count = 0, extent_count = 0;
|
||||
int ret = 1;
|
||||
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
pv = pvl->pv;
|
||||
segno = 0;
|
||||
start_pe = 0;
|
||||
alloced = 0;
|
||||
pv_count++;
|
||||
|
||||
list_iterate_items(peg, &pv->segments) {
|
||||
s = peg->lv_area;
|
||||
@@ -221,30 +226,63 @@ int check_pv_segments(struct volume_group *vg)
|
||||
peg->lvseg ? peg->lvseg->le : 0, s);
|
||||
/* FIXME Add details here on failure instead */
|
||||
if (start_pe != peg->pe) {
|
||||
log_debug("Gap in pvsegs: %u, %u",
|
||||
log_error("Gap in pvsegs: %u, %u",
|
||||
start_pe, peg->pe);
|
||||
ret = 0;
|
||||
}
|
||||
if (peg->lvseg) {
|
||||
if (peg->lvseg->area[s].type != AREA_PV) {
|
||||
log_debug("Wrong lvseg area type");
|
||||
if (seg_type(peg->lvseg, s) != AREA_PV) {
|
||||
log_error("Wrong lvseg area type");
|
||||
ret = 0;
|
||||
}
|
||||
if (peg->lvseg->area[s].u.pv.pvseg != peg) {
|
||||
log_debug("Inconsistent pvseg pointers");
|
||||
if (seg_pvseg(peg->lvseg, s) != peg) {
|
||||
log_error("Inconsistent pvseg pointers");
|
||||
ret = 0;
|
||||
}
|
||||
if (peg->lvseg->area_len != peg->len) {
|
||||
log_debug("Inconsistent length: %u %u",
|
||||
log_error("Inconsistent length: %u %u",
|
||||
peg->len,
|
||||
peg->lvseg->area_len);
|
||||
ret = 0;
|
||||
}
|
||||
alloced += peg->len;
|
||||
}
|
||||
start_pe += peg->len;
|
||||
}
|
||||
|
||||
if (start_pe != pv->pe_count) {
|
||||
log_error("PV segment pe_count mismatch: %u != %u",
|
||||
start_pe, pv->pe_count);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (alloced != pv->pe_alloc_count) {
|
||||
log_error("PV segment pe_alloc_count mismatch: "
|
||||
"%u != %u", alloced, pv->pe_alloc_count);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
extent_count += start_pe;
|
||||
free_count += (start_pe - alloced);
|
||||
}
|
||||
|
||||
if (pv_count != vg->pv_count) {
|
||||
log_error("PV segment VG pv_count mismatch: %u != %u",
|
||||
pv_count, vg->pv_count);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (free_count != vg->free_count) {
|
||||
log_error("PV segment VG free_count mismatch: %u != %u",
|
||||
free_count, vg->free_count);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (extent_count != vg->extent_count) {
|
||||
log_error("PV segment VG extent_count mismatch: %u != %u",
|
||||
extent_count, vg->extent_count);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,10 @@ struct dev_manager;
|
||||
#define seg_is_virtual(seg) ((seg)->segtype->flags & SEG_VIRTUAL ? 1 : 0)
|
||||
#define seg_can_split(seg) ((seg)->segtype->flags & SEG_CAN_SPLIT ? 1 : 0)
|
||||
|
||||
#define segtype_is_striped(segtype) ((segtype)->flags & SEG_AREAS_STRIPED ? 1 : 0)
|
||||
#define segtype_is_mirrored(segtype) ((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0)
|
||||
#define segtype_is_virtual(segtype) ((segtype)->flags & SEG_VIRTUAL ? 1 : 0)
|
||||
|
||||
struct segment_type {
|
||||
struct list list;
|
||||
struct cmd_context *cmd;
|
||||
|
||||
@@ -50,7 +50,7 @@ int vg_add_snapshot(struct format_instance *fid, const char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(snap = lv_create_empty(fid, name, name ? NULL : "snapshot%d",
|
||||
if (!(snap = lv_create_empty(fid, name ? name : "snapshot%d",
|
||||
lvid, LVM_READ | LVM_WRITE | VISIBLE_LV,
|
||||
ALLOC_INHERIT, 1, origin->vg))) {
|
||||
stack;
|
||||
@@ -59,7 +59,7 @@ int vg_add_snapshot(struct format_instance *fid, const char *name,
|
||||
|
||||
snap->le_count = extent_count;
|
||||
|
||||
if (!(seg = alloc_snapshot_seg(snap, 0))) {
|
||||
if (!(seg = alloc_snapshot_seg(snap, 0, 0))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ enum {
|
||||
};
|
||||
|
||||
struct mirror_state {
|
||||
uint32_t region_size;
|
||||
uint32_t default_region_size;
|
||||
};
|
||||
|
||||
static const char *_name(const struct lv_segment *seg)
|
||||
@@ -45,14 +45,25 @@ static const char *_name(const struct lv_segment *seg)
|
||||
|
||||
static void _display(const struct lv_segment *seg)
|
||||
{
|
||||
const char *size;
|
||||
|
||||
log_print(" Mirrors\t\t%u", seg->area_count);
|
||||
log_print(" Mirror size\t\t%u", seg->area_len);
|
||||
if (seg->log_lv)
|
||||
log_print(" Mirror log volume\t%s", seg->log_lv->name);
|
||||
|
||||
if (seg->region_size) {
|
||||
size = display_size(seg->lv->vg->cmd,
|
||||
(uint64_t) seg->region_size,
|
||||
SIZE_SHORT);
|
||||
log_print(" Mirror region size\t%s", size);
|
||||
}
|
||||
|
||||
log_print(" Mirror original:");
|
||||
display_stripe(seg, 0, " ");
|
||||
log_print(" Mirror destination:");
|
||||
display_stripe(seg, 1, " ");
|
||||
log_print(" ");
|
||||
|
||||
}
|
||||
|
||||
static int _text_import_area_count(struct config_node *sn, uint32_t *area_count)
|
||||
@@ -70,6 +81,7 @@ static int _text_import(struct lv_segment *seg, const struct config_node *sn,
|
||||
struct hash_table *pv_hash)
|
||||
{
|
||||
const struct config_node *cn;
|
||||
char *logname = NULL;
|
||||
|
||||
if (find_config_node(sn, "extents_moved")) {
|
||||
if (get_config_uint32(sn, "extents_moved",
|
||||
@@ -82,13 +94,42 @@ static int _text_import(struct lv_segment *seg, const struct config_node *sn,
|
||||
}
|
||||
}
|
||||
|
||||
if (find_config_node(sn, "region_size")) {
|
||||
if (!get_config_uint32(sn, "region_size",
|
||||
&seg->region_size)) {
|
||||
log_error("Couldn't read 'region_size' for "
|
||||
"segment '%s'.", sn->key);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((cn = find_config_node(sn, "mirror_log"))) {
|
||||
if (!cn->v || !cn->v->v.str) {
|
||||
log_error("Mirror log type must be a string.");
|
||||
return 0;
|
||||
}
|
||||
logname = cn->v->v.str;
|
||||
if (!(seg->log_lv = find_lv(seg->lv->vg, logname))) {
|
||||
log_error("Unrecognised mirror log in segment %s.",
|
||||
sn->key);
|
||||
return 0;
|
||||
}
|
||||
seg->log_lv->status |= MIRROR_LOG;
|
||||
}
|
||||
|
||||
if (logname && !seg->region_size) {
|
||||
log_error("Missing region size for mirror log for segment "
|
||||
"'%s'.", sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cn = find_config_node(sn, "mirrors"))) {
|
||||
log_error("Couldn't find mirrors array for segment "
|
||||
"'%s'.", sn->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return text_import_areas(seg, sn, cn, pv_hash);
|
||||
return text_import_areas(seg, sn, cn, pv_hash, MIRROR_IMAGE);
|
||||
}
|
||||
|
||||
static int _text_export(const struct lv_segment *seg, struct formatter *f)
|
||||
@@ -96,7 +137,11 @@ static int _text_export(const struct lv_segment *seg, struct formatter *f)
|
||||
outf(f, "mirror_count = %u", seg->area_count);
|
||||
if (seg->status & PVMOVE)
|
||||
out_size(f, (uint64_t) seg->extents_copied * seg->lv->vg->extent_size,
|
||||
"extents_moved = %u", seg->extents_copied);
|
||||
"extents_moved = %" PRIu32, seg->extents_copied);
|
||||
if (seg->log_lv)
|
||||
outf(f, "mirror_log = \"%s\"", seg->log_lv->name);
|
||||
if (seg->region_size)
|
||||
outf(f, "region_size = %" PRIu32, seg->region_size);
|
||||
|
||||
return out_areas(f, seg, "mirror");
|
||||
}
|
||||
@@ -112,7 +157,7 @@ static struct mirror_state *_init_target(struct pool *mem,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mirr_state->region_size = 2 *
|
||||
mirr_state->default_region_size = 2 *
|
||||
find_config_int(cft->root,
|
||||
"activation/mirror_region_size",
|
||||
DEFAULT_MIRROR_REGION_SIZE);
|
||||
@@ -156,15 +201,23 @@ static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
|
||||
} else {
|
||||
*target = "mirror";
|
||||
|
||||
/* Find largest power of 2 region size unit we can use */
|
||||
region_max = (1 << (ffs(seg->area_len) - 1)) *
|
||||
if (!(seg->status & PVMOVE)) {
|
||||
if (!seg->region_size) {
|
||||
log_error("Missing region size for mirror segment.");
|
||||
return 0;
|
||||
}
|
||||
region_size = seg->region_size;
|
||||
} else {
|
||||
/* Find largest power of 2 region size unit we can use */
|
||||
region_max = (1 << (ffs(seg->area_len) - 1)) *
|
||||
seg->lv->vg->extent_size;
|
||||
|
||||
region_size = mirr_state->region_size;
|
||||
if (region_max < region_size) {
|
||||
region_size = region_max;
|
||||
log_verbose("Using reduced mirror region size of %u sectors",
|
||||
region_size);
|
||||
region_size = mirr_state->default_region_size;
|
||||
if (region_max < region_size) {
|
||||
region_size = region_max;
|
||||
log_verbose("Using reduced mirror region size of %u sectors",
|
||||
region_size);
|
||||
}
|
||||
}
|
||||
|
||||
if ((ret = compose_log_line(dm, seg, params, paramsize, pos,
|
||||
|
||||
@@ -22,7 +22,6 @@ int set_selinux_context(const char *path)
|
||||
{
|
||||
security_context_t scontext;
|
||||
|
||||
log_very_verbose("Setting SELinux context for %s", path);
|
||||
if (is_selinux_enabled() <= 0)
|
||||
return 1;
|
||||
|
||||
@@ -31,6 +30,9 @@ int set_selinux_context(const char *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_very_verbose("Setting SELinux context for %s to %s",
|
||||
path, scontext);
|
||||
|
||||
if ((lsetfilecon(path, scontext) < 0) && (errno != ENOTSUP)) {
|
||||
log_sys_error("lsetfilecon", path);
|
||||
free(scontext);
|
||||
|
||||
@@ -112,6 +112,9 @@ void *malloc_aux(size_t s, const char *file, int line)
|
||||
if (_mem_stats.bytes > _mem_stats.mbytes)
|
||||
_mem_stats.mbytes = _mem_stats.bytes;
|
||||
|
||||
/* log_debug("Allocated: %u %u %u", nb->id, _mem_stats.blocks_allocated,
|
||||
_mem_stats.bytes); */
|
||||
|
||||
return nb + 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
FIELD(LVS, lv, STR, "LV UUID", lvid.id[1], 38, uuid, "lv_uuid")
|
||||
FIELD(LVS, lv, STR, "LV", name, 4, string, "lv_name")
|
||||
FIELD(LVS, lv, STR, "LV", lvid, 4, lvname, "lv_name")
|
||||
FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, "lv_attr")
|
||||
FIELD(LVS, lv, NUM, "Maj", major, 3, int32, "lv_major")
|
||||
FIELD(LVS, lv, NUM, "Min", minor, 3, int32, "lv_minor")
|
||||
@@ -32,6 +32,7 @@ FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, "snap_percent")
|
||||
FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, "copy_percent")
|
||||
FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv")
|
||||
FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags")
|
||||
FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log")
|
||||
|
||||
FIELD(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt")
|
||||
FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid")
|
||||
@@ -67,6 +68,7 @@ FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype")
|
||||
FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes")
|
||||
FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize")
|
||||
FIELD(SEGS, seg, NUM, "Chunk", chunk_size, 5, size32, "chunksize")
|
||||
FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "regionsize")
|
||||
FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start")
|
||||
FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size")
|
||||
FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, "seg_tags")
|
||||
|
||||
@@ -154,14 +154,14 @@ static int _devices_disp(struct report_handle *rh, struct field *field,
|
||||
}
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
switch (seg->area[s].type) {
|
||||
switch (seg_type(seg, s)) {
|
||||
case AREA_LV:
|
||||
name = seg->area[s].u.lv.lv->name;
|
||||
extent = seg->area[s].u.lv.le;
|
||||
name = seg_lv(seg, s)->name;
|
||||
extent = seg_le(seg, s);
|
||||
break;
|
||||
case AREA_PV:
|
||||
name = dev_name(seg->area[s].u.pv.pvseg->pv->dev);
|
||||
extent = seg->area[s].u.pv.pvseg->pe;
|
||||
name = dev_name(seg_dev(seg, s));
|
||||
extent = seg_pe(seg, s);
|
||||
break;
|
||||
default:
|
||||
name = "unknown";
|
||||
@@ -337,6 +337,10 @@ static int _lvstatus_disp(struct report_handle *rh, struct field *field,
|
||||
repstr[0] = 'p';
|
||||
else if (lv->status & MIRRORED)
|
||||
repstr[0] = 'm';
|
||||
else if (lv->status & MIRROR_IMAGE)
|
||||
repstr[0] = 'i';
|
||||
else if (lv->status & MIRROR_LOG)
|
||||
repstr[0] = 'l';
|
||||
else if (lv->status & VIRTUAL)
|
||||
repstr[0] = 'v';
|
||||
else if (lv_is_origin(lv))
|
||||
@@ -490,19 +494,68 @@ static int _origin_disp(struct report_handle *rh, struct field *field,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _loglv_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
struct lv_segment *seg;
|
||||
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
if (!seg_is_mirrored(seg) || !seg->log_lv)
|
||||
continue;
|
||||
return _string_disp(rh, field, &seg->log_lv->name);
|
||||
}
|
||||
|
||||
field->report_string = "";
|
||||
field->sort_value = (const void *) field->report_string;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvname_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
char *repstr;
|
||||
size_t len;
|
||||
|
||||
if (lv->status & VISIBLE_LV) {
|
||||
repstr = lv->name;
|
||||
return _string_disp(rh, field, &repstr);
|
||||
}
|
||||
|
||||
len = strlen(lv->name) + 3;
|
||||
if (!(repstr = pool_zalloc(rh->mem, len))) {
|
||||
log_error("pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(repstr, len, "[%s]", lv->name) < 0) {
|
||||
log_error("lvname snprintf failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
field->report_string = repstr;
|
||||
|
||||
if (!(field->sort_value = pool_strdup(rh->mem, lv->name))) {
|
||||
log_error("pool_strdup failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _movepv_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
const char *name;
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
if (!(seg->status & PVMOVE))
|
||||
continue;
|
||||
name = dev_name(seg->area[0].u.pv.pvseg->pv->dev);
|
||||
name = dev_name(seg_dev(seg, 0));
|
||||
return _string_disp(rh, field, &name);
|
||||
}
|
||||
|
||||
@@ -917,12 +970,9 @@ static int _field_match(struct report_handle *rh, const char *field, size_t len)
|
||||
static int _add_sort_key(struct report_handle *rh, uint32_t field_num,
|
||||
uint32_t flags)
|
||||
{
|
||||
struct list *fh;
|
||||
struct field_properties *fp, *found = NULL;
|
||||
|
||||
list_iterate(fh, &rh->field_props) {
|
||||
fp = list_item(fh, struct field_properties);
|
||||
|
||||
list_iterate_items(fp, &rh->field_props) {
|
||||
if (fp->field_num == field_num) {
|
||||
found = fp;
|
||||
break;
|
||||
@@ -1138,7 +1188,6 @@ int report_object(void *handle, struct volume_group *vg,
|
||||
struct lv_segment *seg, struct pv_segment *pvseg)
|
||||
{
|
||||
struct report_handle *rh = handle;
|
||||
struct list *fh;
|
||||
struct field_properties *fp;
|
||||
struct row *row;
|
||||
struct field *field;
|
||||
@@ -1168,9 +1217,7 @@ int report_object(void *handle, struct volume_group *vg,
|
||||
list_add(&rh->rows, &row->list);
|
||||
|
||||
/* For each field to be displayed, call its report_fn */
|
||||
list_iterate(fh, &rh->field_props) {
|
||||
fp = list_item(fh, struct field_properties);
|
||||
|
||||
list_iterate_items(fp, &rh->field_props) {
|
||||
skip = 0;
|
||||
|
||||
if (!(field = pool_zalloc(rh->mem, sizeof(*field)))) {
|
||||
@@ -1231,7 +1278,6 @@ int report_object(void *handle, struct volume_group *vg,
|
||||
static int _report_headings(void *handle)
|
||||
{
|
||||
struct report_handle *rh = handle;
|
||||
struct list *fh;
|
||||
struct field_properties *fp;
|
||||
const char *heading;
|
||||
char buf[1024];
|
||||
@@ -1250,8 +1296,7 @@ static int _report_headings(void *handle)
|
||||
}
|
||||
|
||||
/* First heading line */
|
||||
list_iterate(fh, &rh->field_props) {
|
||||
fp = list_item(fh, struct field_properties);
|
||||
list_iterate_items(fp, &rh->field_props) {
|
||||
if (fp->flags & FLD_HIDDEN)
|
||||
continue;
|
||||
|
||||
@@ -1268,7 +1313,7 @@ static int _report_headings(void *handle)
|
||||
} else if (!pool_grow_object(rh->mem, heading, strlen(heading)))
|
||||
goto bad;
|
||||
|
||||
if (!list_end(&rh->field_props, fh))
|
||||
if (!list_end(&rh->field_props, &fp->list))
|
||||
if (!pool_grow_object(rh->mem, rh->separator,
|
||||
strlen(rh->separator)))
|
||||
goto bad;
|
||||
@@ -1336,7 +1381,6 @@ static int _row_compare(const void *a, const void *b)
|
||||
static int _sort_rows(struct report_handle *rh)
|
||||
{
|
||||
struct row *(*rows)[];
|
||||
struct list *rowh;
|
||||
uint32_t count = 0;
|
||||
struct row *row;
|
||||
|
||||
@@ -1346,10 +1390,8 @@ static int _sort_rows(struct report_handle *rh)
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_iterate(rowh, &rh->rows) {
|
||||
row = list_item(rowh, struct row);
|
||||
list_iterate_items(row, &rh->rows)
|
||||
(*rows)[count++] = row;
|
||||
}
|
||||
|
||||
qsort(rows, count, sizeof(**rows), _row_compare);
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ static int _text_import(struct lv_segment *seg, const struct config_node *sn,
|
||||
|
||||
seg->area_len /= seg->area_count;
|
||||
|
||||
return text_import_areas(seg, sn, cn, pv_hash);
|
||||
return text_import_areas(seg, sn, cn, pv_hash, 0);
|
||||
}
|
||||
|
||||
static int _text_export(const struct lv_segment *seg, struct formatter *f)
|
||||
@@ -119,10 +119,10 @@ static int _segments_compatible(struct lv_segment *first,
|
||||
|
||||
width = first->area_len;
|
||||
|
||||
if ((first->area[s].u.pv.pvseg->pv !=
|
||||
second->area[s].u.pv.pvseg->pv) ||
|
||||
(first->area[s].u.pv.pvseg->pe + width !=
|
||||
second->area[s].u.pv.pvseg->pe))
|
||||
if ((seg_pv(first, s) !=
|
||||
seg_pv(second, s)) ||
|
||||
(seg_pe(first, s) + width !=
|
||||
seg_pe(second, s)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -144,8 +144,8 @@ static int _merge_segments(struct lv_segment *seg1, struct lv_segment *seg2)
|
||||
|
||||
for (s = 0; s < seg1->area_count; s++)
|
||||
if (seg1->area[s].type == AREA_PV)
|
||||
merge_pv_segments(seg1->area[s].u.pv.pvseg,
|
||||
seg2->area[s].u.pv.pvseg);
|
||||
merge_pv_segments(seg_pvseg(seg1, s),
|
||||
seg_pvseg(seg2, s));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -103,6 +103,14 @@ static inline int list_end(struct list *head, struct list *elem)
|
||||
return elem->n == head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return first element of the list or NULL if empty
|
||||
*/
|
||||
static inline struct list *list_first(struct list *head)
|
||||
{
|
||||
return (list_empty(head) ? NULL : head->n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return last element of the list or NULL if empty
|
||||
*/
|
||||
@@ -194,6 +202,25 @@ static inline struct list *list_next(struct list *head, struct list *elem)
|
||||
*/
|
||||
#define list_iterate_items(v, head) list_iterate_items_gen(v, (head), list)
|
||||
|
||||
/*
|
||||
* Walk a list backwards, setting 'v' in turn to the containing structure
|
||||
* of each item.
|
||||
* The containing structure should be the same type as 'v'.
|
||||
* The 'struct list' variable within the containing structure is 'field'.
|
||||
*/
|
||||
#define list_iterate_back_items_gen(v, head, field) \
|
||||
for (v = list_struct_base((head)->p, typeof(*v), field); \
|
||||
&v->field != (head); \
|
||||
v = list_struct_base(v->field.p, typeof(*v), field))
|
||||
|
||||
/*
|
||||
* Walk a list backwards, setting 'v' in turn to the containing structure
|
||||
* of each item.
|
||||
* The containing structure should be the same type as 'v'.
|
||||
* The list should be 'struct list list' within the containing structure.
|
||||
*/
|
||||
#define list_iterate_back_items(v, head) list_iterate_back_items_gen(v, (head), list)
|
||||
|
||||
/*
|
||||
* Return the number of elements in a list by walking it.
|
||||
*/
|
||||
|
||||
@@ -219,7 +219,7 @@ static int _create_control(const char *control, uint32_t major, uint32_t minor)
|
||||
}
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
if (!set_selinux_context(control)) {
|
||||
if (!set_selinux_context(control, S_IFCHR)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -200,26 +200,28 @@ int dm_task_add_target(struct dm_task *dmt, uint64_t start, uint64_t size,
|
||||
}
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
int set_selinux_context(const char *path)
|
||||
int set_selinux_context(const char *path, mode_t mode)
|
||||
{
|
||||
security_context_t scontext;
|
||||
|
||||
log_debug("Setting SELinux context for %s", path);
|
||||
if (is_selinux_enabled() <= 0)
|
||||
return 1;
|
||||
|
||||
if (matchpathcon(path, 0, &scontext) < 0) {
|
||||
log_error("%s: matchpathcon failed: %s", path, strerror(errno));
|
||||
if (matchpathcon(path, mode, &scontext) < 0) {
|
||||
log_error("%s: matchpathcon %07o failed: %s", path, mode,
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("Setting SELinux context for %s to %s.", path, scontext);
|
||||
|
||||
if ((lsetfilecon(path, scontext) < 0) && (errno != ENOTSUP)) {
|
||||
log_error("%s: lsetfilecon failed: %s", path, strerror(errno));
|
||||
free(scontext);
|
||||
freecon(scontext);
|
||||
return 0;
|
||||
}
|
||||
|
||||
free(scontext);
|
||||
freecon(scontext);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
@@ -265,7 +267,7 @@ static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
|
||||
}
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
if (!set_selinux_context(path))
|
||||
if (!set_selinux_context(path, S_IFBLK))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ int rm_dev_node(const char *dev_name);
|
||||
int rename_dev_node(const char *old_name, const char *new_name);
|
||||
void update_devs(void);
|
||||
|
||||
int set_selinux_context(const char *path);
|
||||
int set_selinux_context(const char *path, mode_t mode);
|
||||
|
||||
#define DM_LIB_VERSION @DM_LIB_VERSION@
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#define FIFO_SERVER "/var/run/dmeventd-server"
|
||||
#define PIDFILE "/var/run/dmeventd.pid"
|
||||
|
||||
#define DEFAULT_TIMEOUT 10
|
||||
/* Commands for the daemon passed in the message below. */
|
||||
enum dmeventd_command {
|
||||
CMD_ACTIVE = 1,
|
||||
@@ -32,6 +33,8 @@ enum dmeventd_command {
|
||||
CMD_UNREGISTER_FOR_EVENT,
|
||||
CMD_GET_REGISTERED_DEVICE,
|
||||
CMD_GET_NEXT_REGISTERED_DEVICE,
|
||||
CMD_SET_TIMEOUT,
|
||||
CMD_GET_TIMEOUT,
|
||||
};
|
||||
|
||||
/* Message passed between client and daemon. */
|
||||
@@ -60,6 +63,7 @@ enum event_type {
|
||||
PATH_ERROR = 0x10, /* Failure on an io path. */
|
||||
ADAPTOR_ERROR = 0x20, /* Failure off a host adaptor. */
|
||||
SYNC_STATUS = 0x40, /* Mirror synchronization completed/failed. */
|
||||
TIMEOUT = 0x80, /* Timeout has occured */
|
||||
};
|
||||
#define ALL_ERRORS (SECTOR_ERROR | DEVICE_ERROR | PATH_ERROR | ADAPTOR_ERROR)
|
||||
|
||||
@@ -69,6 +73,8 @@ int dm_unregister_for_event(char *dso_name, char *device,
|
||||
enum event_type events);
|
||||
int dm_get_registered_device(char **dso_name, char **device,
|
||||
enum event_type *events, int next);
|
||||
int dm_set_event_timeout(char *device, uint32_t timeout);
|
||||
int dm_get_event_timeout(char *device, uint32_t *timeout);
|
||||
|
||||
/* Prototypes for DSO interface. */
|
||||
void process_event(char *device, enum event_type event);
|
||||
|
||||
232
scripts/lvmconf.sh
Normal file
232
scripts/lvmconf.sh
Normal file
@@ -0,0 +1,232 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Edit an lvm.conf file to adjust various properties
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
function usage
|
||||
{
|
||||
echo "usage: $0 <command>"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo "Enable clvm: --enable-cluster --lockinglibdir <dir> [--lockinglib <lib>]"
|
||||
echo "Disable clvm: --disable-cluster"
|
||||
echo ""
|
||||
echo "Global options:"
|
||||
echo "Config file location: --file <configfile>"
|
||||
echo ""
|
||||
}
|
||||
|
||||
|
||||
function parse_args
|
||||
{
|
||||
while [ -n "$1" ]; do
|
||||
case $1 in
|
||||
--enable-cluster)
|
||||
LOCKING_TYPE=2
|
||||
shift
|
||||
;;
|
||||
--disable-cluster)
|
||||
LOCKING_TYPE=1
|
||||
shift
|
||||
;;
|
||||
--lockinglibdir)
|
||||
if [ -n "$2" ]; then
|
||||
LOCKINGLIBDIR=$2
|
||||
shift 2
|
||||
else
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--lockinglib)
|
||||
if [ -n "$2" ]; then
|
||||
LOCKINGLIB=$2
|
||||
shift 2
|
||||
else
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--file)
|
||||
if [ -n "$2" ]; then
|
||||
CONFIGFILE=$2
|
||||
shift 2
|
||||
else
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
function validate_args
|
||||
{
|
||||
[ -z "$CONFIGFILE" ] && CONFIGFILE="/etc/lvm/lvm.conf"
|
||||
|
||||
if [ ! -f "$CONFIGFILE" ]
|
||||
then
|
||||
echo "$CONFIGFILE does not exist"
|
||||
exit 10
|
||||
fi
|
||||
|
||||
if [ -z "$LOCKING_TYPE" ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$LOCKING_TYPE" == "2" ]; then
|
||||
|
||||
[ -z "$LOCKINGLIBDIR" ] && usage && exit 1
|
||||
[ -z "$LOCKINGLIB" ] && LOCKINGLIB="liblvm2clusterlock.so"
|
||||
|
||||
if [ "${LOCKINGLIBDIR:0:1}" != "/" ]
|
||||
then
|
||||
echo "Prefix must be an absolute path name (starting with a /)"
|
||||
exit 12
|
||||
fi
|
||||
|
||||
if [ ! -f "$LOCKINGLIBDIR/$LOCKINGLIB" ]
|
||||
then
|
||||
echo "$LOCKINGLIBDIR/$LOCKINGLIB does not exist, did you do a \"make install\" ?"
|
||||
exit 11
|
||||
fi
|
||||
|
||||
fi
|
||||
}
|
||||
|
||||
umask 0077
|
||||
|
||||
parse_args "$@"
|
||||
|
||||
validate_args
|
||||
|
||||
|
||||
SCRIPTFILE=/etc/lvm/.lvmconf-script.tmp
|
||||
TMPFILE=/etc/lvm/.lvmconf-tmp.tmp
|
||||
|
||||
|
||||
# Flags so we know which parts of the file we can replace and which need
|
||||
# adding. These are return codes from grep, so zero means it IS present!
|
||||
have_type=1
|
||||
have_dir=1
|
||||
have_library=1
|
||||
have_global=1
|
||||
|
||||
grep -q '^[[:blank:]]*locking_type[[:blank:]]*=' $CONFIGFILE
|
||||
have_type=$?
|
||||
|
||||
grep -q '^[[:blank:]]*library_dir[[:blank:]]*=' $CONFIGFILE
|
||||
have_dir=$?
|
||||
|
||||
grep -q '^[[:blank:]]*locking_library[[:blank:]]*=' $CONFIGFILE
|
||||
have_library=$?
|
||||
|
||||
# Those options are in section "global {" so we must have one if any are present.
|
||||
if [ "$have_type" = "0" -o "$have_dir" = "0" -o "$have_library" = "0" ]
|
||||
then
|
||||
|
||||
# See if we can find it...
|
||||
grep -q '^[[:blank:]]*global[[:blank:]]*{' $CONFIGFILE
|
||||
have_global=$?
|
||||
|
||||
if [ "$have_global" = "1" ]
|
||||
then
|
||||
echo "global keys but no 'global {' found, can't edit file"
|
||||
exit 12
|
||||
fi
|
||||
fi
|
||||
|
||||
# So if we don't have "global {" we need to create one and
|
||||
# populate it
|
||||
|
||||
if [ "$have_global" = "1" ]
|
||||
then
|
||||
if [ "$LOCKING_TYPE" = "2" ]; then
|
||||
cat $CONFIGFILE - <<EOF > $TMPFILE
|
||||
global {
|
||||
# Enable locking for cluster LVM
|
||||
locking_type = $LOCKING_TYPE
|
||||
library_dir = "$LOCKINGLIBDIR"
|
||||
locking_library = "$LOCKINGLIB"
|
||||
}
|
||||
EOF
|
||||
fi # if we aren't setting cluster locking, we don't need to create a global section
|
||||
|
||||
if [ $? != 0 ]
|
||||
then
|
||||
echo "failed to create temporary config file, $CONFIGFILE not updated"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
#
|
||||
# We have a "global {" section, so add or replace the
|
||||
# locking entries as appropriate
|
||||
#
|
||||
|
||||
if [ "$have_type" = "0" ]
|
||||
then
|
||||
SEDCMD=" s/^[[:blank:]]*locking_type[[:blank:]]*=.*/\ \ \ \ locking_type = $LOCKING_TYPE/g"
|
||||
else
|
||||
SEDCMD=" /global[[:blank:]]*{/a\ \ \ \ locking_type = $LOCKING_TYPE"
|
||||
fi
|
||||
|
||||
if [ "$LOCKING_TYPE" = "2" ]; then
|
||||
if [ "$have_dir" = "0" ]
|
||||
then
|
||||
SEDCMD="${SEDCMD}\ns'^[[:blank:]]*library_dir[[:blank:]]*=.*'\ \ \ \ library_dir = \"$LOCKINGLIBDIR\"'g"
|
||||
else
|
||||
SEDCMD="${SEDCMD}\n/global[[:blank:]]*{/a\ \ \ \ library_dir = \"$LOCKINGLIBDIR\""
|
||||
fi
|
||||
|
||||
if [ "$have_library" = "0" ]
|
||||
then
|
||||
SEDCMD="${SEDCMD}\ns/^[[:blank:]]*locking_library[[:blank:]]*=.*/\ \ \ \ locking_library = \"$LOCKINGLIB\"/g"
|
||||
else
|
||||
SEDCMD="${SEDCMD}\n/global[[:blank:]]*{/a\ \ \ \ locking_library = \"$LOCKINGLIB\""
|
||||
fi
|
||||
else
|
||||
# if we're not using cluster locking, remove the library dir and locking library name
|
||||
if [ "$have_dir" = "0" ]
|
||||
then
|
||||
SEDCMD="${SEDCMD}\n/^[[:blank:]]*library_dir[[:blank:]]*=.*/d"
|
||||
fi
|
||||
|
||||
if [ "$have_library" = "0" ]
|
||||
then
|
||||
SEDCMD="${SEDCMD}\n/^[[:blank:]]*locking_library[[:blank:]]*=.*/d"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e $SEDCMD > $SCRIPTFILE
|
||||
sed <$CONFIGFILE >$TMPFILE -f $SCRIPTFILE
|
||||
if [ $? != 0 ]
|
||||
then
|
||||
echo "sed failed, $CONFIGFILE not updated"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Now we have a suitably editted config file in a temp place,
|
||||
# backup the original and copy our new one into place.
|
||||
|
||||
cp $CONFIGFILE $CONFIGFILE.lvmconfold
|
||||
if [ $? != 0 ]
|
||||
then
|
||||
echo "failed to backup old config file, $CONFIGFILE not updated"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
cp $TMPFILE $CONFIGFILE
|
||||
if [ $? != 0 ]
|
||||
then
|
||||
echo "failed to copy new config file into place, check $CONFIGFILE is still OK"
|
||||
exit 3
|
||||
fi
|
||||
|
||||
rm -f $SCRIPTFILE $TMPFILE
|
||||
@@ -24,6 +24,7 @@ SOURCES =\
|
||||
dumpconfig.c \
|
||||
formats.c \
|
||||
lvchange.c \
|
||||
lvconvert.c \
|
||||
lvcreate.c \
|
||||
lvdisplay.c \
|
||||
lvextend.c \
|
||||
|
||||
@@ -85,6 +85,7 @@ arg(size_ARG, 'L', "size", size_mb_arg)
|
||||
arg(logicalextent_ARG, 'L', "logicalextent", int_arg_with_sign)
|
||||
arg(persistent_ARG, 'M', "persistent", yes_no_arg)
|
||||
arg(major_ARG, 'j', "major", major_arg)
|
||||
arg(mirrors_ARG, 'm', "mirrors", int_arg)
|
||||
arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_arg)
|
||||
arg(maps_ARG, 'm', "maps", NULL)
|
||||
arg(name_ARG, 'n', "name", string_arg)
|
||||
@@ -100,6 +101,7 @@ arg(physicalvolume_ARG, 'P', "physicalvolume", NULL)
|
||||
arg(readahead_ARG, 'r', "readahead", int_arg)
|
||||
arg(resizefs_ARG, 'r', "resizefs", NULL)
|
||||
arg(reset_ARG, 'R', "reset", NULL)
|
||||
arg(regionsize_ARG, 'R', "regionsize", size_mb_arg)
|
||||
arg(physicalextentsize_ARG, 's', "physicalextentsize", size_mb_arg)
|
||||
arg(stdin_ARG, 's', "stdin", NULL)
|
||||
arg(snapshot_ARG, 's', "snapshot", NULL)
|
||||
|
||||
@@ -78,6 +78,19 @@ xx(lvchange,
|
||||
persistent_ARG, readahead_ARG, refresh_ARG, addtag_ARG, deltag_ARG,
|
||||
test_ARG)
|
||||
|
||||
xx(lvconvert,
|
||||
"Change logical volume layout",
|
||||
"lvconvert " "\n"
|
||||
"\t[--alloc AllocationPolicy]\n"
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[-h|-?|--help]\n"
|
||||
"\t[-m|--mirrors Mirrors]\n"
|
||||
"\t[-v|--verbose]\n"
|
||||
"\t[--version]" "\n"
|
||||
"\tLogicalVolume[Path] [LogicalVolume[Path]...]\n",
|
||||
|
||||
alloc_ARG, mirrors_ARG, test_ARG)
|
||||
|
||||
xx(lvcreate,
|
||||
"Create a logical volume",
|
||||
"lvcreate " "\n"
|
||||
@@ -91,9 +104,11 @@ xx(lvcreate,
|
||||
"\t{-l|--extents LogicalExtentsNumber |\n"
|
||||
"\t -L|--size LogicalVolumeSize[kKmMgGtT]}\n"
|
||||
"\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n"
|
||||
"\t[-m|--mirrors Mirrors]\n"
|
||||
"\t[-n|--name LogicalVolumeName]\n"
|
||||
"\t[-p|--permission {r|rw}]\n"
|
||||
"\t[-r|--readahead ReadAheadSectors]\n"
|
||||
"\t[-R|--regionsize MirrorLogRegionSize]\n"
|
||||
"\t[-t|--test]\n"
|
||||
"\t[--type VolumeType]\n"
|
||||
"\t[-v|--verbose]\n"
|
||||
@@ -122,13 +137,14 @@ xx(lvcreate,
|
||||
"\tOriginalLogicalVolume[Path] [PhysicalVolumePath...]\n\n",
|
||||
|
||||
addtag_ARG, alloc_ARG, autobackup_ARG, chunksize_ARG, contiguous_ARG,
|
||||
extents_ARG, major_ARG, minor_ARG, name_ARG, permission_ARG,
|
||||
persistent_ARG, readahead_ARG, size_ARG, snapshot_ARG, stripes_ARG,
|
||||
stripesize_ARG, test_ARG, type_ARG, zero_ARG)
|
||||
extents_ARG, major_ARG, minor_ARG, mirrors_ARG, name_ARG, permission_ARG,
|
||||
persistent_ARG, readahead_ARG, regionsize_ARG, size_ARG, snapshot_ARG,
|
||||
stripes_ARG, stripesize_ARG, test_ARG, type_ARG, zero_ARG)
|
||||
|
||||
xx(lvdisplay,
|
||||
"Display information about a logical volume",
|
||||
"lvdisplay\n"
|
||||
"\t[-a|--all]\n"
|
||||
"\t[-c|--colon]\n"
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[-h|--help]\n"
|
||||
@@ -143,6 +159,7 @@ xx(lvdisplay,
|
||||
"\n"
|
||||
"lvdisplay --columns|-C\n"
|
||||
"\t[--aligned]\n"
|
||||
"\t[-a|--all]\n"
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[-h|--help]\n"
|
||||
"\t[--ignorelockingfailure]\n"
|
||||
@@ -159,9 +176,10 @@ xx(lvdisplay,
|
||||
"\t[--version]" "\n"
|
||||
"\t[LogicalVolume[Path] [LogicalVolume[Path]...]]\n",
|
||||
|
||||
aligned_ARG, colon_ARG, columns_ARG, disk_ARG, ignorelockingfailure_ARG,
|
||||
maps_ARG, noheadings_ARG, nosuffix_ARG, options_ARG, sort_ARG,
|
||||
partial_ARG, segments_ARG, separator_ARG, unbuffered_ARG, units_ARG)
|
||||
aligned_ARG, all_ARG, colon_ARG, columns_ARG, disk_ARG,
|
||||
ignorelockingfailure_ARG, maps_ARG, noheadings_ARG, nosuffix_ARG,
|
||||
options_ARG, sort_ARG, partial_ARG, segments_ARG, separator_ARG,
|
||||
unbuffered_ARG, units_ARG)
|
||||
|
||||
xx(lvextend,
|
||||
"Add space to a logical volume",
|
||||
@@ -173,6 +191,7 @@ xx(lvextend,
|
||||
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
|
||||
"\t{-l|--extents [+]LogicalExtentsNumber |\n"
|
||||
"\t -L|--size [+]LogicalVolumeSize[kKmMgGtT]}\n"
|
||||
"\t[-m|--mirrors Mirrors]\n"
|
||||
"\t[-n|--nofsck]\n"
|
||||
"\t[-r|--resizefs]\n"
|
||||
"\t[-t|--test]\n"
|
||||
@@ -181,8 +200,9 @@ xx(lvextend,
|
||||
"\t[--version]" "\n"
|
||||
"\tLogicalVolume[Path] [ PhysicalVolumePath... ]\n",
|
||||
|
||||
alloc_ARG, autobackup_ARG, extents_ARG, nofsck_ARG, resizefs_ARG,
|
||||
size_ARG, stripes_ARG, stripesize_ARG, test_ARG, type_ARG)
|
||||
alloc_ARG, autobackup_ARG, extents_ARG, mirrors_ARG, nofsck_ARG,
|
||||
resizefs_ARG, size_ARG, stripes_ARG, stripesize_ARG, test_ARG,
|
||||
type_ARG)
|
||||
|
||||
xx(lvmchange,
|
||||
"With the device mapper, this is obsolete and does nothing.",
|
||||
@@ -298,6 +318,7 @@ xx(lvresize,
|
||||
xx(lvs,
|
||||
"Display information about logical volumes",
|
||||
"lvs" "\n"
|
||||
"\t[-a|--all]\n"
|
||||
"\t[--aligned]\n"
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[-h|--help]\n"
|
||||
@@ -315,9 +336,9 @@ xx(lvs,
|
||||
"\t[--version]" "\n"
|
||||
"\t[LogicalVolume[Path] [LogicalVolume[Path]...]]\n",
|
||||
|
||||
aligned_ARG, ignorelockingfailure_ARG, noheadings_ARG, nolocking_ARG,
|
||||
nosuffix_ARG, options_ARG, partial_ARG, segments_ARG, separator_ARG,
|
||||
sort_ARG, unbuffered_ARG, units_ARG)
|
||||
aligned_ARG, all_ARG, ignorelockingfailure_ARG, noheadings_ARG,
|
||||
nolocking_ARG, nosuffix_ARG, options_ARG, partial_ARG, segments_ARG,
|
||||
separator_ARG, sort_ARG, unbuffered_ARG, units_ARG)
|
||||
|
||||
xx(lvscan,
|
||||
"List all logical volumes in all volume groups",
|
||||
@@ -773,6 +794,7 @@ xx(vgs,
|
||||
"Display information about volume groups",
|
||||
"vgs" "\n"
|
||||
"\t[--aligned]\n"
|
||||
"\t[-a|--all]\n"
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[-h|--help]\n"
|
||||
"\t[--ignorelockingfailure]\n"
|
||||
@@ -788,9 +810,9 @@ xx(vgs,
|
||||
"\t[--version]\n"
|
||||
"\t[VolumeGroupName [VolumeGroupName...]]\n",
|
||||
|
||||
aligned_ARG, ignorelockingfailure_ARG, noheadings_ARG, nolocking_ARG,
|
||||
nosuffix_ARG, options_ARG, partial_ARG, separator_ARG, sort_ARG,
|
||||
unbuffered_ARG, units_ARG)
|
||||
aligned_ARG, all_ARG, ignorelockingfailure_ARG, noheadings_ARG,
|
||||
nolocking_ARG, nosuffix_ARG, options_ARG, partial_ARG, separator_ARG,
|
||||
sort_ARG, unbuffered_ARG, units_ARG)
|
||||
|
||||
xx(vgscan,
|
||||
"Search for all volume groups",
|
||||
|
||||
@@ -405,6 +405,23 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (lv->status & MIRROR_LOG) {
|
||||
log_error("Unable to change mirror log LV %s directly", lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (lv->status & MIRROR_IMAGE) {
|
||||
log_error("Unable to change mirror image LV %s directly",
|
||||
lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(lv->status & VISIBLE_LV)) {
|
||||
log_error("Unable to change internal LV %s directly",
|
||||
lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
/* access permission change */
|
||||
if (arg_count(cmd, permission_ARG)) {
|
||||
if (!archive(lv->vg))
|
||||
|
||||
230
tools/lvconvert.c
Normal file
230
tools/lvconvert.c
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
struct lvconvert_params {
|
||||
struct list *pvh;
|
||||
};
|
||||
|
||||
static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * lv,
|
||||
struct list *allocatable_pvs)
|
||||
{
|
||||
struct lv_segment *first_seg;
|
||||
uint32_t mirrors, existing_mirrors;
|
||||
alloc_policy_t alloc = ALLOC_INHERIT;
|
||||
// struct alloc_handle *ah = NULL;
|
||||
// struct logical_volume *log_lv;
|
||||
|
||||
if (arg_count(cmd, alloc_ARG))
|
||||
alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, alloc);
|
||||
|
||||
mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1;
|
||||
|
||||
if ((mirrors == 1)) {
|
||||
if (!(lv->status & MIRRORED)) {
|
||||
log_error("Logical volume %s is already not mirrored.",
|
||||
lv->name);
|
||||
return 1;
|
||||
}
|
||||
/* FIXME If allocatable_pvs supplied only remove those */
|
||||
if (!remove_all_mirror_images(lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
} else { /* mirrors > 1 */
|
||||
if ((lv->status & MIRRORED)) {
|
||||
if (list_size(&lv->segments) != 1) {
|
||||
log_error("Logical volume %s has multiple "
|
||||
"mirror segments.", lv->name);
|
||||
return 0;
|
||||
}
|
||||
list_iterate_items(first_seg, &lv->segments)
|
||||
break;
|
||||
existing_mirrors = first_seg->area_count;
|
||||
if (mirrors == existing_mirrors) {
|
||||
log_error("Logical volume %s already has %"
|
||||
PRIu32 " mirror(s).", lv->name,
|
||||
mirrors - 1);
|
||||
return 1;
|
||||
}
|
||||
if (mirrors > existing_mirrors) {
|
||||
/* FIXME Unless anywhere, remove PV of log_lv
|
||||
* from allocatable_pvs & allocate
|
||||
* (mirrors - existing_mirrors) new areas
|
||||
*/
|
||||
/* FIXME Create mirror hierarchy to sync */
|
||||
log_error("Adding mirror images is not "
|
||||
"supported yet.");
|
||||
return 0;
|
||||
} else {
|
||||
if (!remove_mirror_images(first_seg, mirrors)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* FIXME Share code with lvcreate */
|
||||
/* region size, log_name, create log_lv, zero it */
|
||||
// Allocate (mirrors) new areas & log - replace mirrored_pv with mirrored_lv
|
||||
// Restructure as mirror - add existing param to create_mirror_layers
|
||||
log_error("Adding mirror images is not supported yet.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
|
||||
|
||||
if (!vg_write(lv->vg)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
backup(lv->vg);
|
||||
|
||||
if (!suspend_lv(cmd, lv->lvid.s)) {
|
||||
log_error("Failed to lock %s", lv->name);
|
||||
vg_revert(lv->vg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vg_commit(lv->vg)) {
|
||||
resume_lv(cmd, lv->lvid.s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_very_verbose("Updating \"%s\" in kernel", lv->name);
|
||||
|
||||
if (!resume_lv(cmd, lv->lvid.s)) {
|
||||
log_error("Problem reactivating %s", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_print("Logical volume %s converted.", lv->name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lvconvert_single(struct cmd_context * cmd, struct logical_volume * lv,
|
||||
int argc, char **argv, void *handle)
|
||||
{
|
||||
struct lvconvert_params *lp = handle;
|
||||
|
||||
if (lv->status & LOCKED) {
|
||||
log_error("Cannot convert locked LV %s", lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (lv_is_origin(lv)) {
|
||||
log_error("Can't convert logical volume \"%s\" under snapshot",
|
||||
lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (lv_is_cow(lv)) {
|
||||
log_error("Can't convert snapshot logical volume \"%s\"",
|
||||
lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (lv->status & PVMOVE) {
|
||||
log_error("Unable to convert pvmove LV %s", lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, mirrors_ARG)) {
|
||||
if (!archive(lv->vg))
|
||||
return ECMD_FAILED;
|
||||
if (!lvconvert_mirrors(cmd, lv, lp->pvh))
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
int lvconvert(struct cmd_context * cmd, int argc, char **argv)
|
||||
{
|
||||
const char *vg_name, *lv_name;
|
||||
char *st;
|
||||
int consistent = 1;
|
||||
struct volume_group *vg;
|
||||
struct lv_list *lvl;
|
||||
struct lvconvert_params lp;
|
||||
int ret = ECMD_FAILED;
|
||||
|
||||
if (!arg_count(cmd, mirrors_ARG)) {
|
||||
log_error("--mirrors argument required");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if (!argc) {
|
||||
log_error("Please give logical volume path(s)");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
lv_name = argv[0];
|
||||
argv++, argc--;
|
||||
|
||||
vg_name = extract_vgname(cmd, lv_name);
|
||||
|
||||
if (!validate_name(vg_name)) {
|
||||
log_error("Please provide a valid volume group name");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
if ((st = strrchr(lv_name, '/')))
|
||||
lv_name = st + 1;
|
||||
|
||||
log_verbose("Checking for existing volume group \"%s\"", vg_name);
|
||||
|
||||
if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
|
||||
log_error("Can't get lock for %s", vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg = vg_read(cmd, vg_name, &consistent))) {
|
||||
log_error("Volume group \"%s\" doesn't exist", vg_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group \"%s\" is exported", vg_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(vg->status & LVM_WRITE)) {
|
||||
log_error("Volume group \"%s\" is read-only", vg_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(lvl = find_lv_in_vg(vg, lv_name))) {
|
||||
log_error("Logical volume \"%s\" not found in "
|
||||
"volume group \"%s\"", lv_name, vg_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (argc) {
|
||||
if (!(lp.pvh = create_pv_list(cmd->mem, vg, argc, argv, 1))) {
|
||||
stack;
|
||||
goto error;
|
||||
}
|
||||
} else
|
||||
lp.pvh = &vg->pvs;
|
||||
|
||||
ret = lvconvert_single(cmd, lvl->lv, argc, argv, &lp);
|
||||
|
||||
error:
|
||||
unlock_vg(cmd, vg_name);
|
||||
return ret;
|
||||
}
|
||||
233
tools/lvcreate.c
233
tools/lvcreate.c
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "tools.h"
|
||||
#include "lv_alloc.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
@@ -31,6 +32,7 @@ struct lvcreate_params {
|
||||
uint32_t stripes;
|
||||
uint32_t stripe_size;
|
||||
uint32_t chunk_size;
|
||||
uint32_t region_size;
|
||||
|
||||
uint32_t mirrors;
|
||||
|
||||
@@ -135,10 +137,8 @@ static int _read_name_params(struct lvcreate_params *lp,
|
||||
if ((ptr = strrchr(lp->lv_name, '/')))
|
||||
lp->lv_name = ptr + 1;
|
||||
|
||||
/* FIXME Remove this restriction eventually */
|
||||
if (!strncmp(lp->lv_name, "snapshot", 8)) {
|
||||
log_error("Names starting \"snapshot\" are reserved. "
|
||||
"Please choose a different LV name.");
|
||||
if (!apply_lvname_restrictions(lp->lv_name)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -228,6 +228,38 @@ static int _read_stripe_params(struct lvcreate_params *lp,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_mirror_params(struct lvcreate_params *lp,
|
||||
struct cmd_context *cmd,
|
||||
int *pargc, char ***pargv)
|
||||
{
|
||||
int argc = *pargc;
|
||||
|
||||
if (argc && (unsigned) argc < lp->mirrors) {
|
||||
log_error("Too few physical volumes on "
|
||||
"command line for %d-way mirroring", lp->mirrors);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg_count(cmd, regionsize_ARG)) {
|
||||
if (arg_sign_value(cmd, regionsize_ARG, 0) == SIGN_MINUS) {
|
||||
log_error("Negative regionsize is invalid");
|
||||
return 0;
|
||||
}
|
||||
lp->region_size = 2 * arg_uint_value(cmd, regionsize_ARG, 0);
|
||||
} else
|
||||
lp->region_size = 2 * find_config_int(cmd->cft->root,
|
||||
"activation/mirror_region_size",
|
||||
DEFAULT_MIRROR_REGION_SIZE);
|
||||
|
||||
if (lp->region_size & (lp->region_size - 1)) {
|
||||
log_error("Region size (%" PRIu32 ") must be a power of 2",
|
||||
lp->region_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd,
|
||||
int argc, char **argv)
|
||||
{
|
||||
@@ -249,6 +281,18 @@ static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd,
|
||||
if (arg_count(cmd, snapshot_ARG) || seg_is_snapshot(lp))
|
||||
lp->snapshot = 1;
|
||||
|
||||
lp->mirrors = 1;
|
||||
|
||||
/* Default to 2 mirrored areas if --type mirror */
|
||||
if (seg_is_mirrored(lp))
|
||||
lp->mirrors = 2;
|
||||
|
||||
if (arg_count(cmd, mirrors_ARG)) {
|
||||
lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1;
|
||||
if (lp->mirrors == 1)
|
||||
log_print("Redundant mirrors argument: default is 0");
|
||||
}
|
||||
|
||||
if (lp->snapshot) {
|
||||
if (arg_count(cmd, zero_ARG)) {
|
||||
log_error("-Z is incompatible with snapshots");
|
||||
@@ -272,6 +316,25 @@ static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd,
|
||||
}
|
||||
}
|
||||
|
||||
if (lp->mirrors > 1) {
|
||||
if (lp->snapshot) {
|
||||
log_error("mirrors and snapshots are currently "
|
||||
"incompatible");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lp->stripes > 1) {
|
||||
log_error("mirrors and stripes are currently "
|
||||
"incompatible");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(lp->segtype = get_segtype_from_string(cmd, "mirror"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (activation() && lp->segtype->ops->target_present &&
|
||||
!lp->segtype->ops->target_present()) {
|
||||
log_error("%s: Required device-mapper target(s) not "
|
||||
@@ -281,8 +344,11 @@ static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd,
|
||||
|
||||
if (!_read_name_params(lp, cmd, &argc, &argv) ||
|
||||
!_read_size_params(lp, cmd, &argc, &argv) ||
|
||||
!_read_stripe_params(lp, cmd, &argc, &argv))
|
||||
!_read_stripe_params(lp, cmd, &argc, &argv) ||
|
||||
!_read_mirror_params(lp, cmd, &argc, &argv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Should we zero the lv.
|
||||
@@ -392,14 +458,18 @@ static int _zero_lv(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
|
||||
static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
{
|
||||
uint32_t size_rest;
|
||||
uint32_t size_rest, region_max;
|
||||
uint32_t status = 0;
|
||||
uint64_t tmp_size;
|
||||
struct volume_group *vg;
|
||||
struct logical_volume *lv, *org = NULL;
|
||||
struct logical_volume *lv, *org = NULL, *log_lv = NULL;
|
||||
struct list *pvh;
|
||||
const char *tag;
|
||||
int consistent = 1;
|
||||
struct alloc_handle *ah = NULL;
|
||||
char *log_name, lv_name_buf[128];
|
||||
const char *lv_name;
|
||||
size_t len;
|
||||
|
||||
status |= lp->permission | VISIBLE_LV;
|
||||
|
||||
@@ -427,6 +497,11 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lp->mirrors && !(vg->fid->fmt->features & FMT_SEGMENTS)) {
|
||||
log_error("Metadata does not support mirroring.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the pv list.
|
||||
*/
|
||||
@@ -505,30 +580,130 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lp->stripes > list_size(pvh)) {
|
||||
if (lp->stripes > list_size(pvh) && lp->alloc != ALLOC_ANYWHERE) {
|
||||
log_error("Number of stripes (%u) must not exceed "
|
||||
"number of physical volumes (%d)", lp->stripes,
|
||||
list_size(pvh));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(lv = lv_create_empty(vg->fid, lp->lv_name, "lvol%d", NULL,
|
||||
status, lp->alloc, 0, vg))) {
|
||||
stack;
|
||||
if (lp->mirrors > 1 && !activation()) {
|
||||
log_error("Can't create mirror without using "
|
||||
"device-mapper kernel driver.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The snapshot segment gets created later */
|
||||
if (lp->snapshot)
|
||||
if (!(lp->segtype = get_segtype_from_string(cmd, "striped"))) {
|
||||
if (lp->snapshot &&
|
||||
!(lp->segtype = get_segtype_from_string(cmd, "striped"))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!archive(vg))
|
||||
return 0;
|
||||
|
||||
if (lp->lv_name)
|
||||
lv_name = lp->lv_name;
|
||||
else {
|
||||
if (!generate_lv_name(vg, "lvol%d", lv_name_buf, sizeof(lv_name_buf))) {
|
||||
log_error("Failed to generate LV name.");
|
||||
return 0;
|
||||
}
|
||||
lv_name = &lv_name_buf[0];
|
||||
}
|
||||
|
||||
if (lp->mirrors > 1) {
|
||||
/* FIXME Adjust lp->region_size if necessary */
|
||||
region_max = (1 << (ffs(lp->extents) - 1)) * vg->extent_size;
|
||||
|
||||
if (region_max < lp->region_size) {
|
||||
lp->region_size = region_max;
|
||||
log_print("Using reduced mirror region size of %" PRIu32
|
||||
" sectors", lp->region_size);
|
||||
}
|
||||
|
||||
/* FIXME Calculate how many extents needed for the log */
|
||||
|
||||
len = strlen(lv_name) + 32;
|
||||
if (!(log_name = alloca(len))) {
|
||||
log_error("log_name allocation failed. "
|
||||
"Remove new LV and retry.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(log_name, len, "%s_mlog", lv_name) < 0) {
|
||||
log_error("log_name allocation failed. "
|
||||
"Remove new LV and retry.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (find_lv_in_vg(vg, log_name)) {
|
||||
if (lvm_snprintf(log_name, len, "%s_mlog_%%d",
|
||||
lv_name) < 0) {
|
||||
log_error("log_name allocation failed. "
|
||||
"Remove new LV and retry.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(log_lv = lv_create_empty(vg->fid, log_name, NULL,
|
||||
VISIBLE_LV | LVM_READ | LVM_WRITE,
|
||||
lp->alloc, 0, vg))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_extend(lv, lp->segtype, lp->stripes, lp->stripe_size,
|
||||
lp->mirrors, lp->extents, NULL, 0u, 0u, pvh, lp->alloc)) {
|
||||
if (!(ah = allocate_extents(vg, NULL, lp->segtype, lp->stripes,
|
||||
lp->mirrors, 1, lp->extents,
|
||||
NULL, 0, 0, pvh, lp->alloc))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_add_log_segment(ah, log_lv)) {
|
||||
stack;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* store mirror log on disk(s) */
|
||||
if (!vg_write(vg)) {
|
||||
stack;
|
||||
goto error;
|
||||
}
|
||||
|
||||
backup(vg);
|
||||
|
||||
if (!vg_commit(vg)) {
|
||||
stack;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!activate_lv(cmd, log_lv->lvid.s)) {
|
||||
log_error("Aborting. Failed to activate mirror log. "
|
||||
"Remove new LVs and retry.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (activation() && !_zero_lv(cmd, log_lv)) {
|
||||
log_error("Aborting. Failed to wipe mirror log. "
|
||||
"Remove new LV and retry.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(cmd, log_lv->lvid.s)) {
|
||||
log_error("Aborting. Failed to deactivate mirror log. "
|
||||
"Remove new LV and retry.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
log_lv->status &= ~VISIBLE_LV;
|
||||
}
|
||||
|
||||
if (!(lv = lv_create_empty(vg->fid, lv_name ? lv_name : "lvol%d", NULL,
|
||||
status, lp->alloc, 0, vg))) {
|
||||
stack;
|
||||
return 0;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (lp->read_ahead) {
|
||||
@@ -547,24 +722,37 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
if (arg_count(cmd, addtag_ARG)) {
|
||||
if (!(tag = arg_str_value(cmd, addtag_ARG, NULL))) {
|
||||
log_error("Failed to get tag");
|
||||
return 0;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(lv->vg->fid->fmt->features & FMT_TAGS)) {
|
||||
log_error("Volume group %s does not support tags",
|
||||
lv->vg->name);
|
||||
return 0;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!str_list_add(cmd->mem, &lv->tags, tag)) {
|
||||
log_error("Failed to add tag %s to %s/%s",
|
||||
tag, lv->vg->name, lv->name);
|
||||
return 0;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!archive(vg))
|
||||
if (lp->mirrors > 1) {
|
||||
if (!create_mirror_layers(ah, 0, lp->mirrors, lv,
|
||||
lp->segtype, 0,
|
||||
lp->region_size, log_lv)) {
|
||||
stack;
|
||||
goto error;
|
||||
}
|
||||
|
||||
alloc_destroy(ah);
|
||||
ah = NULL;
|
||||
} else if (!lv_extend(lv, lp->segtype, lp->stripes, lp->stripe_size,
|
||||
lp->mirrors, lp->extents, NULL, 0u, 0u, pvh, lp->alloc)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* store vg on disk(s) */
|
||||
if (!vg_write(vg)) {
|
||||
@@ -642,6 +830,11 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
*/
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
if (ah)
|
||||
alloc_destroy(ah);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lvcreate(struct cmd_context *cmd, int argc, char **argv)
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
static int _lvdisplay_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
void *handle)
|
||||
{
|
||||
if (!arg_count(cmd, all_ARG) && !(lv->status & VISIBLE_LV))
|
||||
return ECMD_PROCESSED;
|
||||
|
||||
if (arg_count(cmd, colon_ARG))
|
||||
lvdisplay_colons(lv);
|
||||
else {
|
||||
|
||||
@@ -34,6 +34,18 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (lv->status & MIRROR_IMAGE) {
|
||||
log_error("Can't remove logical volume %s used by a mirror",
|
||||
lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (lv->status & MIRROR_LOG) {
|
||||
log_error("Can't remove logical volume %s used as mirror log",
|
||||
lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (lv->status & LOCKED) {
|
||||
log_error("Can't remove locked LV %s", lv->name);
|
||||
return ECMD_FAILED;
|
||||
|
||||
@@ -83,10 +83,8 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
/* FIXME Remove this restriction eventually */
|
||||
if (!strncmp(lv_name_new, "snapshot", 8)) {
|
||||
log_error("Names starting \"snapshot\" are reserved. "
|
||||
"Please choose a different LV name.");
|
||||
if (!apply_lvname_restrictions(lv_name_new)) {
|
||||
stack;
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ struct lvresize_params {
|
||||
|
||||
uint32_t stripes;
|
||||
uint32_t stripe_size;
|
||||
uint32_t mirrors;
|
||||
|
||||
struct segment_type *segtype;
|
||||
|
||||
@@ -119,6 +120,7 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
|
||||
struct lvinfo info;
|
||||
uint32_t stripesize_extents = 0;
|
||||
uint32_t seg_stripes = 0, seg_stripesize = 0, seg_size = 0;
|
||||
uint32_t seg_mirrors = 0;
|
||||
uint32_t extents_used = 0;
|
||||
uint32_t size_rest;
|
||||
alloc_policy_t alloc;
|
||||
@@ -161,6 +163,13 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
|
||||
log_print("Varied striping not supported. Ignoring.");
|
||||
}
|
||||
|
||||
if (arg_count(cmd, mirrors_ARG)) {
|
||||
if (vg->fid->fmt->features & FMT_SEGMENTS)
|
||||
lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 1) + 1;
|
||||
else
|
||||
log_print("Mirrors not supported. Ignoring.");
|
||||
}
|
||||
|
||||
if (arg_count(cmd, stripesize_ARG)) {
|
||||
if (arg_sign_value(cmd, stripesize_ARG, 0) == SIGN_MINUS) {
|
||||
log_error("Stripesize may not be negative.");
|
||||
@@ -171,6 +180,10 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
|
||||
stripesize_ARG, 0);
|
||||
else
|
||||
log_print("Varied stripesize not supported. Ignoring.");
|
||||
if (lp->mirrors) {
|
||||
log_error("Mirrors and striping cannot be combined yet.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
lv = lvl->lv;
|
||||
@@ -277,13 +290,34 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
|
||||
}
|
||||
}
|
||||
|
||||
/* If extending, find mirrors of last segment */
|
||||
if ((lp->extents > lv->le_count)) {
|
||||
list_iterate_back_items(seg, &lv->segments) {
|
||||
if (seg_is_mirrored(seg))
|
||||
seg_mirrors = seg->area_count;
|
||||
else
|
||||
seg_mirrors = 0;
|
||||
break;
|
||||
}
|
||||
if (!arg_count(cmd, mirrors_ARG) && seg_mirrors) {
|
||||
log_print("Extending %" PRIu32 " mirror images.",
|
||||
seg_mirrors);
|
||||
lp->mirrors = seg_mirrors;
|
||||
}
|
||||
if ((arg_count(cmd, mirrors_ARG) || seg_mirrors) &&
|
||||
(lp->mirrors != seg_mirrors)) {
|
||||
log_error("Cannot vary number of mirrors in LV yet.");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
}
|
||||
|
||||
/* If reducing, find stripes, stripesize & size of last segment */
|
||||
if (lp->extents < lv->le_count) {
|
||||
extents_used = 0;
|
||||
|
||||
if (lp->stripes || lp->stripe_size)
|
||||
log_error("Ignoring stripes and stripesize arguments "
|
||||
"when reducing");
|
||||
if (lp->stripes || lp->stripe_size || lp->mirrors)
|
||||
log_error("Ignoring stripes, stripesize and mirrors "
|
||||
"arguments when reducing");
|
||||
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
seg_extents = seg->len;
|
||||
@@ -293,6 +327,11 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
|
||||
seg_stripes = seg->area_count;
|
||||
}
|
||||
|
||||
if (seg_is_mirrored(seg))
|
||||
seg_mirrors = seg->area_count;
|
||||
else
|
||||
seg_mirrors = 0;
|
||||
|
||||
if (lp->extents <= extents_used + seg_extents)
|
||||
break;
|
||||
|
||||
@@ -302,6 +341,7 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
|
||||
seg_size = lp->extents - extents_used;
|
||||
lp->stripe_size = seg_stripesize;
|
||||
lp->stripes = seg_stripes;
|
||||
lp->mirrors = seg_mirrors;
|
||||
}
|
||||
|
||||
if (lp->stripes > 1 && !lp->stripe_size) {
|
||||
@@ -347,6 +387,11 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
|
||||
lp->resize = LV_EXTEND;
|
||||
}
|
||||
|
||||
if (lp->mirrors && activation() &&
|
||||
lv_info(lv, &info, 0) && info.exists) {
|
||||
log_error("Mirrors cannot be resized while active yet.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (lv_is_origin(lv)) {
|
||||
if (lp->resize == LV_REDUCE) {
|
||||
@@ -456,7 +501,7 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
} else if (!lv_extend(lv, lp->segtype, lp->stripes,
|
||||
lp->stripe_size, 0u,
|
||||
lp->stripe_size, lp->mirrors,
|
||||
lp->extents - lv->le_count,
|
||||
NULL, 0u, 0u, pvh, alloc)) {
|
||||
stack;
|
||||
|
||||
@@ -24,9 +24,12 @@ static int _pvchange_single(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
struct pv_list *pvl;
|
||||
struct list mdas;
|
||||
uint64_t sector;
|
||||
uint32_t orig_pe_alloc_count;
|
||||
|
||||
const char *pv_name = dev_name(pv->dev);
|
||||
const char *tag = NULL;
|
||||
const char *orig_vg_name;
|
||||
char uuid[64];
|
||||
|
||||
int consistent = 1;
|
||||
int allocatable = 0;
|
||||
@@ -178,6 +181,24 @@ static int _pvchange_single(struct cmd_context *cmd, struct physical_volume *pv,
|
||||
pv_name);
|
||||
return 0;
|
||||
}
|
||||
if (!id_write_format(&pv->id, uuid, sizeof(uuid))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
log_verbose("Changing uuid of %s to %s.", pv_name, uuid);
|
||||
if (*pv->vg_name) {
|
||||
orig_vg_name = pv->vg_name;
|
||||
orig_pe_alloc_count = pv->pe_alloc_count;
|
||||
pv->vg_name = ORPHAN;
|
||||
pv->pe_alloc_count = 0;
|
||||
if (!(pv_write(cmd, pv, NULL, INT64_C(-1)))) {
|
||||
log_error("pv_write with new uuid failed "
|
||||
"for %s.", pv_name);
|
||||
return 0;
|
||||
}
|
||||
pv->vg_name = orig_vg_name;
|
||||
pv->pe_alloc_count = orig_pe_alloc_count;
|
||||
}
|
||||
}
|
||||
|
||||
log_verbose("Updating physical volume \"%s\"", pv_name);
|
||||
|
||||
@@ -140,7 +140,7 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
|
||||
struct lv_list *lvl;
|
||||
|
||||
/* FIXME Cope with non-contiguous => splitting existing segments */
|
||||
if (!(lv_mirr = lv_create_empty(vg->fid, NULL, "pvmove%d", NULL,
|
||||
if (!(lv_mirr = lv_create_empty(vg->fid, "pvmove%d", NULL,
|
||||
LVM_READ | LVM_WRITE,
|
||||
ALLOC_CONTIGUOUS, 0, vg))) {
|
||||
log_error("Creation of temporary pvmove LV failed");
|
||||
|
||||
@@ -35,6 +35,9 @@ static int _vgs_single(struct cmd_context *cmd, const char *vg_name,
|
||||
static int _lvs_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
void *handle)
|
||||
{
|
||||
if (!arg_count(cmd, all_ARG) && !(lv->status & VISIBLE_LV))
|
||||
return ECMD_PROCESSED;
|
||||
|
||||
if (!report_object(handle, lv->vg, lv, NULL, NULL, NULL))
|
||||
return ECMD_FAILED;
|
||||
|
||||
@@ -78,6 +81,9 @@ static int _pvsegs_sub_single(struct cmd_context *cmd, struct volume_group *vg,
|
||||
static int _lvsegs_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
void *handle)
|
||||
{
|
||||
if (!arg_count(cmd, all_ARG) && !(lv->status & VISIBLE_LV))
|
||||
return ECMD_PROCESSED;
|
||||
|
||||
return process_each_segment_in_lv(cmd, lv, handle, _segs_single);
|
||||
}
|
||||
|
||||
|
||||
@@ -110,9 +110,9 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
|
||||
int ret = 0;
|
||||
int consistent;
|
||||
|
||||
struct list *slh, *tags_arg;
|
||||
struct list *tags_arg;
|
||||
struct list *vgnames; /* VGs to process */
|
||||
struct str_list *sll;
|
||||
struct str_list *sll, *strl;
|
||||
struct volume_group *vg;
|
||||
struct list tags, lvnames;
|
||||
struct list arg_lvnames; /* Cmdline vgname or vgname/lvname */
|
||||
@@ -228,8 +228,8 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
|
||||
}
|
||||
}
|
||||
|
||||
list_iterate(slh, vgnames) {
|
||||
vgname = list_item(slh, struct str_list)->str;
|
||||
list_iterate_items(strl, vgnames) {
|
||||
vgname = strl->str;
|
||||
if (!vgname || !*vgname)
|
||||
continue; /* FIXME Unnecessary? */
|
||||
if (!lock_vol(cmd, vgname, lock_type)) {
|
||||
@@ -1012,3 +1012,48 @@ int exec_cmd(const char *command, const char *fscmd, const char *lv_path,
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int apply_lvname_restrictions(const char *name)
|
||||
{
|
||||
if (!strncmp(name, "snapshot", 8)) {
|
||||
log_error("Names starting \"snapshot\" are reserved. "
|
||||
"Please choose a different LV name.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strncmp(name, "pvmove", 6)) {
|
||||
log_error("Names starting \"pvmove\" are reserved. "
|
||||
"Please choose a different LV name.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strstr(name, "_mlog")) {
|
||||
log_error("Names including \"_mlog\" are reserved. "
|
||||
"Please choose a different LV name.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strstr(name, "_mimage")) {
|
||||
log_error("Names including \"_mimage\" are reserved. "
|
||||
"Please choose a different LV name.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int validate_vg_name(struct cmd_context *cmd, const char *vg_name)
|
||||
{
|
||||
char vg_path[PATH_MAX];
|
||||
|
||||
if (!validate_name(vg_name))
|
||||
return 0;
|
||||
|
||||
snprintf(vg_path, PATH_MAX, "%s%s", cmd->dev_dir, vg_name);
|
||||
if (path_exists(vg_path)) {
|
||||
log_error("%s: already exists in filesystem", vg_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -90,4 +90,8 @@ struct list *clone_pv_list(struct pool *mem, struct list *pvs);
|
||||
int exec_cmd(const char *command, const char *fscmd, const char *lv_path,
|
||||
const char *size);
|
||||
|
||||
int apply_lvname_restrictions(const char *name);
|
||||
|
||||
int validate_vg_name(struct cmd_context *cmd, const char *vg_name);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,10 +30,10 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd,
|
||||
if ((lv->status & SNAPSHOT) || lv_is_cow(lv))
|
||||
continue;
|
||||
|
||||
/* Can't deactive a pvmove LV */
|
||||
/* Can't deactive a pvmove or log LV */
|
||||
/* FIXME There needs to be a controlled way of doing this */
|
||||
if (((activate == CHANGE_AN) || (activate == CHANGE_ALN)) &&
|
||||
(lv->status & PVMOVE))
|
||||
((lv->status & PVMOVE) || (lv->status & MIRROR_LOG)))
|
||||
continue;
|
||||
|
||||
if (activate == CHANGE_AN) {
|
||||
|
||||
@@ -22,7 +22,6 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
|
||||
size_t max_lv, max_pv;
|
||||
uint32_t extent_size;
|
||||
char *vg_name;
|
||||
char vg_path[PATH_MAX];
|
||||
struct volume_group *vg;
|
||||
const char *tag;
|
||||
alloc_policy_t alloc;
|
||||
@@ -89,13 +88,7 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
|
||||
if (!strncmp(vg_name, cmd->dev_dir, strlen(cmd->dev_dir)))
|
||||
vg_name += strlen(cmd->dev_dir);
|
||||
|
||||
snprintf(vg_path, PATH_MAX, "%s%s", cmd->dev_dir, vg_name);
|
||||
if (path_exists(vg_path)) {
|
||||
log_error("%s: already exists in filesystem", vg_path);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!validate_name(vg_name)) {
|
||||
if (!validate_vg_name(cmd, vg_name)) {
|
||||
log_error("New volume group name \"%s\" is invalid", vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
@@ -140,6 +140,33 @@ static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to,
|
||||
}
|
||||
vg_to->pv_count += vg_from->pv_count;
|
||||
|
||||
/* Fix up LVIDs */
|
||||
list_iterate_items(lvl1, &vg_to->lvs) {
|
||||
union lvid *lvid1 = &lvl1->lv->lvid;
|
||||
char uuid[64];
|
||||
|
||||
list_iterate_items(lvl2, &vg_from->lvs) {
|
||||
union lvid *lvid2 = &lvl2->lv->lvid;
|
||||
|
||||
if (id_equal(&lvid1->id[1], &lvid2->id[1])) {
|
||||
if (!id_create(&lvid2->id[1])) {
|
||||
log_error("Failed to generate new "
|
||||
"random LVID for %s",
|
||||
lvl2->lv->name);
|
||||
goto error;
|
||||
}
|
||||
if (!id_write_format(&lvid2->id[1], uuid,
|
||||
sizeof(uuid))) {
|
||||
stack;
|
||||
goto error;
|
||||
}
|
||||
|
||||
log_verbose("Changed LVID for %s to %s",
|
||||
lvl2->lv->name, uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (!list_empty(&vg_from->lvs)) {
|
||||
struct list *lvh = vg_from->lvs.n;
|
||||
|
||||
|
||||
@@ -129,12 +129,12 @@ static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
|
||||
/* Are any segments of this LV on missing PVs? */
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg->area[s].type != AREA_PV)
|
||||
if (seg_type(seg, s) != AREA_PV)
|
||||
continue;
|
||||
|
||||
/* FIXME Also check for segs on deleted LVs */
|
||||
|
||||
pv = seg->area[s].u.pv.pvseg->pv;
|
||||
pv = seg_pv(seg, s);
|
||||
if (!pv || !pv->dev) {
|
||||
if (!_remove_lv(cmd, lv, &list_unsafe)) {
|
||||
stack;
|
||||
|
||||
@@ -51,7 +51,7 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv)
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!validate_name(vg_name_new)) {
|
||||
if (!validate_vg_name(cmd, vg_name_new)) {
|
||||
log_error("New volume group name \"%s\" is invalid",
|
||||
vg_name_new);
|
||||
return ECMD_FAILED;
|
||||
|
||||
@@ -78,10 +78,10 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to)
|
||||
list_iterate_items(seg, &lv->segments) {
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
/* FIXME Check AREA_LV too */
|
||||
if (seg->area[s].type != AREA_PV)
|
||||
if (seg_type(seg, s) != AREA_PV)
|
||||
continue;
|
||||
|
||||
pv = seg->area[s].u.pv.pvseg->pv;
|
||||
pv = seg_pv(seg, s);
|
||||
if (vg_with) {
|
||||
if (!pv_is_in_vg(vg_with, pv)) {
|
||||
log_error("Logical Volume %s "
|
||||
@@ -222,6 +222,12 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!validate_vg_name(cmd, vg_name_to)) {
|
||||
log_error("New volume group name \"%s\" is invalid",
|
||||
vg_name_to);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((active = lvs_in_vg_activated(vg_from))) {
|
||||
/* FIXME Remove this restriction */
|
||||
log_error("Logical volumes in \"%s\" must be inactive",
|
||||
|
||||
Reference in New Issue
Block a user