1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-12-27 00:23:49 +03:00

Compare commits

...

84 Commits

Author SHA1 Message Date
Alasdair Kergon
893ec9a302 1.01.05 2005-09-26 20:44:12 +00:00
Alasdair Kergon
05f65c38e6 Fix chunksize field in reports. 2005-09-23 17:06:01 +00:00
Alasdair Kergon
2e9d062ec0 Don't hide snapshots from default 'lvs' output. 2005-09-23 16:22:17 +00:00
Alasdair Kergon
6b0b394e61 Resync list.h with LVM2. 2005-09-22 12:06:34 +00:00
Alasdair Kergon
25621396c9 Remember increased buffer size and use for subsequent calls. 2005-09-20 18:04:28 +00:00
Alasdair Kergon
82aa0271f3 Explicitly initialise no_open_count 2005-09-20 16:39:12 +00:00
Alasdair Kergon
653cab13f8 On 'buffer full' condition, double buffer size and repeat ioctl. [Untested] 2005-09-19 14:29:17 +00:00
Alasdair Kergon
b526f86b49 Add is_dm_major() for use in duplicate device detection in lvmcache_add(). 2005-09-16 18:53:01 +00:00
Alasdair Kergon
53c0f00888 Really switch device number in lvmcache when it says it is doing so. 2005-09-16 18:44:52 +00:00
Alasdair Kergon
f0c4d9de40 Option for bitset memory allocation using malloc as well as pool. 2005-09-16 18:40:53 +00:00
Alasdair Kergon
03ef8cec83 Don't assume exactly two mirrors when parsing mirror status 2005-09-02 16:59:46 +00:00
Alasdair Kergon
85f2a2e8c2 Suppress fsync() error message on filesystems that don't support it. 2005-09-01 18:37:22 +00:00
Alasdair Kergon
584b3e6642 Fix yes_no_prompt() error handling. 2005-08-31 19:32:10 +00:00
Alasdair Kergon
39b7ef841d add comments to example conf file to warn about common filter line mistakes 2005-08-31 15:05:47 +00:00
Alasdair Kergon
aa16a9098d Fix termination of getopt_long() option array. 2005-08-18 19:40:19 +00:00
Alasdair Kergon
7b8c2707bc lvmconf.sh 2005-08-16 20:42:28 +00:00
Alasdair Kergon
60e26a31a7 Add copyright notice to lvmconf.sh and use unique exit codes. 2005-08-16 20:38:33 +00:00
Alasdair Kergon
3473c25c14 Add format1 dev_write debug messages. 2005-08-16 19:00:55 +00:00
Patrick Caulfield
e52f022026 clvmd no longer takes out locks for non-clusteed LVs,
and non-clustered LVs are only activated on the local node.
2005-08-16 08:25:09 +00:00
Alasdair Kergon
b1a7df8e43 Add clustered VG attribute to report. 2005-08-15 23:34:11 +00:00
Alasdair Kergon
0fd2479b7c Move lvconvert parameters into struct lvconvert_params. 2005-08-15 14:10:28 +00:00
Alasdair Kergon
273857f914 Add clustered VG flag to LV lock requests. 2005-08-15 13:24:46 +00:00
Alasdair Kergon
a08b85dbc8 Change LV locking macros to take lv instead of lvid. 2005-08-15 12:00:04 +00:00
Alasdair Kergon
a0aedf299a Prepare tools to support clustered mirrors. 2005-08-14 23:18:28 +00:00
Alasdair Kergon
3c61426844 Factor out generate_log_name_format(). 2005-08-12 20:02:21 +00:00
Alasdair Kergon
786f228076 Factor out adjusted_mirror_region_size() 2005-08-12 19:23:08 +00:00
Alasdair Kergon
004da28792 Move compose_log_line() into mirror directory. 2005-08-10 17:19:46 +00:00
Alasdair Kergon
6e2be6efb6 Don't kill idling clvmd threads. 2005-08-09 17:29:04 +00:00
Alasdair Kergon
a994dfcfbc Factor out _get_library_path(). 2005-08-09 17:24:21 +00:00
Patrick Caulfield
7a8ea2ac93 Don't send a signal to kill threads that are idling nicely as it upsets them.
This seems to cure bz#159727 on SMP systems.

Alasdair, can you include this patch in the lvm2-cluster package please ?
2005-08-09 10:39:57 +00:00
Alasdair Kergon
0da3965d19 Report 'buffer full' condition with v4 ioctl as well as with v1. 2005-08-08 18:40:17 +00:00
Alasdair Kergon
885fd7bb46 aoe 2005-08-08 17:55:35 +00:00
Alasdair Kergon
08771f9c89 Recognise aoe devices. 2005-08-08 17:54:23 +00:00
Alasdair Kergon
8be48195a5 post-release 2005-08-04 02:07:34 +00:00
Alasdair Kergon
98ce2d650e update po 2005-08-04 02:02:37 +00:00
Alasdair Kergon
3af327116a Fix lvconvert PV parameter in help string. 2005-08-04 01:50:17 +00:00
Alasdair Kergon
b75434db93 fix last checkin 2005-08-04 01:29:18 +00:00
Alasdair Kergon
04e912aacd Prevent snapshots getting activated in a clustered VG. 2005-08-04 01:27:25 +00:00
Alasdair Kergon
d7be352f87 Separate out _build_dev_string. 2005-08-04 01:15:30 +00:00
Alasdair Kergon
96be3ec22c Move zero_lv to toollib. 2005-08-04 01:14:36 +00:00
Alasdair Kergon
32e7e0d790 post-release 2005-08-02 21:46:49 +00:00
Alasdair Kergon
becc320e62 update vsn 2005-08-02 18:00:32 +00:00
Alasdair Kergon
7666ed57d1 Fix dmsetup ls -j and status --target with empty table. 2005-07-29 16:11:23 +00:00
AJ Lewis
5e61d0955e fix pool format handler to work with pvseg code 2005-07-26 21:48:18 +00:00
Alasdair Kergon
e8a4662ae7 post-release 2005-07-13 19:28:09 +00:00
Alasdair Kergon
a48da3bd3b update po 2005-07-13 19:23:48 +00:00
Alasdair Kergon
5f1a5d7b99 2.01.13 2005-07-13 19:15:09 +00:00
Alasdair Kergon
3e28a9db8f Fix pvmove segment splitting.
Abstract vg_validate.
2005-07-12 19:40:59 +00:00
Alasdair Kergon
ebf6071d77 Only make one attempt at contiguous allocation. 2005-07-12 14:50:45 +00:00
Alasdair Kergon
47a35fb9fb Fix lvm1 format metadata read. 2005-06-22 15:31:29 +00:00
Alasdair Kergon
48e88aba44 fix lvm1 non-mirror lvcreate 2005-06-22 14:56:14 +00:00
Benjamin Marzinski
b85f99c140 Fixing some makesfiles, so that the correct things link against pthreads.
Also changed dmevent so that in no longer links against pthreads, and
dynamically loads libdmevent.so.  Everything seems to work just fine like this.
2005-06-14 19:06:26 +00:00
Alasdair Kergon
0a5e0e1f71 preset pl to NULL 2005-06-14 18:29:12 +00:00
Alasdair Kergon
85dc22ebb7 missing fn defs 2005-06-14 18:22:31 +00:00
Alasdair Kergon
5c21526009 post-release 2005-06-14 18:22:22 +00:00
Alasdair Kergon
14dff1cefc 2.01.12 2005-06-14 17:59:57 +00:00
Alasdair Kergon
39fbb844f9 Various allocation-related pvmove fixes. 2005-06-14 17:54:48 +00:00
Patrick Caulfield
ca4e0c973a Log an error if clvmd can't resolve a host name got from CCS
Fix potential spin loop in clvmd
2005-06-14 10:35:02 +00:00
Alasdair Kergon
ecb42bee80 post-release 2005-06-13 14:53:07 +00:00
Alasdair Kergon
674ed2a9f3 2.01.11 2005-06-13 14:43:28 +00:00
Alasdair Kergon
252daf9717 Use matchpathcon mode parameter. 2005-06-13 13:13:15 +00:00
Alasdair Kergon
196b8eaad3 Use matchpathcon mode parameter 2005-06-13 13:11:48 +00:00
Patrick Caulfield
8e526ba1bf Don't defer closing of FDs in clvmd as it can cause trouble. 2005-06-13 10:16:21 +00:00
Alasdair Kergon
19225828d9 update version 2005-06-10 22:00:44 +00:00
Alasdair Kergon
7e594126be fix configure script to reenable selinux 2005-06-10 21:57:49 +00:00
AJ Lewis
d2529e6334 o print the context along with the path when setting selinux context 2005-06-10 21:30:21 +00:00
AJ Lewis
97344f18e2 o set umask and make tempfiles a bit nicer to deal with 2005-06-10 19:10:45 +00:00
AJ Lewis
33934db629 o script to adjust items in lvm.conf file - currently only handles turning
cluster lvm on and off
2005-06-10 17:11:48 +00:00
Patrick Caulfield
6c6165c9f5 Be a bit smarter about reading stuff from the sockets 2005-06-10 09:11:01 +00:00
Benjamin Marzinski
853460b20d Timeout event implementation:
The daemon side of this is mostly the same as the patch I sent out.  To select
a timeout period different than the default and to get the timeout period,
I added two library calls, dm_set_event_timeout() and dm_get_event_timeout().
If people are against them, the other option is to tack extra arguments onto
dm_regiser_for_event() and dm_get_registered_device().  I also added a
-t option to dmevent, so people can try out timeouts.
2005-06-09 18:40:49 +00:00
Alasdair Kergon
cc4d9676c5 Remove hard-coded 64k text metadata writing restriction. 2005-06-07 11:00:07 +00:00
Alasdair Kergon
1cf1b819f4 Make VG name restrictions consistent. 2005-06-06 18:16:33 +00:00
Alasdair Kergon
f916c66d2b Introduce lvconvert. So far only removes mirror images. 2005-06-06 17:12:08 +00:00
Alasdair Kergon
550aa86b45 prevent active mirror resize for now 2005-06-03 22:26:09 +00:00
Alasdair Kergon
014e764758 Allow mirror images to be resized. 2005-06-03 19:48:19 +00:00
Alasdair Kergon
d1fc28432b Allow mirror images to have more than one segment. 2005-06-03 18:07:13 +00:00
Alasdair Kergon
879576f0a2 lvremove mirror images 2005-06-03 15:44:12 +00:00
Alasdair Kergon
69098210be Always insert an intermediate layer for mirrors.
Suppress hidden LVs from reports unless --all is given.
Use square brackets for hidden LVs in reports.
Centralise restrictions on LV names.
2005-06-03 14:49:51 +00:00
Alasdair Kergon
99df4f892d Basic support for mirrors. 2005-06-01 16:51:55 +00:00
AJ Lewis
7bc04fbad3 Change the multilog code to toggle between async and sync writes for all
log types.  This means the threaded_syslog type is no longer valid.  A new
fxn multilog_async is available to toggle between the two modes.  If an
app is compiled without pthreads and tries to use async logging, no logging
will occur while async is enabled.

dmeventd has been modified to use the new code

I'm not positive I like the way the async_logger code calls the log fxn,
but it works for now.  Suggestions for other ways to do it would be helpful
2005-05-25 21:08:36 +00:00
Alasdair Kergon
8a74ce578d Fix non-orphan pvchange -u. 2005-05-24 17:38:26 +00:00
Alasdair Kergon
0805e4e5de Fix mem allocs after archiver code move. 2005-05-24 17:37:39 +00:00
Heinz Mauelshagen
f1060fc88e Exit after last unregister_for_event() 2005-05-20 13:53:26 +00:00
Alasdair Kergon
7d3d3d0a3a Fix vgmerge to handle duplicate LVIDs. 2005-05-19 16:48:51 +00:00
104 changed files with 5404 additions and 2824 deletions

View File

@@ -1 +1 @@
2.01.11-cvs (2005-05-03)
2.01.15-cvs (2005-08-04)

View File

@@ -1,5 +1,79 @@
Version 2.01.11 -
==============================
Version 2.01.15 -
=================================
Fix chunksize field in reports.
Don't hide snapshots from default 'lvs' output.
Add is_dm_major() for use in duplicate device detection in lvmcache_add().
Really switch device number in lvmcache when it says it is doing so.
Option for bitset memory allocation using malloc as well as pool.
Don't assume exactly two mirrors when parsing mirror status.
Suppress fsync() error message on filesystems that don't support it.
Fix yes_no_prompt() error handling.
Add lvm.conf comment warning against multiple filter lines.
Tidy lvmconf.sh.
Add format1 dev_write debug messages.
Add clustered VG attribute to report.
Move lvconvert parameters into struct lvconvert_params.
Add clustered VG flag to LV lock requests.
Change LV locking macros to take lv instead of lvid.
Prepend 'cluster' activation parameter to mirror log when appropriate.
Pass exclusive flag to lv_activate and on to target activation code.
Prevent snapshot creation in a clustered VG for now.
Factor out adjusted_mirror_region_size() and generate_log_name_format().
Move compose_log_line() into mirror directory.
Factor out _get_library_path().
Don't kill idling clvmd threads.
clvmd no longer takes out locks for non-clustered LVs.
Recognise ATA over Ethernet (aoe) devices.
Version 2.01.14 - 4th August 2005
=================================
Fix lvconvert PV parameter in help string.
Prevent snapshots getting activated in a clustered VG.
Separate out _build_dev_string.
Move zero_lv to toollib.
Fix pool format handler to work with pv segment code.
Version 2.01.13 - 13th July 2005
================================
Fix pvmove segment splitting.
Abstract vg_validate.
Only make one attempt at contiguous allocation.
Fix lvm1 format metadata read.
Fix lvm1 format non-mirror lvcreate.
Version 2.01.12 - 14th June 2005
================================
Various allocation-related pvmove fixes.
Log an error if clvmd can't resolve a host name got from CCS.
Fix potential spin loop in clvmd.
Version 2.01.11 - 13th June 2005
================================
Added lvmconf.sh.
Use matchpathcon mode parameter.
Don't defer closing dead FDs in clvmd.
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.

View File

@@ -1,3 +1,20 @@
Version 1.01.05 - 26 Sep 2005
=============================
Resync list.h with LVM2.
Remember increased buffer size and use for subsequent calls.
On 'buffer full' condition, double buffer size and repeat ioctl.
Fix termination of getopt_long() option array.
Report 'buffer full' condition with v4 ioctl as well as with v1.
Version 1.01.04 - 2 Aug 2005
============================
Fix dmsetup ls -j and status --target with empty table.
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.

View File

@@ -109,7 +109,7 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
case CLVMD_CMD_LOCK_LV:
/* This is the biggie */
lock_cmd = args[0];
lock_cmd = args[0] & 0x3F;
lock_flags = args[1];
lockname = &args[2];
status = do_lock_lv(lock_cmd, lock_flags, lockname);
@@ -161,7 +161,7 @@ static int lock_vg(struct local_client *client)
client->bits.localsock.private = (void *)lock_hash;
}
lock_cmd = args[0];
lock_cmd = args[0] & 0x3F;
lock_flags = args[1];
lockname = &args[2];
DEBUGLOG("doing PRE command LOCK_VG '%s' at %x (client=%p)\n", lockname, lock_cmd, client);

View File

@@ -944,7 +944,13 @@ static int get_all_cluster_nodes()
}
else
{
DEBUGLOG("node %s has clvm disabled\n", nodename);
if (!clvmflag) {
DEBUGLOG("node %s has clvm disabled\n", nodename);
}
else {
DEBUGLOG("Cannot resolve host name %s\n", nodename);
log_err("Cannot resolve host name %s\n", nodename);
}
}
free(nodename);
}

View File

@@ -512,6 +512,10 @@ static void main_loop(int local_sock, int cmd_timeout)
FD_ZERO(&in);
for (thisfd = &local_client_head; thisfd != NULL;
thisfd = thisfd->next) {
if (thisfd->removeme)
continue;
/* if the cluster is not quorate then don't listen for new requests */
if ((thisfd->type != LOCAL_RENDEZVOUS &&
thisfd->type != LOCAL_SOCK) || quorate)
@@ -578,6 +582,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);
@@ -742,6 +747,7 @@ static int read_from_local_sock(struct local_client *thisfd)
/* If the client went away in mid command then tidy up */
if (thisfd->bits.localsock.in_progress) {
pthread_kill(thisfd->bits.localsock.threadid, SIGUSR2);
pthread_mutex_lock(&thisfd->bits.localsock.mutex);
thisfd->bits.localsock.state = POST_COMMAND;
pthread_cond_signal(&thisfd->bits.localsock.cond);
@@ -758,7 +764,6 @@ static int read_from_local_sock(struct local_client *thisfd)
thisfd->bits.localsock.state = PRE_COMMAND;
pthread_cond_signal(&thisfd->bits.localsock.cond);
pthread_mutex_unlock(&thisfd->bits.localsock.mutex);
pthread_kill(thisfd->bits.localsock.threadid, SIGUSR2);
jstat =
pthread_join(thisfd->bits.localsock.threadid,
@@ -1610,7 +1615,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;

View File

@@ -168,11 +168,12 @@ int hold_unlock(char *resource)
*/
/* Activate LV exclusive or non-exclusive */
static int do_activate_lv(char *resource, int mode)
static int do_activate_lv(char *resource, unsigned char lock_flags, int mode)
{
int oldmode;
int status;
int activate_lv;
int exclusive = 0;
struct lvinfo lvi;
/* Is it already open ? */
@@ -189,13 +190,17 @@ static int do_activate_lv(char *resource, int mode)
return 0; /* Success, we did nothing! */
/* Do we need to activate exclusively? */
if (activate_lv == 2)
if ((activate_lv == 2) || (mode == LKM_EXMODE)) {
exclusive = 1;
mode = LKM_EXMODE;
}
/* OK, try to get the lock */
status = hold_lock(resource, mode, LKF_NOQUEUE);
if (status)
return errno;
/* Try to get the lock if it's a clustered volume group */
if (lock_flags & LCK_CLUSTER_VG) {
status = hold_lock(resource, mode, LKF_NOQUEUE);
if (status)
return errno;
}
/* If it's suspended then resume it */
if (!lv_info_by_lvid(cmd, resource, &lvi, 0))
@@ -206,7 +211,7 @@ static int do_activate_lv(char *resource, int mode)
return EIO;
/* Now activate it */
if (!lv_activate(cmd, resource))
if (!lv_activate(cmd, resource, exclusive))
return EIO;
return 0;
@@ -255,14 +260,14 @@ static int do_suspend_lv(char *resource)
return 0;
}
static int do_deactivate_lv(char *resource)
static int do_deactivate_lv(char *resource, unsigned char lock_flags)
{
int oldmode;
int status;
/* Is it open ? */
oldmode = get_current_lock(resource);
if (oldmode == -1) {
if (oldmode == -1 && (lock_flags & LCK_CLUSTER_VG)) {
DEBUGLOG("do_deactivate_lock, lock not already held\n");
return 0; /* We don't need to do anything */
}
@@ -270,9 +275,11 @@ static int do_deactivate_lv(char *resource)
if (!lv_deactivate(cmd, resource))
return EIO;
status = hold_unlock(resource);
if (status)
return errno;
if (lock_flags & LCK_CLUSTER_VG) {
status = hold_unlock(resource);
if (status)
return errno;
}
return 0;
}
@@ -283,7 +290,7 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
{
int status = 0;
DEBUGLOG("do_lock_lv: resource '%s', cmd = 0x%x, flags = %d\n",
DEBUGLOG("do_lock_lv: resource '%s', cmd = 0x%x, flags = %x\n",
resource, command, lock_flags);
if (!cmd->config_valid || config_files_changed(cmd)) {
@@ -296,7 +303,7 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
switch (command) {
case LCK_LV_EXCLUSIVE:
status = do_activate_lv(resource, LKM_EXMODE);
status = do_activate_lv(resource, lock_flags, LKM_EXMODE);
break;
case LCK_LV_SUSPEND:
@@ -309,11 +316,11 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
break;
case LCK_LV_ACTIVATE:
status = do_activate_lv(resource, LKM_CRMODE);
status = do_activate_lv(resource, lock_flags, LKM_CRMODE);
break;
case LCK_LV_DEACTIVATE:
status = do_deactivate_lv(resource);
status = do_deactivate_lv(resource, lock_flags);
break;
default:
@@ -433,23 +440,24 @@ static void drop_vg_locks()
*/
static void *get_initial_state()
{
char lv[64], vg[64], flags[25];
char lv[64], vg[64], flags[25], vg_flags[25];
char uuid[65];
char line[255];
FILE *lvs =
popen
("lvm lvs --nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr",
("lvm lvs --nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr,vg_attr",
"r");
if (!lvs)
return NULL;
while (fgets(line, sizeof(line), lvs)) {
if (sscanf(line, "%s %s %s\n", vg, lv, flags) == 3) {
if (sscanf(line, "%s %s %s %s\n", vg, lv, flags, vg_flags) == 4) {
/* States: s:suspended a:active S:dropped snapshot I:invalid snapshot */
if (strlen(vg) == 38 && /* is is a valid UUID ? */
(flags[4] == 'a' || flags[4] == 's')) { /* is it active or suspended? */
(flags[4] == 'a' || flags[4] == 's') && /* is it active or suspended? */
vg_flags[5] == 'c') { /* is it clustered ? */
/* Convert hyphen-separated UUIDs into one */
memcpy(&uuid[0], &vg[0], 6);
memcpy(&uuid[6], &vg[7], 4);

View File

@@ -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

View File

@@ -28,7 +28,7 @@ else
LIB_SHARED = libdmeventdnoop.so
endif
LDFLAGS += -ldl -ldevmapper -lpthread -lmultilog
LDFLAGS += -ldl -ldevmapper -lmultilog
include ../make.tmpl
@@ -36,11 +36,11 @@ libdmeventdnoop.so: noop.o
dmevent: dmevent.o $(interfacedir)/libdevmapper.$(LIB_SUFFIX) $(top_srcdir)/lib/event/libdmevent.$(LIB_SUFFIX)
$(CC) -o $@ dmevent.o $(LDFLAGS) \
-L$(interfacedir) -L$(DESTDIR)/lib -L$(top_srcdir)/lib/event -L$(top_srcdir)/multilog -ldmevent $(LIBS)
-L$(interfacedir) -L$(DESTDIR)/lib -L$(top_srcdir)/lib/event -L$(top_srcdir)/multilog $(LIBS)
dmeventd: dmeventd.o $(interfacedir)/libdevmapper.$(LIB_SUFFIX) $(top_srcdir)/lib/event/libdmevent.$(LIB_SUFFIX)
$(CC) -o $@ dmeventd.o $(LDFLAGS) \
-L$(interfacedir) -L$(DESTDIR)/lib -L$(top_srcdir)/lib/event -L$(top_srcdir)/multilog -ldmevent $(LIBS)
-L$(interfacedir) -L$(DESTDIR)/lib -L$(top_srcdir)/lib/event -L$(top_srcdir)/multilog -lpthread -ldmevent $(LIBS)
install: $(INSTALL_TYPE)

View File

@@ -26,10 +26,23 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
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;
struct event_ops {
int (*dm_register_for_event)(char *dso_name, char *device,
enum event_type event_types);
int (*dm_unregister_for_event)(char *dso_name, char *device,
enum event_type event_types);
int (*dm_get_registered_device)(char **dso_name, char **device,
enum event_type *event_types, int next);
int (*dm_set_event_timeout)(char *device, uint32_t time);
int (*dm_get_event_timeout)(char *device, uint32_t *time);
};
/* Display help. */
static void print_usage(char *name)
@@ -45,6 +58,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 +68,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 +84,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;
@@ -92,21 +114,48 @@ static int parse_argv(int argc, char **argv, char **dso_name_arg,
return 1;
}
static int lookup_symbol(void *dl, void **symbol, const char *name)
{
if ((*symbol = dlsym(dl, name)))
return 1;
fprintf(stderr, "error looking up %s symbol: %s\n", name, dlerror());
return 0;
}
static int lookup_symbols(void *dl, struct event_ops *e)
{
return lookup_symbol(dl, (void *) &e->dm_register_for_event,
"dm_register_for_event") &&
lookup_symbol(dl, (void *) &e->dm_unregister_for_event,
"dm_unregister_for_event") &&
lookup_symbol(dl, (void *) &e->dm_get_registered_device,
"dm_get_registered_device") &&
lookup_symbol(dl, (void *) &e->dm_set_event_timeout,
"dm_set_event_timeout") &&
lookup_symbol(dl, (void *) &e->dm_get_event_timeout,
"dm_get_event_timeout");
}
int main(int argc, char **argv)
{
void *dl;
struct event_ops e;
int list = 0, next = 0, ret, reg = default_reg;
char *device, *device_arg = NULL, *dso_name, *dso_name_arg = NULL;
if (!parse_argv(argc, argv, &dso_name_arg, &device_arg, &reg, &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 {
@@ -118,34 +167,54 @@ int main(int argc, char **argv)
multilog_add_type(standard, NULL);
multilog_init_verbose(standard, _LOG_DEBUG);
if (!(dl = dlopen("libdmevent.so", RTLD_NOW))){
fprintf(stderr, "Cannot dlopen libdmevent.so: %s\n", dlerror());
goto out;
}
if (!(lookup_symbols(dl, &e)))
goto out;
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= e.dm_get_registered_device(&dso_name,
&device,
&events, next)))
break;
printf("%s %s 0x%x", dso_name, device, events);
if (events & TIMEOUT){
if ((ret = e.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;
}
if ((ret = reg ? dm_register_for_event(dso_name, device, events) :
dm_unregister_for_event(dso_name, device, events))) {
if ((ret = reg ? e.dm_register_for_event(dso_name, device, events) :
e.dm_unregister_for_event(dso_name, device, events))) {
fprintf(stderr, "Failed to %sregister %s: %s\n",
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 = e.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:

View File

@@ -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);

View File

@@ -33,8 +33,12 @@ devices {
# pattern, the device is accepted; otherwise if any name matches any 'r'
# pattern it is rejected; otherwise it is accepted.
# Remember to run vgscan after you change this parameter to ensure
# that the cache file gets regenerated (see below).
# Don't have more than one filter line active at once: only one gets used.
# Run vgscan after you change this parameter to ensure that
# the cache file gets regenerated (see below).
# If it doesn't do what you expect, check the output of 'vgscan -vvvv'.
# By default we accept every block device:
filter = [ "a/.*/" ]

View File

@@ -130,11 +130,11 @@ int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
{
return 1;
}
int lv_activate(struct cmd_context *cmd, const char *lvid_s)
int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive)
{
return 1;
}
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s)
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive)
{
return 1;
}
@@ -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;
@@ -705,7 +701,8 @@ int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
return 1;
}
static int _lv_activate(struct cmd_context *cmd, const char *lvid_s, int filter)
static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
int exclusive, int filter)
{
struct logical_volume *lv;
struct lvinfo info;
@@ -736,6 +733,9 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s, int filter)
if (info.exists && !info.suspended)
return 1;
if (exclusive)
lv->status |= ACTIVATE_EXCL;
memlock_inc();
r = _lv_activate_lv(lv);
memlock_dec();
@@ -745,15 +745,15 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s, int filter)
}
/* Activate LV */
int lv_activate(struct cmd_context *cmd, const char *lvid_s)
int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive)
{
return _lv_activate(cmd, lvid_s, 0);
return _lv_activate(cmd, lvid_s, exclusive, 0);
}
/* Activate LV only if it passes filter */
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s)
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s, int exclusive)
{
return _lv_activate(cmd, lvid_s, 1);
return _lv_activate(cmd, lvid_s, exclusive, 1);
}
int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)

View File

@@ -46,8 +46,9 @@ int lv_suspend(struct cmd_context *cmd, const char *lvid_s);
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s);
int lv_resume(struct cmd_context *cmd, const char *lvid_s);
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s);
int lv_activate(struct cmd_context *cmd, const char *lvid_s);
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s);
int lv_activate(struct cmd_context *cmd, const char *lvid_s, int exclusive);
int lv_activate_with_filter(struct cmd_context *cmd, const char *lvid_s,
int exclusive);
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s);
int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv);

View File

@@ -727,21 +727,24 @@ static int _emit_target_line(struct dev_manager *dm, struct dm_task *dmt,
return 1;
}
int compose_log_line(struct dev_manager *dm, struct lv_segment *seg,
char *params, size_t paramsize, int *pos, int areas,
uint32_t region_size)
int build_dev_string(struct dev_manager *dm, char *dlid, char *devbuf,
size_t bufsize, const char *desc)
{
int tw;
struct dev_layer *dl;
tw = lvm_snprintf(params, paramsize, "core 1 %u %u ",
region_size, areas);
if (tw < 0) {
stack;
return -1;
if (!(dl = hash_lookup(dm->layers, dlid))) {
log_error("%s device layer %s missing from hash",
desc, dlid);
return 0;
}
*pos += tw;
if (!dm_format_dev(devbuf, bufsize, dl->info.major,
dl->info.minor)) {
log_error("Failed to format %s device number for %s as dm "
"target (%u,%u)",
desc, dlid, dl->info.major, dl->info.minor);
return 0;
}
return 1;
}
@@ -754,48 +757,39 @@ int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
int tw = 0;
const char *trailing_space;
uint64_t esize = seg->lv->vg->extent_size;
struct dev_layer *dl;
char devbuf[10];
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))) {
log_error("device layer %s missing from hash",
seg->area[s].u.lv.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);
else if (seg_type(seg, s) == AREA_LV) {
if (!build_dev_string(dm, seg_lv(seg, s)->lvid.s, devbuf,
sizeof(devbuf), "LV")) {
stack;
return 0;
}
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);
} else {
log_error("Internal error: Unassigned area found in LV %s.",
seg->lv->name);
return 0;
}
if (tw < 0) {
@@ -842,14 +836,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;
@@ -864,22 +856,14 @@ static int _populate_origin(struct dev_manager *dm,
{
char *real;
char params[PATH_MAX + 32];
struct dev_layer *dlr;
if (!(real = _build_dlid(dm->mem, dl->lv->lvid.s, "real"))) {
stack;
return 0;
}
if (!(dlr = hash_lookup(dm->layers, real))) {
log_error("Couldn't find real device layer %s in hash", real);
return 0;
}
if (!dm_format_dev(params, sizeof(params), dlr->info.major,
dlr->info.minor)) {
log_error("Couldn't create origin device parameters for '%s'.",
real);
if (!build_dev_string(dm, real, params, sizeof(params), "origin")) {
stack;
return 0;
}
@@ -900,7 +884,6 @@ static int _populate_snapshot(struct dev_manager *dm,
char *origin, *cow;
char params[PATH_MAX * 2 + 32];
struct lv_segment *snap_seg;
struct dev_layer *dlo, *dlc;
char devbufo[10], devbufc[10];
uint64_t size;
@@ -920,28 +903,13 @@ static int _populate_snapshot(struct dev_manager *dm,
return 0;
}
if (!(dlo = hash_lookup(dm->layers, origin))) {
log_error("Couldn't find origin device layer %s in hash",
origin);
if (!build_dev_string(dm, origin, devbufo, sizeof(devbufo), "origin")) {
stack;
return 0;
}
if (!(dlc = hash_lookup(dm->layers, cow))) {
log_error("Couldn't find cow device layer %s in hash", cow);
return 0;
}
if (!dm_format_dev(devbufo, sizeof(devbufo), dlo->info.major,
dlo->info.minor)) {
log_error("Couldn't create origin device parameters for '%s'.",
snap_seg->origin->name);
return 0;
}
if (!dm_format_dev(devbufc, sizeof(devbufc), dlc->info.major,
dlc->info.minor)) {
log_error("Couldn't create cow device parameters for '%s'.",
snap_seg->cow->name);
if (!build_dev_string(dm, cow, devbufc, sizeof(devbufc), "cow")) {
stack;
return 0;
}
@@ -1201,7 +1169,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,19 +1186,30 @@ 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) {
// When do we need? _set_flag(dl, REMOVE) on the log?
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;
}
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;
}
// ? if (seg_lv(seg, s)->status & PVMOVE)
_set_flag(dl, NOPROPAGATE);
// When do we need? _set_flag(dl, REMOVE)
}
}
@@ -1300,14 +1278,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);
}
@@ -1382,11 +1360,19 @@ static int _expand_lv(struct dev_manager *dm, struct logical_volume *lv)
/*
* FIXME: this doesn't cope with recursive snapshots yet.
*/
if ((snap_seg = find_cow(lv)))
if ((snap_seg = find_cow(lv))) {
if (lv->vg->status & CLUSTERED) {
log_error("Clustered snapshots are not yet supported");
return 0;
}
return _expand_snapshot(dm, lv, snap_seg);
else if (lv_is_origin(lv))
} else if (lv_is_origin(lv)) {
if (lv->vg->status & CLUSTERED) {
log_error("Clustered snapshots are not yet supported");
return 0;
}
return _expand_origin(dm, lv);
}
return _expand_vanilla(dm, lv, 0);
}
@@ -1411,12 +1397,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 +1452,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 +1477,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 +1511,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 +1549,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 +1561,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 +1618,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 +1666,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 +1689,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 +1715,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 +1738,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 +1926,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 +1942,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 +1956,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 +1977,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 +1993,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 +2015,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 +2032,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 +2081,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 +2097,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;
}

View File

@@ -180,7 +180,7 @@ static int _mk_link(const char *dev_dir, const char *vg_name,
}
#ifdef HAVE_SELINUX
if (!set_selinux_context(lv_path)) {
if (!set_selinux_context(lv_path, S_IFLNK)) {
stack;
return 0;
}

View File

@@ -23,8 +23,7 @@ int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
char *params, size_t paramsize, int *pos,
int start_area, int areas);
int compose_log_line(struct dev_manager *dm, struct lv_segment *seg,
char *params, size_t paramsize, int *pos, int areas,
uint32_t region_size);
int build_dev_string(struct dev_manager *dm, char *dlid, char *devbuf,
size_t bufsize, const char *desc);
#endif

40
lib/cache/lvmcache.c vendored
View File

@@ -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) {
@@ -498,17 +495,32 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
pvid, dev_name(dev),
dev_name(existing->dev));
return NULL;
} else if (is_dm_major(MAJOR(existing->dev->dev)) &&
!is_dm_major(MAJOR(dev->dev))) {
log_very_verbose("Ignoring duplicate PV %s on "
"%s - using dm %s",
pvid, dev_name(dev),
dev_name(existing->dev));
return NULL;
} else if (MAJOR(existing->dev->dev) != md_major() &&
MAJOR(dev->dev) == md_major())
log_very_verbose("Duplicate PV %s on %s - "
"using md %s", pvid,
dev_name(existing->dev),
dev_name(dev));
else if (!is_dm_major(MAJOR(existing->dev->dev)) &&
is_dm_major(MAJOR(dev->dev)))
log_very_verbose("Duplicate PV %s on %s - "
"using dm %s", pvid,
dev_name(existing->dev),
dev_name(dev));
else
log_error("Found duplicate PV %s: using %s not "
"%s", pvid, dev_name(dev),
dev_name(existing->dev));
}
/* Switch over to new preferred device */
existing->dev = dev;
info = existing;
/* Has labeller changed? */
if (info->label->labeller != labeller) {

View File

@@ -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;

View File

@@ -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"

View File

@@ -23,12 +23,21 @@ bitset_t bitset_create(struct pool *mem, unsigned num_bits)
{
unsigned n = (num_bits / BITS_PER_INT) + 2;
size_t size = sizeof(int) * n;
unsigned *bs = pool_zalloc(mem, size);
bitset_t bs;
if (mem)
bs = pool_zalloc(mem, size);
else
bs = dbg_malloc(size);
if (!bs)
return NULL;
*bs = num_bits;
if (!mem)
bit_clear_all(bs);
return bs;
}

View File

@@ -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.
*/

View File

@@ -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;
}
@@ -247,6 +247,8 @@ static int _insert_dev(const char *path, dev_t d)
/* Generate pretend device numbers for loopfiles */
if (!d) {
if (hash_lookup(_cache.names, path))
return 1;
d = ++loopfile_count;
loopfile = 1;
}
@@ -414,20 +416,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);
@@ -631,6 +629,10 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
if (!d) {
_insert(name, 0);
d = (struct device *) hash_lookup(_cache.names, name);
if (!d) {
_full_scan(0);
d = (struct device *) hash_lookup(_cache.names, name);
}
}
return (d && (!f || (d->flags & DEV_REGULAR) ||

View File

@@ -449,30 +449,31 @@ 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);
break;
case AREA_UNASSIGNED:
log_print("%sUnassigned area", pre);
}
}

View File

@@ -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));

View File

@@ -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) {

View File

@@ -19,6 +19,7 @@
#include "lvm-string.h"
#include "config.h"
#include "metadata.h"
#include "bitset.h"
#include <dirent.h>
#include <unistd.h>
@@ -38,12 +39,18 @@ typedef struct {
} device_info_t;
static int _md_major = -1;
static bitset_t _dm_bitset;
int md_major(void)
{
return _md_major;
}
int is_dm_major(int major)
{
return bit(_dm_bitset, major) ? 1 : 0;
}
/*
* Devices are only checked for partition tables if their minor number
* is a multiple of the number corresponding to their type below
@@ -71,6 +78,7 @@ static const device_info_t device_info[] = {
{"iseries/vd", 8}, /* iSeries disks */
{"gnbd", 1}, /* Network block device */
{"ramdisk", 1}, /* RAM disk */
{"aoe", 16}, /* ATA over Ethernet */
{NULL, 0}
};
@@ -180,6 +188,11 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn)
if (!strncmp("md", line + i, 2) && isspace(*(line + i + 2)))
_md_major = line_maj;
/* Look for dm devices */
if (!strncmp("device-mapper", line + i, 13) &&
isspace(*(line + i + 13)))
bit_set(_dm_bitset, line_maj);
/* Go through the valid device names and if there is a
match store max number of partitions */
for (j = 0; device_info[j].name != NULL; j++) {
@@ -250,6 +263,12 @@ struct dev_filter *lvm_type_filter_create(const char *proc,
f->destroy = lvm_type_filter_destroy;
f->private = NULL;
if (!(_dm_bitset = bitset_create(NULL, NUMBER_OF_MAJORS))) {
stack;
dbg_free(f);
return NULL;
}
if (!_scan_proc_dev(proc, cn)) {
stack;
return NULL;
@@ -260,6 +279,7 @@ struct dev_filter *lvm_type_filter_create(const char *proc,
void lvm_type_filter_destroy(struct dev_filter *f)
{
bitset_destroy(_dm_bitset);
dbg_free(f);
return;
}

View File

@@ -36,7 +36,7 @@ struct dev_filter *lvm_type_filter_create(const char *proc,
void lvm_type_filter_destroy(struct dev_filter *f);
int md_major(void);
int is_dm_major(int major);
int max_partitions(int major);
#endif

View File

@@ -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);
@@ -506,6 +506,9 @@ static int _write_vgd(struct disk_list *data)
struct vg_disk *vgd = &data->vgd;
uint64_t pos = data->pvd.vg_on_disk.base;
log_debug("Writing %s VG metadata to %s at %" PRIu64 " len %" PRIsize_t,
data->pvd.vg_name, dev_name(data->dev), pos, sizeof(*vgd));
_xlate_vgd(vgd);
if (!dev_write(data->dev, pos, sizeof(*vgd), vgd))
fail;
@@ -518,18 +521,20 @@ 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);
log_debug("Writing %s uuidlist to %s at %" PRIu64 " len %"
PRIsize_t, data->pvd.vg_name, dev_name(data->dev),
pos, NAME_LEN);
if (!dev_write(data->dev, pos, NAME_LEN, ul->uuid))
fail;
@@ -541,6 +546,10 @@ static int _write_uuids(struct disk_list *data)
static int _write_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
{
log_debug("Writing %s LV %s metadata to %s at %" PRIu64 " len %"
PRIsize_t, disk->vg_name, disk->lv_name, dev_name(dev),
pos, sizeof(*disk));
_xlate_lvd(disk);
if (!dev_write(dev, pos, sizeof(*disk), disk))
fail;
@@ -552,7 +561,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 +572,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);
@@ -585,6 +592,10 @@ static int _write_extents(struct disk_list *data)
struct pe_disk *extents = data->extents;
uint64_t pos = data->pvd.pe_on_disk.base;
log_debug("Writing %s extents metadata to %s at %" PRIu64 " len %"
PRIsize_t, data->pvd.vg_name, dev_name(data->dev),
pos, len);
_xlate_extents(extents, data->pvd.pe_total);
if (!dev_write(data->dev, pos, len, extents))
fail;
@@ -617,6 +628,10 @@ static int _write_pvd(struct disk_list *data)
memset(buf, 0, size);
memcpy(buf, &data->pvd, sizeof(struct pv_disk));
log_debug("Writing %s PV metadata to %s at %" PRIu64 " len %"
PRIsize_t, data->pvd.vg_name, dev_name(data->dev),
pos, size);
_xlate_pvd((struct pv_disk *) buf);
if (!dev_write(data->dev, pos, size, buf)) {
dbg_free(buf);
@@ -704,11 +719,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;

View File

@@ -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;

View File

@@ -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);
@@ -241,7 +241,7 @@ int import_vg(struct pool *mem,
vg->extent_size = vgd->pe_size;
vg->extent_count = vgd->pe_total;
vg->free_count = vgd->pe_total - vgd->pe_allocated;
vg->free_count = vgd->pe_total;
vg->max_lv = vgd->lv_max;
vg->max_pv = vgd->pv_max;
vg->alloc = ALLOC_NORMAL;
@@ -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) {
log_error("LV stripe found in LV %s: "
if (seg_type(seg, s) != AREA_PV) {
log_error("Non-PV 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;
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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 lvmcache_info *info;
struct pool_list *pl = NULL;
struct pool *tmpmem = NULL;
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);

View File

@@ -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;

View File

@@ -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);
@@ -48,7 +45,7 @@ int import_pool_vg(struct volume_group *vg, struct pool *mem, struct list *pls)
get_pool_vg_uuid(&vg->id, &pl->pd);
vg->extent_size = POOL_PE_SIZE;
vg->status |= LVM_READ | LVM_WRITE | CLUSTERED | SHARED;
vg->free_count = 0;
vg->free_count = vg->extent_count;
vg->max_lv = 1;
vg->max_pv = POOL_MAX_DEVICES;
vg->alloc = ALLOC_NORMAL;
@@ -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;
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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,29 +458,31 @@ 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) ? "" : ",");
break;
case AREA_UNASSIGNED:
return 0;
}
}
@@ -467,24 +491,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 +563,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 +598,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 +612,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 +666,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 +721,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 +734,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 +748,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 +761,4 @@ int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
}
#undef outf
#undef outnl

View File

@@ -52,9 +52,12 @@ static struct flag _lv_flags[] = {
{VISIBLE_LV, "VISIBLE"},
{PVMOVE, "PVMOVE"},
{LOCKED, "LOCKED"},
{MIRROR_IMAGE, NULL},
{MIRROR_LOG, NULL},
{MIRRORED, NULL},
{VIRTUAL, NULL},
{SNAPSHOT, NULL},
{ACTIVATE_EXCL, NULL},
{0, NULL}
};

View File

@@ -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;
}
@@ -672,7 +666,7 @@ static int _vg_write_file(struct format_instance *fid, struct volume_group *vg,
return 0;
}
if (fsync(fd)) {
if (fsync(fd) && (errno != EROFS) && (errno != EINVAL)) {
log_sys_error("fsync", tc->path_edit);
fclose(fp);
return 0;
@@ -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;

View File

@@ -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);

View File

@@ -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;
@@ -366,13 +364,9 @@ int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
stack;
return 0;
}
/*
* 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 +430,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;
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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))) {

View File

@@ -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;

View File

@@ -327,8 +327,8 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
args = alloca(len);
strcpy(args + 2, name);
args[0] = flags & 0xBF; /* Maskoff LOCAL flag */
args[1] = 0; /* Not used now */
args[0] = flags & 0x7F; /* Maskoff lock flags */
args[1] = flags & 0xC0; /* Bitmap flags */
/*
* VG locks are just that: locks, and have no side effects
@@ -339,7 +339,8 @@ static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
*/
if (cmd == CLVMD_CMD_LOCK_VG ||
(flags & LCK_TYPE_MASK) == LCK_EXCL ||
(flags & LCK_LOCAL))
(flags & LCK_LOCAL) ||
!(flags & LCK_CLUSTER_VG))
node = ".";
status = _cluster_request(cmd, node, args, len,

View File

@@ -243,7 +243,7 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
break;
case LCK_READ:
log_debug("Locking LV %s (R)", resource);
if (!lv_activate_with_filter(cmd, resource))
if (!lv_activate_with_filter(cmd, resource, 0))
return 0;
break;
case LCK_WRITE:
@@ -253,7 +253,7 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
break;
case LCK_EXCL:
log_debug("Locking LV %s (EX)", resource);
if (!lv_activate_with_filter(cmd, resource))
if (!lv_activate_with_filter(cmd, resource, 1))
return 0;
break;
default:

View File

@@ -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);
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)) {
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);
}
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)) {
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);
}
return 0;

View File

@@ -65,6 +65,7 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
#define LCK_NONBLOCK 0x00000010 /* Don't block waiting for lock? */
#define LCK_HOLD 0x00000020 /* Hold lock when lock_vol returns? */
#define LCK_LOCAL 0x00000040 /* Don't propagate to other nodes */
#define LCK_CLUSTER_VG 0x00000080 /* VG is clustered */
/*
* Common combinations
@@ -79,22 +80,27 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
#define LCK_LV_ACTIVATE (LCK_LV | LCK_READ | LCK_NONBLOCK)
#define LCK_LV_DEACTIVATE (LCK_LV | LCK_NULL | LCK_NONBLOCK)
#define LCK_LV_CLUSTERED(lv) \
(((lv)->vg->status & CLUSTERED) ? LCK_CLUSTER_VG : 0)
#define lock_lv_vol(cmd, lv, flags) \
lock_vol(cmd, (lv)->lvid.s, flags | LCK_LV_CLUSTERED(lv))
#define unlock_vg(cmd, vol) lock_vol(cmd, vol, LCK_VG_UNLOCK)
#define resume_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_RESUME)
#define suspend_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_SUSPEND | LCK_HOLD)
#define deactivate_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_DEACTIVATE)
#define activate_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_ACTIVATE | LCK_HOLD)
#define activate_lv_excl(cmd, vol) \
lock_vol(cmd, vol, LCK_LV_EXCLUSIVE | LCK_HOLD)
#define activate_lv_local(cmd, vol) \
lock_vol(cmd, vol, LCK_LV_ACTIVATE | LCK_HOLD | LCK_LOCAL)
#define deactivate_lv_local(cmd, vol) \
lock_vol(cmd, vol, LCK_LV_DEACTIVATE | LCK_LOCAL)
#define resume_lv(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_RESUME)
#define suspend_lv(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_SUSPEND | LCK_HOLD)
#define deactivate_lv(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_DEACTIVATE)
#define activate_lv(cmd, lv) lock_lv_vol(cmd, lv, LCK_LV_ACTIVATE | LCK_HOLD)
#define activate_lv_excl(cmd, lv) \
lock_lv_vol(cmd, lv, LCK_LV_EXCLUSIVE | LCK_HOLD)
#define activate_lv_local(cmd, lv) \
lock_lv_vol(cmd, lv, LCK_LV_ACTIVATE | LCK_HOLD | LCK_LOCAL)
#define deactivate_lv_local(cmd, lv) \
lock_lv_vol(cmd, lv, LCK_LV_DEACTIVATE | LCK_LOCAL)
/* Process list of LVs */
int suspend_lvs(struct cmd_context *cmd, struct list *lvs);
int resume_lvs(struct cmd_context *cmd, struct list *lvs);
int activate_lvs_excl(struct cmd_context *cmd, struct list *lvs);

View File

@@ -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);

View File

@@ -58,11 +58,11 @@ static int _no_lock_resource(struct cmd_context *cmd, const char *resource,
case LCK_UNLOCK:
return lv_resume_if_active(cmd, resource);
case LCK_READ:
return lv_activate_with_filter(cmd, resource);
return lv_activate_with_filter(cmd, resource, 0);
case LCK_WRITE:
return lv_suspend_if_active(cmd, resource);
case LCK_EXCL:
return lv_activate_with_filter(cmd, resource);
return lv_activate_with_filter(cmd, resource, 1);
default:
break;
}

View File

@@ -22,17 +22,62 @@ 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);
int move_lv_segment_area(struct lv_segment *seg_to, uint32_t area_to,
struct lv_segment *seg_from, uint32_t area_from);
void release_lv_segment_area(struct lv_segment *seg, uint32_t s,
uint32_t area_reduction);
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

View File

@@ -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,65 @@ 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_UNASSIGNED) {
log_error("LV %s: segment %u has unassigned "
"area %u.",
lv->name, seg_count, s);
r = 0;
} else 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;
}
/* FIXME I don't think this ever holds?
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 +155,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,38 +183,38 @@ 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 (!(seg_pvseg(split_seg, s) =
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)) {
split_seg, s))) {
stack;
return 0;
}
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);
case AREA_UNASSIGNED:
log_error("Unassigned area %u found in segment", s);
return 0;
}
}
@@ -192,5 +247,10 @@ int lv_split_segment(struct logical_volume *lv, uint32_t le)
return 0;
}
if (!vg_validate(lv->vg)) {
stack;
return 0;
}
return 1;
}

View File

@@ -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,16 +458,16 @@ 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;
return 0;
}
break;
default:
log_error("Unrecognised segment type "
"%u", seg->area[s].type);
case AREA_UNASSIGNED:
log_error("Unassigned area %u found in "
"segment", 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;
@@ -723,18 +697,38 @@ int vg_remove(struct volume_group *vg)
return 1;
}
int vg_validate(struct volume_group *vg)
{
struct lv_list *lvl;
if (!check_pv_segments(vg)) {
log_error("Internal error: PV segments corrupted in %s.",
vg->name);
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;
}
}
return 1;
}
/*
* After vg_write() returns success,
* caller MUST call either vg_commit() or vg_revert()
*/
int vg_write(struct volume_group *vg)
{
struct list *mdah, *mdah2;
struct list *mdah;
struct metadata_area *mda;
if (!check_pv_segments(vg)) {
log_error("Internal error: PV segments corrupted in %s.",
vg->name);
if (!vg_validate(vg)) {
stack;
return 0;
}
@@ -752,14 +746,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 +764,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 +777,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 +798,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 +815,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 +824,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 +840,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 +863,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 +893,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 +936,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 +979,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))) ||
@@ -1074,7 +1056,27 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
int *consistent)
{
return _vg_read(cmd, vgname, consistent, 0);
struct volume_group *vg;
struct lv_list *lvl;
if (!(vg = _vg_read(cmd, vgname, consistent, 0)))
return NULL;
if (!check_pv_segments(vg)) {
log_error("Internal error: PV segments corrupted in %s.",
vg->name);
return NULL;
}
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 NULL;
}
}
return vg;
}
struct volume_group *vg_read_precommitted(struct cmd_context *cmd,
@@ -1091,9 +1093,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 +1127,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 +1234,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 +1265,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;

View File

@@ -55,6 +55,9 @@
#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 ACTIVATE_EXCL 0x00080000 /* LV - internal use only */
#define LVM_READ 0x00000100 /* LV VG */
#define LVM_WRITE 0x00000200 /* LV VG */
@@ -79,6 +82,7 @@ typedef enum {
} alloc_policy_t;
typedef enum {
AREA_UNASSIGNED = 0,
AREA_PV,
AREA_LV
} area_type_t;
@@ -228,8 +232,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 +254,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;
@@ -378,6 +392,7 @@ struct format_handler {
/*
* Utility functions
*/
int vg_validate(struct volume_group *vg);
int vg_write(struct volume_group *vg);
int vg_commit(struct volume_group *vg);
int vg_revert(struct volume_group *vg);
@@ -425,16 +440,18 @@ 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,
int import,
struct volume_group *vg);
/* Entry point for all LV extent reductions */
/* Reduce the size of an LV by extents */
int lv_reduce(struct logical_volume *lv, uint32_t extents);
/* Empty an LV prior to deleting it */
int lv_empty(struct logical_volume *lv);
/* Entry point for all LV extent allocations */
int lv_extend(struct logical_volume *lv,
struct segment_type *segtype,
@@ -492,7 +509,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
@@ -526,6 +543,20 @@ int vg_remove_snapshot(struct logical_volume *cow);
/*
* Mirroring functions
*/
struct alloc_handle;
uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
uint32_t region_size);
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 remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors);
int remove_all_mirror_images(struct logical_volume *lv);
int insert_pvmove_mirrors(struct cmd_context *cmd,
struct logical_volume *lv_mirr,
struct list *source_pvl,
@@ -548,6 +579,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 +594,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;

View File

@@ -20,6 +20,161 @@
#include "display.h"
#include "activate.h"
#include "lv_alloc.h"
#include "lvm-string.h"
/*
* Ensure region size is compatible with volume size.
*/
uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
uint32_t region_size)
{
uint32_t region_max;
region_max = (1 << (ffs(extents) - 1)) * extent_size;
if (region_max < region_size) {
region_size = region_max;
log_print("Using reduced mirror region size of %" PRIu32
" sectors", region_max);
return region_max;
}
return region_size;
}
/*
* 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,10 +188,11 @@ 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;
struct physical_volume *pv;
uint32_t pe;
int lv_used = 0;
uint32_t s, start_le, extent_count = 0u;
struct segment_type *segtype;
@@ -59,16 +215,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 +259,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 +277,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 */
@@ -139,25 +292,26 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
lv_used = 1;
}
pv = seg_pv(seg, s);
pe = seg_pe(seg, s);
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->area_len - 1,
pe, pe + seg->area_len - 1,
lv->vg->name, lv->name);
start_le = lv_mirr->le_count;
/* FIXME Clean this up */
release_lv_segment_area(seg, s, seg->area_len);
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,
pv, pe,
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 +332,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 +362,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");
@@ -226,22 +378,22 @@ int remove_pvmove_mirrors(struct volume_group *vg,
else
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)) {
if (!move_lv_segment_area(seg, s, mir_seg, c)) {
stack;
return 0;
}
/* Replace mirror with old area */
release_lv_segment_area(mir_seg, !c, mir_seg->area_len);
/* Replace mirror with error segment */
if (!
(mir_seg->segtype =
get_segtype_from_string(vg->cmd,
"striped"))) {
log_error("Missing striped segtype");
"error"))) {
log_error("Missing error segtype");
return 0;
}
mir_seg->area_count = 1;
mir_seg->area_count = 0;
/* FIXME Assumes only one pvmove at a time! */
lv1->status &= ~LOCKED;
@@ -252,22 +404,24 @@ int remove_pvmove_mirrors(struct volume_group *vg,
}
if (!lv_empty(lv_mirr)) {
stack;
return 0;
}
return 1;
}
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)
if (seg_type(seg, 0) != 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 +429,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 +447,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);
if (seg->area[0].type != AREA_PV)
list_iterate_items(seg, &lv->segments) {
if (seg_type(seg, 0) != AREA_PV)
continue;
if (seg->area[0].u.pv.pvseg->pv->dev != dev)
if (seg_dev(seg, 0) != dev)
continue;
return lv;
}
@@ -338,9 +489,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 +503,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 +533,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))

View File

@@ -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);

View File

@@ -100,6 +100,11 @@ static int _pv_split_segment(struct physical_volume *pv, struct pv_segment *peg,
list_add_h(&peg->list, &peg_new->list);
if (peg->lvseg) {
peg->pv->pe_alloc_count -= peg_new->len;
peg->lvseg->lv->vg->free_count += peg_new->len;
}
return 1;
}
@@ -162,12 +167,24 @@ struct pv_segment *assign_peg_to_lvseg(struct physical_volume *pv,
peg->lvseg = seg;
peg->lv_area = area_num;
peg->pv->pe_alloc_count += area_len;
peg->lvseg->lv->vg->free_count -= area_len;
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) {
if (!peg->lvseg) {
log_error("release_pv_segment with unallocated segment: "
"%s PE %" PRIu32, dev_name(peg->pv->dev), peg->pe);
return 0;
}
if (peg->lvseg->area_len == area_reduction) {
peg->pv->pe_alloc_count -= area_reduction;
peg->lvseg->lv->vg->free_count += area_reduction;
peg->lvseg = NULL;
peg->lv_area = 0;
@@ -176,7 +193,8 @@ 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 -
area_reduction)) {
stack;
return 0;
}
@@ -203,13 +221,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 +242,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;
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);
@@ -120,6 +165,47 @@ static struct mirror_state *_init_target(struct pool *mem,
return mirr_state;
}
static int _compose_log_line(struct dev_manager *dm, struct lv_segment *seg,
char *params, size_t paramsize, int *pos,
int areas, uint32_t region_size)
{
int tw;
char devbuf[10];
const char *clustered = "";
/*
* Use clustered mirror log for non-exclusive activation
* in clustered VG.
*/
if ((!(seg->lv->status & ACTIVATE_EXCL) &&
(seg->lv->vg->status & CLUSTERED)))
clustered = "cluster ";
if (!seg->log_lv)
tw = lvm_snprintf(params, paramsize, "%score 1 %u %u ",
clustered, region_size, areas);
else {
if (!build_dev_string(dm, seg->log_lv->lvid.s, devbuf,
sizeof(devbuf), "log")) {
stack;
return 0;
}
/* FIXME add sync parm? */
tw = lvm_snprintf(params, paramsize, "%sdisk 2 %s %u %u ",
clustered, devbuf, region_size, areas);
}
if (tw < 0) {
stack;
return -1;
}
*pos += tw;
return 1;
}
static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
struct config_tree *cft, void **target_state,
struct lv_segment *seg, char *params,
@@ -156,19 +242,27 @@ 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,
areas, region_size)) <= 0) {
if ((ret = _compose_log_line(dm, seg, params, paramsize, pos,
areas, region_size)) <= 0) {
stack;
return ret;
}
@@ -185,18 +279,41 @@ static int _target_percent(void **target_state, struct pool *mem,
{
struct mirror_state *mirr_state;
uint64_t numerator, denominator;
unsigned mirror_count, m;
int used;
char *pos = params;
if (!*target_state)
*target_state = _init_target(mem, cft);
mirr_state = *target_state;
/* Status line: <#mirrors> (maj:min)+ <synced>/<total_regions> */
log_debug("Mirror status: %s", params);
if (sscanf(params, "%*d %*x:%*x %*x:%*x %" PRIu64
"/%" PRIu64, &numerator, &denominator) != 2) {
log_error("Failure parsing mirror status: %s", params);
if (sscanf(pos, "%u %n", mirror_count, used) != 1) {
log_error("Failure parsing mirror status mirror count: %s",
params);
return 0;
}
pos += used;
for (m = 0; m < mirror_count; m++) {
if (sscanf(pos, "%*x:%*x %n", &used) != 0) {
log_error("Failure parsing mirror status devices: %s",
params);
return 0;
}
pos += used;
}
if (sscanf(pos, "%" PRIu64 "/%" PRIu64 "%n", &numerator, &denominator,
&used) != 2) {
log_error("Failure parsing mirror status fraction: %s", params);
return 0;
}
pos += used;
*total_numerator += numerator;
*total_denominator += denominator;

View File

@@ -236,7 +236,7 @@ void sync_dir(const char *file)
goto out;
}
if (fsync(fd) == -1)
if (fsync(fd) && (errno != EROFS) && (errno != EINVAL))
log_sys_error("fsync", dir);
close(fd);

View File

@@ -18,25 +18,28 @@
#include <selinux/selinux.h>
int set_selinux_context(const char *path)
int set_selinux_context(const char *path, mode_t mode)
{
security_context_t scontext;
log_very_verbose("Setting SELinux context for %s", path);
if (is_selinux_enabled() <= 0)
return 1;
if (matchpathcon(path, 0, &scontext) < 0) {
log_sys_error("matchpathcon", path);
if (matchpathcon(path, mode, &scontext) < 0) {
log_error("%s: matchpathcon %07o failed: %s", path, mode,
strerror(errno));
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);
freecon(scontext);
return 0;
}
free(scontext);
freecon(scontext);
return 1;
}

View File

@@ -15,6 +15,8 @@
#ifndef _LVM_SELINUX_H
#define _LVM_SELINUX_H
int set_selinux_context(const char * path);
#include <sys/types.h>
int set_selinux_context(const char * path, mode_t mode);
#endif

View File

@@ -22,21 +22,28 @@
#include <sys/stat.h>
#include <dlfcn.h>
void *load_shared_library(struct config_tree *cft, const char *libname,
const char *desc)
static void _get_library_path(struct config_tree *cft, const char *libname,
char *path, int path_len)
{
char path[PATH_MAX];
struct stat info;
const char *lib_dir;
void *library;
/* If libname doesn't begin with '/' then use lib_dir/libname,
* if present */
if (libname[0] == '/' ||
!(lib_dir = find_config_str(cft->root, "global/library_dir", 0)) ||
(lvm_snprintf(path, sizeof(path), "%s/%s", lib_dir,
(lvm_snprintf(path, path_len, "%s/%s", lib_dir,
libname) == -1) || stat(path, &info) == -1)
strncpy(path, libname, sizeof(path));
strncpy(path, libname, path_len);
}
void *load_shared_library(struct config_tree *cft, const char *libname,
const char *desc)
{
char path[PATH_MAX];
void *library;
_get_library_path(cft, libname, path, sizeof(path));
log_very_verbose("Opening shared %s library %s", desc, path);

View File

@@ -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;
}

View File

@@ -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")
@@ -66,7 +67,8 @@ FIELD(VGS, vg, STR, "VG Tags", tags, 7, tags, "vg_tags")
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, "Chunk", list, 5, chunksize, "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")

View File

@@ -154,17 +154,17 @@ 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";
case AREA_UNASSIGNED:
name = "unassigned";
extent = 0;
}
@@ -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))
@@ -428,7 +432,7 @@ static int _vgstatus_disp(struct report_handle *rh, struct field *field,
const struct volume_group *vg = (const struct volume_group *) data;
char *repstr;
if (!(repstr = pool_zalloc(rh->mem, 6))) {
if (!(repstr = pool_zalloc(rh->mem, 7))) {
log_error("pool_alloc failed");
return 0;
}
@@ -455,6 +459,11 @@ static int _vgstatus_disp(struct report_handle *rh, struct field *field,
repstr[4] = _alloc_policy_char(vg->alloc);
if (vg->status & CLUSTERED)
repstr[5] = 'c';
else
repstr[5] = '-';
field->report_string = repstr;
field->sort_value = (const void *) field->report_string;
@@ -490,19 +499,69 @@ 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;
/* FIXME Remove need for snapshot special case */
if (lv->status & VISIBLE_LV || lv_is_cow(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);
}
@@ -601,6 +660,21 @@ static int _segsize_disp(struct report_handle *rh, struct field *field,
return _size64_disp(rh, field, &size);
}
static int _chunksize_disp(struct report_handle *rh, struct field *field,
const void *data)
{
const struct lv_segment *seg = (const struct lv_segment *) data;
struct lv_segment *snap_seg;
uint64_t size;
if ((snap_seg = find_cow(seg->lv)))
size = (uint64_t) snap_seg->chunk_size;
else
size = 0;
return _size64_disp(rh, field, &size);
}
static int _pvused_disp(struct report_handle *rh, struct field *field,
const void *data)
{
@@ -917,12 +991,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 +1209,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 +1238,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 +1299,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 +1317,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 +1334,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 +1402,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 +1411,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);

View File

@@ -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)
@@ -115,14 +115,15 @@ static int _segments_compatible(struct lv_segment *first,
/* FIXME Relax this to first area type != second area type */
/* plus the additional AREA_LV checks needed */
if ((first->area[s].type != AREA_PV) ||
(second->area[s].type != AREA_PV)) return 0;
(second->area[s].type != AREA_PV))
return 0;
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 +145,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;
}

View File

@@ -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.
*/

View File

@@ -63,6 +63,7 @@ static int _log_suppress = 0;
static int _control_fd = -1;
static int _version_checked = 0;
static int _version_ok = 1;
static unsigned _ioctl_buffer_double_factor = 0;
/*
* Support both old and new major numbers to ease the transition.
@@ -219,7 +220,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;
}
@@ -610,8 +611,10 @@ static int _dm_task_run_v1(struct dm_task *dmt)
if (dmt->type == DM_DEVICE_TABLE)
dmi->flags |= DM_STATUS_TABLE_FLAG;
log_debug("dm %s %s %s %s", _cmd_data_v1[dmt->type].name, dmi->name,
dmi->uuid, dmt->newname ? dmt->newname : "");
log_debug("dm %s %s %s%s%s [%u]", _cmd_data_v1[dmt->type].name,
dmi->name, dmi->uuid, dmt->newname ? " " : "",
dmt->newname ? dmt->newname : "",
dmi->data_size);
if (dmt->type == DM_DEVICE_LIST) {
if (!_dm_names_v1(dmi))
goto bad;
@@ -1026,7 +1029,7 @@ static void *_add_target(struct target *t, void *out, void *end)
return out;
}
static struct dm_ioctl *_flatten(struct dm_task *dmt)
static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
{
const size_t min_size = 16 * 1024;
const int (*version)[3];
@@ -1077,6 +1080,10 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt)
if (len < min_size)
len = min_size;
/* Increase buffer size if repeating because buffer was too small */
while (repeat_count--)
len *= 2;
if (!(dmi = malloc(len)))
return NULL;
@@ -1276,10 +1283,59 @@ static int _create_and_load_v4(struct dm_task *dmt)
return r;
}
static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
unsigned repeat_count)
{
struct dm_ioctl *dmi;
dmi = _flatten(dmt, repeat_count);
if (!dmi) {
log_error("Couldn't create ioctl argument");
return NULL;
}
if (dmt->type == DM_DEVICE_TABLE)
dmi->flags |= DM_STATUS_TABLE_FLAG;
dmi->flags |= DM_EXISTS_FLAG; /* FIXME */
if (dmt->no_open_count)
dmi->flags |= DM_SKIP_BDGET_FLAG;
log_debug("dm %s %s %s%s%s %c %.0llu %s [%u]",
_cmd_data_v4[dmt->type].name,
dmi->name, dmi->uuid, dmt->newname ? " " : "",
dmt->newname ? dmt->newname : "",
dmt->no_open_count ? 'N' : 'O',
dmt->sector, dmt->message ? dmt->message : "",
dmi->data_size);
#ifdef DM_IOCTLS
if (ioctl(_control_fd, command, dmi) < 0) {
if (errno == ENXIO && ((dmt->type == DM_DEVICE_INFO) ||
(dmt->type == DM_DEVICE_MKNODES)))
dmi->flags &= ~DM_EXISTS_FLAG; /* FIXME */
else {
if (_log_suppress)
log_verbose("device-mapper ioctl "
"cmd %d failed: %s",
_IOC_NR(command), strerror(errno));
else
log_error("device-mapper ioctl "
"cmd %d failed: %s",
_IOC_NR(command), strerror(errno));
free(dmi);
return NULL;
}
}
#else /* Userspace alternative for testing */
#endif
return dmi;
}
int dm_task_run(struct dm_task *dmt)
{
struct dm_ioctl *dmi = NULL;
unsigned int command;
struct dm_ioctl *dmi;
unsigned command;
#ifdef DM_COMPAT
if (_dm_version == 1)
@@ -1290,7 +1346,7 @@ int dm_task_run(struct dm_task *dmt)
(sizeof(_cmd_data_v4) / sizeof(*_cmd_data_v4))) {
log_error("Internal error: unknown device-mapper task %d",
dmt->type);
goto bad;
return 0;
}
command = _cmd_data_v4[dmt->type].cmd;
@@ -1306,43 +1362,25 @@ int dm_task_run(struct dm_task *dmt)
if (!_open_control())
return 0;
dmi = _flatten(dmt);
if (!dmi) {
log_error("Couldn't create ioctl argument");
repeat_ioctl:
if (!(dmi = _do_dm_ioctl(dmt, command, _ioctl_buffer_double_factor)))
return 0;
}
if (dmt->type == DM_DEVICE_TABLE)
dmi->flags |= DM_STATUS_TABLE_FLAG;
dmi->flags |= DM_EXISTS_FLAG; /* FIXME */
if (dmt->no_open_count)
dmi->flags |= DM_SKIP_BDGET_FLAG;
log_debug("dm %s %s %s %s%c %.0llu %s", _cmd_data_v4[dmt->type].name,
dmi->name, dmi->uuid, dmt->newname ? dmt->newname : "",
dmt->no_open_count ? 'N' : 'O',
dmt->sector, dmt->message ? dmt->message : "");
#ifdef DM_IOCTLS
if (ioctl(_control_fd, command, dmi) < 0) {
if (errno == ENXIO && ((dmt->type == DM_DEVICE_INFO) ||
(dmt->type == DM_DEVICE_MKNODES)))
dmi->flags &= ~DM_EXISTS_FLAG; /* FIXME */
else {
if (_log_suppress)
log_verbose("device-mapper ioctl "
"cmd %d failed: %s",
_IOC_NR(command), strerror(errno));
else
log_error("device-mapper ioctl "
"cmd %d failed: %s",
_IOC_NR(command), strerror(errno));
goto bad;
if (dmi->flags & DM_BUFFER_FULL_FLAG) {
switch (dmt->type) {
case DM_DEVICE_LIST_VERSIONS:
case DM_DEVICE_LIST:
case DM_DEVICE_DEPS:
case DM_DEVICE_STATUS:
case DM_DEVICE_TABLE:
case DM_DEVICE_WAITEVENT:
_ioctl_buffer_double_factor++;
free(dmi);
goto repeat_ioctl;
default:
log_error("Warning: libdevmapper buffer too small for data");
}
}
#else /* Userspace alternative for testing */
#endif
switch (dmt->type) {
case DM_DEVICE_CREATE:

View File

@@ -111,6 +111,7 @@ struct dm_task *dm_task_create(int type)
dmt->uid = DEVICE_UID;
dmt->gid = DEVICE_GID;
dmt->mode = DEVICE_MODE;
dmt->no_open_count = 0;
return dmt;
}
@@ -200,26 +201,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 +268,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

View File

@@ -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@

View File

@@ -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);

View File

@@ -37,7 +37,7 @@ vg_tags.
Any "vg_" prefixes are optional. Columns mentioned in either \fBpvs (8)\fP
or \fBlvs (8)\fP can also be chosen, but columns cannot be taken from both
at the same time. The vg_attr bits are: (w)riteable, (r)eadonly,
resi(z)eable, e(x)ported, (p)artial.
resi(z)eable, e(x)ported, (p)artial and (c)lustered.
.TP
.I \-O, \-\-sort
Comma-separated ordered list of columns to sort by. Replaces the default

2800
po/lvm2.po

File diff suppressed because it is too large Load Diff

243
scripts/lvmconf.sh Normal file
View File

@@ -0,0 +1,243 @@
#!/bin/sh
#
# Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
#
# This file is part of the lvm2-cluster package.
#
# 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
#
# 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 13
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 14
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 15
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

View File

@@ -24,6 +24,7 @@ SOURCES =\
dumpconfig.c \
formats.c \
lvchange.c \
lvconvert.c \
lvcreate.c \
lvdisplay.c \
lvextend.c \

View File

@@ -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)

View File

@@ -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] [PhysicalVolume[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",

View File

@@ -757,13 +757,16 @@ static int _status(int argc, char **argv, void *data)
if (!dm_task_run(dmt))
goto out;
if (!name)
name = (char *) dm_task_get_name(dmt);
/* Fetch targets and print 'em */
do {
next = dm_get_next_target(dmt, next, &start, &length,
&target_type, &params);
/* Skip if target type doesn't match */
if (_switches[TARGET_ARG] && target_type &&
strcmp(target_type, _target))
if (_switches[TARGET_ARG] &&
(!target_type || strcmp(target_type, _target)))
continue;
if (ls_only) {
if (!_switches[EXEC_ARG] || !_command ||
@@ -1038,7 +1041,7 @@ static int _process_switches(int *argc, char ***argv)
{"uuid", 1, &ind, UUID_ARG},
{"verbose", 1, &ind, VERBOSE_ARG},
{"version", 0, &ind, VERSION_ARG},
{"", 0, NULL, 0}
{0, 0, 0, 0}
};
#else
struct option long_options;

View File

@@ -52,19 +52,19 @@ static int lvchange_permission(struct cmd_context *cmd,
backup(lv->vg);
if (!suspend_lv(cmd, lv->lvid.s)) {
if (!suspend_lv(cmd, lv)) {
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);
resume_lv(cmd, lv);
return 0;
}
log_very_verbose("Updating permissions for \"%s\" in kernel", lv->name);
if (!resume_lv(cmd, lv->lvid.s)) {
if (!resume_lv(cmd, lv)) {
log_error("Problem reactivating %s", lv->name);
return 0;
}
@@ -83,13 +83,13 @@ static int lvchange_availability(struct cmd_context *cmd,
if (activate == CHANGE_ALN) {
log_verbose("Deactivating logical volume \"%s\" locally",
lv->name);
if (!deactivate_lv_local(cmd, lv->lvid.s)) {
if (!deactivate_lv_local(cmd, lv)) {
stack;
return 0;
}
} else if (activate == CHANGE_AN) {
log_verbose("Deactivating logical volume \"%s\"", lv->name);
if (!deactivate_lv(cmd, lv->lvid.s)) {
if (!deactivate_lv(cmd, lv)) {
stack;
return 0;
}
@@ -103,21 +103,21 @@ static int lvchange_availability(struct cmd_context *cmd,
if (lv_is_origin(lv) || (activate == CHANGE_AE)) {
log_verbose("Activating logical volume \"%s\" "
"exclusively", lv->name);
if (!activate_lv_excl(cmd, lv->lvid.s)) {
if (!activate_lv_excl(cmd, lv)) {
stack;
return 0;
}
} else if (activate == CHANGE_ALY) {
log_verbose("Activating logical volume \"%s\" locally",
lv->name);
if (!activate_lv_local(cmd, lv->lvid.s)) {
if (!activate_lv_local(cmd, lv)) {
stack;
return 0;
}
} else {
log_verbose("Activating logical volume \"%s\"",
lv->name);
if (!activate_lv(cmd, lv->lvid.s)) {
if (!activate_lv(cmd, lv)) {
stack;
return 0;
}
@@ -137,7 +137,7 @@ static int lvchange_availability(struct cmd_context *cmd,
static int lvchange_refresh(struct cmd_context *cmd, struct logical_volume *lv)
{
log_verbose("Refreshing logical volume \"%s\" (if active)", lv->name);
if (!suspend_lv(cmd, lv->lvid.s) || !resume_lv(cmd, lv->lvid.s))
if (!suspend_lv(cmd, lv) || !resume_lv(cmd, lv))
return 0;
return 1;
@@ -216,19 +216,19 @@ static int lvchange_readahead(struct cmd_context *cmd,
backup(lv->vg);
if (!suspend_lv(cmd, lv->lvid.s)) {
if (!suspend_lv(cmd, lv)) {
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);
resume_lv(cmd, lv);
return 0;
}
log_very_verbose("Updating permissions for \"%s\" in kernel", lv->name);
if (!resume_lv(cmd, lv->lvid.s)) {
if (!resume_lv(cmd, lv)) {
log_error("Problem reactivating %s", lv->name);
return 0;
}
@@ -274,7 +274,7 @@ static int lvchange_persistent(struct cmd_context *cmd,
active = 1;
}
log_verbose("Ensuring %s is inactive.", lv->name);
if (!deactivate_lv(cmd, lv->lvid.s)) {
if (!deactivate_lv(cmd, lv)) {
log_error("%s: deactivation failed", lv->name);
return 0;
}
@@ -286,7 +286,7 @@ static int lvchange_persistent(struct cmd_context *cmd,
if (active) {
log_verbose("Re-activating logical volume \"%s\"",
lv->name);
if (!activate_lv(cmd, lv->lvid.s)) {
if (!activate_lv(cmd, lv)) {
log_error("%s: reactivation failed", lv->name);
return 0;
}
@@ -301,19 +301,19 @@ static int lvchange_persistent(struct cmd_context *cmd,
backup(lv->vg);
if (!suspend_lv(cmd, lv->lvid.s)) {
if (!suspend_lv(cmd, lv)) {
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);
resume_lv(cmd, lv);
return 0;
}
log_very_verbose("Updating permissions for \"%s\" in kernel", lv->name);
if (!resume_lv(cmd, lv->lvid.s)) {
if (!resume_lv(cmd, lv)) {
log_error("Problem reactivating %s", lv->name);
return 0;
}
@@ -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))

255
tools/lvconvert.c Normal file
View File

@@ -0,0 +1,255 @@
/*
* 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 {
const char *lv_name;
uint32_t mirrors;
alloc_policy_t alloc;
int pv_count;
char **pvs;
struct list *pvh;
};
static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
int argc, char **argv)
{
memset(lp, 0, sizeof(*lp));
lp->alloc = ALLOC_INHERIT;
if (arg_count(cmd, alloc_ARG))
lp->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG,
lp->alloc);
if (!arg_count(cmd, mirrors_ARG)) {
log_error("--mirrors argument required");
return 0;
}
lp->mirrors = arg_uint_value(cmd, mirrors_ARG, 0) + 1;
if (!argc) {
log_error("Please give logical volume path");
return 0;
}
lp->lv_name = argv[0];
argv++, argc--;
lp->pv_count = argc;
lp->pvs = argv;
return 1;
}
static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * lv,
struct lvconvert_params *lp)
{
struct lv_segment *first_seg;
uint32_t existing_mirrors;
// struct alloc_handle *ah = NULL;
// struct logical_volume *log_lv;
if ((lp->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 (lp->mirrors == existing_mirrors) {
log_error("Logical volume %s already has %"
PRIu32 " mirror(s).", lv->name,
lp->mirrors - 1);
return 1;
}
if (lp->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, lp->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)) {
log_error("Failed to lock %s", lv->name);
vg_revert(lv->vg);
return 0;
}
if (!vg_commit(lv->vg)) {
resume_lv(cmd, lv);
return 0;
}
log_very_verbose("Updating \"%s\" in kernel", lv->name);
if (!resume_lv(cmd, lv)) {
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,
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))
return ECMD_FAILED;
}
return ECMD_PROCESSED;
}
int lvconvert(struct cmd_context * cmd, int argc, char **argv)
{
const char *vg_name;
char *st;
int consistent = 1;
struct volume_group *vg;
struct lv_list *lvl;
struct lvconvert_params lp;
int ret = ECMD_FAILED;
if (!_read_params(&lp, cmd, argc, argv)) {
stack;
return EINVALID_CMD_LINE;
}
vg_name = extract_vgname(cmd, lp.lv_name);
if (!validate_name(vg_name)) {
log_error("Please provide a valid volume group name");
return EINVALID_CMD_LINE;
}
if ((st = strrchr(lp.lv_name, '/')))
lp.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, lp.lv_name))) {
log_error("Logical volume \"%s\" not found in "
"volume group \"%s\"", lp.lv_name, vg_name);
goto error;
}
if (lp.pv_count) {
if (!(lp.pvh = create_pv_list(cmd->mem, vg, lp.pv_count,
lp.pvs, 1))) {
stack;
goto error;
}
} else
lp.pvh = &vg->pvs;
ret = lvconvert_single(cmd, lvl->lv, &lp);
error:
unlock_vg(cmd, vg_name);
return ret;
}

View File

@@ -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.
@@ -348,58 +414,20 @@ static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd,
return 1;
}
/*
* Volumes may be zeroed to remove old application data.
*/
static int _zero_lv(struct cmd_context *cmd, struct logical_volume *lv)
{
struct device *dev;
char *name;
/*
* FIXME:
* <clausen> also, more than 4k
* <clausen> say, reiserfs puts it's superblock 32k in, IIRC
* <ejt_> k, I'll drop a fixme to that effect
* (I know the device is at least 4k, but not 32k)
*/
if (!(name = pool_alloc(cmd->mem, PATH_MAX))) {
log_error("Name allocation failed - device not zeroed");
return 0;
}
if (lvm_snprintf(name, PATH_MAX, "%s%s/%s", cmd->dev_dir,
lv->vg->name, lv->name) < 0) {
log_error("Name too long - device not zeroed (%s)", lv->name);
return 0;
}
log_verbose("Zeroing start of logical volume \"%s\"", lv->name);
if (!(dev = dev_cache_get(name, NULL))) {
log_error("%s: not found: device not zeroed", name);
return 0;
}
if (!dev_open_quiet(dev))
return 0;
dev_zero(dev, UINT64_C(0), (size_t) 4096);
dev_close_immediate(dev);
return 1;
}
static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
{
uint32_t size_rest;
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 +455,11 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
return 0;
}
if (lp->mirrors > 1 && !(vg->fid->fmt->features & FMT_SEGMENTS)) {
log_error("Metadata does not support mirroring.");
return 0;
}
/*
* Create the pv list.
*/
@@ -473,6 +506,11 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
"device-mapper kernel driver");
return 0;
}
/* FIXME Allow exclusive activation. */
if (vg->status & CLUSTERED) {
log_error("Clustered snapshots are not yet supported.");
return 0;
}
if (!(org = find_lv(vg, lp->origin))) {
log_err("Couldn't find origin volume '%s'.",
lp->origin);
@@ -505,30 +543,111 @@ 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) {
lp->region_size = adjusted_mirror_region_size(vg->extent_size,
lp->extents,
lp->region_size);
/* FIXME Calculate how many extents needed for the log */
len = strlen(lv_name) + 32;
if (!(log_name = alloca(len)) ||
!(generate_log_name_format(vg, lv_name, log_name, len))) {
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)) {
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)) {
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 +666,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)) {
@@ -579,7 +711,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
return 0;
}
if (!activate_lv(cmd, lv->lvid.s)) {
if (!activate_lv(cmd, lv)) {
if (lp->snapshot)
/* FIXME Remove the failed lv we just added */
log_error("Aborting. Failed to activate snapshot "
@@ -590,7 +722,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
}
if ((lp->zero || lp->snapshot) && activation()) {
if (!_zero_lv(cmd, lv) && lp->snapshot) {
if (!zero_lv(cmd, lv) && lp->snapshot) {
/* FIXME Remove the failed lv we just added */
log_error("Aborting. Failed to wipe snapshot "
"exception store. Remove new LV and retry.");
@@ -605,13 +737,13 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
/* Reset permission after zeroing */
if (!(lp->permission & LVM_WRITE))
lv->status &= ~LVM_WRITE;
if (!deactivate_lv(cmd, lv->lvid.s)) {
if (!deactivate_lv(cmd, lv)) {
log_err("Couldn't deactivate new snapshot.");
return 0;
}
/* FIXME write/commit/backup sequence issue */
if (!suspend_lv(cmd, org->lvid.s)) {
if (!suspend_lv(cmd, org)) {
log_error("Failed to suspend origin %s", org->name);
return 0;
}
@@ -626,7 +758,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
if (!vg_write(vg) || !vg_commit(vg))
return 0;
if (!resume_lv(cmd, org->lvid.s)) {
if (!resume_lv(cmd, org)) {
log_error("Problem reactivating origin %s", org->name);
return 0;
}
@@ -642,6 +774,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)

View File

@@ -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 {

View File

@@ -350,21 +350,30 @@ int segtype_arg(struct cmd_context *cmd, struct arg *a)
char yes_no_prompt(const char *prompt, ...)
{
int c = 0;
int c = 0, ret = 0;
va_list ap;
while (c != 'y' && c != 'n') {
if (c == '\n' || c == 0) {
do {
if (c == '\n' || !c) {
va_start(ap, prompt);
vprintf(prompt, ap);
va_end(ap);
}
c = tolower(getchar());
}
while (getchar() != '\n') ;
if ((c = getchar()) == EOF) {
ret = 'n';
break;
}
return c;
c = tolower(c);
if ((c == 'y') || (c == 'n'))
ret = c;
} while (!ret || c != '\n');
if (c != '\n')
printf("\n");
return ret;
}
static void __alloc(int size)

View File

@@ -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;
@@ -62,7 +74,7 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
if (!archive(vg))
return ECMD_FAILED;
if (!deactivate_lv(cmd, lv->lvid.s)) {
if (!deactivate_lv(cmd, lv)) {
log_error("Unable to deactivate logical volume \"%s\"",
lv->name);
return ECMD_FAILED;

View File

@@ -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;
}
@@ -160,18 +158,18 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
backup(lv->vg);
if (!suspend_lv(cmd, lv->lvid.s)) {
if (!suspend_lv(cmd, lv)) {
stack;
goto error;
}
if (!vg_commit(vg)) {
stack;
resume_lv(cmd, lv->lvid.s);
resume_lv(cmd, lv);
goto error;
}
resume_lv(cmd, lv->lvid.s);
resume_lv(cmd, lv);
unlock_vg(cmd, vg_name);

View File

@@ -23,6 +23,7 @@ struct lvresize_params {
uint32_t stripes;
uint32_t stripe_size;
uint32_t mirrors;
struct segment_type *segtype;
@@ -119,10 +120,11 @@ 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;
char *lock_lvid;
struct logical_volume *lock_lv;
struct lv_list *lvl;
int consistent = 1;
struct lv_segment *seg;
@@ -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;
@@ -473,11 +518,11 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
/* If snapshot, must suspend all associated devices */
if ((snap_seg = find_cow(lv)))
lock_lvid = snap_seg->origin->lvid.s;
lock_lv = snap_seg->origin;
else
lock_lvid = lv->lvid.s;
lock_lv = lv;
if (!suspend_lv(cmd, lock_lvid)) {
if (!suspend_lv(cmd, lock_lv)) {
log_error("Failed to suspend %s", lp->lv_name);
vg_revert(vg);
return ECMD_FAILED;
@@ -485,11 +530,11 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
if (!vg_commit(vg)) {
stack;
resume_lv(cmd, lock_lvid);
resume_lv(cmd, lock_lv);
return ECMD_FAILED;
}
if (!resume_lv(cmd, lock_lvid)) {
if (!resume_lv(cmd, lock_lv)) {
log_error("Problem reactivating %s", lp->lv_name);
return ECMD_FAILED;
}

View File

@@ -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);

View File

@@ -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");
@@ -170,6 +170,14 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
log_print("Skipping mirror LV %s", lv->name);
continue;
}
if (lv->status & MIRROR_LOG) {
log_print("Skipping mirror log LV %s", lv->name);
continue;
}
if (lv->status & MIRROR_IMAGE) {
log_print("Skipping mirror image LV %s", lv->name);
continue;
}
if (lv->status & LOCKED) {
log_print("Skipping locked LV %s", lv->name);
continue;
@@ -211,7 +219,7 @@ static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg,
/* Suspend mirrors on subsequent calls */
if (!first_time) {
if (!suspend_lv(cmd, lv_mirr->lvid.s)) {
if (!suspend_lv(cmd, lv_mirr)) {
stack;
resume_lvs(cmd, lvs_changed);
vg_revert(vg);
@@ -223,15 +231,16 @@ static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg,
if (!vg_commit(vg)) {
log_error("ABORTING: Volume group metadata update failed.");
if (!first_time)
resume_lv(cmd, lv_mirr->lvid.s);
resume_lv(cmd, lv_mirr);
resume_lvs(cmd, lvs_changed);
return 0;
}
/* Activate the temporary mirror LV */
/* Only the first mirror segment gets activated as a mirror */
/* FIXME: Add option to use a log */
if (first_time) {
if (!activate_lv(cmd, lv_mirr->lvid.s)) {
if (!activate_lv_excl(cmd, lv_mirr)) {
if (!test_mode())
log_error("ABORTING: Temporary mirror "
"activation failed. "
@@ -240,7 +249,7 @@ static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg,
resume_lvs(cmd, lvs_changed);
return 0;
}
} else if (!resume_lv(cmd, lv_mirr->lvid.s)) {
} else if (!resume_lv(cmd, lv_mirr)) {
log_error("Unable to reactivate logical volume \"%s\"",
lv_mirr->name);
resume_lvs(cmd, lvs_changed);
@@ -309,7 +318,7 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
}
/* Ensure mirror LV is active */
if (!activate_lv(cmd, lv_mirr->lvid.s)) {
if (!activate_lv_excl(cmd, lv_mirr)) {
log_error
("ABORTING: Temporary mirror activation failed.");
unlock_vg(cmd, pv->vg_name);
@@ -406,7 +415,7 @@ static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg,
}
/* Suspend mirror LV to flush pending I/O */
if (!suspend_lv(cmd, lv_mirr->lvid.s)) {
if (!suspend_lv(cmd, lv_mirr)) {
log_error("Suspension of temporary mirror LV failed");
r = 0;
}
@@ -416,13 +425,13 @@ static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg,
log_error("ABORTING: Failed to write new data locations "
"to disk.");
vg_revert(vg);
resume_lv(cmd, lv_mirr->lvid.s);
resume_lv(cmd, lv_mirr);
resume_lvs(cmd, lvs_changed);
return 0;
}
/* Release mirror LV. (No pending I/O because it's been suspended.) */
if (!resume_lv(cmd, lv_mirr->lvid.s)) {
if (!resume_lv(cmd, lv_mirr)) {
log_error("Unable to reactivate logical volume \"%s\"",
lv_mirr->name);
r = 0;
@@ -432,7 +441,7 @@ static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg,
resume_lvs(cmd, lvs_changed);
/* Deactivate mirror LV */
if (!deactivate_lv(cmd, lv_mirr->lvid.s)) {
if (!deactivate_lv(cmd, lv_mirr)) {
log_error("ABORTING: Unable to deactivate temporary logical "
"volume \"%s\"", lv_mirr->name);
r = 0;

View File

@@ -35,6 +35,11 @@ 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)
{
/* FIXME Avoid snapshot special-case */
if (!arg_count(cmd, all_ARG) && !(lv->status & VISIBLE_LV) &&
!(lv_is_cow(lv)))
return ECMD_PROCESSED;
if (!report_object(handle, lv->vg, lv, NULL, NULL, NULL))
return ECMD_FAILED;
@@ -78,6 +83,11 @@ 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)
{
/* FIXME Avoid snapshot special-case */
if (!arg_count(cmd, all_ARG) && !(lv->status & VISIBLE_LV) &&
!(lv_is_cow(lv)))
return ECMD_PROCESSED;
return process_each_segment_in_lv(cmd, lv, handle, _segs_single);
}

View File

@@ -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,109 @@ 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;
}
int generate_log_name_format(struct volume_group *vg, const char *lv_name,
char *buffer, size_t size)
{
if (lvm_snprintf(buffer, size, "%s_mlog", lv_name) < 0) {
stack;
return 0;
}
if (find_lv_in_vg(vg, buffer) &&
lvm_snprintf(buffer, size, "%s_mlog_%%d",
lv_name) < 0) {
stack;
return 0;
}
return 1;
}
/*
* Volumes may be zeroed to remove old application data.
*/
int zero_lv(struct cmd_context *cmd, struct logical_volume *lv)
{
struct device *dev;
char *name;
/*
* FIXME:
* <clausen> also, more than 4k
* <clausen> say, reiserfs puts it's superblock 32k in, IIRC
* <ejt_> k, I'll drop a fixme to that effect
* (I know the device is at least 4k, but not 32k)
*/
if (!(name = pool_alloc(cmd->mem, PATH_MAX))) {
log_error("Name allocation failed - device not zeroed");
return 0;
}
if (lvm_snprintf(name, PATH_MAX, "%s%s/%s", cmd->dev_dir,
lv->vg->name, lv->name) < 0) {
log_error("Name too long - device not zeroed (%s)", lv->name);
return 0;
}
log_verbose("Zeroing start of logical volume \"%s\"", lv->name);
if (!(dev = dev_cache_get(name, NULL))) {
log_error("%s: not found: device not zeroed", name);
return 0;
}
if (!dev_open_quiet(dev))
return 0;
dev_zero(dev, UINT64_C(0), (size_t) 4096);
dev_close_immediate(dev);
return 1;
}

View File

@@ -90,4 +90,13 @@ 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);
int generate_log_name_format(struct volume_group *vg, const char *lv_name,
char *buffer, size_t size);
int zero_lv(struct cmd_context *cmd, struct logical_volume *lv);
#endif

View File

@@ -30,25 +30,25 @@ 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) {
if (!deactivate_lv(cmd, lv->lvid.s))
if (!deactivate_lv(cmd, lv))
continue;
} else if (activate == CHANGE_ALN) {
if (!deactivate_lv_local(cmd, lv->lvid.s))
if (!deactivate_lv_local(cmd, lv))
continue;
} else if (lv_is_origin(lv) || (activate == CHANGE_AE)) {
if (!activate_lv_excl(cmd, lv->lvid.s))
if (!activate_lv_excl(cmd, lv))
continue;
} else if (activate == CHANGE_ALY) {
if (!activate_lv_local(cmd, lv->lvid.s))
if (!activate_lv_local(cmd, lv))
continue;
} else if (!activate_lv(cmd, lv->lvid.s))
} else if (!activate_lv(cmd, lv))
continue;
if ((lv->status & PVMOVE) &&
@@ -182,6 +182,7 @@ static int _vgchange_clustered(struct cmd_context *cmd,
struct volume_group *vg)
{
int clustered = !strcmp(arg_str_value(cmd, clustered_ARG, "n"), "y");
struct lv_list *lvl;
if (clustered && (vg->status & CLUSTERED)) {
log_error("Volume group \"%s\" is already clustered",
@@ -195,6 +196,17 @@ static int _vgchange_clustered(struct cmd_context *cmd,
return ECMD_FAILED;
}
if (clustered) {
list_iterate_items(lvl, &vg->lvs) {
if (lvl->lv->origin_count || lvl->lv->snapshot) {
log_error("Volume group %s contains snapshots "
"that are not yet supported.",
vg->name);
return ECMD_FAILED;
}
}
}
if (!archive(vg))
return ECMD_FAILED;

View File

@@ -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;
}

Some files were not shown because too many files have changed in this diff Show More