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

Compare commits

...

74 Commits

Author SHA1 Message Date
Alasdair Kergon
40377032e3 1.01.02 2005-05-17 15:50:25 +00:00
Alasdair Kergon
b2971edd7d Start merging cloned allocation functions. 2005-05-17 13:49:45 +00:00
Alasdair Kergon
c37d723692 Move archiver code from tools into library. 2005-05-17 13:46:38 +00:00
Alasdair Kergon
30f9026e1d vgscan/change/display/vgs automatically create metadata backup if out-of-date or missing. 2005-05-17 13:44:02 +00:00
Alasdair Kergon
332286072e Add dmsetup ls --exec. 2005-05-16 20:46:46 +00:00
Alasdair Kergon
d6da172a2a Add --target to dmsetup ls. 2005-05-16 16:04:34 +00:00
Alasdair Kergon
ebfe584afc Call dm_lib_exit() and dm_lib_release() automatically now. 2005-05-16 15:15:34 +00:00
Alasdair Kergon
6250023583 Add --target <target_type> filter to dmsetup table/status.
Fix dmsetup getopt_long usage.
2005-05-16 14:53:23 +00:00
Alasdair Kergon
6b4f3d63b8 Fix contiguous allocations with linear. 2005-05-11 16:46:59 +00:00
AJ Lewis
56db773a09 more clvmd rhel4 initscript cleanup
- don't echo after an 'action' call - action does the echo itself
 - use vgdisplay/vgs to determine which VGs are marked clustered and only
   deactivate those VGs (unless the LVM_VGS var is set in
   /etc/sysconfig/cluster)
2005-05-11 15:21:44 +00:00
Alasdair Kergon
fc6c472401 Cope with missing format1 PVs again. 2005-05-11 15:04:06 +00:00
Alasdair Kergon
2cd42a6866 Remove lists of free PV segments.
Simplify pv_maps code and remove slow bitset algorithm.
2005-05-11 15:02:49 +00:00
AJ Lewis
36a90c345c updated to reflect clvmd rhel4 initscript being redhatified 2005-05-10 20:15:39 +00:00
AJ Lewis
ef1e82c72c Fixes bz#155478
Redhatify the rhel4 initscript (use /etc/init.d/functions)
2005-05-10 20:14:33 +00:00
AJ Lewis
88f9534685 o Changed the multilog API a bit (I warned you)
- multilog_add_type, multilog_del_type, multilog_custom, and
     multilog_init_verbose all have different arguments.
   - Primary change is that caller only passes in config info, and the
     lib keeps track of state internally.  No more exporting of
     'struct log_data'.
   - Custom callers now only get the custom data pointer passed into their
     log fxn (that is set with multilog_custom)
   - Added basic README that describes libmultilog
2005-05-09 18:44:35 +00:00
Alasdair Kergon
68254a052a %Zu->zu 2005-05-09 17:45:06 +00:00
Alasdair Kergon
2425b3a166 fix compiler warnings 2005-05-09 17:41:36 +00:00
Alasdair Kergon
5524ed753b Fix loopfiles mem alloc. 2005-05-09 17:02:52 +00:00
Alasdair Kergon
89711723da Un-inline dbg_strdup. 2005-05-09 17:01:06 +00:00
Alasdair Kergon
bed2740ffd lv_reduce tidying.
Remove some unnecessary parameters.
Introduce seg_is macros.
2005-05-09 16:59:01 +00:00
Alasdair Kergon
751d633c3d post-release 2005-05-09 16:41:48 +00:00
Benjamin Marzinski
45952cbdf2 oops. Those are char **'s not char *'s 2005-05-04 19:24:03 +00:00
Benjamin Marzinski
b355dd7b23 fixed dmevent so that it doesn't do a double free when you run
# dmevent -l

Also, changed the behaviour of dm_get_registered_device(), so that it doesn't
change the pointer you passed in without freeing the memory on a non-next call,
and doesn't free your pointer without setting it to NULL on a failed next call.
2005-05-04 18:53:28 +00:00
Heinz Mauelshagen
48a186f172 o libmultilog needs introducing of list locking in order to stand
multilog_add_type()/multilog_del_type cycles correctly.
o fixed segfault in multilog_add_type()
o fixed test-multilog.c
o cleaned up libmultilog (list macros, indentation, braces, comments)
2005-05-04 11:52:07 +00:00
Jonathan Earl Brassow
39dc7ec2ab - make noop use multilog
- add event_nr to thread_status struct and set appropriately so that the
  thread actually waits for an event
- essentially make error_detected return true.  Let the DSOs determine
  how to interpret the status info
2005-05-04 01:57:31 +00:00
AJ Lewis
2fedabd3b9 o stick multilog into the dm-event lib and dmeventd code again
o more tweaks to libmultilog calls - the api isn't set in stone yet, so
   don't get too comfortable.
 o not sure the dmeventd in device-mapper/dmeventd works - i've been using
   the one in lib/event/
 o currently both daemons are set to log only to syslog
2005-05-03 21:29:13 +00:00
Alasdair Kergon
6d719e9480 2.01.10 2005-05-03 17:43:47 +00:00
Alasdair Kergon
05e278afda Don't create backup and archive dirs till needed. 2005-05-03 17:31:56 +00:00
Alasdair Kergon
87dbf462cb Reinstate full PV size when removing from VG.
Support loopfiles for testing.
Complete the pv_segment support.
2005-05-03 17:28:23 +00:00
Heinz Mauelshagen
40e896bc5b working dm_get_registered_device(). dmevent.c update to use it. 2005-05-03 16:15:20 +00:00
Heinz Mauelshagen
3e940f80c7 more dm_get_registered_device() code 2005-05-03 13:50:42 +00:00
Benjamin Marzinski
dbf2888d43 dmeventd was looking for dsos with libdmeventd<name>.so
The Makefile turned noop.c into    libdmeventnoop.so
The Makefile now turns noop.c into libdmeventdnoop.so
2005-05-02 19:34:25 +00:00
Benjamin Marzinski
d412355324 stopped printing a string after we erased the pointer to it. 2005-05-02 18:43:23 +00:00
Benjamin Marzinski
178732217f removed the -lmultilog for now. 2005-05-02 18:42:07 +00:00
Benjamin Marzinski
de17b95c3d get the makefile to clean up the .o's 2005-05-02 17:41:54 +00:00
Heinz Mauelshagen
d14e774525 Introduce exit() in main() and cleanup signal settings for parent/child 2005-05-02 11:02:19 +00:00
Benjamin Marzinski
ca5402a7fa more variable initialization. 2005-04-29 22:12:09 +00:00
Benjamin Marzinski
7a6fa7c5b4 changed client_path and sever_path from 'char *' to 'const char *' to stop
compiler warning messages.
2005-04-29 21:52:46 +00:00
Heinz Mauelshagen
da36c286a6 o checking in instrumented code for AJ to follow up on comms and logging
o changed

  int dm_get_next_registered_device(char **dso_name, char **device,
                                    enum event_type *events);

  to

  int dm_get_registered_device(char **dso_name, char **device,
                               enum event_type *events, int next)

  so that the daemon is able to retrive the next one of the list without
  running into locking issues.

o changed dmevent.c to use dm_get_registered_device()

o couldn't test this yet because of the comms issues
  (daemon exits in do_process_request())
2005-04-29 14:56:35 +00:00
Heinz Mauelshagen
d3901bcf2e first changes to get comms back to work after flock changes 2005-04-29 13:41:25 +00:00
Heinz Mauelshagen
94c8d4fdfb minor cleanup 2005-04-29 10:58:34 +00:00
AJ Lewis
ab8bdc18bb o Build dmeventd against multilog 2005-04-28 22:47:52 +00:00
Alasdair Kergon
c9dcd7442a build libdmeventnoop.so for testing 2005-04-28 17:32:27 +00:00
Alasdair Kergon
34c8f13346 test.c->dmevent.c 2005-04-28 14:49:41 +00:00
Alasdair Kergon
7a8ccda95c o adds dm_get_next_registered_device() (not functional yet)
to retrieve which devices got registered with the daemon;
  needs locking changes as well
2005-04-28 14:02:30 +00:00
Alasdair Kergon
44a1448542 Prototype for a device-mapper event-handling daemon. 2005-04-27 22:32:00 +00:00
Alasdair Kergon
c87d89ffaf extend alloc_lv_segment 2005-04-22 15:44:00 +00:00
Alasdair Kergon
0868749d42 set_lv_segment_area_pv/lv 2005-04-22 15:43:02 +00:00
Alasdair Kergon
1d40ee23f0 Initial pv_segment code. 2005-04-19 20:58:25 +00:00
Alasdair Kergon
8893f32603 initial pv_segment defns 2005-04-19 20:52:35 +00:00
Alasdair Kergon
adcf7e8dc3 _copy_pv -> int 2005-04-19 20:44:21 +00:00
Patrick Caulfield
901f7c5c36 Tidy clvmd's SIGHUP handler so it doesn't do all that work. 2005-04-19 10:36:42 +00:00
Alasdair Kergon
775bb413b3 vgchange --physicalextentsize (but only if it's an exact fit - may need to
use pvmove first)
2005-04-18 14:56:42 +00:00
Alasdair Kergon
64cd5b5a46 extract compose_log_line 2005-04-17 23:59:04 +00:00
Alasdair Kergon
ae356609b1 get_pv_from_vg_by_id 2005-04-17 23:57:44 +00:00
Patrick Caulfield
6102a5d2b0 Make clvmd work around some "limitations" in gulm's node state notifications.
Also make clvmd debuglog timestamps a little more helpful.
2005-04-13 13:50:07 +00:00
Alasdair Kergon
f8782ee2d7 Internal snapshot code restructuring. 2005-04-07 12:39:44 +00:00
Alasdair Kergon
6181ec4c77 add lvid to lv_create_empty 2005-04-07 12:29:46 +00:00
Alasdair Kergon
e0e7a685ef Remove unused internal non-persistent snapshot option. 2005-04-07 12:27:57 +00:00
Alasdair Kergon
ae1f8cdad2 fix unused o_direct label 2005-04-07 12:25:33 +00:00
Alasdair Kergon
a4cf792e6d store snapshot id as lvid internally 2005-04-07 12:24:48 +00:00
Alasdair Kergon
89109ded53 Allow offline extension of snapshot volumes.
NB Requires kernel patch that is not upstream.
2005-04-07 12:17:46 +00:00
Alasdair Kergon
e20e52a4b2 Move from 2-step to 3-step on-disk metadata commit. 2005-04-06 18:59:55 +00:00
Alasdair Kergon
20c4b1cbec Add ramdisk. 2005-04-06 16:43:59 +00:00
Alasdair Kergon
5238b0241d _vg_posn -> _find_vg_rlocn 2005-04-06 16:35:33 +00:00
Alasdair Kergon
9cdf6c203d more refinements 2005-04-06 15:21:28 +00:00
Alasdair Kergon
839335cae6 Annotate, tidy and extend list.h. 2005-04-06 14:50:37 +00:00
Alasdair Kergon
a99b2ce167 Alignment tidying. 2005-04-06 13:47:41 +00:00
Alasdair Kergon
b695141d87 post-release 2005-04-04 15:46:14 +00:00
Alasdair Kergon
92d5c9f866 2.01.09 2005-04-04 15:41:51 +00:00
Alasdair Kergon
7f18a1ffe0 Add --ignorelockingfailure to vgmknodes. 2005-04-04 14:44:49 +00:00
Patrick Caulfield
8c3fdaaa62 set SO_KEEPALIVE on sockets 2005-04-01 16:03:00 +00:00
Patrick Caulfield
5ac1c69710 Don't allow user operations to start until the lvm thread is fully up.
Hopefully finally nails bz#146056
2005-04-01 13:01:01 +00:00
Alasdair Kergon
de2d5fba63 post-release 2005-03-29 18:10:57 +00:00
95 changed files with 5612 additions and 2614 deletions

View File

@@ -1 +1 @@
2.01.09-cvs (2005-03-22)
2.01.11-cvs (2005-05-03)

View File

@@ -1,5 +1,43 @@
Version 2.01.09 -
=================================
Version 2.01.11 -
==============================
Move archiver code from tools into library.
vgscan/change/display/vgs automatically create metadata backups if needed.
Merge cloned allocation functions.
Fix contiguous allocation policy with linear.
Cope with missing format1 PVs again.
Remove lists of free PV segments.
Simplify pv_maps code and remove slow bitset algorithm.
Red-Hat-ify the clvmd rhel4 initscript.
%Zu->%zu
Fix loopfiles alias alloc & mem debugging.
Un-inline dbg_strdup.
lv_reduce tidying.
Remove some unnecessary parameters.
Introduce seg_is macros.
Version 2.01.10 - 3rd May 2005
==============================
Don't create backup and archive dirs till needed.
Reinstate full PV size when removing from VG.
Support loopfiles for testing.
Tidy lv_segment interface.
pv_segment support.
vgchange --physicalextentsize
Internal snapshot restructuring.
Remove unused internal non-persistent snapshot option.
Allow offline extension of snapshot volumes.
Move from 2-step to 3-step on-disk metadata commit.
Scan ramdisks too and allow non-O_DIRECT fallback.
Annotate, tidy and extend list.h.
Alignment tidying.
Make clvmd work around some "bugs" in gulm's node state notifications.
Tidy clvmd's SIGHUP handler
Version 2.01.09 - 4th April 2005
================================
Add --ignorelockingfailure to vgmknodes.
clvmd: Don't allow user operations to start until the lvm thread is fully up.
clvmd-gulm: set KEEPALIVE on sockets.
Version 2.01.08 - 22nd March 2005
=================================

View File

@@ -1,3 +1,10 @@
Version 1.01.02 - 17 May 2005
=============================
Call dm_lib_exit() and dm_lib_release() automatically now.
Add --target <target_type> filter to dmsetup table/status/ls.
Add --exec <command> to dmsetup ls.
Fix dmsetup getopt_long usage.
Version 1.01.01 - 29 Mar 2005
=============================
Update dmsetup man page.

View File

@@ -40,6 +40,7 @@ struct cluster_ops {
void (*get_our_csid) (char *csid);
void (*add_up_node) (char *csid);
void (*reread_config) (void);
void (*cluster_closedown) (void);
int (*sync_lock) (const char *resource, int mode, int flags, int *lockid);

View File

@@ -60,8 +60,9 @@ static struct hash_table *node_hash;
/* hash list of outstanding lock requests */
static struct hash_table *lock_hash;
/* Copy of the current core state */
static uint8_t current_corestate;
/* Copy of the current quorate state */
static uint8_t gulm_quorate = 0;
static enum {INIT_NOTDONE, INIT_DONE, INIT_WAITQUORATE} init_state = INIT_NOTDONE;
/* Number of active nodes */
static int num_nodes;
@@ -135,12 +136,11 @@ static void badsig_handler(int sig)
exit(0);
}
static void sighup_handler(int sig)
static void _reread_config(void)
{
DEBUGLOG("got SIGHUP\n");
/* Re-read CCS node list */
get_all_cluster_nodes();
/* Re-read CCS node list */
DEBUGLOG("Re-reading CCS config\n");
get_all_cluster_nodes();
}
static int _init_cluster(void)
@@ -243,9 +243,6 @@ static int _init_cluster(void)
signal(SIGINT, badsig_handler);
signal(SIGTERM, badsig_handler);
/* Re-read the node list on SIGHUP */
signal(SIGHUP, sighup_handler);
return 0;
}
@@ -312,12 +309,16 @@ static int core_login_reply(void *misc, uint64_t gen, uint32_t error, uint32_t r
if (error)
exit(error);
current_corestate = corestate;
/* Get the current core state (for quorum) */
lg_core_corestate(gulm_if);
return 0;
}
static void set_node_state(struct node_info *ninfo, char *csid, uint8_t nodestate)
{
int oldstate = ninfo->state;
if (nodestate == lg_core_Logged_in)
{
/* Don't clobber NODE_CLVMD state */
@@ -339,11 +340,17 @@ static void set_node_state(struct node_info *ninfo, char *csid, uint8_t nodestat
if (ninfo->state != NODE_DOWN)
num_nodes--;
ninfo->state = NODE_DOWN;
tcp_remove_client(csid);
}
}
DEBUGLOG("set_node_state, '%s' state = %d, num_nodes=%d\n",
ninfo->name, ninfo->state, num_nodes);
/* Gulm doesn't always send node DOWN events, so even if this a a node UP we must
* assume (ahem) that it prevously went down at some time. So we close
* the sockets here to make sure that we don't have any dead connections
* to that node.
*/
tcp_remove_client(csid);
DEBUGLOG("set_node_state, '%s' state = %d (oldstate=%d), num_nodes=%d\n",
ninfo->name, ninfo->state, oldstate, num_nodes);
}
static struct node_info *add_or_set_node(char *name, struct in6_addr *ip, uint8_t state)
@@ -400,7 +407,16 @@ static int core_nodelist(void *misc, lglcb_t type, char *name, struct in6_addr *
char ourcsid[GULM_MAX_CSID_LEN];
DEBUGLOG("Got Nodelist, stop\n");
clvmd_cluster_init_completed();
if (gulm_quorate)
{
clvmd_cluster_init_completed();
init_state = INIT_DONE;
}
else
{
if (init_state == INIT_NOTDONE)
init_state = INIT_WAITQUORATE;
}
/* Mark ourself as up */
_get_our_csid(ourcsid);
@@ -418,10 +434,15 @@ static int core_nodelist(void *misc, lglcb_t type, char *name, struct in6_addr *
static int core_statechange(void *misc, uint8_t corestate, uint8_t quorate, struct in6_addr *masterip, char *mastername)
{
DEBUGLOG("CORE Got statechange corestate:%#x mastername:%s\n",
corestate, mastername);
DEBUGLOG("CORE Got statechange. quorate:%d, corestate:%x mastername:%s\n",
quorate, corestate, mastername);
current_corestate = corestate;
gulm_quorate = quorate;
if (quorate && init_state == INIT_WAITQUORATE)
{
clvmd_cluster_init_completed();
init_state = INIT_DONE;
}
return 0;
}
@@ -474,7 +495,7 @@ static int lock_login_reply(void *misc, uint32_t error, uint8_t which)
lock_start_flag = 0;
pthread_mutex_unlock(&lock_start_mutex);
}
return 0;
}
@@ -615,7 +636,11 @@ void gulm_add_up_node(char *csid)
}
DEBUGLOG("gulm_add_up_node %s\n", ninfo->name);
if (ninfo->state == NODE_DOWN)
num_nodes++;
ninfo->state = NODE_CLVMD;
return;
}
@@ -853,12 +878,7 @@ static int _sync_unlock(const char *resource, int lockid)
static int _is_quorate()
{
if (current_corestate == lg_core_Slave ||
current_corestate == lg_core_Master ||
current_corestate == lg_core_Client)
return 1;
else
return 0;
return gulm_quorate;
}
/* Get all the cluster node names & IPs from CCS and
@@ -962,6 +982,7 @@ static struct cluster_ops _cluster_gulm_ops = {
.is_quorate = _is_quorate,
.get_our_csid = _get_our_csid,
.add_up_node = gulm_add_up_node,
.reread_config = _reread_config,
.cluster_closedown = _cluster_closedown,
.sync_lock = _sync_lock,
.sync_unlock = _sync_unlock,

View File

@@ -87,8 +87,10 @@ struct lvm_thread_cmd {
static pthread_t lvm_thread;
static pthread_mutex_t lvm_thread_mutex;
static pthread_cond_t lvm_thread_cond;
static pthread_mutex_t lvm_start_mutex;
static struct list lvm_cmd_head;
static volatile sig_atomic_t quit = 0;
static volatile sig_atomic_t reread_config = 0;
static int child_pipe[2];
/* Reasons the daemon failed initialisation */
@@ -100,6 +102,7 @@ static int child_pipe[2];
/* Prototypes for code further down */
static void sigusr2_handler(int sig);
static void sighup_handler(int sig);
static void sigterm_handler(int sig);
static void send_local_reply(struct local_client *client, int status,
int clientid);
@@ -221,8 +224,10 @@ int main(int argc, char *argv[])
/* Set up signal handlers, USR1 is for cluster change notifications (in cman)
USR2 causes child threads to exit.
HUP causes gulm version to re-read nodes list from CCS.
PIPE should be ignored */
signal(SIGUSR2, sigusr2_handler);
signal(SIGHUP, sighup_handler);
signal(SIGPIPE, SIG_IGN);
/* Block SIGUSR2 in the main process */
@@ -234,6 +239,7 @@ int main(int argc, char *argv[])
list_init(&lvm_cmd_head);
pthread_mutex_init(&lvm_thread_mutex, NULL);
pthread_cond_init(&lvm_thread_cond, NULL);
pthread_mutex_init(&lvm_start_mutex, NULL);
init_lvhash();
/* Start the cluster interface */
@@ -278,6 +284,7 @@ int main(int argc, char *argv[])
child_init_signal(DFAIL_MALLOC);
newfd->fd = local_sock;
newfd->removeme = 0;
newfd->type = LOCAL_RENDEZVOUS;
newfd->callback = local_rendezvous_callback;
newfd->next = local_client_head.next;
@@ -344,6 +351,7 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
newfd->fd = client_fd;
newfd->type = LOCAL_SOCK;
newfd->xid = 0;
newfd->removeme = 0;
newfd->callback = local_sock_callback;
newfd->bits.localsock.replies = NULL;
newfd->bits.localsock.expected_replies = 0;
@@ -510,13 +518,38 @@ static void main_loop(int local_sock, int cmd_timeout)
FD_SET(thisfd->fd, &in);
}
if ((select_status = select(FD_SETSIZE, &in, NULL, NULL, &tv)) > 0) {
select_status = select(FD_SETSIZE, &in, NULL, NULL, &tv);
if (reread_config) {
int saved_errno = errno;
reread_config = 0;
if (clops->reread_config)
clops->reread_config();
errno = saved_errno;
}
if (select_status > 0) {
struct local_client *lastfd = NULL;
char csid[MAX_CSID_LEN];
char buf[max_cluster_message];
for (thisfd = &local_client_head; thisfd != NULL;
thisfd = thisfd->next) {
if (thisfd->removeme) {
struct local_client *free_fd;
lastfd->next = thisfd->next;
free_fd = thisfd;
thisfd = lastfd;
DEBUGLOG("removeme set for fd %d\n", free_fd->fd);
/* Queue cleanup, this also frees the client struct */
add_to_lvmqueue(free_fd, NULL, 0, NULL);
break;
}
if (FD_ISSET(thisfd->fd, &in)) {
struct local_client *newfd;
int ret;
@@ -903,6 +936,7 @@ static int read_from_local_sock(struct local_client *thisfd)
DEBUGLOG("creating pipe, [%d, %d]\n", comms_pipe[0],
comms_pipe[1]);
newfd->fd = comms_pipe[0];
newfd->removeme = 0;
newfd->type = THREAD_PIPE;
newfd->callback = local_pipe_callback;
newfd->next = thisfd->next;
@@ -1059,8 +1093,8 @@ void process_remote_command(struct clvm_header *msg, int msglen, int fd,
/* Get the node name as we /may/ need it later */
clops->name_from_csid(csid, nodename);
DEBUGLOG("process_remote_command %d for clientid 0x%x on node %s\n",
msg->cmd, msg->clientid, nodename);
DEBUGLOG("process_remote_command %d for clientid 0x%x XID %d on node %s\n",
msg->cmd, msg->clientid, msg->xid, nodename);
/* Is the data to be found in the system LV ? */
if (msg->flags & CLVMD_FLAG_SYSTEMLV) {
@@ -1303,6 +1337,11 @@ static void *pre_and_post_thread(void *arg)
DEBUGLOG("in sub thread: client = %p\n", client);
/* Don't start until the LVM thread is ready */
pthread_mutex_lock(&lvm_start_mutex);
pthread_mutex_unlock(&lvm_start_mutex);
DEBUGLOG("Sub thread ready for work.\n");
/* Ignore SIGUSR1 (handled by master process) but enable
SIGUSR2 (kills subthreads) */
sigemptyset(&ss);
@@ -1568,9 +1607,10 @@ static int send_message(void *buf, int msglen, char *csid, int fd,
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;
@@ -1597,6 +1637,9 @@ static void *lvm_thread_fn(void *arg)
sigset_t ss;
int using_gulm = (int)arg;
/* Don't let anyone else to do work until we are started */
pthread_mutex_lock(&lvm_start_mutex);
DEBUGLOG("LVM thread function started\n");
/* Ignore SIGUSR1 & 2 */
@@ -1608,6 +1651,9 @@ static void *lvm_thread_fn(void *arg)
/* Initialise the interface to liblvm */
init_lvm(using_gulm);
/* Allow others to get moving */
pthread_mutex_unlock(&lvm_start_mutex);
/* Now wait for some actual work */
for (;;) {
DEBUGLOG("LVM thread waiting for work\n");
@@ -1625,7 +1671,8 @@ static void *lvm_thread_fn(void *arg)
pthread_mutex_unlock(&lvm_thread_mutex);
process_work_item(cmd);
free(cmd->msg);
if (cmd->msg)
free(cmd->msg);
free(cmd);
pthread_mutex_lock(&lvm_thread_mutex);
@@ -1788,6 +1835,12 @@ static void sigterm_handler(int sig)
return;
}
static void sighup_handler(int sig)
{
DEBUGLOG("got SIGHUP\n");
reread_config = 1;
}
int sync_lock(const char *resource, int mode, int flags, int *lockid)
{
return clops->sync_lock(resource, mode, flags, lockid);

View File

@@ -86,6 +86,7 @@ struct local_client {
struct local_client *next;
unsigned short xid;
fd_callback_t callback;
uint8_t removeme;
union {
struct localsock_bits localsock;
@@ -95,7 +96,7 @@ struct local_client {
};
#ifdef DEBUG
#define DEBUGLOG(fmt, args...) fprintf(stderr, "CLVMD[%x]: %ld ", (int)pthread_self(), time(NULL) ); fprintf(stderr, fmt, ## args)
#define DEBUGLOG(fmt, args...) {time_t P; time(&P); fprintf(stderr, "CLVMD[%x]: %.15s ", (int)pthread_self(), ctime(&P)+4 ); fprintf(stderr, fmt, ## args);}
#else
#define DEBUGLOG(fmt, args...)
#endif

View File

@@ -69,6 +69,7 @@ int init_comms(unsigned short port)
{
int one = 1;
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
setsockopt(listen_fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(int));
}
memset(&addr, 0, sizeof(addr)); // Bind to INADDR_ANY
@@ -104,6 +105,7 @@ void tcp_remove_client(char *csid)
if (client)
{
hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
client->removeme = 1;
}
/* Look for a mangled one too */
@@ -113,6 +115,7 @@ void tcp_remove_client(char *csid)
if (client)
{
hash_remove_binary(sock_hash, csid, GULM_MAX_CSID_LEN);
client->removeme = 1;
}
/* Put it back as we found it */
@@ -286,7 +289,7 @@ static int read_from_tcpsock(struct local_client *client, char *buf, int len, ch
else {
gulm_add_up_node(csid);
/* Send it back to clvmd */
process_message(client, buf, len, csid);
process_message(client, buf, status, csid);
}
return status;
}
@@ -296,6 +299,7 @@ int gulm_connect_csid(char *csid, struct local_client **newclient)
int fd;
struct sockaddr_in6 addr;
int status;
int one = 1;
DEBUGLOG("Connecting socket\n");
fd = socket(PF_INET6, SOCK_STREAM, 0);
@@ -327,6 +331,7 @@ int gulm_connect_csid(char *csid, struct local_client **newclient)
/* Set Close-on-exec */
fcntl(fd, F_SETFD, 1);
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(int));
status = alloc_client(fd, csid, newclient);
if (status)

View File

@@ -0,0 +1,3 @@
process_event
register_device
unregister_device

View File

@@ -0,0 +1,51 @@
#
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
#
# This file is part of the device-mapper userspace tools.
#
# 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
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
TARGETS = dmevent dmeventd
INSTALL_TYPE = install_dynamic
SOURCES = noop.c
CLEAN_TARGETS = dmevent.o dmeventd.o
ifeq ("@LIB_SUFFIX@","dylib")
LIB_SHARED = libdmeventdnoop.dylib
else
LIB_SHARED = libdmeventdnoop.so
endif
LDFLAGS += -ldl -ldevmapper -lpthread -lmultilog
include ../make.tmpl
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)
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)
install: $(INSTALL_TYPE)
.PHONY: install_dynamic
install_dynamic: dmeventd
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) dmeventd $(sbindir)/dmeventd

171
daemons/dmeventd/dmevent.c Normal file
View File

@@ -0,0 +1,171 @@
/*
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* 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 Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser 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 "libdevmapper.h"
#include "libdm-event.h"
#include "libmultilog.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.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 */
/* Display help. */
static void print_usage(char *name)
{
char *cmd = strrchr(name, '/');
cmd = cmd ? cmd + 1 : name;
printf("Usage::\n"
"%s [options] <device>\n"
"\n"
"Options:\n"
" -d <dso> Specify the DSO to use.\n"
" -h Print this usage.\n"
" -l List registered devices.\n"
" -r Register for event (default).\n"
" -u Unregister for event.\n"
"\n", cmd);
}
/* Parse command line arguments. */
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";
while ((c = getopt(argc, argv, options)) != -1) {
switch (c) {
case 'd':
*dso_name_arg = optarg;
break;
case 'h':
print_usage(argv[0]);
exit(EXIT_SUCCESS);
case 'l':
*list = 1;
break;
case 'r':
*reg = 1;
break;
case 'u':
*reg = 0;
break;
default:
fprintf(stderr, "Unknown option '%c'.\n"
"Try '-h' for help.\n", c);
return 0;
}
}
if (optind >= argc) {
if (!*list) {
fprintf(stderr, "You need to specify a device.\n");
return 0;
}
} else
*device_arg = argv[optind];
return 1;
}
int main(int argc, char **argv)
{
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 = strdup(device_arg)))
exit(EXIT_FAILURE);
} else
device = NULL;
if (dso_name_arg){
if (!(dso_name = strdup(dso_name_arg)))
exit(EXIT_FAILURE);
} else {
if (!(dso_name = strdup(default_dso_name)))
exit(EXIT_FAILURE);
}
/* FIXME: use -v/-q options to set this */
multilog_add_type(standard, NULL);
multilog_init_verbose(standard, _LOG_DEBUG);
if (list) {
do {
if (!(ret= dm_get_registered_device(&dso_name,
&device,
&events, next))) {
printf("%s %s 0x%x\n",
dso_name, device, events);
if (device_arg)
break;
next = 1;
}
} while (!ret);
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))) {
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;
}
out:
multilog_del_type(standard);
if (device)
free(device);
if (dso_name)
free(dso_name);
exit(ret);
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/

1084
daemons/dmeventd/dmeventd.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
#!/bin/sh
#
# Create test devices for dmeventd
#
trap "rm -f /tmp/tmp.$$" 0 1 2 3 15
echo "0 1024 zero" > /tmp/tmp.$$
dmsetup create test /tmp/tmp.$$
dmsetup create test1 /tmp/tmp.$$
kill -15 $$

39
daemons/dmeventd/noop.c Normal file
View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* 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 Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser 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 "libdm-event.h"
#include "libmultilog.h"
void process_event(char *device, enum event_type event)
{
log_err("[%s] %s(%d) - Device: %s, Event %d\n",
__FILE__, __func__, __LINE__, device, event);
}
int register_device(char *device)
{
log_err("[%s] %s(%d) - Device: %s\n",
__FILE__, __func__, __LINE__, device);
return 1;
}
int unregister_device(char *device)
{
log_err("[%s] %s(%d) - Device: %s\n",
__FILE__, __func__, __LINE__, device);
return 1;
}

View File

@@ -23,6 +23,7 @@
../lib/filters/filter.h
../lib/format1/format1.h
../lib/format_pool/format_pool.h
../lib/format_text/archiver.h
../lib/format_text/format-text.h
../lib/format_text/text_export.h
../lib/format_text/text_import.h
@@ -31,6 +32,7 @@
../lib/log/log.h
../lib/metadata/lv_alloc.h
../lib/metadata/metadata.h
../lib/metadata/pv_alloc.h
../lib/metadata/segtype.h
../lib/mm/dbg_malloc.h
../lib/mm/memlock.h

View File

@@ -54,6 +54,7 @@ SOURCES =\
filters/filter-md.c \
filters/filter.c \
format_text/archive.c \
format_text/archiver.c \
format_text/export.c \
format_text/flags.c \
format_text/format-text.c \
@@ -70,6 +71,7 @@ SOURCES =\
metadata/merge.c \
metadata/metadata.c \
metadata/mirror.c \
metadata/pv_manip.c \
metadata/pv_map.c \
metadata/segtype.c \
metadata/snapshot_manip.c \

View File

@@ -727,6 +727,25 @@ 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 tw;
tw = lvm_snprintf(params, paramsize, "core 1 %u %u ",
region_size, areas);
if (tw < 0) {
stack;
return -1;
}
*pos += tw;
return 1;
}
int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
char *params, size_t paramsize, int *pos, int start_area,
int areas)
@@ -741,7 +760,9 @@ int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
for (s = start_area; s < areas; s++, *pos += tw) {
trailing_space = (areas - s - 1) ? " " : "";
if ((seg->area[s].type == AREA_PV &&
(!seg->area[s].u.pv.pv || !seg->area[s].u.pv.pv->dev)) ||
(!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))
tw = lvm_snprintf(params + *pos, paramsize - *pos,
"%s 0%s", dm->stripe_filler,
@@ -749,9 +770,12 @@ int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
else if (seg->area[s].type == AREA_PV)
tw = lvm_snprintf(params + *pos, paramsize - *pos,
"%s %" PRIu64 "%s",
dev_name(seg->area[s].u.pv.pv->dev),
(seg->area[s].u.pv.pv->pe_start +
(esize * seg->area[s].u.pv.pe)),
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)),
trailing_space);
else {
if (!(dl = hash_lookup(dm->layers,
@@ -875,22 +899,23 @@ static int _populate_snapshot(struct dev_manager *dm,
{
char *origin, *cow;
char params[PATH_MAX * 2 + 32];
struct snapshot *s;
struct lv_segment *snap_seg;
struct dev_layer *dlo, *dlc;
char devbufo[10], devbufc[10];
uint64_t size;
if (!(s = find_cow(dl->lv))) {
if (!(snap_seg = find_cow(dl->lv))) {
log_error("Couldn't find snapshot for '%s'.", dl->lv->name);
return 0;
}
if (!(origin = _build_dlid(dm->mem, s->origin->lvid.s, "real"))) {
if (!(origin = _build_dlid(dm->mem, snap_seg->origin->lvid.s,
"real"))) {
stack;
return 0;
}
if (!(cow = _build_dlid(dm->mem, s->cow->lvid.s, "cow"))) {
if (!(cow = _build_dlid(dm->mem, snap_seg->cow->lvid.s, "cow"))) {
stack;
return 0;
}
@@ -909,24 +934,24 @@ static int _populate_snapshot(struct dev_manager *dm,
if (!dm_format_dev(devbufo, sizeof(devbufo), dlo->info.major,
dlo->info.minor)) {
log_error("Couldn't create origin device parameters for '%s'.",
s->origin->name);
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'.",
s->cow->name);
snap_seg->cow->name);
return 0;
}
if (lvm_snprintf(params, sizeof(params), "%s %s P %d",
devbufo, devbufc, s->chunk_size) == -1) {
devbufo, devbufc, snap_seg->chunk_size) == -1) {
stack;
return 0;
}
size = (uint64_t) s->le_count * s->origin->vg->extent_size;
size = (uint64_t) snap_seg->len * snap_seg->origin->vg->extent_size;
log_debug("Adding target: 0 %" PRIu64 " snapshot %s", size, params);
if (!dm_task_add_target(dmt, UINT64_C(0), size, "snapshot", params)) {
@@ -1274,7 +1299,7 @@ static int _expand_origin_real(struct dev_manager *dm,
static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv)
{
struct logical_volume *active;
struct snapshot *s;
struct lv_segment *snap_seg;
struct list *sh;
/*
@@ -1283,7 +1308,7 @@ static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv)
*/
list_iterate(sh, &dm->active_list) {
active = list_item(sh, struct lv_list)->lv;
if ((s = find_cow(active)) && (s->origin == lv))
if ((snap_seg = find_cow(active)) && (snap_seg->origin == lv))
return _expand_origin_real(dm, lv);
}
@@ -1294,7 +1319,7 @@ static int _expand_origin(struct dev_manager *dm, struct logical_volume *lv)
}
static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv,
struct snapshot *s)
struct lv_segment *snap_seg)
{
/*
* snapshot(org, cow)
@@ -1331,13 +1356,15 @@ static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv,
/* add the dependency on the real origin device */
if (!str_list_add(dm->mem, &dl->pre_create,
_build_dlid(dm->mem, s->origin->lvid.s, "real"))) {
_build_dlid(dm->mem, snap_seg->origin->lvid.s,
"real"))) {
stack;
return 0;
}
/* add the dependency on the visible origin device */
if (!str_list_add(dm->mem, &dl->pre_suspend, s->origin->lvid.s)) {
if (!str_list_add(dm->mem, &dl->pre_suspend,
snap_seg->origin->lvid.s)) {
stack;
return 0;
}
@@ -1350,13 +1377,13 @@ static int _expand_snapshot(struct dev_manager *dm, struct logical_volume *lv,
*/
static int _expand_lv(struct dev_manager *dm, struct logical_volume *lv)
{
struct snapshot *s;
struct lv_segment *snap_seg;
/*
* FIXME: this doesn't cope with recursive snapshots yet.
*/
if ((s = find_cow(lv)))
return _expand_snapshot(dm, lv, s);
if ((snap_seg = find_cow(lv)))
return _expand_snapshot(dm, lv, snap_seg);
else if (lv_is_origin(lv))
return _expand_origin(dm, lv);
@@ -1445,6 +1472,8 @@ static int _mark_lvs(struct dev_manager *dm, struct list *lvs, int flag)
list_iterate(lvh, lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if (lv->status & SNAPSHOT)
continue;
if (!(dl = _lookup(dm, lv->lvid.s, NULL))) {
stack;
@@ -1606,14 +1635,16 @@ 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 *lvt;
struct logical_volume *lv;
/*
* Build layers for complete vg.
*/
list_iterate(lvh, &vg->lvs) {
lvt = list_item(lvh, struct lv_list)->lv;
if (!_expand_lv(dm, lvt)) {
lv = list_item(lvh, struct lv_list)->lv;
if (lv->status & SNAPSHOT)
continue;
if (!_expand_lv(dm, lv)) {
stack;
return 0;
}
@@ -1915,12 +1946,14 @@ static int _add_lvs(struct pool *mem,
struct list *head, struct logical_volume *origin)
{
struct logical_volume *lv;
struct snapshot *s;
struct lv_segment *snap_seg;
struct list *lvh;
list_iterate(lvh, &origin->vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if ((s = find_cow(lv)) && s->origin == origin)
if (lv->status & SNAPSHOT)
continue;
if ((snap_seg = find_cow(lv)) && snap_seg->origin == origin)
if (!_add_lv(mem, head, lv))
return 0;
}
@@ -1945,7 +1978,7 @@ static void _remove_lv(struct list *head, struct logical_volume *lv)
static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv)
{
struct logical_volume *active, *old_origin;
struct snapshot *s;
struct lv_segment *snap_seg;
struct list *sh, *active_head;
active_head = &dm->active_list;
@@ -1953,22 +1986,23 @@ static int _remove_lvs(struct dev_manager *dm, struct logical_volume *lv)
/* Remove any snapshots with given origin */
list_iterate(sh, active_head) {
active = list_item(sh, struct lv_list)->lv;
if ((s = find_cow(active)) && s->origin == lv) {
if ((snap_seg = find_cow(active)) && snap_seg->origin == lv) {
_remove_lv(active_head, active);
}
}
_remove_lv(active_head, lv);
if (!(s = find_cow(lv)))
if (!(snap_seg = find_cow(lv)))
return 1;
old_origin = s->origin;
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;
if ((s = find_cow(active)) && s->origin == old_origin) {
if ((snap_seg = find_cow(active)) &&
snap_seg->origin == old_origin) {
return 1;
}
}
@@ -1980,7 +2014,7 @@ static int _remove_suspended_lvs(struct dev_manager *dm,
struct logical_volume *lv)
{
struct logical_volume *suspended;
struct snapshot *s;
struct lv_segment *snap_seg;
struct list *sh, *suspend_head;
suspend_head = &dm->suspend_list;
@@ -1988,7 +2022,8 @@ static int _remove_suspended_lvs(struct dev_manager *dm,
/* Remove from list any snapshots with given origin */
list_iterate(sh, suspend_head) {
suspended = list_item(sh, struct lv_list)->lv;
if ((s = find_cow(suspended)) && s->origin == lv) {
if ((snap_seg = find_cow(suspended)) &&
snap_seg->origin == lv) {
_remove_lv(suspend_head, suspended);
}
}
@@ -2074,6 +2109,8 @@ static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg)
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if (lv->status & SNAPSHOT)
continue;
if (!(dlid = _build_dlid(dm->mem, lv->lvid.s, NULL))) {
stack;

View File

@@ -19,7 +19,12 @@
struct dev_manager;
struct lv_segment;
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_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);
#endif

View File

@@ -36,9 +36,10 @@ struct volume_group;
struct lvmcache_vginfo {
struct list list; /* Join these vginfos together */
struct list infos; /* List head for lvmcache_infos */
const struct format_type *fmt;
char *vgname; /* "" == orphan */
char vgid[ID_LEN + 1];
const struct format_type *fmt;
char _padding[7];
};
struct lvmcache_info {

View File

@@ -35,6 +35,8 @@
#include "str_list.h"
#include "segtype.h"
#include "lvmcache.h"
#include "dev-cache.h"
#include "archiver.h"
#ifdef HAVE_LIBDL
#include "sharedlib.h"
@@ -493,6 +495,24 @@ static int _init_dev_cache(struct cmd_context *cmd)
}
}
if (!(cn = find_config_node(cmd->cft->root, "devices/loopfiles")))
return 1;
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != CFG_STRING) {
log_error("Invalid string in config file: "
"devices/loopfiles");
return 0;
}
if (!dev_cache_add_loopfile(cv->v.str)) {
log_error("Failed to add loopfile %s to internal "
"device cache", cv->v.str);
return 0;
}
}
return 1;
}
@@ -795,6 +815,69 @@ static int _init_hostname(struct cmd_context *cmd)
return 1;
}
static int _init_backup(struct cmd_context *cmd)
{
uint32_t days, min;
char default_dir[PATH_MAX];
const char *dir;
if (!cmd->sys_dir) {
log_warn("WARNING: Metadata changes will NOT be backed up");
backup_init(cmd, "");
archive_init(cmd, "", 0, 0);
return 1;
}
/* set up archiving */
cmd->default_settings.archive =
find_config_bool(cmd->cft->root, "backup/archive",
DEFAULT_ARCHIVE_ENABLED);
days = (uint32_t) find_config_int(cmd->cft->root, "backup/retain_days",
DEFAULT_ARCHIVE_DAYS);
min = (uint32_t) find_config_int(cmd->cft->root, "backup/retain_min",
DEFAULT_ARCHIVE_NUMBER);
if (lvm_snprintf
(default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir,
DEFAULT_ARCHIVE_SUBDIR) == -1) {
log_err("Couldn't create default archive path '%s/%s'.",
cmd->sys_dir, DEFAULT_ARCHIVE_SUBDIR);
return 0;
}
dir = find_config_str(cmd->cft->root, "backup/archive_dir",
default_dir);
if (!archive_init(cmd, dir, days, min)) {
log_debug("backup_init failed.");
return 0;
}
/* set up the backup */
cmd->default_settings.backup =
find_config_bool(cmd->cft->root, "backup/backup",
DEFAULT_BACKUP_ENABLED);
if (lvm_snprintf
(default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir,
DEFAULT_BACKUP_SUBDIR) == -1) {
log_err("Couldn't create default backup path '%s/%s'.",
cmd->sys_dir, DEFAULT_BACKUP_SUBDIR);
return 0;
}
dir = find_config_str(cmd->cft->root, "backup/backup_dir", default_dir);
if (!backup_init(cmd, dir)) {
log_debug("backup_init failed.");
return 0;
}
return 1;
}
/* Entry point */
struct cmd_context *create_toolcontext(struct arg *the_args)
{
@@ -883,6 +966,9 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
if (!_init_segtypes(cmd))
goto error;
if (!_init_backup(cmd))
goto error;
cmd->current_settings = cmd->default_settings;
cmd->config_valid = 1;
@@ -993,6 +1079,8 @@ void destroy_toolcontext(struct cmd_context *cmd)
if (cmd->dump_filter)
persistent_filter_dump(cmd->filter);
archive_exit(cmd);
backup_exit(cmd);
activation_exit();
lvmcache_destroy();
label_exit();

View File

@@ -32,20 +32,20 @@ struct config_info {
int syslog;
int activation;
int suffix;
uint64_t unit_factor;
char unit_type;
const char *msg_prefix;
int cmd_name; /* Show command name? */
int archive; /* should we archive ? */
int backup; /* should we backup ? */
const char *msg_prefix;
struct format_type *fmt;
uint64_t unit_factor;
int cmd_name; /* Show command name? */
mode_t umask;
char unit_type;
char _padding[1];
};
struct config_tree;
struct archive_params;
struct backup_params;
/* FIXME Split into tool & library contexts */
/* command-instance-related variables needed by library */
@@ -75,6 +75,9 @@ struct cmd_context {
struct config_info default_settings;
struct config_info current_settings;
struct archive_params *archive_params;
struct backup_params *backup_params;
/* List of defined tags */
struct list tags;
int hosttags;

View File

@@ -235,7 +235,7 @@ int read_config_file(struct config_tree *cft)
return 1;
}
if (!(dev = dev_create_file(c->filename, NULL, NULL))) {
if (!(dev = dev_create_file(c->filename, NULL, NULL, 1))) {
stack;
return 0;
}

View File

@@ -95,15 +95,18 @@
#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_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"
#define DEFAULT_PVSEGS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"
#define DEFAULT_LVS_SORT "vg_name,lv_name"
#define DEFAULT_VGS_SORT "vg_name"
#define DEFAULT_PVS_SORT "pv_name"
#define DEFAULT_SEGS_SORT "vg_name,lv_name,seg_start"
#define DEFAULT_PVSEGS_SORT "pv_name,pvseg_start"
#endif /* _LVM_DEFAULTS_H */

View File

@@ -18,17 +18,30 @@
#include <assert.h>
/*
* A list consists of a list head plus elements.
* Each element has 'next' and 'previous' pointers.
* The list head's pointers point to the first and the last element.
*/
struct list {
struct list *n, *p;
};
/*
* Initialise a list before use.
* The list head's next and previous pointers point back to itself.
*/
#define LIST_INIT(name) struct list name = { &(name), &(name) }
static inline void list_init(struct list *head)
{
head->n = head->p = head;
}
/*
* Insert an element before 'head'.
* If 'head' is the list head, this adds an element to the end of the list.
*/
static inline void list_add(struct list *head, struct list *elem)
{
assert(head->n);
@@ -40,6 +53,10 @@ static inline void list_add(struct list *head, struct list *elem)
head->p = elem;
}
/*
* Insert an element after 'head'.
* If 'head' is the list head, this adds an element to the front of the list.
*/
static inline void list_add_h(struct list *head, struct list *elem)
{
assert(head->n);
@@ -51,53 +68,135 @@ static inline void list_add_h(struct list *head, struct list *elem)
head->n = elem;
}
/*
* Delete an element from its list.
* Note that this doesn't change the element itself - it may still be safe
* to follow its pointers.
*/
static inline void list_del(struct list *elem)
{
elem->n->p = elem->p;
elem->p->n = elem->n;
}
/*
* Is the list empty?
*/
static inline int list_empty(struct list *head)
{
return head->n == head;
}
/*
* Is this the first element of the list?
*/
static inline int list_start(struct list *head, struct list *elem)
{
return elem->p == head;
}
/*
* Is this the last element of the list?
*/
static inline int list_end(struct list *head, struct list *elem)
{
return elem->n == head;
}
/*
* Return last element of the list or NULL if empty
*/
static inline struct list *list_last(struct list *head)
{
return (list_empty(head) ? NULL : head->p);
}
/*
* Return the previous element of the list, or NULL if we've reached the start.
*/
static inline struct list *list_prev(struct list *head, struct list *elem)
{
return (list_start(head, elem) ? NULL : elem->p);
}
/*
* Return the next element of the list, or NULL if we've reached the end.
*/
static inline struct list *list_next(struct list *head, struct list *elem)
{
return (list_end(head, elem) ? NULL : elem->n);
}
#define list_item(v, t) \
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list))
/*
* Given the address v of an instance of 'struct list' called 'head'
* contained in a structure of type t, return the containing structure.
*/
#define list_struct_base(v, t, head) \
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->head))
#define list_struct_base(v, t, h) \
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->h))
/*
* Given the address v of an instance of 'struct list list' contained in
* a structure of type t, return the containing structure.
*/
#define list_item(v, t) list_struct_base((v), t, list)
/* Given a known element in a known structure, locate another */
/*
* Given the address v of one known element e in a known structure of type t,
* return another element f.
*/
#define struct_field(v, t, e, f) \
(((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->f)
/* Given a known element in a known structure, locate the list head */
/*
* Given the address v of a known element e in a known structure of type t,
* return the list head 'list'
*/
#define list_head(v, t, e) struct_field(v, t, e, list)
/*
* Set v to each element of a list in turn.
*/
#define list_iterate(v, head) \
for (v = (head)->n; v != head; v = v->n)
/*
* Set v to each element in a list in turn, starting from the element
* in front of 'start'.
* You can use this to 'unwind' a list_iterate and back out actions on
* already-processed elements.
* If 'start' is 'head' it walks the list backwards.
*/
#define list_uniterate(v, head, start) \
for (v = (start)->p; v != head; v = v->p)
/*
* A safe way to walk a list and delete and free some elements along
* the way.
* t must be defined as a temporary variable of the same type as v.
*/
#define list_iterate_safe(v, t, head) \
for (v = (head)->n, t = v->n; v != head; v = t, t = v->n)
#define list_iterate_items(v, head) \
for (v = list_item((head)->n, typeof(*v)); &v->list != (head); \
v = list_item(v->list.n, typeof(*v)))
/*
* Walk a list, 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_items_gen(v, head, field) \
for (v = list_struct_base((head)->n, typeof(*v), field); \
&v->field != (head); \
v = list_struct_base(v->field.n, typeof(*v), field))
/*
* Walk a list, 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_items(v, head) list_iterate_items_gen(v, (head), list)
/*
* Return the number of elements in a list by walking it.
*/
static inline unsigned int list_size(const struct list *head)
{
unsigned int s = 0;

View File

@@ -22,7 +22,7 @@
#include <inttypes.h>
/* Define some portable printing types */
#define PRIsize_t "Zu"
#define PRIsize_t "zu"
struct str_list {
struct list list;

View File

@@ -44,39 +44,60 @@ static struct {
int has_scanned;
struct list dirs;
struct list files;
} _cache;
#define _alloc(x) pool_alloc(_cache.mem, (x))
#define _alloc(x) pool_zalloc(_cache.mem, (x))
#define _free(x) pool_free(_cache.mem, (x))
#define _strdup(x) pool_strdup(_cache.mem, (x))
static int _insert(const char *path, int rec);
struct device *dev_create_file(const char *filename, struct device *dev,
struct str_list *alias)
struct str_list *alias, int use_malloc)
{
int allocate = !dev;
if (allocate && !(dev = dbg_malloc(sizeof(*dev)))) {
log_error("struct device allocation failed");
return NULL;
}
if (allocate && !(alias = dbg_malloc(sizeof(*alias)))) {
log_error("struct str_list allocation failed");
dbg_free(dev);
return NULL;
}
if (!(alias->str = dbg_strdup(filename))) {
log_error("filename strdup failed");
if (allocate) {
dbg_free(dev);
dbg_free(alias);
if (allocate) {
if (use_malloc) {
if (!(dev = dbg_malloc(sizeof(*dev)))) {
log_error("struct device allocation failed");
return NULL;
}
if (!(alias = dbg_malloc(sizeof(*alias)))) {
log_error("struct str_list allocation failed");
dbg_free(dev);
return NULL;
}
if (!(alias->str = dbg_strdup(filename))) {
log_error("filename strdup failed");
dbg_free(dev);
dbg_free(alias);
return NULL;
}
dev->flags = DEV_ALLOCED;
} else {
if (!(dev = _alloc(sizeof(*dev)))) {
log_error("struct device allocation failed");
return NULL;
}
if (!(alias = _alloc(sizeof(*alias)))) {
log_error("struct str_list allocation failed");
_free(dev);
return NULL;
}
if (!(alias->str = _strdup(filename))) {
log_error("filename strdup failed");
return NULL;
}
}
} else if (!(alias->str = dbg_strdup(filename))) {
log_error("filename strdup failed");
return NULL;
}
dev->flags = DEV_REGULAR;
if (allocate)
dev->flags |= DEV_ALLOCED;
dev->flags |= DEV_REGULAR;
list_init(&dev->aliases);
list_add(&dev->aliases, &alias->list);
dev->end = UINT64_C(0);
@@ -221,12 +242,25 @@ static int _add_alias(struct device *dev, const char *path)
static int _insert_dev(const char *path, dev_t d)
{
struct device *dev;
static dev_t loopfile_count = 0;
int loopfile = 0;
/* Generate pretend device numbers for loopfiles */
if (!d) {
d = ++loopfile_count;
loopfile = 1;
}
/* is this device already registered ? */
if (!(dev = (struct device *) btree_lookup(_cache.devices,
(uint32_t) d))) {
/* create new device */
if (!(dev = _dev_create(d))) {
if (loopfile) {
if (!(dev = dev_create_file(path, NULL, NULL, 0))) {
stack;
return 0;
}
} else if (!(dev = _dev_create(d))) {
stack;
return 0;
}
@@ -238,7 +272,7 @@ static int _insert_dev(const char *path, dev_t d)
}
}
if (!_add_alias(dev, path)) {
if (!loopfile && !_add_alias(dev, path)) {
log_err("Couldn't add alias to dev cache.");
return 0;
}
@@ -314,6 +348,28 @@ static int _insert_dir(const char *dir)
return r;
}
static int _insert_file(const char *path)
{
struct stat info;
if (stat(path, &info) < 0) {
log_sys_very_verbose("stat", path);
return 0;
}
if (!S_ISREG(info.st_mode)) {
log_debug("%s: Not a regular file", path);
return 0;
}
if (!_insert_dev(path, 0)) {
stack;
return 0;
}
return 1;
}
static int _insert(const char *path, int rec)
{
struct stat info;
@@ -368,6 +424,11 @@ static void _full_scan(int dev_scan)
_insert_dir(dl->dir);
};
list_iterate(dh, &_cache.files) {
struct dir_list *dl = list_item(dh, struct dir_list);
_insert_file(dl->dir);
};
_cache.has_scanned = 1;
init_full_scan_done(1);
}
@@ -408,6 +469,7 @@ int dev_cache_init(void)
}
list_init(&_cache.dirs);
list_init(&_cache.files);
return 1;
@@ -445,6 +507,7 @@ void dev_cache_exit(void)
_cache.devices = NULL;
_cache.has_scanned = 0;
list_init(&_cache.dirs);
list_init(&_cache.files);
}
int dev_cache_add_dir(const char *path)
@@ -473,6 +536,32 @@ int dev_cache_add_dir(const char *path)
return 1;
}
int dev_cache_add_loopfile(const char *path)
{
struct dir_list *dl;
struct stat st;
if (stat(path, &st)) {
log_error("Ignoring %s: %s", path, strerror(errno));
/* But don't fail */
return 1;
}
if (!S_ISREG(st.st_mode)) {
log_error("Ignoring %s: Not a regular file", path);
return 1;
}
if (!(dl = _alloc(sizeof(*dl) + strlen(path) + 1))) {
log_error("dir_list allocation failed for file");
return 0;
}
strcpy(dl->dir, path);
list_add(&_cache.files, &dl->list);
return 1;
}
/* Check cached device name is still valid before returning it */
/* This should be a rare occurrence */
/* set quiet if the cache is expected to be out-of-date */
@@ -483,6 +572,9 @@ const char *dev_name_confirmed(struct device *dev, int quiet)
const char *name;
int r;
if ((dev->flags & DEV_REGULAR))
return dev_name(dev);
while ((r = stat(name = list_item(dev->aliases.n,
struct str_list)->str, &buf)) ||
(buf.st_rdev != dev->dev)) {
@@ -527,6 +619,9 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
struct stat buf;
struct device *d = (struct device *) hash_lookup(_cache.names, name);
if (d && (d->flags & DEV_REGULAR))
return d;
/* If the entry's wrong, remove it */
if (d && (stat(name, &buf) || (buf.st_rdev != d->dev))) {
hash_remove(_cache.names, name);
@@ -538,7 +633,8 @@ struct device *dev_cache_get(const char *name, struct dev_filter *f)
d = (struct device *) hash_lookup(_cache.names, name);
}
return (d && (!f || f->passes_filter(f, d))) ? d : NULL;
return (d && (!f || (d->flags & DEV_REGULAR) ||
f->passes_filter(f, d))) ? d : NULL;
}
struct dev_iter *dev_iter_create(struct dev_filter *f, int dev_scan)
@@ -580,7 +676,7 @@ struct device *dev_iter_get(struct dev_iter *iter)
{
while (iter->current) {
struct device *d = _iter_next(iter);
if (!iter->filter ||
if (!iter->filter || (d->flags & DEV_REGULAR) ||
iter->filter->passes_filter(iter->filter, d))
return d;
}

View File

@@ -39,6 +39,7 @@ void dev_cache_scan(int do_scan);
int dev_cache_has_scanned(void);
int dev_cache_add_dir(const char *path);
int dev_cache_add_loopfile(const char *path);
struct device *dev_cache_get(const char *name, struct dev_filter *f);
/*

View File

@@ -222,11 +222,25 @@ static int _aligned_io(struct device_area *where, void *buffer,
return 1;
}
/*-----------------------------------------------------------------
* Public functions
*---------------------------------------------------------------*/
static int _dev_get_size_file(const struct device *dev, uint64_t *size)
{
const char *name = dev_name(dev);
struct stat info;
int dev_get_size(const struct device *dev, uint64_t *size)
if (stat(name, &info)) {
log_sys_error("stat", name);
return 0;
}
*size = info.st_size;
*size >>= SECTOR_SHIFT; /* Convert to sectors */
log_very_verbose("%s: size is %" PRIu64 " sectors", name, *size);
return 1;
}
static int _dev_get_size_dev(const struct device *dev, uint64_t *size)
{
int fd;
const char *name = dev_name(dev);
@@ -252,6 +266,18 @@ int dev_get_size(const struct device *dev, uint64_t *size)
return 1;
}
/*-----------------------------------------------------------------
* Public functions
*---------------------------------------------------------------*/
int dev_get_size(const struct device *dev, uint64_t *size)
{
if ((dev->flags & DEV_REGULAR))
return _dev_get_size_file(dev, size);
else
return _dev_get_size_dev(dev, size);
}
/* FIXME Unused
int dev_get_sectsize(struct device *dev, uint32_t *size)
{
@@ -330,8 +356,13 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
}
#ifdef O_DIRECT_SUPPORT
if (direct)
flags |= O_DIRECT;
if (direct) {
if (!(dev->flags & DEV_O_DIRECT_TESTED))
dev->flags |= DEV_O_DIRECT;
if ((dev->flags & DEV_O_DIRECT))
flags |= O_DIRECT;
}
#endif
#ifdef O_NOATIME
@@ -341,6 +372,16 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
#endif
if ((dev->fd = open(name, flags, 0777)) < 0) {
#ifdef O_DIRECT_SUPPORT
if (direct && !(dev->flags & DEV_O_DIRECT_TESTED)) {
flags &= ~O_DIRECT;
if ((dev->fd = open(name, flags, 0777)) >= 0) {
dev->flags &= ~DEV_O_DIRECT;
log_debug("%s: Not using O_DIRECT", name);
goto opened;
}
}
#endif
if (quiet)
log_sys_debug("open", name);
else
@@ -348,8 +389,14 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
return 0;
}
#ifdef O_DIRECT_SUPPORT
opened:
if (direct)
dev->flags |= DEV_O_DIRECT_TESTED;
#endif
dev->open_count++;
dev->flags &= ~DEV_ACCESSED_W;
if ((flags & O_ACCMODE) == O_RDWR)
dev->flags |= DEV_OPENED_RW;
else
@@ -373,8 +420,9 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
list_add(&_open_devices, &dev->open_list);
log_debug("Opened %s %s", dev_name(dev),
dev->flags & DEV_OPENED_RW ? "RW" : "RO");
log_debug("Opened %s %s%s", dev_name(dev),
dev->flags & DEV_OPENED_RW ? "RW" : "RO",
dev->flags & DEV_O_DIRECT ? " O_DIRECT" : "");
return 1;
}

View File

@@ -23,6 +23,8 @@
#define DEV_REGULAR 0x00000002 /* Regular file? */
#define DEV_ALLOCED 0x00000004 /* dbg_malloc used */
#define DEV_OPENED_RW 0x00000008 /* Opened RW */
#define DEV_O_DIRECT 0x00000010 /* Use O_DIRECT */
#define DEV_O_DIRECT_TESTED 0x00000020 /* DEV_O_DIRECT is reliable */
/*
* All devices in LVM will be represented by one of these.
@@ -41,6 +43,7 @@ struct device {
struct list open_list;
char pvid[ID_LEN + 1];
char _padding[7];
};
struct device_list {
@@ -63,7 +66,7 @@ int dev_get_sectsize(struct device *dev, uint32_t *size);
/* Use quiet version if device number could change e.g. when opening LV */
int dev_open(struct device *dev);
int dev_open_quiet(struct device *dev);
int dev_open_flags(struct device *dev, int flags, int append, int quiet);
int dev_open_flags(struct device *dev, int flags, int direct, int quiet);
int dev_close(struct device *dev);
int dev_close_immediate(struct device *dev);
void dev_close_all(void);
@@ -80,7 +83,7 @@ int dev_zero(struct device *dev, uint64_t offset, size_t len);
void dev_flush(struct device *dev);
struct device *dev_create_file(const char *filename, struct device *dev,
struct str_list *alias);
struct str_list *alias, int use_malloc);
static inline const char *dev_name(const struct device *dev)
{

View File

@@ -337,10 +337,9 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
void *handle)
{
struct lvinfo info;
int inkernel, snap_active;
int inkernel, snap_active = 0;
char uuid[64];
struct snapshot *snap = NULL;
struct list *slh, *snaplist;
struct lv_segment *snap_seg = NULL;
float snap_percent; /* fused, fsize; */
if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) {
@@ -364,27 +363,30 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
if (lv_is_origin(lv)) {
log_print("LV snapshot status source of");
snaplist = find_snapshots(lv);
list_iterate(slh, snaplist) {
snap = list_item(slh, struct snapshot_list)->snapshot;
snap_active = lv_snapshot_percent(snap->cow,
&snap_percent);
if (!snap_active || snap_percent < 0 ||
snap_percent >= 100) snap_active = 0;
list_iterate_items_gen(snap_seg, &lv->snapshot_segs,
origin_list) {
if (inkernel &&
(snap_active = lv_snapshot_percent(snap_seg->cow,
&snap_percent)))
if (snap_percent < 0 || snap_percent >= 100)
snap_active = 0;
log_print(" %s%s/%s [%s]",
lv->vg->cmd->dev_dir, lv->vg->name,
snap->cow->name,
snap_seg->cow->name,
(snap_active > 0) ? "active" : "INACTIVE");
}
snap = NULL;
} else if ((snap = find_cow(lv))) {
snap_active = lv_snapshot_percent(lv, &snap_percent);
if (!snap_active || snap_percent < 0 || snap_percent >= 100)
snap_active = 0;
snap_seg = NULL;
} else if ((snap_seg = find_cow(lv))) {
if (inkernel &&
(snap_active = lv_snapshot_percent(snap_seg->cow,
&snap_percent)))
if (snap_percent < 0 || snap_percent >= 100)
snap_active = 0;
log_print("LV snapshot status %s destination for %s%s/%s",
(snap_active > 0) ? "active" : "INACTIVE",
lv->vg->cmd->dev_dir, lv->vg->name,
snap->origin->name);
snap_seg->origin->name);
}
if (inkernel && info.suspended)
@@ -402,15 +404,24 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
log_print("LV Size %s",
display_size(cmd,
snap ? snap->origin->size : lv->size,
snap_seg ? snap_seg->origin->size : lv->size,
SIZE_SHORT));
log_print("Current LE %u",
snap ? snap->origin->le_count : lv->le_count);
snap_seg ? snap_seg->origin->le_count : lv->le_count);
/********** FIXME allocation
log_print("Allocated LE %u", lv->allocated_le);
**********/
if (snap_seg) {
log_print("COW-table size %s",
display_size(cmd, (uint64_t) lv->size, SIZE_SHORT));
log_print("COW-table LE %u", lv->le_count);
if (snap_active)
log_print("Allocated to snapshot %.2f%% ", snap_percent);
log_print("Snapshot chunk size %s",
display_size(cmd, (uint64_t) snap_seg->chunk_size,
SIZE_SHORT));
}
log_print("Segments %u", list_size(&lv->segments));
@@ -418,31 +429,6 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
log_print("Stripe size (KByte) %u", lv->stripesize / 2);
***********/
if (snap) {
if (snap_percent == -1)
snap_percent = 100;
log_print("Snapshot chunk size %s",
display_size(cmd, (uint64_t) snap->chunk_size,
SIZE_SHORT));
/*
size = display_size(lv->size, SIZE_SHORT);
sscanf(size, "%f", &fsize);
fused = fsize * snap_percent / 100;
*/
log_print("Allocated to snapshot %.2f%% ", /* [%.2f/%s]", */
snap_percent); /*, fused, size); */
/* dbg_free(size); */
}
/********** FIXME Snapshot
size = ???
log_print("Allocated to COW-table %s", size);
dbg_free(size);
}
******************/
log_print("Allocation %s", get_alloc_string(lv->alloc));
log_print("Read ahead sectors %u", lv->read_ahead);
@@ -465,14 +451,17 @@ void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre)
{
switch (seg->area[s].type) {
case AREA_PV:
/* FIXME Re-check the conditions for 'Missing' */
log_print("%sPhysical volume\t%s", pre,
seg->area[s].u.pv.pv ?
dev_name(seg->area[s].u.pv.pv->dev) : "Missing");
seg->area[s].u.pv.pvseg->pv ?
dev_name(seg->area[s].u.pv.pvseg->pv->dev) :
"Missing");
if (seg->area[s].u.pv.pv)
if (seg->area[s].u.pv.pvseg->pv)
log_print("%sPhysical extents\t%d to %d", pre,
seg->area[s].u.pv.pe,
seg->area[s].u.pv.pe + seg->area_len - 1);
seg->area[s].u.pv.pvseg->pe,
seg->area[s].u.pv.pvseg->pe +
seg->area_len - 1);
break;
case AREA_LV:
log_print("%sLogical volume\t%s", pre,
@@ -550,7 +539,7 @@ void vgdisplay_full(struct volume_group *vg)
vg->status & SHARED ? "yes" : "no");
}
log_print("MAX LV %u", vg->max_lv);
log_print("Cur LV %u", vg->lv_count);
log_print("Cur LV %u", vg->lv_count + vg->snapshot_count);
log_print("Open LV %u", lvs_in_vg_opened(vg));
/****** FIXME Max LV Size
log_print ( "MAX LV Size %s",

View File

@@ -70,6 +70,7 @@ static const device_info_t device_info[] = {
{"i2o_block", 16}, /* i2o Block Disk */
{"iseries/vd", 8}, /* iSeries disks */
{"gnbd", 1}, /* Network block device */
{"ramdisk", 1}, /* RAM disk */
{NULL, 0}
};

View File

@@ -148,7 +148,6 @@ static struct volume_group *_build_vg(struct format_instance *fid,
vg->seqno = 0;
list_init(&vg->pvs);
list_init(&vg->lvs);
list_init(&vg->snapshots);
list_init(&vg->tags);
if (!_check_vgs(pvs, &partial))

View File

@@ -26,6 +26,7 @@
#include "filter.h"
#include "toolcontext.h"
#include "segtype.h"
#include "pv_alloc.h"
#include <time.h>
@@ -89,6 +90,12 @@ int import_pv(struct pool *mem, struct device *dev,
pv->pe_alloc_count = pvd->pe_allocated;
list_init(&pv->tags);
list_init(&pv->segments);
if (!alloc_pv_segment_whole_pv(mem, pv)) {
stack;
return 0;
}
return 1;
}
@@ -323,6 +330,8 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
lv->size = lvd->lv_size;
lv->le_count = lvd->lv_allocated_le;
lv->snapshot = NULL;
list_init(&lv->snapshot_segs);
list_init(&lv->segments);
list_init(&lv->tags);
@@ -393,11 +402,12 @@ int export_extents(struct disk_list *dl, uint32_t lv_num,
"unsupported by format1", lv->name);
return 0;
}
if (seg->area[s].u.pv.pv != pv)
if (seg->area[s].u.pv.pvseg->pv != pv)
continue; /* not our pv */
for (pe = 0; pe < (seg->len / seg->area_count); pe++) {
ped = &dl->extents[pe + seg->area[s].u.pv.pe];
ped = &dl->extents[pe +
seg->area[s].u.pv.pvseg->pe];
ped->lv_num = lv_num;
ped->le_num = (seg->le / seg->area_count) + pe +
s * (lv->le_count / seg->area_count);
@@ -495,7 +505,7 @@ 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, *sh;
struct list *lvh;
struct lv_list *ll;
struct lvd_list *lvdl;
size_t len;
@@ -524,6 +534,9 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
list_iterate(lvh, &vg->lvs) {
ll = list_item(lvh, struct lv_list);
if (ll->lv->status & SNAPSHOT)
continue;
if (!(lvdl = pool_alloc(dl->mem, sizeof(*lvdl)))) {
stack;
goto out;
@@ -532,7 +545,6 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
_export_lv(&lvdl->lvd, vg, ll->lv, dev_dir);
lv_num = lvnum_from_lvid(&ll->lv->lvid);
lvdl->lvd.lv_number = lv_num;
if (!hash_insert(lvd_hash, ll->lv->name, &lvdl->lvd)) {
@@ -545,37 +557,20 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
goto out;
}
if (lv_is_origin(ll->lv))
lvdl->lvd.lv_access |= LV_SNAPSHOT_ORG;
if (lv_is_cow(ll->lv)) {
lvdl->lvd.lv_access |= LV_SNAPSHOT;
lvdl->lvd.lv_chunk_size = ll->lv->snapshot->chunk_size;
lvdl->lvd.lv_snapshot_minor =
lvnum_from_lvid(&ll->lv->snapshot->origin->lvid);
}
list_add(&dl->lvds, &lvdl->list);
dl->pvd.lv_cur++;
}
/*
* Now we need to run through the snapshots, exporting
* the SNAPSHOT_ORG flags etc.
*/
list_iterate(sh, &vg->snapshots) {
struct lv_disk *org, *cow;
struct snapshot *s = list_item(sh,
struct snapshot_list)->snapshot;
if (!(org = hash_lookup(lvd_hash, s->origin->name))) {
log_err("Couldn't find snapshot origin '%s'.",
s->origin->name);
goto out;
}
if (!(cow = hash_lookup(lvd_hash, s->cow->name))) {
log_err("Couldn't find snapshot cow store '%s'.",
s->cow->name);
goto out;
}
org->lv_access |= LV_SNAPSHOT_ORG;
cow->lv_access |= LV_SNAPSHOT;
cow->lv_snapshot_minor = org->lv_number;
cow->lv_chunk_size = s->chunk_size;
}
r = 1;
out:
@@ -646,7 +641,8 @@ int import_snapshots(struct pool *mem, struct volume_group *vg,
continue;
/* insert the snapshot */
if (!vg_add_snapshot(org, cow, 1, NULL, org->le_count,
if (!vg_add_snapshot(vg->fid, NULL, org, cow, NULL,
org->le_count,
lvd->lv_chunk_size)) {
log_err("Couldn't add snapshot.");
return 0;

View File

@@ -60,6 +60,8 @@ static struct hash_table *_create_lv_maps(struct pool *mem,
list_iterate(llh, &vg->lvs) {
ll = list_item(llh, struct lv_list);
if (ll->lv->status & SNAPSHOT)
continue;
if (!(lvm = pool_alloc(mem, sizeof(*lvm)))) {
stack;
@@ -205,58 +207,59 @@ static int _check_maps_are_complete(struct hash_table *maps)
static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
{
uint32_t le = 0;
uint32_t le = 0, len;
struct lv_segment *seg;
struct segment_type *segtype;
if (!(segtype = get_segtype_from_string(cmd, "striped"))) {
stack;
return 0;
}
while (le < lvm->lv->le_count) {
seg = alloc_lv_segment(cmd->mem, 1);
len = 0;
seg->lv = lvm->lv;
if (!(seg->segtype = get_segtype_from_string(cmd, "striped"))) {
do
len++;
while ((lvm->map[le + len].pv == lvm->map[le].pv) &&
(lvm->map[le].pv &&
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))) {
log_error("Failed to allocate linear segment.");
return 0;
}
if (!set_lv_segment_area_pv(seg, 0, lvm->map[le].pv,
lvm->map[le].pe)) {
stack;
return 0;
}
seg->le = le;
seg->len = 0;
seg->area_len = 0;
seg->stripe_size = 0;
seg->area[0].type = AREA_PV;
seg->area[0].u.pv.pv = lvm->map[le].pv;
seg->area[0].u.pv.pe = lvm->map[le].pe;
do {
seg->len++;
seg->area_len++;
} while ((lvm->map[le + seg->len].pv == seg->area[0].u.pv.pv) &&
(seg->area[0].u.pv.pv &&
lvm->map[le + seg->len].pe == seg->area[0].u.pv.pe +
seg->len));
list_add(&lvm->lv->segments, &seg->list);
le += seg->len;
list_add(&lvm->lv->segments, &seg->list);
}
return 1;
}
static int _check_stripe(struct lv_map *lvm, struct lv_segment *seg,
uint32_t base_le, uint32_t len)
static int _check_stripe(struct lv_map *lvm, uint32_t area_count,
uint32_t seg_len, uint32_t base_le, uint32_t len)
{
uint32_t le, st;
le = base_le + seg->len;
uint32_t st;
/*
* Is the next physical extent in every stripe adjacent to the last?
*/
for (st = 0; st < seg->area_count; st++)
if ((lvm->map[le + st * len].pv != seg->area[st].u.pv.pv) ||
(seg->area[st].u.pv.pv &&
lvm->map[le + st * len].pe !=
seg->area[st].u.pv.pe + seg->len)) return 0;
for (st = 0; st < area_count; st++)
if ((lvm->map[base_le + st * len + seg_len].pv !=
lvm->map[base_le + st * len].pv) ||
(lvm->map[base_le + st * len].pv &&
lvm->map[base_le + st * len + seg_len].pe !=
lvm->map[base_le + st * len].pe + seg_len))
return 0;
return 1;
}
@@ -264,7 +267,9 @@ static int _check_stripe(struct lv_map *lvm, struct lv_segment *seg,
static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
{
uint32_t st, le = 0, len;
uint32_t area_len;
struct lv_segment *seg;
struct segment_type *segtype;
/*
* Work out overall striped length
@@ -276,43 +281,45 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
}
len = lvm->lv->le_count / lvm->stripes;
if (!(segtype = get_segtype_from_string(cmd, "striped"))) {
stack;
return 0;
}
while (le < len) {
if (!(seg = alloc_lv_segment(cmd->mem, lvm->stripes))) {
stack;
return 0;
}
seg->lv = lvm->lv;
if (!(seg->segtype = get_segtype_from_string(cmd, "striped"))) {
stack;
return 0;
}
seg->stripe_size = lvm->stripe_size;
seg->le = seg->area_count * le;
seg->len = 1;
seg->area_len = 1;
/*
* Set up start positions of each stripe in this segment
*/
for (st = 0; st < seg->area_count; st++) {
seg->area[st].u.pv.pv = lvm->map[le + st * len].pv;
seg->area[st].u.pv.pe = lvm->map[le + st * len].pe;
}
area_len = 1;
/*
* Find how many blocks are contiguous in all stripes
* and so can form part of this segment
*/
while (_check_stripe(lvm, seg, le, len)) {
seg->len++;
seg->area_len++;
while (_check_stripe(lvm, lvm->stripes,
area_len * lvm->stripes, le, len))
area_len++;
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))) {
log_error("Failed to allocate striped segment.");
return 0;
}
le += seg->len;
seg->len *= seg->area_count;
/*
* Set up start positions of each stripe in this segment
*/
for (st = 0; st < seg->area_count; st++)
if (!set_lv_segment_area_pv(seg, st,
lvm->map[le + st * len].pv,
lvm->map[le + st * len].pe)) {
stack;
return 0;
}
list_add(&lvm->lv->segments, &seg->list);
le += seg->len;
}
return 1;

View File

@@ -132,7 +132,6 @@ static struct volume_group *_build_vg_from_pds(struct format_instance
vg->system_id = NULL;
list_init(&vg->pvs);
list_init(&vg->lvs);
list_init(&vg->snapshots);
list_init(&vg->tags);
if (!import_pool_vg(vg, smem, pds)) {

View File

@@ -21,6 +21,7 @@
#include "disk_rep.h"
#include "sptype_names.h"
#include "lv_alloc.h"
#include "pv_alloc.h"
#include "str_list.h"
#include "display.h"
#include "segtype.h"
@@ -82,6 +83,8 @@ int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls)
lv->name = NULL;
lv->le_count = 0;
lv->read_ahead = 0;
lv->snapshot = NULL;
list_init(&lv->snapshot_segs);
list_init(&lv->segments);
list_init(&lv->tags);
@@ -112,6 +115,8 @@ int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls)
} else {
lv->minor = -1;
}
lv->snapshot = NULL;
list_init(&lv->snapshot_segs);
list_init(&lv->segments);
list_init(&lv->tags);
}
@@ -178,6 +183,12 @@ int import_pool_pv(const struct format_type *fmt, struct pool *mem,
pv->pe_alloc_count = pv->pe_count;
list_init(&pv->tags);
list_init(&pv->segments);
if (!alloc_pv_segment_whole_pv(mem, pv)) {
stack;
return 0;
}
return 1;
}
@@ -200,40 +211,44 @@ static int _add_stripe_seg(struct pool *mem,
uint32_t *le_cur)
{
struct lv_segment *seg;
struct segment_type *segtype;
int j;
uint32_t area_len;
if (!(seg = alloc_lv_segment(mem, usp->num_devs))) {
log_error("Unable to allocate striped lv_segment structure");
return 0;
}
if(usp->striping & (usp->striping - 1)) {
if (usp->striping & (usp->striping - 1)) {
log_error("Stripe size must be a power of 2");
return 0;
}
seg->stripe_size = usp->striping;
seg->status |= 0;
seg->le += *le_cur;
/* add the subpool type to the segment tag list */
str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
area_len = (usp->devs[0].blocks) / POOL_PE_SIZE;
for (j = 0; j < usp->num_devs; j++) {
if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd,
"striped"))) {
if (!(segtype = get_segtype_from_string(lv->vg->cmd,
"striped"))) {
stack;
return 0;
}
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))) {
log_error("Unable to allocate striped lv_segment structure");
return 0;
}
for (j = 0; j < usp->num_devs; j++)
if (!set_lv_segment_area_pv(seg, j, usp->devs[j].pv, 0)) {
stack;
return 0;
}
seg->area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
seg->len += seg->area_len;
*le_cur += seg->area_len;
seg->lv = lv;
/* add the subpool type to the segment tag list */
str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
seg->area[j].type = AREA_PV;
seg->area[j].u.pv.pv = usp->devs[j].pv;
seg->area[j].u.pv.pe = 0;
}
list_add(&lv->segments, &seg->list);
*le_cur += seg->len;
return 1;
}
@@ -242,37 +257,38 @@ static int _add_linear_seg(struct pool *mem,
uint32_t *le_cur)
{
struct lv_segment *seg;
struct segment_type *segtype;
int j;
uint32_t area_len;
if (!(segtype = get_segtype_from_string(lv->vg->cmd, "striped"))) {
stack;
return 0;
}
for (j = 0; j < usp->num_devs; j++) {
/* linear segments only have 1 data area */
if (!(seg = alloc_lv_segment(mem, 1))) {
area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
if (!(seg = alloc_lv_segment(mem, segtype, lv, *le_cur,
area_len, 0, usp->striping,
1, area_len, POOL_PE_SIZE, 0))) {
log_error("Unable to allocate linear lv_segment "
"structure");
return 0;
}
seg->stripe_size = usp->striping;
seg->le += *le_cur;
seg->chunk_size = POOL_PE_SIZE;
seg->status |= 0;
if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd,
"striped"))) {
stack;
return 0;
}
/* add the subpool type to the segment tag list */
str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
seg->lv = lv;
seg->area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
seg->len = seg->area_len;
*le_cur += seg->len;
seg->area[0].type = AREA_PV;
seg->area[0].u.pv.pv = usp->devs[j].pv;
seg->area[0].u.pv.pe = 0;
if (!set_lv_segment_area_pv(seg, 0, usp->devs[j].pv, 0)) {
stack;
return 0;
}
list_add(&lv->segments, &seg->list);
*le_cur += seg->len;
}
return 1;
}
@@ -288,8 +304,11 @@ int import_pool_segments(struct list *lvs, struct pool *mem,
list_iterate(lvhs, lvs) {
lvl = list_item(lvhs, struct lv_list);
lv = lvl->lv;
if (lv->status & SNAPSHOT)
continue;
for (i = 0; i < subpools; i++) {
if (usp[i].striping) {
if (!_add_stripe_seg(mem, &usp[i], lv, &le_cur)) {

View File

@@ -148,7 +148,7 @@ static struct list *_scan_archive(struct pool *mem,
/* Sort fails beyond 5-digit indexes */
if ((count = scandir(dir, &dirent, NULL, alphasort)) < 0) {
log_err("Couldn't scan archive directory.");
log_err("Couldn't scan the archive directory (%s).", dir);
return 0;
}
@@ -273,7 +273,7 @@ int archive_vg(struct volume_group *vg,
* Now we want to rename this file to <vg>_index.vg.
*/
if (!(archives = _scan_archive(vg->cmd->mem, vg->name, dir))) {
log_err("Couldn't scan the archive directory (%s).", dir);
stack;
return 0;
}
@@ -349,7 +349,7 @@ int archive_list(struct cmd_context *cmd, const char *dir, const char *vgname)
struct archive_file *af;
if (!(archives = _scan_archive(cmd->mem, vgname, dir))) {
log_err("Couldn't scan the archive directory (%s).", dir);
stack;
return 0;
}

View File

@@ -13,53 +13,63 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "tools.h"
#include "lib.h"
#include "archiver.h"
#include "format-text.h"
#include "lvm-file.h"
#include "lvm-string.h"
#include "lvmcache.h"
#include "toolcontext.h"
static struct {
#include <unistd.h>
struct archive_params {
int enabled;
char *dir;
unsigned int keep_days;
unsigned int keep_number;
};
} _archive_params;
static struct {
struct backup_params {
int enabled;
char *dir;
};
} _backup_params;
int archive_init(const char *dir, unsigned int keep_days, unsigned int keep_min)
int archive_init(struct cmd_context *cmd, const char *dir,
unsigned int keep_days, unsigned int keep_min)
{
_archive_params.dir = NULL;
if (!(cmd->archive_params = pool_zalloc(cmd->mem, sizeof(*cmd->archive_params)))) {
log_error("archive_params alloc failed");
return 0;
}
cmd->archive_params->dir = NULL;
if (!*dir)
return 1;
if (!create_dir(dir))
return 0;
if (!(_archive_params.dir = dbg_strdup(dir))) {
if (!(cmd->archive_params->dir = dbg_strdup(dir))) {
log_error("Couldn't copy archive directory name.");
return 0;
}
_archive_params.keep_days = keep_days;
_archive_params.keep_number = keep_min;
_archive_params.enabled = 1;
cmd->archive_params->keep_days = keep_days;
cmd->archive_params->keep_number = keep_min;
cmd->archive_params->enabled = 1;
return 1;
}
void archive_exit(void)
void archive_exit(struct cmd_context *cmd)
{
if (_archive_params.dir)
dbg_free(_archive_params.dir);
memset(&_archive_params, 0, sizeof(_archive_params));
if (cmd->archive_params->dir)
dbg_free(cmd->archive_params->dir);
memset(cmd->archive_params, 0, sizeof(*cmd->archive_params));
}
void archive_enable(int flag)
void archive_enable(struct cmd_context *cmd, int flag)
{
_archive_params.enabled = flag;
cmd->archive_params->enabled = flag;
}
static char *_build_desc(struct pool *mem, const char *line, int before)
@@ -91,14 +101,14 @@ static int __archive(struct volume_group *vg)
return 0;
}
return archive_vg(vg, _archive_params.dir, desc,
_archive_params.keep_days,
_archive_params.keep_number);
return archive_vg(vg, vg->cmd->archive_params->dir, desc,
vg->cmd->archive_params->keep_days,
vg->cmd->archive_params->keep_number);
}
int archive(struct volume_group *vg)
{
if (!_archive_params.enabled || !_archive_params.dir)
if (!vg->cmd->archive_params->enabled || !vg->cmd->archive_params->dir)
return 1;
if (test_mode()) {
@@ -106,7 +116,16 @@ int archive(struct volume_group *vg)
return 1;
}
log_verbose("Archiving volume group \"%s\" metadata.", vg->name);
if (!create_dir(vg->cmd->archive_params->dir))
return 0;
/* Trap a read-only file system */
if ((access(vg->cmd->archive_params->dir, R_OK | W_OK | X_OK) == -1) &&
(errno == EROFS))
return 0;
log_verbose("Archiving volume group \"%s\" metadata (seqno %u).", vg->name,
vg->seqno);
if (!__archive(vg)) {
log_error("Volume group \"%s\" metadata archive failed.",
vg->name);
@@ -121,23 +140,25 @@ int archive_display(struct cmd_context *cmd, const char *vg_name)
int r1, r2;
init_partial(1);
r1 = archive_list(cmd, _archive_params.dir, vg_name);
r2 = backup_list(cmd, _backup_params.dir, vg_name);
r1 = archive_list(cmd, cmd->archive_params->dir, vg_name);
r2 = backup_list(cmd, cmd->backup_params->dir, vg_name);
init_partial(0);
return r1 && r2;
}
int backup_init(const char *dir)
int backup_init(struct cmd_context *cmd, const char *dir)
{
_backup_params.dir = NULL;
if (!(cmd->backup_params = pool_zalloc(cmd->mem, sizeof(*cmd->archive_params)))) {
log_error("archive_params alloc failed");
return 0;
}
cmd->backup_params->dir = NULL;
if (!*dir)
return 1;
if (!create_dir(dir))
return 0;
if (!(_backup_params.dir = dbg_strdup(dir))) {
if (!(cmd->backup_params->dir = dbg_strdup(dir))) {
log_error("Couldn't copy backup directory name.");
return 0;
}
@@ -145,16 +166,16 @@ int backup_init(const char *dir)
return 1;
}
void backup_exit(void)
void backup_exit(struct cmd_context *cmd)
{
if (_backup_params.dir)
dbg_free(_backup_params.dir);
memset(&_backup_params, 0, sizeof(_backup_params));
if (cmd->backup_params->dir)
dbg_free(cmd->backup_params->dir);
memset(cmd->backup_params, 0, sizeof(*cmd->backup_params));
}
void backup_enable(int flag)
void backup_enable(struct cmd_context *cmd, int flag)
{
_backup_params.enabled = flag;
cmd->backup_params->enabled = flag;
}
static int __backup(struct volume_group *vg)
@@ -168,7 +189,7 @@ static int __backup(struct volume_group *vg)
}
if (lvm_snprintf(name, sizeof(name), "%s/%s",
_backup_params.dir, vg->name) < 0) {
vg->cmd->backup_params->dir, vg->name) < 0) {
log_error("Failed to generate volume group metadata backup "
"filename.");
return 0;
@@ -179,7 +200,7 @@ static int __backup(struct volume_group *vg)
int backup(struct volume_group *vg)
{
if (!_backup_params.enabled || !_backup_params.dir) {
if (!vg->cmd->backup_params->enabled || !vg->cmd->backup_params->dir) {
log_print("WARNING: This metadata update is NOT backed up");
return 1;
}
@@ -189,6 +210,14 @@ int backup(struct volume_group *vg)
return 1;
}
if (!create_dir(vg->cmd->backup_params->dir))
return 0;
/* Trap a read-only file system */
if ((access(vg->cmd->backup_params->dir, R_OK | W_OK | X_OK) == -1) &&
(errno == EROFS))
return 0;
if (!__backup(vg)) {
log_error("Backup of volume group %s metadata failed.",
vg->name);
@@ -198,12 +227,12 @@ int backup(struct volume_group *vg)
return 1;
}
int backup_remove(const char *vg_name)
int backup_remove(struct cmd_context *cmd, const char *vg_name)
{
char path[PATH_MAX];
if (lvm_snprintf(path, sizeof(path), "%s/%s",
_backup_params.dir, vg_name) < 0) {
cmd->backup_params->dir, vg_name) < 0) {
log_err("Failed to generate backup filename (for removal).");
return 0;
}
@@ -269,7 +298,7 @@ int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg)
return 0;
}
if (cmd->fmt != info->fmt) {
log_error("PV %s is a different format (%s)",
log_error("PV %s is a different format (seqno %s)",
dev_name(pv->dev), info->fmt->name);
return 0;
}
@@ -312,7 +341,7 @@ int backup_restore(struct cmd_context *cmd, const char *vg_name)
char path[PATH_MAX];
if (lvm_snprintf(path, sizeof(path), "%s/%s",
_backup_params.dir, vg_name) < 0) {
cmd->backup_params->dir, vg_name) < 0) {
log_err("Failed to generate backup filename (for restore).");
return 0;
}
@@ -330,7 +359,7 @@ int backup_to_file(const char *file, const char *desc, struct volume_group *vg)
cmd = vg->cmd;
log_verbose("Creating volume group backup \"%s\"", file);
log_verbose("Creating volume group backup \"%s\" (seqno %u).", file, vg->seqno);
if (!(context = create_text_context(cmd, file, desc)) ||
!(tf = cmd->fmt_backup->ops->create_instance(cmd->fmt_backup, NULL,
@@ -354,3 +383,34 @@ int backup_to_file(const char *file, const char *desc, struct volume_group *vg)
tf->fmt->ops->destroy_instance(tf);
return r;
}
/*
* Update backup (and archive) if they're out-of-date or don't exist.
*/
void check_current_backup(struct volume_group *vg)
{
char path[PATH_MAX];
struct volume_group *vg_backup;
if ((vg->status & PARTIAL_VG) || (vg->status & EXPORTED_VG))
return;
if (lvm_snprintf(path, sizeof(path), "%s/%s",
vg->cmd->backup_params->dir, vg->name) < 0) {
log_debug("Failed to generate backup filename.");
return;
}
log_suppress(1);
/* Up-to-date backup exists? */
if ((vg_backup = backup_read_vg(vg->cmd, vg->name, path)) &&
(vg->seqno == vg_backup->seqno) &&
(id_equal(&vg->id, &vg_backup->id)))
return;
log_suppress(0);
if (vg_backup)
archive(vg_backup);
archive(vg);
backup(vg);
}

View File

@@ -18,11 +18,6 @@
#include "metadata.h"
/*
* FIXME: This file is going to merge with the archiving code in
* lib/format_text at some point.
*/
/*
* There are two operations that come under the general area of
* backups. 'Archiving' occurs just before a volume group
@@ -36,20 +31,20 @@
* Typically backups will be stored in /etc/lvm/backups.
*/
int archive_init(const char *dir,
int archive_init(struct cmd_context *cmd, const char *dir,
unsigned int keep_days, unsigned int keep_min);
void archive_exit(void);
void archive_exit(struct cmd_context *cmd);
void archive_enable(int flag);
void archive_enable(struct cmd_context *cmd, int flag);
int archive(struct volume_group *vg);
int archive_display(struct cmd_context *cmd, const char *vg_name);
int backup_init(const char *dir);
void backup_exit(void);
int backup_init(struct cmd_context *cmd, const char *dir);
void backup_exit(struct cmd_context *cmd);
void backup_enable(int flag);
void backup_enable(struct cmd_context *cmd, int flag);
int backup(struct volume_group *vg);
int backup_remove(const char *vg_name);
int backup_remove(struct cmd_context *cmd, const char *vg_name);
struct volume_group *backup_read_vg(struct cmd_context *cmd,
const char *vg_name, const char *file);
@@ -60,4 +55,6 @@ int backup_restore(struct cmd_context *cmd, const char *vg_name);
int backup_to_file(const char *file, const char *desc, struct volume_group *vg);
void check_current_backup(struct volume_group *vg);
#endif

View File

@@ -444,13 +444,14 @@ int out_areas(struct formatter *f, const struct lv_segment *seg,
for (s = 0; s < seg->area_count; s++) {
switch (seg->area[s].type) {
case AREA_PV:
if (!(name = _get_pv_name(f, seg->area[s].u.pv.pv))) {
if (!(name = _get_pv_name(f, seg->area[s].u.pv.pvseg->
pv))) {
stack;
return 0;
}
outf(f, "\"%s\", %u%s", name,
seg->area[s].u.pv.pe,
seg->area[s].u.pv.pvseg->pe,
(s == seg->area_count - 1) ? "" : ",");
break;
case AREA_LV:
@@ -477,87 +478,6 @@ static int _count_segments(struct logical_volume *lv)
return r;
}
static int _print_snapshot(struct formatter *f, struct snapshot *snap,
unsigned int count)
{
char buffer[256];
struct lv_segment seg;
f->nl(f);
outf(f, "snapshot%u {", count);
_inc_indent(f);
if (!id_write_format(&snap->id, buffer, sizeof(buffer))) {
stack;
return 0;
}
outf(f, "id = \"%s\"", buffer);
seg.status = LVM_READ | LVM_WRITE | VISIBLE_LV;
if (!print_flags(seg.status, LV_FLAGS, buffer, sizeof(buffer))) {
stack;
return 0;
}
outf(f, "status = %s", buffer);
outf(f, "segment_count = 1");
f->nl(f);
if (!(seg.segtype = get_segtype_from_string(snap->origin->vg->cmd,
"snapshot"))) {
stack;
return 0;
}
seg.le = 0;
seg.len = snap->le_count;
seg.origin = snap->origin;
seg.cow = snap->cow;
seg.chunk_size = snap->chunk_size;
/* FIXME Dummy values */
list_init(&seg.list);
seg.lv = snap->cow;
seg.stripe_size = 0;
seg.area_count = 0;
seg.area_len = 0;
seg.extents_copied = 0;
/* Can't tag a snapshot independently of its origin */
list_init(&seg.tags);
if (!_print_segment(f, snap->origin->vg, 1, &seg)) {
stack;
return 0;
}
_dec_indent(f);
outf(f, "}");
return 1;
}
static int _print_snapshots(struct formatter *f, struct volume_group *vg)
{
struct list *sh;
struct snapshot *s;
unsigned int count = 0;
list_iterate(sh, &vg->snapshots) {
s = list_item(sh, struct snapshot_list)->snapshot;
if (!_print_snapshot(f, s, count++)) {
stack;
return 0;
}
}
return 1;
}
static int _print_lvs(struct formatter *f, struct volume_group *vg)
{
struct list *lvh;
@@ -629,11 +549,6 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
outf(f, "}");
}
if (!_print_snapshots(f, vg)) {
stack;
return 0;
}
_dec_indent(f);
outf(f, "}");

View File

@@ -54,6 +54,7 @@ static struct flag _lv_flags[] = {
{LOCKED, "LOCKED"},
{MIRRORED, NULL},
{VIRTUAL, NULL},
{SNAPSHOT, NULL},
{0, NULL}
};

View File

@@ -183,27 +183,30 @@ static int _raw_write_mda_header(const struct format_type *fmt,
static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
struct mda_header *mdah,
const char *vgname)
const char *vgname,
int precommit)
{
size_t len;
char vgnamebuf[NAME_LEN + 2];
struct raw_locn *rlocn;
struct lvmcache_info *info;
rlocn = mdah->raw_locns;
rlocn = mdah->raw_locns; /* Slot 0 */
if (precommit)
rlocn++; /* Slot 1 */
/* FIXME Loop through rlocns two-at-a-time. List null-terminated. */
/* FIXME Ignore if checksum incorrect!!! */
while (rlocn->offset) {
if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
sizeof(vgnamebuf), vgnamebuf)) {
stack;
goto error;
}
if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
(isspace(vgnamebuf[len]) || vgnamebuf[len] == '{')) {
return rlocn;
}
rlocn++;
if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
sizeof(vgnamebuf), vgnamebuf)) {
stack;
goto error;
}
if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
(isspace(vgnamebuf[len]) || vgnamebuf[len] == '{')) {
return rlocn;
}
error:
@@ -213,32 +216,41 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
return NULL;
}
static struct raw_locn *_vg_posn(struct format_instance *fid,
struct device_area *dev_area,
const char *vgname)
/*
* Determine offset for uncommitted metadata
*/
static uint64_t _next_rlocn_offset(struct raw_locn *rlocn,
struct mda_header *mdah)
{
if (!rlocn)
/* Find an empty slot */
/* FIXME Assume only one VG per mdah for now */
return MDA_HEADER_SIZE;
struct mda_header *mdah;
if (!(mdah = _raw_read_mda_header(fid->fmt, dev_area))) {
stack;
return NULL;
}
return _find_vg_rlocn(dev_area, mdah, vgname);
/* Start of free space - round up to next sector; circular */
return ((rlocn->offset + rlocn->size +
(SECTOR_SIZE - rlocn->size % SECTOR_SIZE) -
MDA_HEADER_SIZE) % (mdah->size - MDA_HEADER_SIZE))
+ MDA_HEADER_SIZE;
}
static int _raw_holds_vgname(struct format_instance *fid,
struct device_area *dev_area, const char *vgname)
{
int r = 0;
struct mda_header *mdah;
if (!dev_open(dev_area->dev)) {
stack;
return 0;
}
if (_vg_posn(fid, dev_area, vgname))
if (!(mdah = _raw_read_mda_header(fid->fmt, dev_area))) {
stack;
return 0;
}
if (_find_vg_rlocn(dev_area, mdah, vgname, 0))
r = 1;
if (!dev_close(dev_area->dev))
@@ -249,7 +261,8 @@ static int _raw_holds_vgname(struct format_instance *fid,
static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
const char *vgname,
struct device_area *area)
struct device_area *area,
int precommit)
{
struct volume_group *vg = NULL;
struct raw_locn *rlocn;
@@ -268,7 +281,7 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
goto out;
}
if (!(rlocn = _vg_posn(fid, area, vgname))) {
if (!(rlocn = _find_vg_rlocn(area, mdah, vgname, precommit))) {
log_debug("VG %s not found on %s", vgname, dev_name(area->dev));
goto out;
}
@@ -292,8 +305,9 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
stack;
goto out;
}
log_debug("Read %s metadata (%u) from %s at %" PRIu64 " size %" PRIu64,
vg->name, vg->seqno, dev_name(area->dev),
log_debug("Read %s %smetadata (%u) from %s at %" PRIu64 " size %"
PRIu64, vg->name, precommit ? "pre-commit " : "",
vg->seqno, dev_name(area->dev),
area->start + rlocn->offset, rlocn->size);
out:
@@ -309,7 +323,16 @@ static struct volume_group *_vg_read_raw(struct format_instance *fid,
{
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
return _vg_read_raw_area(fid, vgname, &mdac->area);
return _vg_read_raw_area(fid, vgname, &mdac->area, 0);
}
static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
const char *vgname,
struct metadata_area *mda)
{
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
return _vg_read_raw_area(fid, vgname, &mdac->area, 1);
}
static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
@@ -349,18 +372,8 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
goto out;
}
if ((rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name))) {
/* Start of free space - round up to next sector; circular */
mdac->rlocn.offset =
((rlocn->offset + rlocn->size +
(SECTOR_SIZE - rlocn->size % SECTOR_SIZE) -
MDA_HEADER_SIZE) % (mdah->size - MDA_HEADER_SIZE))
+ MDA_HEADER_SIZE;
} else {
/* Find an empty slot */
/* FIXME Assume only one VG per mdah for now */
mdac->rlocn.offset = MDA_HEADER_SIZE;
}
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)))) {
log_error("VG %s metadata writing failed", vg->name);
@@ -425,8 +438,10 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
return r;
}
static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
struct metadata_area *mda)
static int _vg_commit_raw_rlocn(struct format_instance *fid,
struct volume_group *vg,
struct metadata_area *mda,
int precommit)
{
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
struct mda_header *mdah;
@@ -453,18 +468,23 @@ static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
goto out;
}
if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name))) {
rlocn = &mdah->raw_locns[0];
if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, 0))) {
mdah->raw_locns[0].offset = 0;
mdah->raw_locns[1].offset = 0;
mdah->raw_locns[2].offset = 0;
rlocn = &mdah->raw_locns[0];
}
if (precommit)
rlocn++;
rlocn->offset = mdac->rlocn.offset;
rlocn->size = mdac->rlocn.size;
rlocn->checksum = mdac->rlocn.checksum;
log_debug("Committing %s metadata (%u) to %s header at %" PRIu64,
vg->name, vg->seqno, dev_name(mdac->area.dev),
mdac->area.start);
log_debug("%sCommitting %s metadata (%u) to %s header at %" PRIu64,
precommit ? "Pre-" : "", vg->name, vg->seqno,
dev_name(mdac->area.dev), mdac->area.start);
if (!_raw_write_mda_header(fid->fmt, mdac->area.dev, mdac->area.start,
mdah)) {
log_error("Failed to write metadata area header");
@@ -474,12 +494,25 @@ static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
r = 1;
out:
if (!dev_close(mdac->area.dev))
if (!precommit && !dev_close(mdac->area.dev))
stack;
return r;
}
static int _vg_commit_raw(struct format_instance *fid, struct volume_group *vg,
struct metadata_area *mda)
{
return _vg_commit_raw_rlocn(fid, vg, mda, 0);
}
static int _vg_precommit_raw(struct format_instance *fid,
struct volume_group *vg,
struct metadata_area *mda)
{
return _vg_commit_raw_rlocn(fid, vg, mda, 1);
}
/* Close metadata area devices */
static int _vg_revert_raw(struct format_instance *fid, struct volume_group *vg,
struct metadata_area *mda)
@@ -525,7 +558,7 @@ static int _vg_remove_raw(struct format_instance *fid, struct volume_group *vg,
goto out;
}
if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name))) {
if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, vg->name, 0))) {
rlocn = &mdah->raw_locns[0];
mdah->raw_locns[1].offset = 0;
}
@@ -551,13 +584,13 @@ static int _vg_remove_raw(struct format_instance *fid, struct volume_group *vg,
static struct volume_group *_vg_read_file_name(struct format_instance *fid,
const char *vgname,
const char *path_live)
const char *read_path)
{
struct volume_group *vg;
time_t when;
char *desc;
if (!(vg = text_vg_import_file(fid, path_live, &when, &desc))) {
if (!(vg = text_vg_import_file(fid, read_path, &when, &desc))) {
stack;
return NULL;
}
@@ -570,10 +603,10 @@ static struct volume_group *_vg_read_file_name(struct format_instance *fid,
if (vgname && strcmp(vgname, vg->name)) {
pool_free(fid->fmt->cmd->mem, vg);
log_err("'%s' does not contain volume group '%s'.",
path_live, vgname);
read_path, vgname);
return NULL;
} else
log_debug("Read volume group %s from %s", vg->name, path_live);
log_debug("Read volume group %s from %s", vg->name, read_path);
return vg;
}
@@ -587,6 +620,15 @@ static struct volume_group *_vg_read_file(struct format_instance *fid,
return _vg_read_file_name(fid, vgname, tc->path_live);
}
static struct volume_group *_vg_read_precommit_file(struct format_instance *fid,
const char *vgname,
struct metadata_area *mda)
{
struct text_context *tc = (struct text_context *) mda->metadata_locn;
return _vg_read_file_name(fid, vgname, tc->path_edit);
}
static int _vg_write_file(struct format_instance *fid, struct volume_group *vg,
struct metadata_area *mda)
{
@@ -858,7 +900,7 @@ static int _scan_raw(const struct format_type *fmt)
if (vgname_from_mda(fmt, &rl->dev_area, vgnamebuf,
sizeof(vgnamebuf))) {
if ((vg = _vg_read_raw_area(&fid, vgnamebuf,
&rl->dev_area)))
&rl->dev_area, 0)))
lvmcache_update_vg(vg);
}
}
@@ -1107,34 +1149,6 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
return 1;
}
static int _get_pv_from_vg(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;
if (!(vg = vg_read(fmt->cmd, vg_name, &consistent))) {
log_error("format_text: _vg_read failed to read VG %s",
vg_name);
return 0;
}
if (!consistent)
log_error("Warning: Volume group %s is not consistent",
vg_name);
list_iterate(pvh, &vg->pvs) {
pvl = list_item(pvh, struct pv_list);
if (id_equal(&pvl->pv->id, (const struct id *) id)) {
memcpy(pv, pvl->pv, sizeof(*pv));
return 1;
}
}
return 0;
}
static int _add_raw(struct list *raw_list, struct device_area *dev_area)
{
struct raw_list *rl;
@@ -1183,8 +1197,8 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
/* Have we already cached vgname? */
if (info->vginfo && info->vginfo->vgname && *info->vginfo->vgname &&
_get_pv_from_vg(info->fmt, info->vginfo->vgname, info->dev->pvid,
pv)) {
get_pv_from_vg_by_id(info->fmt, info->vginfo->vgname,
info->dev->pvid, pv)) {
return 1;
}
@@ -1194,8 +1208,8 @@ static int _pv_read(const struct format_type *fmt, const char *pv_name,
if (info->vginfo && info->vginfo->vgname &&
*info->vginfo->vgname &&
_get_pv_from_vg(info->fmt, info->vginfo->vgname,
info->dev->pvid, pv)) {
get_pv_from_vg_by_id(info->fmt, info->vginfo->vgname,
info->dev->pvid, pv)) {
return 1;
}
}
@@ -1280,6 +1294,7 @@ static void _destroy(const struct format_type *fmt)
static struct metadata_area_ops _metadata_text_file_ops = {
vg_read:_vg_read_file,
vg_read_precommit:_vg_read_precommit_file,
vg_write:_vg_write_file,
vg_remove:_vg_remove_file,
vg_commit:_vg_commit_file
@@ -1294,8 +1309,10 @@ static struct metadata_area_ops _metadata_text_file_backup_ops = {
static struct metadata_area_ops _metadata_text_raw_ops = {
vg_read:_vg_read_raw,
vg_read_precommit:_vg_read_precommit_raw,
vg_write:_vg_write_raw,
vg_remove:_vg_remove_raw,
vg_precommit:_vg_precommit_raw,
vg_commit:_vg_commit_raw,
vg_revert:_vg_revert_raw
};
@@ -1651,7 +1668,8 @@ struct format_type *create_text_format(struct cmd_context *cmd)
fmt->ops = &_text_handler;
fmt->name = FMT_TEXT_NAME;
fmt->alias = FMT_TEXT_ALIAS;
fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS | FMT_UNLIMITED_VOLS;
fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS | FMT_PRECOMMIT |
FMT_UNLIMITED_VOLS;
if (!(mda_lists = dbg_malloc(sizeof(struct mda_lists)))) {
log_error("Failed to allocate dir_list");

View File

@@ -22,6 +22,7 @@
#include "toolcontext.h"
#include "lvmcache.h"
#include "lv_alloc.h"
#include "pv_alloc.h"
#include "segtype.h"
#include "text_import.h"
@@ -190,6 +191,7 @@ static int _read_pv(struct format_instance *fid, struct pool *mem,
}
list_init(&pv->tags);
list_init(&pv->segments);
/* Optional tags */
if ((cn = find_config_node(pvn, "tags")) &&
@@ -208,6 +210,11 @@ static int _read_pv(struct format_instance *fid, struct pool *mem,
pv->pe_alloc_count = 0;
pv->fmt = fid->fmt;
if (!alloc_pv_segment_whole_pv(mem, pv)) {
stack;
return 0;
}
vg->pv_count++;
list_add(&vg->pvs, &pvl->list);
@@ -283,19 +290,13 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
return 0;
}
if (!(seg = alloc_lv_segment(mem, area_count))) {
if (!(seg = alloc_lv_segment(mem, segtype, lv, start_extent,
extent_count, 0, 0, area_count,
extent_count, 0, 0))) {
log_error("Segment allocation failed");
return 0;
}
seg->lv = lv;
seg->le = start_extent;
seg->len = extent_count;
seg->area_len = extent_count;
seg->status = 0u;
seg->segtype = segtype;
seg->extents_copied = 0u;
if (seg->segtype->ops->text_import &&
!seg->segtype->ops->text_import(seg, sn, pv_hash)) {
stack;
@@ -315,10 +316,10 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
*/
_insert_segment(lv, seg);
if (seg->segtype->flags & SEG_AREAS_MIRRORED)
if (seg_is_mirrored(seg))
lv->status |= MIRRORED;
if (seg->segtype->flags & SEG_VIRTUAL)
if (seg_is_virtual(seg))
lv->status |= VIRTUAL;
return 1;
@@ -361,19 +362,17 @@ int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
/* FIXME Cope if LV not yet read in */
if ((pv = hash_lookup(pv_hash, cv->v.str))) {
seg->area[s].type = AREA_PV;
seg->area[s].u.pv.pv = pv;
seg->area[s].u.pv.pe = cv->next->v.i;
if (!set_lv_segment_area_pv(seg, s, pv, cv->next->v.i)) {
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))) {
seg->area[s].type = AREA_LV;
seg->area[s].u.lv.lv = lv1;
seg->area[s].u.lv.le = cv->next->v.i;
set_lv_segment_area_lv(seg, s, lv1, cv->next->v.i);
} else {
log_error("Couldn't find volume '%s' "
"for segment '%s'.",
@@ -508,6 +507,8 @@ static int _read_lvnames(struct format_instance *fid, struct pool *mem,
if (!_read_int32(lvn, "read_ahead", &lv->read_ahead))
lv->read_ahead = 0;
lv->snapshot = NULL;
list_init(&lv->snapshot_segs);
list_init(&lv->segments);
list_init(&lv->tags);
@@ -561,24 +562,29 @@ static int _read_lvsegs(struct format_instance *fid, struct pool *mem,
lv->size = (uint64_t) lv->le_count * (uint64_t) vg->extent_size;
/* Skip this for now for snapshots */
if (!(lv->status & SNAPSHOT)) {
lv->minor = -1;
if ((lv->status & FIXED_MINOR) &&
!_read_int32(lvn, "minor", &lv->minor)) {
log_error("Couldn't read minor number for logical "
"volume %s.", lv->name);
return 0;
}
lv->major = -1;
if ((lv->status & FIXED_MINOR) &&
!_read_int32(lvn, "major", &lv->major)) {
log_error("Couldn't read major number for logical "
"volume %s.", lv->name);
}
} else {
/*
* FIXME We now have 2 LVs for each snapshot. The real one was
* created by vg_add_snapshot from the segment text_import.
*/
if (lv->status & SNAPSHOT) {
vg->lv_count--;
list_del(&lvl->list);
return 1;
}
lv->minor = -1;
if ((lv->status & FIXED_MINOR) &&
!_read_int32(lvn, "minor", &lv->minor)) {
log_error("Couldn't read minor number for logical "
"volume %s.", lv->name);
return 0;
}
lv->major = -1;
if ((lv->status & FIXED_MINOR) &&
!_read_int32(lvn, "major", &lv->major)) {
log_error("Couldn't read major number for logical "
"volume %s.", lv->name);
}
return 1;
@@ -736,7 +742,6 @@ static struct volume_group *_read_vg(struct format_instance *fid,
}
list_init(&vg->lvs);
list_init(&vg->snapshots);
list_init(&vg->tags);
/* Optional tags */

View File

@@ -72,7 +72,7 @@ void init_log_direct(const char *log_file, int append)
{
int open_flags = append ? 0 : O_TRUNC;
dev_create_file(log_file, &_log_dev, &_log_dev_alias);
dev_create_file(log_file, &_log_dev, &_log_dev_alias, 1);
if (!dev_open_flags(&_log_dev, O_RDWR | O_CREAT | open_flags, 1, 0))
return;

View File

@@ -16,5 +16,23 @@
#ifndef _LVM_LV_ALLOC_H
#include "pool.h"
struct lv_segment *alloc_lv_segment(struct pool *mem, uint32_t num_areas);
struct lv_segment *alloc_lv_segment(struct pool *mem,
struct segment_type *segtype,
struct logical_volume *lv,
uint32_t le, uint32_t len,
uint32_t status,
uint32_t stripe_size,
uint32_t area_count,
uint32_t area_len,
uint32_t chunk_size,
uint32_t extents_copied);
struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv,
uint32_t allocated);
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);
#endif

View File

@@ -20,6 +20,7 @@
#include "lvm-string.h"
#include "toolcontext.h"
#include "lv_alloc.h"
#include "pv_alloc.h"
#include "display.h"
#include "segtype.h"
@@ -36,7 +37,7 @@ static void _get_extents(struct lv_segment *seg)
if (seg->area[s].type != AREA_PV)
continue;
pv = seg->area[s].u.pv.pv;
pv = seg->area[s].u.pv.pvseg->pv;
count = seg->area_len;
pv->pe_alloc_count += count;
}
@@ -51,7 +52,7 @@ static void _put_extents(struct lv_segment *seg)
if (seg->area[s].type != AREA_PV)
continue;
pv = seg->area[s].u.pv.pv;
pv = seg->area[s].u.pv.pvseg->pv;
if (pv) {
count = seg->area_len;
@@ -61,61 +62,129 @@ static void _put_extents(struct lv_segment *seg)
}
}
struct lv_segment *alloc_lv_segment(struct pool *mem, uint32_t num_areas)
struct lv_segment *alloc_lv_segment(struct pool *mem,
struct segment_type *segtype,
struct logical_volume *lv,
uint32_t le, uint32_t len,
uint32_t status,
uint32_t stripe_size,
uint32_t area_count,
uint32_t area_len,
uint32_t chunk_size,
uint32_t extents_copied)
{
struct lv_segment *seg;
uint32_t len = sizeof(*seg) + (num_areas * sizeof(seg->area[0]));
uint32_t sz = sizeof(*seg) + (area_count * sizeof(seg->area[0]));
if (!(seg = pool_zalloc(mem, len))) {
if (!(seg = pool_zalloc(mem, sz))) {
stack;
return NULL;
}
seg->area_count = num_areas;
seg->segtype = segtype;
seg->lv = lv;
seg->le = le;
seg->len = len;
seg->status = status;
seg->stripe_size = stripe_size;
seg->area_count = area_count;
seg->area_len = area_len;
seg->chunk_size = chunk_size;
seg->extents_copied = extents_copied;
list_init(&seg->tags);
return seg;
}
static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
uint32_t stripe_size,
struct segment_type *segtype,
struct pv_area **areas, uint32_t *ix)
int set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num,
struct physical_volume *pv, uint32_t pe)
{
uint32_t count, area_len, smallest;
uint32_t s;
struct lv_segment *seg;
int striped = 0;
seg->area[area_num].type = AREA_PV;
/* Striped or mirrored? */
if (segtype->flags & SEG_AREAS_STRIPED)
striped = 1;
count = lv->le_count - *ix;
area_len = count / (striped ? area_count : 1);
smallest = areas[area_count - 1]->count;
if (smallest < area_len)
area_len = smallest;
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, area_count))) {
log_err("Couldn't allocate new parallel segment.");
if (!(seg->area[area_num].u.pv.pvseg =
assign_peg_to_lvseg(pv, pe, seg->area_len, seg, area_num))) {
stack;
return 0;
}
seg->lv = lv;
seg->segtype = segtype;
seg->le = *ix;
seg->len = area_len * (striped ? area_count : 1);
seg->area_len = area_len;
seg->stripe_size = stripe_size;
seg->extents_copied = 0u;
return 1;
}
void set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num,
struct logical_volume *lv, uint32_t le)
{
seg->area[area_num].type = AREA_LV;
seg->area[area_num].u.lv.lv = lv;
seg->area[area_num].u.lv.le = le;
}
static void _shrink_lv_segment(struct lv_segment *seg)
{
uint32_t s;
for (s = 0; s < seg->area_count; s++) {
if (seg->area[s].type != AREA_PV)
continue;
release_pv_segment(seg->area[s].u.pv.pvseg, seg->area_len);
}
}
/*
* The heart of the allocation code. This function takes a list of
* pv_area and allocates them to the lv. If the lv doesn't need
* the complete area then the area is split, otherwise the area
* is unlinked from the pv_map.
*/
static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
uint32_t stripe_size,
struct segment_type *segtype,
struct pv_area **areas, uint32_t *ix,
struct physical_volume *mirrored_pv,
uint32_t mirrored_pe)
{
uint32_t area_len, smallest, remaining;
uint32_t s;
uint32_t extra_areas = 0;
struct lv_segment *seg;
struct pv_area *pva;
int striped = 0;
/* Striped or mirrored? */
if (seg_is_striped(seg))
striped = 1;
if (mirrored_pv)
extra_areas = 1;
remaining = lv->le_count - *ix;
area_len = remaining / (striped ? area_count : 1);
smallest = areas[area_count - 1]->count;
if (area_len > smallest)
area_len = smallest;
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, *ix,
area_len * (striped ? area_count : 1),
0u, stripe_size, area_count + extra_areas,
area_len, 0u, 0u))) {
log_error("Couldn't allocate new LV segment.");
return 0;
}
if (extra_areas) {
if (!set_lv_segment_area_pv(seg, 0, mirrored_pv, mirrored_pe)) {
stack;
return 0;
}
}
for (s = 0; s < area_count; s++) {
struct pv_area *pva = areas[s];
seg->area[s].type = AREA_PV;
seg->area[s].u.pv.pv = pva->map->pvl->pv;
seg->area[s].u.pv.pe = pva->start;
pva = areas[s];
if (!set_lv_segment_area_pv(seg, s + extra_areas, pva->map->pv,
pva->start)) {
stack;
return 0;
}
consume_pv_area(pva, area_len);
}
@@ -142,67 +211,100 @@ static int _comp_area(const void *l, const void *r)
return 0;
}
static int _alloc_parallel(struct logical_volume *lv,
static int _alloc_parallel(struct logical_volume *lv, alloc_policy_t alloc,
struct list *pvms, uint32_t allocated,
uint32_t stripes, uint32_t stripe_size,
uint32_t mirrors, struct segment_type *segtype)
uint32_t mirrors, struct segment_type *segtype,
struct physical_volume *mirrored_pv,
uint32_t mirrored_pe)
{
int r = 0;
struct list *pvmh;
struct pv_area **areas;
unsigned int pv_count = 0, ix;
struct pv_area **areas, *pva;
unsigned int pv_count, ix;
struct pv_map *pvm;
size_t len;
uint32_t area_count;
uint32_t area_count, largest = 0;
if (stripes > 1 && mirrors > 1) {
log_error("striped mirrors are not supported yet");
return 0;
}
if ((stripes > 1 || mirrors > 1) && mirrored_pv) {
log_error("Can't mix striping or mirroring with "
"creation of a mirrored PV yet");
return 0;
}
if (stripes > 1)
area_count = stripes;
else if (mirrored_pv)
area_count = 1;
else
area_count = mirrors;
list_iterate(pvmh, pvms)
pv_count++;
pv_count = list_size(pvms);
/* allocate an array of pv_areas, one candidate per pv */
len = sizeof(*areas) * pv_count;
if (!(areas = dbg_malloc(sizeof(*areas) * pv_count))) {
log_err("Couldn't allocate areas array.");
return 0;
}
while (allocated != lv->le_count) {
ix = 0;
list_iterate(pvmh, pvms) {
pvm = list_item(pvmh, struct pv_map);
/* Put the largest area on each PV into areas array */
list_iterate_items(pvm, pvms) {
if (list_empty(&pvm->areas))
continue;
areas[ix++] = list_item(pvm->areas.n, struct pv_area);
list_iterate_items(pva, &pvm->areas) {
if (pva->count > largest)
largest = pva->count;
if (mirrored_pv) {
if (pva->count < lv->le_count - allocated)
goto next_pv;
}
areas[ix++] = pva;
if (mirrored_pv)
goto try_it;
}
next_pv:
;
}
if (ix < area_count) {
log_error("Insufficient allocatable extents suitable "
"for parallel use for logical volume "
"%s: %u required", lv->name, lv->le_count);
goto out;
}
try_it:
if (ix < area_count)
break;
/* sort the areas so we allocate from the biggest */
qsort(areas, ix, sizeof(*areas), _comp_area);
if (ix > 1)
qsort(areas, ix, sizeof(*areas), _comp_area);
if (!_alloc_parallel_area(lv, area_count, stripe_size, segtype,
areas, &allocated)) {
areas, &allocated, mirrored_pv, mirrored_pe)) {
stack;
goto out;
}
if (mirrored_pv)
break;
}
if (allocated != lv->le_count) {
if (mirrored_pv)
log_error("Insufficient contiguous allocatable extents "
"(%u) for logical volume %s: %u required",
largest, lv->name, lv->le_count - allocated);
else
log_error("Insufficient allocatable extents suitable "
"for parallel use for logical volume %s: "
"%u more required", lv->name,
lv->le_count - allocated);
goto out;
}
r = 1;
out:
@@ -211,205 +313,72 @@ static int _alloc_parallel(struct logical_volume *lv,
}
/*
* The heart of the allocation code. This function takes a
* pv_area and allocates it to the lv. If the lv doesn't need
* the complete area then the area is split, otherwise the area
* is unlinked from the pv_map.
* For contiguous, only one area per pv is allowed, so we search
* for the biggest area, or the first area that can complete
* the allocation. If there is an existing segment, new space must
* be contiguous to it.
*/
static int _alloc_linear_area(struct logical_volume *lv, uint32_t *ix,
struct pv_map *map, struct pv_area *pva)
static int _alloc_next_free(struct logical_volume *lv, alloc_policy_t alloc,
struct list *pvms, uint32_t allocated,
struct segment_type *segtype)
{
uint32_t count, remaining;
struct lv_segment *seg;
count = pva->count;
remaining = lv->le_count - *ix;
if (count > remaining)
count = remaining;
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, 1))) {
log_err("Couldn't allocate new stripe segment.");
return 0;
}
seg->lv = lv;
if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd, "striped"))) {
stack;
return 0;
}
seg->le = *ix;
seg->len = count;
seg->area_len = count;
seg->stripe_size = 0;
seg->area[0].type = AREA_PV;
seg->area[0].u.pv.pv = map->pvl->pv;
seg->area[0].u.pv.pe = pva->start;
list_add(&lv->segments, &seg->list);
consume_pv_area(pva, count);
*ix += count;
return 1;
}
static int _alloc_mirrored_area(struct logical_volume *lv, uint32_t *ix,
struct pv_map *map, struct pv_area *pva,
struct segment_type *segtype,
struct physical_volume *mirrored_pv,
uint32_t mirrored_pe)
{
uint32_t count, remaining;
struct lv_segment *seg;
count = pva->count;
remaining = lv->le_count - *ix;
if (count > remaining)
count = remaining;
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, 2))) {
log_err("Couldn't allocate new mirrored segment.");
return 0;
}
seg->lv = lv;
seg->segtype = segtype;
seg->le = *ix;
seg->status = 0u;
seg->len = count;
seg->area_len = count;
seg->stripe_size = 0;
seg->extents_copied = 0u;
/* FIXME Remove AREA_PV restriction here? */
seg->area[0].type = AREA_PV;
seg->area[0].u.pv.pv = mirrored_pv;
seg->area[0].u.pv.pe = mirrored_pe;
seg->area[1].type = AREA_PV;
seg->area[1].u.pv.pv = map->pvl->pv;
seg->area[1].u.pv.pe = pva->start;
list_add(&lv->segments, &seg->list);
consume_pv_area(pva, count);
*ix += count;
return 1;
}
/*
* Only one area per pv is allowed, so we search
* for the biggest area, or the first area that
* can complete the allocation.
*/
/*
* FIXME: subsequent lvextends may not be contiguous.
*/
static int _alloc_contiguous(struct logical_volume *lv,
struct list *pvms, uint32_t allocated)
{
struct list *tmp1;
struct pv_map *pvm;
struct pv_area *pva;
uint32_t prev_allocated = allocated;
struct lv_segment *prev_lvseg;
struct pv_segment *prev_pvseg = NULL;
uint32_t largest = 0;
int contiguous = 0;
list_iterate(tmp1, pvms) {
pvm = list_item(tmp1, struct pv_map);
/* So far the only case is exactly one area */
if ((alloc == ALLOC_CONTIGUOUS))
contiguous = 1;
if (list_empty(&pvm->areas))
if (contiguous &&
(prev_lvseg = list_item(list_last(&lv->segments),
struct lv_segment)) &&
(prev_lvseg->area_count == 1) &&
(prev_lvseg->area[0].type == AREA_PV))
prev_pvseg = prev_lvseg->area[0].u.pv.pvseg;
list_iterate_items(pvm, pvms) {
if (prev_pvseg && (prev_pvseg->pv != pvm->pv))
continue;
/* first item in the list is the biggest */
pva = list_item(pvm->areas.n, struct pv_area);
if (pva->count < lv->le_count)
continue;
list_iterate_items(pva, &pvm->areas) {
if (prev_pvseg &&
(prev_pvseg->pe + prev_pvseg->len != pva->start))
continue;
if (!_alloc_linear_area(lv, &allocated, pvm, pva)) {
stack;
return 0;
if (pva->count > largest)
largest = pva->count;
/* first item in the list is the biggest */
if (contiguous &&
pva->count < lv->le_count - allocated)
goto next_pv;
if (!_alloc_parallel_area(lv, 1, 0, segtype, &pva,
&allocated, NULL, 0)) {
stack;
return 0;
}
if (contiguous || (allocated == lv->le_count))
goto out;
}
break;
next_pv:
;
}
out:
if (allocated != lv->le_count) {
log_error("Insufficient allocatable extents (%u) "
log_error("Insufficient %sallocatable extents (%u) "
"for logical volume %s: %u required",
allocated, lv->name, lv->le_count);
return 0;
}
return 1;
}
/* FIXME Contiguous depends on *segment* (i.e. stripe) not LV */
static int _alloc_mirrored(struct logical_volume *lv,
struct list *pvms, uint32_t allocated,
struct segment_type *segtype,
struct physical_volume *mirrored_pv,
uint32_t mirrored_pe)
{
struct list *tmp1;
struct pv_map *pvm;
struct pv_area *pva;
uint32_t max_found = 0;
/* Try each PV in turn */
list_iterate(tmp1, pvms) {
pvm = list_item(tmp1, struct pv_map);
if (list_empty(&pvm->areas))
continue;
/* first item in the list is the biggest */
pva = list_item(pvm->areas.n, struct pv_area);
if (pva->count < lv->le_count - allocated) {
max_found = pva->count;
continue;
}
if (!_alloc_mirrored_area(lv, &allocated, pvm, pva, segtype,
mirrored_pv, mirrored_pe)) {
stack;
return 0;
}
break;
}
if (allocated != lv->le_count) {
log_error("Insufficient contiguous allocatable extents (%u) "
"for logical volume %s: %u required",
allocated + max_found, lv->name, lv->le_count);
return 0;
}
return 1;
}
/*
* Areas just get allocated in order until the lv
* is full.
*/
static int _alloc_next_free(struct logical_volume *lv,
struct list *pvms, uint32_t allocated)
{
struct list *tmp1, *tmp2;
struct pv_map *pvm;
struct pv_area *pva;
list_iterate(tmp1, pvms) {
pvm = list_item(tmp1, struct pv_map);
list_iterate(tmp2, &pvm->areas) {
pva = list_item(tmp2, struct pv_area);
if (!_alloc_linear_area(lv, &allocated, pvm, pva) ||
(allocated == lv->le_count))
goto done;
}
}
done:
if (allocated != lv->le_count) {
log_error("Insufficient allocatable logical extents (%u) "
"for logical volume %s: %u required",
allocated, lv->name, lv->le_count);
contiguous ? "contiguous " : "",
contiguous ? largest : allocated - prev_allocated,
lv->name, lv->le_count - prev_allocated);
return 0;
}
@@ -421,29 +390,48 @@ static int _alloc_virtual(struct logical_volume *lv,
{
struct lv_segment *seg;
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, 0))) {
log_err("Couldn't allocate new zero segment.");
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, allocated,
lv->le_count - allocated, 0, 0, 0,
lv->le_count - allocated, 0, 0))) {
log_error("Couldn't allocate new zero segment.");
return 0;
}
seg->lv = lv;
seg->segtype = segtype;
seg->status = 0u;
seg->le = allocated;
seg->len = lv->le_count - allocated;
seg->area_len = seg->len;
seg->stripe_size = 0;
seg->extents_copied = 0u;
list_add(&lv->segments, &seg->list);
lv->status |= VIRTUAL;
return 1;
}
struct lv_segment *alloc_snapshot_seg(struct logical_volume *lv,
uint32_t allocated)
{
struct lv_segment *seg;
struct segment_type *segtype;
segtype = get_segtype_from_string(lv->vg->cmd, "snapshot");
if (!segtype) {
log_error("Failed to find snapshot segtype");
return NULL;
}
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, allocated,
lv->le_count - allocated, 0, 0, 0,
lv->le_count - allocated, 0, 0))) {
log_error("Couldn't allocate new snapshot segment.");
return NULL;
}
list_add(&lv->segments, &seg->list);
lv->status |= VIRTUAL;
return seg;
}
/*
* Chooses a correct allocation policy.
*/
static int _allocate(struct volume_group *vg, struct logical_volume *lv,
static int _allocate(struct logical_volume *lv,
struct list *allocatable_pvs, uint32_t allocated,
alloc_policy_t alloc, struct segment_type *segtype,
uint32_t stripes, uint32_t stripe_size, uint32_t mirrors,
@@ -464,42 +452,29 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv,
}
if (alloc == ALLOC_INHERIT)
alloc = vg->alloc;
alloc = lv->vg->alloc;
/*
* Build the sets of available areas on the pv's.
*/
if (!(pvms = create_pv_maps(scratch, vg, allocatable_pvs)))
if (!(pvms = create_pv_maps(scratch, lv->vg, allocatable_pvs)))
goto out;
if (stripes > 1 || mirrors > 1)
r = _alloc_parallel(lv, pvms, allocated, stripes, stripe_size,
mirrors, segtype);
else if (mirrored_pv)
r = _alloc_mirrored(lv, pvms, allocated, segtype, mirrored_pv,
mirrored_pe);
else if (alloc == ALLOC_CONTIGUOUS)
r = _alloc_contiguous(lv, pvms, allocated);
else if (alloc == ALLOC_NORMAL || alloc == ALLOC_ANYWHERE)
r = _alloc_next_free(lv, pvms, allocated);
else {
log_error("Unrecognised allocation policy: "
"unable to set up logical volume.");
goto out;
}
if (stripes > 1 || mirrors > 1 || mirrored_pv)
r = _alloc_parallel(lv, alloc, pvms, allocated, stripes,
stripe_size, mirrors, segtype,
mirrored_pv, mirrored_pe);
else
r = _alloc_next_free(lv, alloc, pvms, allocated, segtype);
if (r) {
vg->free_count -= lv->le_count - allocated;
lv->vg->free_count -= lv->le_count - allocated;
/*
* Iterate through the new segments, updating pe
* counts in pv's.
*/
for (segh = lv->segments.p; segh != old_tail; segh = segh->p) {
list_uniterate(segh, old_tail, &lv->segments) {
seg = list_item(segh, struct lv_segment);
_get_extents(seg);
seg->status = status;
@@ -520,14 +495,11 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv,
static char *_generate_lv_name(struct volume_group *vg, const char *format,
char *buffer, size_t len)
{
struct list *lvh;
struct logical_volume *lv;
struct lv_list *lvl;
int high = -1, i;
list_iterate(lvh, &vg->lvs) {
lv = (list_item(lvh, struct lv_list)->lv);
if (sscanf(lv->name, format, &i) != 1)
list_iterate_items(lvl, &vg->lvs) {
if (sscanf(lvl->lv->name, format, &i) != 1)
continue;
if (i > high)
@@ -543,8 +515,10 @@ static char *_generate_lv_name(struct volume_group *vg, const char *format,
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)
{
struct cmd_context *cmd = vg->cmd;
@@ -565,7 +539,8 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
return NULL;
}
log_verbose("Creating logical volume %s", name);
if (!import)
log_verbose("Creating logical volume %s", name);
if (!(ll = pool_zalloc(cmd->mem, sizeof(*ll))) ||
!(ll->lv = pool_zalloc(cmd->mem, sizeof(*ll->lv)))) {
@@ -592,9 +567,14 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
lv->minor = -1;
lv->size = UINT64_C(0);
lv->le_count = 0;
lv->snapshot = NULL;
list_init(&lv->snapshot_segs);
list_init(&lv->segments);
list_init(&lv->tags);
if (lvid)
lv->lvid = *lvid;
if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
stack;
if (ll)
@@ -602,14 +582,18 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
return NULL;
}
vg->lv_count++;
if (!import)
vg->lv_count++;
list_add(&vg->lvs, &ll->list);
return lv;
}
int lv_extend(struct format_instance *fid,
struct logical_volume *lv,
/*
* Entry point for all extent allocations
*/
int lv_extend(struct logical_volume *lv,
struct segment_type *segtype,
uint32_t stripes, uint32_t stripe_size,
uint32_t mirrors, uint32_t extents,
@@ -623,17 +607,17 @@ int lv_extend(struct format_instance *fid,
lv->le_count += extents;
lv->size += (uint64_t) extents *lv->vg->extent_size;
if (fid->fmt->ops->segtype_supported &&
!fid->fmt->ops->segtype_supported(fid, segtype)) {
if (lv->vg->fid->fmt->ops->segtype_supported &&
!lv->vg->fid->fmt->ops->segtype_supported(lv->vg->fid, segtype)) {
log_error("Metadata format (%s) does not support required "
"LV segment type (%s).", fid->fmt->name,
"LV segment type (%s).", lv->vg->fid->fmt->name,
segtype->name);
log_error("Consider changing the metadata format by running "
"vgconvert.");
return 0;
}
if (!_allocate(lv->vg, lv, allocatable_pvs, old_le_count, alloc,
if (!_allocate(lv, allocatable_pvs, old_le_count, alloc,
segtype, stripes, stripe_size, mirrors, mirrored_pv,
mirrored_pe, status)) {
lv->le_count = old_le_count;
@@ -648,7 +632,8 @@ int lv_extend(struct format_instance *fid,
return 0;
}
if (fid->fmt->ops->lv_setup && !fid->fmt->ops->lv_setup(fid, lv)) {
if (lv->vg->fid->fmt->ops->lv_setup &&
!lv->vg->fid->fmt->ops->lv_setup(lv->vg->fid, lv)) {
stack;
return 0;
}
@@ -656,47 +641,65 @@ int lv_extend(struct format_instance *fid,
return 1;
}
int lv_reduce(struct format_instance *fi,
struct logical_volume *lv, uint32_t extents)
static int _lv_segment_reduce(struct lv_segment *seg, uint32_t reduction)
{
_put_extents(seg);
seg->len -= reduction;
/* Caller must ensure exact divisibility */
if (seg_is_striped(seg)) {
if (reduction % seg->area_count) {
log_error("Segment extent reduction %" PRIu32
"not divisible by #stripes %" PRIu32,
reduction, seg->area_count);
return 0;
}
seg->area_len -= (reduction / seg->area_count);
} else
seg->area_len -= reduction;
_shrink_lv_segment(seg);
_get_extents(seg);
return 1;
}
/*
* Entry point for all extent reductions
*/
int lv_reduce(struct logical_volume *lv, uint32_t extents)
{
struct list *segh;
struct lv_segment *seg;
uint32_t count = extents;
int striped;
uint32_t reduction;
for (segh = lv->segments.p;
(segh != &lv->segments) && count; segh = segh->p) {
list_uniterate(segh, &lv->segments, &lv->segments) {
seg = list_item(segh, struct lv_segment);
if (!count)
break;
if (seg->len <= count) {
/* remove this segment completely */
count -= seg->len;
_put_extents(seg);
list_del(segh);
} else {
/* reduce this segment */
_put_extents(seg);
seg->len -= count;
striped = seg->segtype->flags & SEG_AREAS_STRIPED;
/* Caller must ensure exact divisibility */
if (striped && (count % seg->area_count)) {
log_error("Segment extent reduction %" PRIu32
"not divisible by #stripes %" PRIu32,
count, seg->area_count);
return 0;
}
seg->area_len -=
count / (striped ? seg->area_count : 1);
_get_extents(seg);
count = 0;
reduction = seg->len;
} else
reduction = count;
if (!_lv_segment_reduce(seg, reduction)) {
stack;
return 0;
}
count -= reduction;
}
lv->le_count -= extents;
lv->size = (uint64_t) lv->le_count * lv->vg->extent_size;
lv->vg->free_count += extents;
if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
if (lv->le_count && lv->vg->fid->fmt->ops->lv_setup &&
!lv->vg->fid->fmt->ops->lv_setup(lv->vg->fid, lv)) {
stack;
return 0;
}
@@ -704,26 +707,25 @@ int lv_reduce(struct format_instance *fi,
return 1;
}
int lv_remove(struct volume_group *vg, struct logical_volume *lv)
int lv_remove(struct logical_volume *lv)
{
struct list *segh;
struct lv_list *lvl;
/* find the lv list */
if (!(lvl = find_lv_in_vg(vg, lv->name))) {
if (!lv_reduce(lv, lv->le_count)) {
stack;
return 0;
}
/* iterate through the lv's segments freeing off the pe's */
list_iterate(segh, &lv->segments)
_put_extents(list_item(segh, struct lv_segment));
vg->lv_count--;
vg->free_count += lv->le_count;
/* find the lv list */
if (!(lvl = find_lv_in_vg(lv->vg, lv->name))) {
stack;
return 0;
}
list_del(&lvl->list);
lv->vg->lv_count--;
return 1;
}
@@ -731,14 +733,12 @@ uint32_t find_free_lvnum(struct logical_volume *lv)
{
int lvnum_used[MAX_RESTRICTED_LVS + 1];
uint32_t i = 0;
struct list *lvh;
struct lv_list *lvl;
int lvnum;
memset(&lvnum_used, 0, sizeof(lvnum_used));
list_iterate(lvh, &lv->vg->lvs) {
lvl = list_item(lvh, struct lv_list);
list_iterate_items(lvl, &lv->vg->lvs) {
lvnum = lvnum_from_lvid(&lvl->lv->lvid);
if (lvnum <= MAX_RESTRICTED_LVS)
lvnum_used[lvnum] = 1;

View File

@@ -17,6 +17,7 @@
#include "metadata.h"
#include "toolcontext.h"
#include "lv_alloc.h"
#include "pv_alloc.h"
#include "str_list.h"
#include "segtype.h"
@@ -85,27 +86,28 @@ int lv_check_segments(struct logical_volume *lv)
static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
uint32_t le)
{
size_t len;
struct lv_segment *split_seg;
uint32_t s;
uint32_t offset = le - seg->le;
uint32_t area_offset;
if (!(seg->segtype->flags & SEG_CAN_SPLIT)) {
if (!seg_can_split(seg)) {
log_error("Unable to split the %s segment at LE %" PRIu32
" in LV %s", seg->segtype->name, le, lv->name);
return 0;
}
/* Clone the existing segment */
if (!(split_seg = alloc_lv_segment(lv->vg->cmd->mem, seg->area_count))) {
log_error("Couldn't allocate new LV segment.");
if (!(split_seg = alloc_lv_segment(lv->vg->cmd->mem, seg->segtype,
seg->lv, seg->le, seg->len,
seg->status, seg->stripe_size,
seg->area_count, seg->area_len,
seg->chunk_size,
seg->extents_copied))) {
log_error("Couldn't allocate cloned LV segment.");
return 0;
}
len = sizeof(*seg) + (seg->area_count * sizeof(seg->area[0]));
memcpy(split_seg, seg, len);
if (!str_list_dup(lv->vg->cmd->mem, &split_seg->tags, &seg->tags)) {
log_error("LV segment tags duplication failed");
return 0;
@@ -113,37 +115,9 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
/* In case of a striped segment, the offset has to be / stripes */
area_offset = offset;
if (seg->segtype->flags & SEG_AREAS_STRIPED)
if (seg_is_striped(seg))
area_offset /= seg->area_count;
/* Adjust the PV mapping */
for (s = 0; s < seg->area_count; s++) {
/* Split area at the offset */
switch (seg->area[s].type) {
case AREA_LV:
split_seg->area[s].u.lv.le =
seg->area[s].u.lv.le + area_offset;
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);
break;
case AREA_PV:
split_seg->area[s].u.pv.pe =
seg->area[s].u.pv.pe + area_offset;
log_debug("Split %s:%u[%u] at %u: %s PE %u", lv->name,
seg->le, s, le,
dev_name(seg->area[s].u.pv.pv->dev),
split_seg->area[s].u.pv.pe);
break;
default:
log_error("Unrecognised segment type %u",
seg->area[s].type);
return 0;
}
}
split_seg->area_len -= area_offset;
seg->area_len = area_offset;
@@ -152,6 +126,44 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
split_seg->le = seg->le + seg->len;
/* Adjust the PV mapping */
for (s = 0; s < seg->area_count; s++) {
split_seg->area[s].type = seg->area[s].type;
/* Split area at the offset */
switch (seg->area[s].type) {
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;
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);
break;
case AREA_PV:
if (!assign_peg_to_lvseg(seg->area[s].u.pv.pvseg->pv,
seg->area[s].u.pv.pvseg->pe +
seg->area_len,
seg->area[s].u.pv.pvseg->len -
seg->area_len,
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);
break;
default:
log_error("Unrecognised segment type %u",
seg->area[s].type);
return 0;
}
}
/* Add split off segment to the list _after_ the original one */
list_add_h(&seg->list, &split_seg->list);

View File

@@ -21,6 +21,8 @@
#include "lvm-string.h"
#include "lvmcache.h"
#include "memlock.h"
#include "str_list.h"
#include "pv_alloc.h"
static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
const char *pv_name)
@@ -99,9 +101,14 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
return 0;
}
pvl->pv = pv;
if (!alloc_pv_segment_whole_pv(mem, pv)) {
stack;
return 0;
}
pvl->pv = pv;
list_add(&vg->pvs, &pvl->list);
vg->pv_count++;
vg->extent_count += pv->pe_count;
vg->free_count += pv->pe_count;
@@ -109,6 +116,57 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
return 1;
}
static int _copy_pv(struct physical_volume *pv_to,
struct physical_volume *pv_from)
{
memcpy(pv_to, pv_from, sizeof(*pv_to));
if (!str_list_dup(pv_to->fmt->cmd->mem, &pv_to->tags, &pv_from->tags)) {
log_error("PV tags duplication failed");
return 0;
}
if (!peg_dup(pv_to->fmt->cmd->mem, &pv_to->segments,
&pv_from->segments)) {
stack;
return 0;
}
return 1;
}
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;
if (!(vg = vg_read(fmt->cmd, vg_name, &consistent))) {
log_error("get_pv_from_vg_by_id: vg_read failed to read VG %s",
vg_name);
return 0;
}
if (!consistent)
log_error("Warning: Volume group %s is not consistent",
vg_name);
list_iterate(pvh, &vg->pvs) {
pvl = list_item(pvh, struct pv_list);
if (id_equal(&pvl->pv->id, (const struct id *) id)) {
if (!_copy_pv(pv, pvl->pv)) {
stack;
return 0;
}
return 1;
}
}
return 0;
}
int vg_rename(struct cmd_context *cmd, struct volume_group *vg,
const char *new_name)
{
@@ -221,7 +279,6 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
list_init(&vg->lvs);
vg->snapshot_count = 0;
list_init(&vg->snapshots);
list_init(&vg->tags);
@@ -249,6 +306,182 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
return NULL;
}
static int _recalc_extents(uint32_t *extents, const char *desc1,
const char *desc2, uint32_t old_size,
uint32_t new_size)
{
uint64_t size = (uint64_t) old_size * (*extents);
if (size % new_size) {
log_error("New size %" PRIu64 " for %s%s not an exact number "
"of new extents.", size, desc1, desc2);
return 0;
}
size /= new_size;
if (size > UINT32_MAX) {
log_error("New extent count %" PRIu64 " for %s%s exceeds "
"32 bits.", size, desc1, desc2);
return 0;
}
*extents = (uint32_t) size;
return 1;
}
int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
uint32_t new_size)
{
uint32_t old_size = vg->extent_size;
struct pv_list *pvl;
struct lv_list *lvl;
struct physical_volume *pv;
struct logical_volume *lv;
struct lv_segment *seg;
struct pv_segment *pvseg;
uint32_t s;
vg->extent_size = new_size;
if (vg->fid->fmt->ops->vg_setup &&
!vg->fid->fmt->ops->vg_setup(vg->fid, vg)) {
stack;
return 0;
}
if (!_recalc_extents(&vg->extent_count, vg->name, "", old_size,
new_size)) {
stack;
return 0;
}
if (!_recalc_extents(&vg->free_count, vg->name, " free space",
old_size, new_size)) {
stack;
return 0;
}
/* foreach PV */
list_iterate_items(pvl, &vg->pvs) {
pv = pvl->pv;
pv->pe_size = new_size;
if (!_recalc_extents(&pv->pe_count, dev_name(pv->dev), "",
old_size, new_size)) {
stack;
return 0;
}
if (!_recalc_extents(&pv->pe_alloc_count, dev_name(pv->dev),
" allocated space", old_size, new_size)) {
stack;
return 0;
}
/* foreach free PV Segment */
list_iterate_items(pvseg, &pv->segments) {
if (pvseg->lvseg)
continue;
if (!_recalc_extents(&pvseg->pe, dev_name(pv->dev),
" PV segment start", old_size,
new_size)) {
stack;
return 0;
}
if (!_recalc_extents(&pvseg->len, dev_name(pv->dev),
" PV segment length", old_size,
new_size)) {
stack;
return 0;
}
}
}
/* foreach LV */
list_iterate_items(lvl, &vg->lvs) {
lv = lvl->lv;
if (!_recalc_extents(&lv->le_count, lv->name, "", old_size,
new_size)) {
stack;
return 0;
}
list_iterate_items(seg, &lv->segments) {
if (!_recalc_extents(&seg->le, lv->name,
" segment start", old_size,
new_size)) {
stack;
return 0;
}
if (!_recalc_extents(&seg->len, lv->name,
" segment length", old_size,
new_size)) {
stack;
return 0;
}
if (!_recalc_extents(&seg->area_len, lv->name,
" area length", old_size,
new_size)) {
stack;
return 0;
}
if (!_recalc_extents(&seg->extents_copied, lv->name,
" extents moved", old_size,
new_size)) {
stack;
return 0;
}
/* foreach area */
for (s = 0; s < seg->area_count; s++) {
switch (seg->area[s].type) {
case AREA_PV:
if (!_recalc_extents
(&seg->area[s].u.pv.pvseg->pe,
lv->name,
" pvseg start", old_size,
new_size)) {
stack;
return 0;
}
if (!_recalc_extents
(&seg->area[s].u.pv.pvseg->len,
lv->name,
" pvseg length", old_size,
new_size)) {
stack;
return 0;
}
break;
case AREA_LV:
if (!_recalc_extents
(&seg->area[s].u.lv.le, lv->name,
" area start", old_size,
new_size)) {
stack;
return 0;
}
break;
default:
log_error("Unrecognised segment type "
"%u", seg->area[s].type);
return 0;
}
}
}
}
return 1;
}
/* Sizes in sectors */
struct physical_volume *pv_create(const struct format_type *fmt,
struct device *dev,
@@ -311,6 +544,7 @@ struct physical_volume *pv_create(const struct format_type *fmt,
pv->fmt = fmt;
list_init(&pv->tags);
list_init(&pv->segments);
if (!fmt->ops->pv_setup(fmt, pe_start, existing_extent_count,
existing_extent_size,
@@ -457,6 +691,19 @@ struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le)
return NULL;
}
/* Find segment at a given physical extent in a PV */
struct pv_segment *find_peg_by_pe(struct physical_volume *pv, uint32_t pe)
{
struct pv_segment *peg;
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;
@@ -485,6 +732,12 @@ int vg_write(struct volume_group *vg)
struct list *mdah, *mdah2;
struct metadata_area *mda;
if (!check_pv_segments(vg)) {
log_error("Internal error: PV segments corrupted in %s.",
vg->name);
return 0;
}
if (vg->status & PARTIAL_VG) {
log_error("Cannot change metadata for partial volume group %s",
vg->name);
@@ -507,6 +760,7 @@ int vg_write(struct volume_group *vg)
/* Revert */
list_uniterate(mdah2, &vg->fid->metadata_areas, mdah) {
mda = list_item(mdah2, struct metadata_area);
if (mda->ops->vg_revert &&
!mda->ops->vg_revert(vg->fid, vg, mda)) {
stack;
@@ -528,6 +782,24 @@ 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);
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);
if (mda->ops->vg_revert &&
!mda->ops->vg_revert(vg->fid, vg, mda)) {
stack;
}
}
return 0;
}
}
return 1;
}
@@ -598,7 +870,6 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
}
list_init(&vg->pvs);
list_init(&vg->lvs);
list_init(&vg->snapshots);
list_init(&vg->tags);
vg->cmd = cmd;
if (!(vg->name = pool_strdup(cmd->mem, ORPHAN))) {
@@ -630,8 +901,9 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
* and take appropriate action if it isn't (e.g. abort; get write lock
* and call vg_read again).
*/
struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
int *consistent)
static struct volume_group *_vg_read(struct cmd_context *cmd,
const char *vgname,
int *consistent, int precommitted)
{
struct format_instance *fid;
const struct format_type *fmt;
@@ -641,6 +913,11 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
int inconsistent = 0;
if (!*vgname) {
if (precommitted) {
log_error("Internal error: vg_read requires vgname "
"with pre-commit.");
return NULL;
}
*consistent = 1;
return _vg_read_orphans(cmd);
}
@@ -662,6 +939,12 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
}
}
if (precommitted && !(fmt->features & FMT_PRECOMMIT)) {
log_error("Internal error: %s doesn't support "
"pre-commit", fmt->name);
return NULL;
}
/* create format instance with appropriate metadata area */
if (!(fid = fmt->ops->create_instance(fmt, vgname, NULL))) {
log_error("Failed to create format instance");
@@ -671,7 +954,10 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
/* Ensure contents of all metadata areas match - else do recovery */
list_iterate(mdah, &fid->metadata_areas) {
mda = list_item(mdah, struct metadata_area);
if (!(vg = mda->ops->vg_read(fid, vgname, mda))) {
if ((precommitted &&
!(vg = mda->ops->vg_read_precommit(fid, vgname, mda))) ||
(!precommitted &&
!(vg = mda->ops->vg_read(fid, vgname, mda)))) {
inconsistent = 1;
continue;
}
@@ -697,6 +983,12 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
return NULL;
}
if (precommitted && !(fmt->features & FMT_PRECOMMIT)) {
log_error("Internal error: %s doesn't support "
"pre-commit", fmt->name);
return NULL;
}
/* create format instance with appropriate metadata area */
if (!(fid = fmt->ops->create_instance(fmt, vgname, NULL))) {
log_error("Failed to create format instance");
@@ -706,7 +998,11 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
/* Ensure contents of all metadata areas match - else recover */
list_iterate(mdah, &fid->metadata_areas) {
mda = list_item(mdah, struct metadata_area);
if (!(vg = mda->ops->vg_read(fid, vgname, mda))) {
if ((precommitted &&
!(vg = mda->ops->vg_read_precommit(fid, vgname,
mda))) ||
(!precommitted &&
!(vg = mda->ops->vg_read(fid, vgname, mda)))) {
inconsistent = 1;
continue;
}
@@ -732,6 +1028,12 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
lvmcache_update_vg(correct_vg);
if (inconsistent) {
if (precommitted) {
log_error("Inconsistent pre-commit metadata copies "
"for volume group %s", vgname);
return NULL;
}
if (!*consistent)
return correct_vg;
@@ -769,6 +1071,19 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vgname,
return correct_vg;
}
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_read_precommitted(struct cmd_context *cmd,
const char *vgname,
int *consistent)
{
return _vg_read(cmd, vgname, consistent, 1);
}
/* This is only called by lv_from_lvid, which is only called from
* activate.c so we know the appropriate VG lock is already held and
* the vg_read is therefore safe.
@@ -868,14 +1183,14 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
stack;
return 0;
return NULL;
}
if (!(label_read(dev, &label))) {
if (warnings)
log_error("No physical volume label read from %s",
pv_name);
return 0;
return NULL;
}
info = (struct lvmcache_info *) label->info;
@@ -884,22 +1199,28 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
if (!(pv = pool_zalloc(cmd->mem, sizeof(*pv)))) {
log_error("pv allocation for '%s' failed", pv_name);
return 0;
return NULL;
}
list_init(&pv->tags);
list_init(&pv->segments);
/* FIXME Move more common code up here */
if (!(info->fmt->ops->pv_read(info->fmt, pv_name, pv, mdas))) {
log_error("Failed to read existing physical volume '%s'",
pv_name);
return 0;
return NULL;
}
if (!pv->size)
return NULL;
else
return pv;
if (!alloc_pv_segment_whole_pv(cmd->mem, pv)) {
stack;
return NULL;
}
return pv;
}
/* May return empty list */

View File

@@ -50,7 +50,7 @@
#define VISIBLE_LV 0x00000040 /* LV */
#define FIXED_MINOR 0x00000080 /* LV */
/* FIXME Remove when metadata restructuring is completed */
#define SNAPSHOT 0x00001000 /* LV - tmp internal use only */
#define SNAPSHOT 0x00001000 /* LV - internal use only */
#define PVMOVE 0x00002000 /* VG LV SEG */
#define LOCKED 0x00004000 /* LV */
#define MIRRORED 0x00008000 /* LV - internal use only */
@@ -68,6 +68,7 @@
#define FMT_UNLIMITED_VOLS 0x00000008 /* Unlimited PVs/LVs? */
#define FMT_RESTRICTED_LVIDS 0x00000010 /* LVID <= 255 */
#define FMT_ORPHAN_ALLOCATABLE 0x00000020 /* Orphan PV allocatable? */
#define FMT_PRECOMMIT 0x00000040 /* Supports pre-commit? */
typedef enum {
ALLOC_INVALID,
@@ -98,6 +99,18 @@ struct format_type {
void *private;
};
struct pv_segment {
struct list list; /* Member of pv->segments: ordered list
* covering entire data area on this PV */
struct physical_volume *pv;
uint32_t pe;
uint32_t len;
struct lv_segment *lvseg; /* NULL if free space */
uint32_t lv_area; /* Index to area in LV segment */
};
struct physical_volume {
struct id id;
struct device *dev;
@@ -113,6 +126,7 @@ struct physical_volume {
uint32_t pe_count;
uint32_t pe_alloc_count;
struct list segments; /* Ordered pv_segments covering complete PV */
struct list tags;
};
@@ -124,6 +138,9 @@ struct metadata_area_ops {
struct volume_group *(*vg_read) (struct format_instance * fi,
const char *vg_name,
struct metadata_area * mda);
struct volume_group *(*vg_read_precommit) (struct format_instance * fi,
const char *vg_name,
struct metadata_area * mda);
/*
* Write out complete VG metadata. You must ensure internal
* consistency before calling. eg. PEs can't refer to PVs not
@@ -140,6 +157,9 @@ struct metadata_area_ops {
*/
int (*vg_write) (struct format_instance * fid, struct volume_group * vg,
struct metadata_area * mda);
int (*vg_precommit) (struct format_instance * fid,
struct volume_group * vg,
struct metadata_area * mda);
int (*vg_commit) (struct format_instance * fid,
struct volume_group * vg, struct metadata_area * mda);
int (*vg_revert) (struct format_instance * fid,
@@ -184,11 +204,8 @@ struct volume_group {
/* logical volumes */
uint32_t lv_count;
struct list lvs;
/* snapshots */
uint32_t snapshot_count;
struct list snapshots;
struct list lvs;
struct list tags;
};
@@ -210,7 +227,8 @@ struct lv_segment {
uint32_t area_len;
struct logical_volume *origin;
struct logical_volume *cow;
uint32_t chunk_size;
struct list origin_list;
uint32_t chunk_size; /* In sectors */
uint32_t extents_copied;
struct list tags;
@@ -220,8 +238,7 @@ struct lv_segment {
area_type_t type;
union {
struct {
struct physical_volume *pv;
uint32_t pe;
struct pv_segment *pvseg;
} pv;
struct {
struct logical_volume *lv;
@@ -246,21 +263,14 @@ struct logical_volume {
uint64_t size;
uint32_t le_count;
uint32_t origin_count;
struct list snapshot_segs;
struct lv_segment *snapshot;
struct list segments;
struct list tags;
};
struct snapshot {
struct id id;
int persistent; /* boolean */
uint32_t chunk_size; /* in 512 byte sectors */
uint32_t le_count;
struct logical_volume *origin;
struct logical_volume *cow;
};
struct name_list {
struct list list;
char *name;
@@ -284,17 +294,16 @@ struct lv_list {
struct logical_volume *lv;
};
struct snapshot_list {
struct list list;
struct snapshot *snapshot;
};
struct mda_list {
struct list list;
struct device_area mda;
};
struct peg_list {
struct list list;
struct pv_segment *peg;
};
/*
* Ownership of objects passes to caller.
*/
@@ -374,6 +383,9 @@ int vg_commit(struct volume_group *vg);
int vg_revert(struct volume_group *vg);
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
int *consistent);
struct volume_group *vg_read_precommitted(struct cmd_context *cmd,
const char *vg_name,
int *consistent);
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid);
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
struct list *mdas, uint64_t *label_sector,
@@ -407,20 +419,24 @@ int vg_rename(struct cmd_context *cmd, struct volume_group *vg,
const char *new_name);
int vg_extend(struct format_instance *fi, struct volume_group *vg,
int pv_count, char **pv_names);
int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
uint32_t new_extent_size);
/* 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);
int lv_reduce(struct format_instance *fi,
struct logical_volume *lv, uint32_t extents);
/* Entry point for all LV extent reductions */
int lv_reduce(struct logical_volume *lv, uint32_t extents);
int lv_extend(struct format_instance *fid,
struct logical_volume *lv,
/* Entry point for all LV extent allocations */
int lv_extend(struct logical_volume *lv,
struct segment_type *segtype,
uint32_t stripes, uint32_t stripe_size,
uint32_t mirrors, uint32_t extents,
@@ -428,8 +444,8 @@ int lv_extend(struct format_instance *fid,
uint32_t status, struct list *allocatable_pvs,
alloc_policy_t alloc);
/* lv must be part of vg->lvs */
int lv_remove(struct volume_group *vg, struct logical_volume *lv);
/* lv must be part of lv->vg->lvs */
int lv_remove(struct logical_volume *lv);
/* Manipulate PV structures */
int pv_add(struct volume_group *vg, struct physical_volume *pv);
@@ -440,6 +456,8 @@ struct physical_volume *pv_find(struct volume_group *vg, const char *pv_name);
struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name);
struct physical_volume *find_pv_in_vg_by_uuid(struct volume_group *vg,
struct id *id);
int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
const char *id, struct physical_volume *pv);
/* Find an LV within a given VG */
struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name);
@@ -463,6 +481,9 @@ struct physical_volume *find_pv_by_name(struct cmd_context *cmd,
/* Find LV segment containing given LE */
struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le);
/* Find PV segment containing given LE */
struct pv_segment *find_peg_by_pe(struct physical_volume *pv, uint32_t pe);
/*
* Remove a dev_dir if present.
*/
@@ -493,15 +514,14 @@ int lv_is_cow(const struct logical_volume *lv);
int pv_is_in_vg(struct volume_group *vg, struct physical_volume *pv);
struct snapshot *find_cow(const struct logical_volume *lv);
struct snapshot *find_origin(const struct logical_volume *lv);
struct list *find_snapshots(const struct logical_volume *lv);
struct lv_segment *find_cow(const struct logical_volume *lv);
int vg_add_snapshot(struct logical_volume *origin, struct logical_volume *cow,
int persistent, struct id *id, uint32_t extent_count,
int vg_add_snapshot(struct format_instance *fid, const char *name,
struct logical_volume *origin, struct logical_volume *cow,
union lvid *lvid, uint32_t extent_count,
uint32_t chunk_size);
int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow);
int vg_remove_snapshot(struct logical_volume *cow);
/*
* Mirroring functions
@@ -511,6 +531,7 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
struct list *source_pvl,
struct logical_volume *lv,
struct list *allocatable_pvs,
alloc_policy_t alloc,
struct list *lvs_changed);
int remove_pvmove_mirrors(struct volume_group *vg,
struct logical_volume *lv_mirr);

View File

@@ -19,6 +19,7 @@
#include "segtype.h"
#include "display.h"
#include "activate.h"
#include "lv_alloc.h"
/*
* Replace any LV segments on given PV with temporary mirror.
@@ -29,6 +30,7 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
struct list *source_pvl,
struct logical_volume *lv,
struct list *allocatable_pvs,
alloc_policy_t alloc,
struct list *lvs_changed)
{
struct list *segh;
@@ -61,12 +63,12 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
seg = list_item(segh, struct lv_segment);
for (s = 0; s < seg->area_count; s++) {
if (seg->area[s].type != AREA_PV ||
seg->area[s].u.pv.pv->dev != pvl->pv->dev)
seg->area[s].u.pv.pvseg->pv->dev != pvl->pv->dev)
continue;
/* Do these PEs need moving? */
list_iterate_items(per, pvl->pe_ranges) {
pe_start = seg->area[s].u.pv.pe;
pe_start = seg->area[s].u.pv.pvseg->pe;
pe_end = pe_start + seg->area_len - 1;
per_end = per->start + per->count - 1;
@@ -75,7 +77,7 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
(pe_start > per_end))
continue;
if (seg->segtype->flags & SEG_AREAS_STRIPED)
if (seg_is_striped(seg))
stripe_multiplier = seg->area_count;
else
stripe_multiplier = 1;
@@ -106,10 +108,10 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
seg = list_item(segh, struct lv_segment);
for (s = 0; s < seg->area_count; s++) {
if (seg->area[s].type != AREA_PV ||
seg->area[s].u.pv.pv->dev != pvl->pv->dev)
seg->area[s].u.pv.pvseg->pv->dev != pvl->pv->dev)
continue;
pe_start = seg->area[s].u.pv.pe;
pe_start = seg->area[s].u.pv.pvseg->pe;
/* Do these PEs need moving? */
list_iterate_items(per, pvl->pe_ranges) {
@@ -121,8 +123,10 @@ 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.pv->dev),
seg->area[s].u.pv.pe, seg->area_len);
dev_name(seg->area[s].u.pv.pvseg->
pv->dev),
seg->area[s].u.pv.pvseg->pe,
seg->area_len);
/* First time, add LV to list of LVs affected */
if (!lv_used) {
@@ -137,25 +141,23 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
log_very_verbose("Moving %s:%u-%u of %s/%s",
dev_name(pvl->pv->dev),
seg->area[s].u.pv.pe,
seg->area[s].u.pv.pe +
seg->area[s].u.pv.pvseg->pe,
seg->area[s].u.pv.pvseg->pe +
seg->area_len - 1,
lv->vg->name, lv->name);
start_le = lv_mirr->le_count;
if (!lv_extend(lv->vg->fid, lv_mirr, segtype, 1,
if (!lv_extend(lv_mirr, segtype, 1,
seg->area_len, 0u, seg->area_len,
seg->area[s].u.pv.pv,
seg->area[s].u.pv.pe,
seg->area[s].u.pv.pvseg->pv,
seg->area[s].u.pv.pvseg->pe,
PVMOVE, allocatable_pvs,
lv->alloc)) {
alloc)) {
log_error("Unable to allocate "
"temporary LV for pvmove.");
return 0;
}
seg->area[s].type = AREA_LV;
seg->area[s].u.lv.lv = lv_mirr;
seg->area[s].u.lv.le = start_le;
set_lv_segment_area_lv(seg, s, lv_mirr, start_le);
extent_count += seg->area_len;
@@ -206,8 +208,7 @@ int remove_pvmove_mirrors(struct volume_group *vg,
/* Check the segment params are compatible */
/* FIXME Improve error mesg & remove restrcn */
if ((!(mir_seg->segtype->flags
& SEG_AREAS_MIRRORED)) ||
if (!seg_is_mirrored(mir_seg) ||
!(mir_seg->status & PVMOVE) ||
mir_seg->le != seg->area[s].u.lv.le ||
mir_seg->area_count != 2 ||
@@ -225,9 +226,12 @@ int remove_pvmove_mirrors(struct volume_group *vg,
else
c = 0;
seg->area[s].type = AREA_PV;
seg->area[s].u.pv.pv = mir_seg->area[c].u.pv.pv;
seg->area[s].u.pv.pe = mir_seg->area[c].u.pv.pe;
if (!set_lv_segment_area_pv(seg, s,
mir_seg->area[c].u.pv.pvseg->pv,
mir_seg->area[c].u.pv.pvseg->pe)) {
stack;
return 0;
}
/* Replace mirror with old area */
if (!
@@ -259,11 +263,11 @@ const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr)
list_iterate(segh, &lv_mirr->segments) {
seg = list_item(segh, struct lv_segment);
if (!(seg->segtype->flags & SEG_AREAS_MIRRORED))
if (!seg_is_mirrored(seg))
continue;
if (seg->area[0].type != AREA_PV)
continue;
return dev_name(seg->area[0].u.pv.pv->dev);
return dev_name(seg->area[0].u.pv.pvseg->pv->dev);
}
return NULL;
@@ -307,7 +311,7 @@ struct logical_volume *find_pvmove_lv(struct volume_group *vg,
seg = list_item(segh, struct lv_segment);
if (seg->area[0].type != AREA_PV)
continue;
if (seg->area[0].u.pv.pv->dev != dev)
if (seg->area[0].u.pv.pvseg->pv->dev != dev)
continue;
return lv;
}
@@ -387,7 +391,7 @@ float copy_percent(struct logical_volume *lv_mirr)
denominator += seg->area_len;
if (seg->segtype->flags & SEG_AREAS_MIRRORED)
if (seg_is_mirrored(seg))
numerator += seg->extents_copied;
else
numerator += seg->area_len;

29
lib/metadata/pv_alloc.h Normal file
View File

@@ -0,0 +1,29 @@
/*
* 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
*/
#ifndef _LVM_PV_ALLOC_H
#include "pool.h"
int alloc_pv_segment_whole_pv(struct pool *mem, struct physical_volume *pv);
int peg_dup(struct pool *mem, struct list *peg_new, struct list *peg_old);
struct pv_segment *assign_peg_to_lvseg(struct physical_volume *pv, uint32_t pe,
uint32_t area_len,
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 check_pv_segments(struct volume_group *vg);
void merge_pv_segments(struct pv_segment *peg1, struct pv_segment *peg2);
#endif

250
lib/metadata/pv_manip.c Normal file
View File

@@ -0,0 +1,250 @@
/*
* Copyright (C) 2003 Sistina Software, Inc. All rights reserved.
* Copyright (C) 2004 - 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 "lib.h"
#include "pool.h"
#include "metadata.h"
#include "pv_alloc.h"
#include "toolcontext.h"
static struct pv_segment *_alloc_pv_segment(struct pool *mem,
struct physical_volume *pv,
uint32_t pe, uint32_t len,
struct lv_segment *lvseg,
uint32_t lv_area)
{
struct pv_segment *peg;
if (!(peg = pool_zalloc(mem, sizeof(*peg)))) {
log_error("pv_segment allocation failed");
return NULL;
}
peg->pv = pv;
peg->pe = pe;
peg->len = len;
peg->lvseg = lvseg;
peg->lv_area = lv_area;
list_init(&peg->list);
return peg;
}
int alloc_pv_segment_whole_pv(struct pool *mem, struct physical_volume *pv)
{
struct pv_segment *peg;
if (!pv->pe_count)
return 1;
/* FIXME Cope with holes in PVs */
if (!(peg = _alloc_pv_segment(mem, pv, 0, pv->pe_count, NULL, 0))) {
stack;
return 0;
}
list_add(&pv->segments, &peg->list);
return 1;
}
int peg_dup(struct pool *mem, struct list *peg_new, struct list *peg_old)
{
struct pv_segment *peg, *pego;
list_init(peg_new);
list_iterate_items(pego, peg_old) {
if (!(peg = _alloc_pv_segment(mem, pego->pv, pego->pe,
pego->len, pego->lvseg,
pego->lv_area))) {
stack;
return 0;
}
list_add(peg_new, &peg->list);
}
return 1;
}
/*
* Split peg at given extent.
* Second part is always deallocated.
*/
static int _pv_split_segment(struct physical_volume *pv, struct pv_segment *peg,
uint32_t pe)
{
struct pv_segment *peg_new;
if (!(peg_new = _alloc_pv_segment(pv->fmt->cmd->mem, peg->pv, pe,
peg->len + peg->pe - pe,
NULL, 0))) {
stack;
return 0;
}
peg->len = peg->len - peg_new->len;
list_add_h(&peg->list, &peg_new->list);
return 1;
}
/*
* Ensure there is a PV segment boundary at the given extent.
*/
int pv_split_segment(struct physical_volume *pv, uint32_t pe)
{
struct pv_segment *peg;
if (pe == pv->pe_count)
return 1;
if (!(peg = find_peg_by_pe(pv, pe))) {
log_error("Segment with extent %" PRIu32 " in PV %s not found",
pe, dev_name(pv->dev));
return 0;
}
/* This is a peg start already */
if (pe == peg->pe)
return 1;
if (!_pv_split_segment(pv, peg, pe)) {
stack;
return 0;
}
return 1;
}
static struct pv_segment null_pv_segment = {
pv: NULL,
pe: 0
};
struct pv_segment *assign_peg_to_lvseg(struct physical_volume *pv,
uint32_t pe, uint32_t area_len,
struct lv_segment *seg,
uint32_t area_num)
{
struct pv_segment *peg;
/* Missing format1 PV */
if (!pv)
return &null_pv_segment;
if (!pv_split_segment(pv, pe) ||
!pv_split_segment(pv, pe + area_len)) {
stack;
return NULL;
}
if (!(peg = find_peg_by_pe(pv, pe))) {
log_error("Missing PV segment on %s at %u.",
dev_name(pv->dev), pe);
return NULL;
}
peg->lvseg = seg;
peg->lv_area = area_num;
return peg;
}
int release_pv_segment(struct pv_segment *peg, uint32_t new_area_len)
{
if (new_area_len == 0) {
peg->lvseg = NULL;
peg->lv_area = 0;
/* FIXME merge free space */
return 1;
}
if (!pv_split_segment(peg->pv, peg->pe + new_area_len)) {
stack;
return 0;
}
return 1;
}
/*
* Only for use by lv_segment merging routines.
*/
void merge_pv_segments(struct pv_segment *peg1, struct pv_segment *peg2)
{
peg1->len += peg2->len;
list_del(&peg2->list);
}
/*
* Check all pv_segments in VG for consistency
*/
int check_pv_segments(struct volume_group *vg)
{
struct physical_volume *pv;
struct pv_list *pvl;
struct pv_segment *peg;
unsigned s, segno;
uint32_t start_pe;
int ret = 1;
list_iterate_items(pvl, &vg->pvs) {
pv = pvl->pv;
segno = 0;
start_pe = 0;
list_iterate_items(peg, &pv->segments) {
s = peg->lv_area;
/* FIXME Remove this next line eventually */
log_debug("%s %u: %6u %6u: %s(%u:%u)",
dev_name(pv->dev), segno++, peg->pe, peg->len,
peg->lvseg ? peg->lvseg->lv->name : "NULL",
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",
start_pe, peg->pe);
ret = 0;
}
if (peg->lvseg) {
if (peg->lvseg->area[s].type != AREA_PV) {
log_debug("Wrong lvseg area type");
ret = 0;
}
if (peg->lvseg->area[s].u.pv.pvseg != peg) {
log_debug("Inconsistent pvseg pointers");
ret = 0;
}
if (peg->lvseg->area_len != peg->len) {
log_debug("Inconsistent length: %u %u",
peg->len,
peg->lvseg->area_len);
ret = 0;
}
}
start_pe += peg->len;
}
}
return ret;
}

View File

@@ -16,16 +16,121 @@
#include "lib.h"
#include "pv_map.h"
#include "hash.h"
#include "pv_alloc.h"
static int _create_maps(struct pool *mem, struct list *pvs, struct list *maps)
/*
* Areas are maintained in size order, largest first.
*/
static void _insert_area(struct list *head, struct pv_area *a)
{
struct pv_area *pva;
list_iterate_items(pva, head) {
if (a->count > pva->count)
break;
}
list_add(&pva->list, &a->list);
}
static int _create_single_area(struct pool *mem, struct pv_map *pvm,
uint32_t start, uint32_t length)
{
struct pv_area *pva;
if (!(pva = pool_zalloc(mem, sizeof(*pva)))) {
stack;
return 0;
}
log_debug("Allowing allocation on %s start PE %" PRIu32 " length %"
PRIu32, dev_name(pvm->pv->dev), start, length);
pva->map = pvm;
pva->start = start;
pva->count = length;
_insert_area(&pvm->areas, pva);
return 1;
}
static int _create_alloc_areas_for_pv(struct pool *mem, struct pv_map *pvm,
uint32_t start, uint32_t count)
{
struct pv_segment *peg;
uint32_t pe, end, area_len;
/* Only select extents from start to end inclusive */
end = start + count - 1;
if (end > pvm->pv->pe_count - 1)
end = pvm->pv->pe_count - 1;
pe = start;
/* Walk through complete ordered list of device segments */
list_iterate_items(peg, &pvm->pv->segments) {
/* pe holds the next extent we want to check */
/* Beyond the range we're interested in? */
if (pe > end)
break;
/* Skip if we haven't reached the first seg we want yet */
if (pe > peg->pe + peg->len - 1)
continue;
/* Free? */
if (peg->lvseg)
goto next;
/* How much of this peg do we need? */
area_len = (end >= peg->pe + peg->len - 1) ?
peg->len - (pe - peg->pe) : end - pe + 1;
if (!_create_single_area(mem, pvm, pe, area_len)) {
stack;
return 0;
}
next:
pe = peg->pe + peg->len;
}
return 1;
}
static int _create_all_areas_for_pv(struct pool *mem, struct pv_map *pvm,
struct list *pe_ranges)
{
struct pe_range *aa;
if (!pe_ranges) {
/* Use whole PV */
if (!_create_alloc_areas_for_pv(mem, pvm, UINT32_C(0),
pvm->pv->pe_count)) {
stack;
return 0;
}
return 1;
}
list_iterate_items(aa, pe_ranges) {
if (!_create_alloc_areas_for_pv(mem, pvm, aa->start,
aa->count)) {
stack;
return 0;
}
}
return 1;
}
static int _create_maps(struct pool *mem, struct list *pvs, struct list *pvms)
{
struct list *tmp;
struct pv_map *pvm;
struct pv_list *pvl;
list_iterate(tmp, pvs) {
pvl = list_item(tmp, struct pv_list);
list_iterate_items(pvl, pvs) {
if (!(pvl->pv->status & ALLOCATABLE_PV))
continue;
@@ -34,255 +139,43 @@ static int _create_maps(struct pool *mem, struct list *pvs, struct list *maps)
return 0;
}
pvm->pvl = pvl;
if (!(pvm->allocated_extents =
bitset_create(mem, pvl->pv->pe_count))) {
pvm->pv = pvl->pv;
list_init(&pvm->areas);
list_add(pvms, &pvm->list);
if (!_create_all_areas_for_pv(mem, pvm, pvl->pe_ranges)) {
stack;
return 0;
}
list_init(&pvm->areas);
list_add(maps, &pvm->list);
}
return 1;
}
static int _set_allocd(struct hash_table *hash,
struct physical_volume *pv, uint32_t pe)
{
struct pv_map *pvm;
if (!(pvm = (struct pv_map *) hash_lookup(hash, dev_name(pv->dev)))) {
/*
* it doesn't matter that this fails, it just
* means this part of the lv is on a pv that
* we're not interested in allocating to.
*/
return 1;
}
/* sanity check */
if (bit(pvm->allocated_extents, pe)) {
log_error("Physical extent %d of %s referenced by more than "
"one logical volume", pe, dev_name(pv->dev));
return 0;
}
bit_set(pvm->allocated_extents, pe);
return 1;
}
static int _fill_bitsets(struct volume_group *vg, struct list *maps)
{
struct list *lvh, *pvmh, *segh;
struct logical_volume *lv;
struct pv_map *pvm;
uint32_t s, pe;
struct hash_table *hash;
struct lv_segment *seg;
int r = 0;
if (!(hash = hash_create(128))) {
log_err("Couldn't create hash table for pv maps.");
return 0;
}
/* populate the hash table */
list_iterate(pvmh, maps) {
pvm = list_item(pvmh, struct pv_map);
if (!hash_insert(hash, dev_name(pvm->pvl->pv->dev), pvm)) {
stack;
goto out;
}
}
/* iterate through all the lv's setting bit's for used pe's */
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct lv_segment);
for (s = 0u; s < seg->area_count; s++) {
for (pe = 0u; pe < seg->area_len; pe++) {
if (seg->area[s].type != AREA_PV)
continue;
if (!_set_allocd(hash,
seg->area[s].u.pv.pv,
seg->area[s].u.pv.pe
+ pe)) {
stack;
goto out;
}
}
}
}
}
r = 1;
out:
hash_destroy(hash);
return r;
}
/*
* Areas are maintained in size order.
* Create list of PV areas available for this particular allocation
*/
static void _insert_area(struct list *head, struct pv_area *a)
{
struct list *pvah;
struct pv_area *pva = NULL;
if (list_empty(head)) {
list_add(head, &a->list);
return;
}
list_iterate(pvah, head) {
pva = list_item(pvah, struct pv_area);
if (pva->count < a->count)
break;
}
list_add_h(&pva->list, &a->list);
}
static int _create_single_area(struct pool *mem, struct pv_map *pvm,
uint32_t end, uint32_t *extent)
{
uint32_t e = *extent, b;
struct pv_area *pva;
while (e <= end && bit(pvm->allocated_extents, e))
e++;
if (e > end) {
*extent = e;
return 1;
}
b = e++;
while (e <= end && !bit(pvm->allocated_extents, e))
e++;
if (!(pva = pool_zalloc(mem, sizeof(*pva)))) {
stack;
return 0;
}
log_debug("Allowing allocation on %s start PE %" PRIu32 " length %"
PRIu32, dev_name(pvm->pvl->pv->dev), b, e - b);
pva->map = pvm;
pva->start = b;
pva->count = e - b;
_insert_area(&pvm->areas, pva);
*extent = e;
return 1;
}
static int _create_areas(struct pool *mem, struct pv_map *pvm, uint32_t start,
uint32_t count)
{
uint32_t pe, end;
end = start + count - 1;
if (end > pvm->pvl->pv->pe_count - 1)
end = pvm->pvl->pv->pe_count - 1;
pe = start;
while (pe <= end)
if (!_create_single_area(mem, pvm, end, &pe)) {
stack;
return 0;
}
return 1;
}
static int _create_allocatable_areas(struct pool *mem, struct pv_map *pvm)
{
struct list *alloc_areas, *aah;
struct pe_range *aa;
alloc_areas = pvm->pvl->pe_ranges;
if (alloc_areas) {
list_iterate(aah, alloc_areas) {
aa = list_item(aah, struct pe_range);
if (!_create_areas(mem, pvm, aa->start, aa->count)) {
stack;
return 0;
}
}
} else {
/* Use whole PV */
if (!_create_areas(mem, pvm, UINT32_C(0),
pvm->pvl->pv->pe_count)) {
stack;
return 0;
}
}
return 1;
}
static int _create_all_areas(struct pool *mem, struct list *maps,
struct list *pvs)
{
struct list *tmp;
struct pv_map *pvm;
list_iterate(tmp, maps) {
pvm = list_item(tmp, struct pv_map);
if (!_create_allocatable_areas(mem, pvm)) {
stack;
return 0;
}
}
return 1;
}
struct list *create_pv_maps(struct pool *mem, struct volume_group *vg,
struct list *pvs)
struct list *allocatable_pvs)
{
struct list *maps = pool_zalloc(mem, sizeof(*maps));
struct list *pvms;
if (!maps) {
stack;
if (!(pvms = pool_zalloc(mem, sizeof(*pvms)))) {
log_error("create_pv_maps alloc failed");
return NULL;
}
list_init(maps);
list_init(pvms);
if (!_create_maps(mem, pvs, maps)) {
if (!_create_maps(mem, allocatable_pvs, pvms)) {
log_error("Couldn't create physical volume maps in %s",
vg->name);
goto bad;
pool_free(mem, pvms);
return NULL;
}
if (!_fill_bitsets(vg, maps)) {
log_error("Couldn't fill extent allocation bitmaps in %s",
vg->name);
goto bad;
}
if (!_create_all_areas(mem, maps, pvs)) {
log_error("Couldn't create area maps in %s", vg->name);
goto bad;
}
return maps;
bad:
pool_free(mem, maps);
return NULL;
return pvms;
}
void consume_pv_area(struct pv_area *pva, uint32_t to_go)

View File

@@ -33,19 +33,21 @@ struct pv_area {
uint32_t start;
uint32_t count;
struct list list;
struct list list; /* pv_map.areas */
};
struct pv_map {
struct pv_list *pvl;
bitset_t allocated_extents;
struct list areas;
struct physical_volume *pv;
struct list areas; /* struct pv_areas */
struct list list;
};
struct list *create_pv_maps(struct pool *mem,
struct volume_group *vg, struct list *pvs);
/*
* Find intersection between available_pvs and free space in VG
*/
struct list *create_pv_maps(struct pool *mem, struct volume_group *vg,
struct list *allocatable_pvs);
void consume_pv_area(struct pv_area *area, uint32_t to_go);

View File

@@ -33,6 +33,12 @@ struct dev_manager;
#define SEG_FORMAT1_SUPPORT 0x00000010
#define SEG_VIRTUAL 0x00000020
#define seg_is_mirrored(seg) ((seg)->segtype->flags & SEG_AREAS_MIRRORED ? 1 : 0)
#define seg_is_striped(seg) ((seg)->segtype->flags & SEG_AREAS_STRIPED ? 1 : 0)
#define seg_is_snapshot(seg) ((seg)->segtype->flags & SEG_SNAPSHOT ? 1 : 0)
#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)
struct segment_type {
struct list list;
struct cmd_context *cmd;

View File

@@ -16,101 +16,31 @@
#include "lib.h"
#include "metadata.h"
#include "toolcontext.h"
#include "lv_alloc.h"
int lv_is_origin(const struct logical_volume *lv)
{
struct list *slh;
struct snapshot *s;
list_iterate(slh, &lv->vg->snapshots) {
s = list_item(slh, struct snapshot_list)->snapshot;
if (s->origin == lv)
return 1;
}
return 0;
return lv->origin_count ? 1 : 0;
}
int lv_is_cow(const struct logical_volume *lv)
{
struct list *slh;
struct snapshot *s;
list_iterate(slh, &lv->vg->snapshots) {
s = list_item(slh, struct snapshot_list)->snapshot;
if (s->cow == lv)
return 1;
}
return 0;
return lv->snapshot ? 1 : 0;
}
struct snapshot *find_origin(const struct logical_volume *lv)
/* Given a cow LV, return the snapshot lv_segment that uses it */
struct lv_segment *find_cow(const struct logical_volume *lv)
{
struct list *slh;
struct snapshot *s;
list_iterate(slh, &lv->vg->snapshots) {
s = list_item(slh, struct snapshot_list)->snapshot;
if (s->origin == lv)
return s;
}
return NULL;
return lv->snapshot;
}
struct snapshot *find_cow(const struct logical_volume *lv)
int vg_add_snapshot(struct format_instance *fid, const char *name,
struct logical_volume *origin,
struct logical_volume *cow, union lvid *lvid,
uint32_t extent_count, uint32_t chunk_size)
{
struct list *slh;
struct snapshot *s;
list_iterate(slh, &lv->vg->snapshots) {
s = list_item(slh, struct snapshot_list)->snapshot;
if (s->cow == lv)
return s;
}
return NULL;
}
struct list *find_snapshots(const struct logical_volume *lv)
{
struct list *slh;
struct list *snaplist;
struct snapshot *s;
struct snapshot_list *newsl;
struct pool *mem = lv->vg->cmd->mem;
if (!(snaplist = pool_alloc(mem, sizeof(*snaplist)))) {
log_error("snapshot name list allocation failed");
return NULL;
}
list_init(snaplist);
list_iterate(slh, &lv->vg->snapshots) {
s = list_item(slh, struct snapshot_list)->snapshot;
if (!(s->origin == lv))
continue;
if (!(newsl = pool_alloc(mem, sizeof(*newsl)))) {
log_error("snapshot_list structure allocation failed");
pool_free(mem, snaplist);
return NULL;
}
newsl->snapshot = s;
list_add(snaplist, &newsl->list);
}
return snaplist;
}
int vg_add_snapshot(struct logical_volume *origin, struct logical_volume *cow,
int persistent, struct id *id, uint32_t extent_count,
uint32_t chunk_size)
{
struct snapshot *s;
struct snapshot_list *sl;
struct pool *mem = origin->vg->cmd->mem;
struct logical_volume *snap;
struct lv_segment *seg;
/*
* Is the cow device already being used ?
@@ -120,55 +50,53 @@ int vg_add_snapshot(struct logical_volume *origin, struct logical_volume *cow,
return 0;
}
if (!(s = pool_alloc(mem, sizeof(*s)))) {
if (!(snap = lv_create_empty(fid, name, name ? NULL : "snapshot%d",
lvid, LVM_READ | LVM_WRITE | VISIBLE_LV,
ALLOC_INHERIT, 1, origin->vg))) {
stack;
return 0;
}
s->persistent = persistent;
s->chunk_size = chunk_size;
s->le_count = extent_count;
s->origin = origin;
s->cow = cow;
snap->le_count = extent_count;
if (id)
s->id = *id;
else if (!id_create(&s->id)) {
log_error("Random UUID creation failed for snapshot %s.",
cow->name);
return 0;
}
if (!(sl = pool_alloc(mem, sizeof(*sl)))) {
if (!(seg = alloc_snapshot_seg(snap, 0))) {
stack;
pool_free(mem, s);
return 0;
}
seg->chunk_size = chunk_size;
seg->origin = origin;
seg->cow = cow;
seg->lv->status |= SNAPSHOT;
origin->origin_count++;
origin->vg->snapshot_count++;
origin->vg->lv_count--;
cow->snapshot = seg;
cow->status &= ~VISIBLE_LV;
sl->snapshot = s;
list_add(&origin->vg->snapshots, &sl->list);
origin->vg->snapshot_count++;
list_add(&origin->snapshot_segs, &seg->origin_list);
return 1;
}
int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow)
int vg_remove_snapshot(struct logical_volume *cow)
{
struct list *slh;
struct snapshot_list *sl;
list_del(&cow->snapshot->origin_list);
cow->snapshot->origin->origin_count--;
list_iterate(slh, &vg->snapshots) {
sl = list_item(slh, struct snapshot_list);
if (sl->snapshot->cow == cow) {
list_del(slh);
vg->snapshot_count--;
return 1;
}
if (!lv_remove(cow->snapshot->lv)) {
log_error("Failed to remove internal snapshot LV %s",
cow->snapshot->lv->name);
return 0;
}
/* fail */
log_err("Asked to remove an unknown snapshot.");
return 0;
cow->snapshot = NULL;
cow->vg->snapshot_count--;
cow->vg->lv_count++;
cow->status |= VISIBLE_LV;
return 1;
}

View File

@@ -131,6 +131,7 @@ static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
int areas = seg->area_count;
int start_area = 0u;
uint32_t region_size, region_max;
int ret;
if (!*target_state)
*target_state = _init_target(mem, cft);
@@ -166,10 +167,10 @@ static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
region_size);
}
if ((*pos = lvm_snprintf(params, paramsize, "core 1 %u %u ",
region_size, areas)) < 0) {
if ((ret = compose_log_line(dm, seg, params, paramsize, pos,
areas, region_size)) <= 0) {
stack;
return -1;
return ret;
}
}

View File

@@ -152,7 +152,8 @@ static int _create_dir_recursive(const char *dir)
if (*orig) {
rc = mkdir(orig, 0777);
if (rc < 0 && errno != EEXIST) {
log_sys_error("mkdir", orig);
if (errno != EROFS)
log_sys_error("mkdir", orig);
dbg_free(orig);
return 0;
}
@@ -164,7 +165,8 @@ static int _create_dir_recursive(const char *dir)
/* Create final directory */
rc = mkdir(dir, 0777);
if (rc < 0 && errno != EEXIST) {
log_sys_error("mkdir", dir);
if (errno != EROFS)
log_sys_error("mkdir", dir);
return 0;
}
return 1;

View File

@@ -19,6 +19,16 @@
#include <stdarg.h>
char *dbg_strdup(const char *str)
{
char *ret = dbg_malloc(strlen(str) + 1);
if (ret)
strcpy(ret, str);
return ret;
}
#ifdef DEBUG_MEM
struct memblock {
@@ -183,6 +193,8 @@ int dump_memory(void)
for (c = 0; c < sizeof(str) - 1; c++) {
if (c >= mb->length)
str[c] = ' ';
else if (*(char *)(mb->magic + c) == '\0')
str[c] = '\0';
else if (*(char *)(mb->magic + c) < ' ')
str[c] = '?';
else

View File

@@ -21,7 +21,9 @@
#include <string.h>
void *malloc_aux(size_t s, const char *file, int line);
# define dbg_malloc(s) malloc_aux((s), __FILE__, __LINE__)
#define dbg_malloc(s) malloc_aux((s), __FILE__, __LINE__)
char *dbg_strdup(const char *str);
#ifdef DEBUG_MEM
@@ -42,14 +44,4 @@ void bounds_check(void);
#endif
static inline char *dbg_strdup(const char *str)
{
char *ret = dbg_malloc(strlen(str) + 1);
if (ret)
strcpy(ret, str);
return ret;
}
#endif

View File

@@ -71,4 +71,7 @@ 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")
FIELD(SEGS, seg, STR, "Devices", list, 5, devices, "devices")
FIELD(PVSEGS, pvseg, NUM, "Start", pe, 5, uint32, "pvseg_start")
FIELD(PVSEGS, pvseg, NUM, "SSize", len, 5, uint32, "pvseg_size")
/* *INDENT-ON* */

View File

@@ -31,6 +31,7 @@ static union {
struct logical_volume _lv;
struct volume_group _vg;
struct lv_segment _seg;
struct pv_segment _pvseg;
} _dummy;
/*
@@ -159,8 +160,8 @@ static int _devices_disp(struct report_handle *rh, struct field *field,
extent = seg->area[s].u.lv.le;
break;
case AREA_PV:
name = dev_name(seg->area[s].u.pv.pv->dev);
extent = seg->area[s].u.pv.pe;
name = dev_name(seg->area[s].u.pv.pvseg->pv->dev);
extent = seg->area[s].u.pv.pvseg->pe;
break;
default:
name = "unknown";
@@ -324,7 +325,7 @@ static int _lvstatus_disp(struct report_handle *rh, struct field *field,
const struct logical_volume *lv = (const struct logical_volume *) data;
struct lvinfo info;
char *repstr;
struct snapshot *snap;
struct lv_segment *snap_seg;
float snap_percent;
if (!(repstr = pool_zalloc(rh->mem, 7))) {
@@ -373,8 +374,8 @@ static int _lvstatus_disp(struct report_handle *rh, struct field *field,
repstr[5] = '-';
/* Snapshot dropped? */
if ((snap = find_cow(lv)) &&
(!lv_snapshot_percent(snap->cow, &snap_percent) ||
if ((snap_seg = find_cow(lv)) &&
(!lv_snapshot_percent(snap_seg->cow, &snap_percent) ||
snap_percent < 0 || snap_percent >= 100)) {
repstr[0] = toupper(repstr[0]);
if (info.suspended)
@@ -478,10 +479,10 @@ static int _origin_disp(struct report_handle *rh, struct field *field,
const void *data)
{
const struct logical_volume *lv = (const struct logical_volume *) data;
struct snapshot *snap;
struct lv_segment *snap_seg;
if ((snap = find_cow(lv)))
return _string_disp(rh, field, &snap->origin->name);
if ((snap_seg = find_cow(lv)))
return _string_disp(rh, field, &snap_seg->origin->name);
field->report_string = "";
field->sort_value = (const void *) field->report_string;
@@ -501,7 +502,7 @@ static int _movepv_disp(struct report_handle *rh, struct field *field,
seg = list_item(segh, struct lv_segment);
if (!(seg->status & PVMOVE))
continue;
name = dev_name(seg->area[0].u.pv.pv->dev);
name = dev_name(seg->area[0].u.pv.pvseg->pv->dev);
return _string_disp(rh, field, &name);
}
@@ -762,7 +763,7 @@ static int _snpercent_disp(struct report_handle *rh, struct field *field,
const void *data)
{
const struct logical_volume *lv = (const struct logical_volume *) data;
struct snapshot *snap;
struct lv_segment *snap_seg;
struct lvinfo info;
float snap_percent;
uint64_t *sortval;
@@ -773,15 +774,16 @@ static int _snpercent_disp(struct report_handle *rh, struct field *field,
return 0;
}
if (!(snap = find_cow(lv)) ||
(lv_info(snap->cow, &info, 0) && !info.exists)) {
if (!(snap_seg = find_cow(lv)) ||
(lv_info(snap_seg->cow, &info, 0) && !info.exists)) {
field->report_string = "";
*sortval = UINT64_C(0);
field->sort_value = sortval;
return 1;
}
if (!lv_snapshot_percent(snap->cow, &snap_percent) || snap_percent < 0) {
if (!lv_snapshot_percent(snap_seg->cow, &snap_percent)
|| snap_percent < 0) {
field->report_string = "100.00";
*sortval = UINT64_C(100);
field->sort_value = sortval;
@@ -855,9 +857,9 @@ static int _copypercent_disp(struct report_handle *rh, struct field *field,
static struct {
report_type_t type;
const char id[30];
const char id[32];
off_t offset;
const char heading[30];
const char heading[32];
int width;
uint32_t flags;
field_report_fn report_fn;
@@ -1077,6 +1079,9 @@ void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
case SEGS:
rh->field_prefix = "seg_";
break;
case PVSEGS:
rh->field_prefix = "pvseg_";
break;
default:
rh->field_prefix = "";
}
@@ -1096,6 +1101,8 @@ void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
/* Ensure options selected are compatible */
if (rh->type & SEGS)
rh->type |= LVS;
if (rh->type & PVSEGS)
rh->type |= PVS;
if ((rh->type & LVS) && (rh->type & PVS)) {
log_error("Can't report LV and PV fields at the same time");
return NULL;
@@ -1106,6 +1113,8 @@ void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
*report_type = SEGS;
else if (rh->type & LVS)
*report_type = LVS;
else if (rh->type & PVSEGS)
*report_type = PVSEGS;
else if (rh->type & PVS)
*report_type = PVS;
@@ -1126,7 +1135,7 @@ void report_free(void *handle)
*/
int report_object(void *handle, struct volume_group *vg,
struct logical_volume *lv, struct physical_volume *pv,
struct lv_segment *seg)
struct lv_segment *seg, struct pv_segment *pvseg)
{
struct report_handle *rh = handle;
struct list *fh;
@@ -1186,6 +1195,9 @@ int report_object(void *handle, struct volume_group *vg,
break;
case SEGS:
data = (void *) seg + _fields[fp->field_num].offset;
break;
case PVSEGS:
data = (void *) pvseg + _fields[fp->field_num].offset;
}
if (skip) {

View File

@@ -18,7 +18,7 @@
#include "metadata.h"
typedef enum { LVS = 1, PVS = 2, VGS = 4, SEGS = 8 } report_type_t;
typedef enum { LVS = 1, PVS = 2, VGS = 4, SEGS = 8, PVSEGS = 16 } report_type_t;
struct field;
struct report_handle;
@@ -32,7 +32,7 @@ void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
void report_free(void *handle);
int report_object(void *handle, struct volume_group *vg,
struct logical_volume *lv, struct physical_volume *pv,
struct lv_segment *seg);
struct lv_segment *seg, struct pv_segment *pvseg);
int report_output(void *handle);
#endif

View File

@@ -70,8 +70,8 @@ static int _text_import(struct lv_segment *seg, const struct config_node *sn,
return 0;
}
if (!vg_add_snapshot(org, cow, 1, &seg->lv->lvid.id[1], seg->len,
chunk_size)) {
if (!vg_add_snapshot(seg->lv->vg->fid, seg->lv->name, org, cow,
&seg->lv->lvid, seg->len, chunk_size)) {
stack;
return 0;
}

View File

@@ -26,6 +26,7 @@
#include "targets.h"
#include "lvm-string.h"
#include "activate.h"
#include "pv_alloc.h"
static const char *_name(const struct lv_segment *seg)
{
@@ -118,8 +119,10 @@ static int _segments_compatible(struct lv_segment *first,
width = first->area_len;
if ((first->area[s].u.pv.pv != second->area[s].u.pv.pv) ||
(first->area[s].u.pv.pe + width != second->area[s].u.pv.pe))
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))
return 0;
}
@@ -131,12 +134,19 @@ static int _segments_compatible(struct lv_segment *first,
static int _merge_segments(struct lv_segment *seg1, struct lv_segment *seg2)
{
uint32_t s;
if (!_segments_compatible(seg1, seg2))
return 0;
seg1->len += seg2->len;
seg1->area_len += seg2->area_len;
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);
return 1;
}

View File

@@ -25,11 +25,11 @@ struct id {
/*
* Unique logical volume identifier
* With format1 this is VG uuid + LV uuid + '\0'
* With format1 this is VG uuid + LV uuid + '\0' + padding
*/
union lvid {
struct id id[2];
char s[2 * sizeof(struct id) + 1];
char s[2 * sizeof(struct id) + 1 + 7];
};
int lvid_from_lvnum(union lvid *lvid, struct id *vgid, uint32_t lv_num);

View File

@@ -17,6 +17,14 @@ top_srcdir = @top_srcdir@
VPATH = @srcdir@
interface = @interface@
ifeq ("@DMEVENTD@", "yes")
SUBDIRS += event
endif
ifeq ($(MAKECMDGOALS),distclean)
SUBDIRS += event
endif
SOURCES = libdm-common.c libdm-file.c $(interface)/libdm-iface.c
INCLUDES = -I$(interface)

View File

@@ -18,17 +18,30 @@
#include <assert.h>
/*
* A list consists of a list head plus elements.
* Each element has 'next' and 'previous' pointers.
* The list head's pointers point to the first and the last element.
*/
struct list {
struct list *n, *p;
};
/*
* Initialise a list before use.
* The list head's next and previous pointers point back to itself.
*/
#define LIST_INIT(name) struct list name = { &(name), &(name) }
static inline void list_init(struct list *head)
{
head->n = head->p = head;
}
/*
* Insert an element before 'head'.
* If 'head' is the list head, this adds an element to the end of the list.
*/
static inline void list_add(struct list *head, struct list *elem)
{
assert(head->n);
@@ -40,6 +53,10 @@ static inline void list_add(struct list *head, struct list *elem)
head->p = elem;
}
/*
* Insert an element after 'head'.
* If 'head' is the list head, this adds an element to the front of the list.
*/
static inline void list_add_h(struct list *head, struct list *elem)
{
assert(head->n);
@@ -51,53 +68,135 @@ static inline void list_add_h(struct list *head, struct list *elem)
head->n = elem;
}
/*
* Delete an element from its list.
* Note that this doesn't change the element itself - it may still be safe
* to follow its pointers.
*/
static inline void list_del(struct list *elem)
{
elem->n->p = elem->p;
elem->p->n = elem->n;
}
/*
* Is the list empty?
*/
static inline int list_empty(struct list *head)
{
return head->n == head;
}
/*
* Is this the first element of the list?
*/
static inline int list_start(struct list *head, struct list *elem)
{
return elem->p == head;
}
/*
* Is this the last element of the list?
*/
static inline int list_end(struct list *head, struct list *elem)
{
return elem->n == head;
}
/*
* Return last element of the list or NULL if empty
*/
static inline struct list *list_last(struct list *head)
{
return (list_empty(head) ? NULL : head->p);
}
/*
* Return the previous element of the list, or NULL if we've reached the start.
*/
static inline struct list *list_prev(struct list *head, struct list *elem)
{
return (list_start(head, elem) ? NULL : elem->p);
}
/*
* Return the next element of the list, or NULL if we've reached the end.
*/
static inline struct list *list_next(struct list *head, struct list *elem)
{
return (list_end(head, elem) ? NULL : elem->n);
}
#define list_item(v, t) \
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->list))
/*
* Given the address v of an instance of 'struct list' called 'head'
* contained in a structure of type t, return the containing structure.
*/
#define list_struct_base(v, t, head) \
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->head))
#define list_struct_base(v, t, h) \
((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->h))
/*
* Given the address v of an instance of 'struct list list' contained in
* a structure of type t, return the containing structure.
*/
#define list_item(v, t) list_struct_base((v), t, list)
/* Given a known element in a known structure, locate another */
/*
* Given the address v of one known element e in a known structure of type t,
* return another element f.
*/
#define struct_field(v, t, e, f) \
(((t *)((uintptr_t)(v) - (uintptr_t)&((t *) 0)->e))->f)
/* Given a known element in a known structure, locate the list head */
/*
* Given the address v of a known element e in a known structure of type t,
* return the list head 'list'
*/
#define list_head(v, t, e) struct_field(v, t, e, list)
/*
* Set v to each element of a list in turn.
*/
#define list_iterate(v, head) \
for (v = (head)->n; v != head; v = v->n)
/*
* Set v to each element in a list in turn, starting from the element
* in front of 'start'.
* You can use this to 'unwind' a list_iterate and back out actions on
* already-processed elements.
* If 'start' is 'head' it walks the list backwards.
*/
#define list_uniterate(v, head, start) \
for (v = (start)->p; v != head; v = v->p)
/*
* A safe way to walk a list and delete and free some elements along
* the way.
* t must be defined as a temporary variable of the same type as v.
*/
#define list_iterate_safe(v, t, head) \
for (v = (head)->n, t = v->n; v != head; v = t, t = v->n)
#define list_iterate_items(v, head) \
for (v = list_item((head)->n, typeof(*v)); &v->list != (head); \
v = list_item(v->list.n, typeof(*v)))
/*
* Walk a list, 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_items_gen(v, head, field) \
for (v = list_struct_base((head)->n, typeof(*v), field); \
&v->field != (head); \
v = list_struct_base(v->field.n, typeof(*v), field))
/*
* Walk a list, 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_items(v, head) list_iterate_items_gen(v, (head), list)
/*
* Return the number of elements in a list by walking it.
*/
static inline unsigned int list_size(const struct list *head)
{
unsigned int s = 0;

View File

@@ -117,6 +117,7 @@ static void *_align(void *ptr, unsigned int a)
return (void *) (((unsigned long) ptr + agn) & ~agn);
}
#ifdef DM_IOCTLS
static int _get_proc_number(const char *file, const char *name,
uint32_t *number)
{
@@ -226,6 +227,7 @@ static int _create_control(const char *control, uint32_t major, uint32_t minor)
return 1;
}
#endif
static int _open_control(void)
{
@@ -1396,10 +1398,7 @@ void dm_lib_release(void)
void dm_lib_exit(void)
{
if (_control_fd != -1) {
close(_control_fd);
_control_fd = -1;
}
dm_lib_release();
_version_ok = 1;
_version_checked = 0;
}

View File

@@ -166,6 +166,6 @@ const char *dm_dir(void);
/* Release library resources */
void dm_lib_release(void);
void dm_lib_exit(void);
void dm_lib_exit(void) __attribute((destructor));
#endif /* LIB_DEVICE_MAPPER_H */

89
libdm/libdm-event.h Normal file
View File

@@ -0,0 +1,89 @@
/*
* Copyright (C) 2005 Red Hat, Inc. All rights reserved.
*
* This file is part of the device-mapper userspace tools.
*
* 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 Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser 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
*/
#ifndef LIB_DMEVENT_H
#define LIB_DMEVENT_H
#include "list.h"
#include <stdint.h>
#define DAEMON "/sbin/dmeventd"
#define LOCKFILE "/var/lock/dmeventd"
#define FIFO_CLIENT "/var/run/dmeventd-client"
#define FIFO_SERVER "/var/run/dmeventd-server"
#define PIDFILE "/var/run/dmeventd.pid"
/* Commands for the daemon passed in the message below. */
enum dmeventd_command {
CMD_ACTIVE = 1,
CMD_REGISTER_FOR_EVENT,
CMD_UNREGISTER_FOR_EVENT,
CMD_GET_REGISTERED_DEVICE,
CMD_GET_NEXT_REGISTERED_DEVICE,
};
/* Message passed between client and daemon. */
struct daemon_message {
union {
unsigned int cmd;
int status;
} opcode;
char msg[252];
} __attribute__((packed));
/* Fifos for client/daemon communication. */
struct fifos {
int client;
int server;
const char *client_path;
const char *server_path;
};
/* Event type definitions. */
enum event_type {
SINGLE = 0x01, /* Report multiple errors just once. */
MULTI = 0x02, /* Report all of them. */
SECTOR_ERROR = 0x04, /* Failure on a particular sector. */
DEVICE_ERROR = 0x08, /* Device failure. */
PATH_ERROR = 0x10, /* Failure on an io path. */
ADAPTOR_ERROR = 0x20, /* Failure off a host adaptor. */
SYNC_STATUS = 0x40, /* Mirror synchronization completed/failed. */
};
#define ALL_ERRORS (SECTOR_ERROR | DEVICE_ERROR | PATH_ERROR | ADAPTOR_ERROR)
/* Prototypes for event lib interface. */
int dm_register_for_event(char *dso_name, char *device, enum event_type events);
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);
/* Prototypes for DSO interface. */
void process_event(char *device, enum event_type event);
int register_device(char *device);
int unregister_device(char *device);
#endif
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/

View File

@@ -29,7 +29,7 @@ dmsetup \- low level logical volume management
.B dmsetup rename
.I device_name new_name
.br
.B dmsetup ls
.B dmsetup ls [--target target_type] [--exec command]
.br
.B dmsetup info
.I [device_name]
@@ -40,10 +40,10 @@ dmsetup \- low level logical volume management
.B dmsetup deps
.I [device_name]
.br
.B dmsetup status
.B dmsetup status [--target target_type]
.I [device_name]
.br
.B dmsetup table
.B dmsetup table [--target target_type]
.I [device_name]
.br
.B dmsetup wait
@@ -145,8 +145,12 @@ Outputs some brief information about the device in the form:
.br
UUID
.IP \fBls
.I [--target target_type]
.I [--exec command]
.br
List device names.
List device names. Optionally only list devices that have at least
one target of the specified type. Optionally execute a command for
each device. The device name is appended to the supplied command.
.IP \fBload|reload
.I device_name [table_file]
.br
@@ -172,9 +176,12 @@ Un-suspends a device.
If an inactive table has been loaded, it becomes live.
Postponed I/O then gets re-queued for processing.
.IP \fBstatus
.I [--target target_type]
.I [device_name]
.br
Outputs status information for each of the device's targets.
With --target, only information relating to the specified target type
is displayed.
.IP \fBsuspend
.I device_name
.br
@@ -182,10 +189,13 @@ Suspends a device. Any I/O that has already been mapped by the device
but has not yet completed will be flushed. Any further I/O to that
device will be postponed for as long as the device is suspended.
.IP \fBtable
.I [--target target_type]
.I [device_name]
.br
Outputs the current table for the device in a format that can be fed
back in using the create or load commands.
With --target, only information relating to the specified target type
is displayed.
.IP \fBtargets
.br
Displays the names and versions of the currently-loaded targets.

1931
po/lvm2.po

File diff suppressed because it is too large Load Diff

View File

@@ -13,6 +13,8 @@
LVDISPLAY="/usr/sbin/lvdisplay"
VGCHANGE="/usr/sbin/vgchange"
VGSCAN="/usr/sbin/vgscan"
VGDISPLAY="/usr/sbin/vgdisplay"
VGS="/usr/sbin/vgs"
[ -f /etc/sysconfig/cluster ] && . /etc/sysconfig/cluster
@@ -24,20 +26,15 @@ start()
do
if ! pidof clvmd > /dev/null
then
echo -n "Starting clvmd:"
clvmd > /dev/null 2>&1
echo -n "Starting clvmd: "
daemon clvmd
rtrn=$?
if [ $rtrn -eq 0 ]
echo
if [ $rtrn -ne 0 ]
then
success
echo
else
failure
echo
break
fi
fi
fi
# refresh cache
$VGSCAN > /dev/null 2>&1
@@ -45,28 +42,16 @@ start()
then
for vg in $LVM_VGS
do
echo -n "Activating lvm $vg:"
if $VGCHANGE -ayl $vg > /dev/null 2>&1
if ! action "Activating VG $vg:" $VGCHANGE -ayl $vg
then
success
echo
else
rtrn=$?
failure
echo
fi
fi
done
else
echo -n "Activating lvms:"
if $VGCHANGE -ayl > /dev/null 2>&1
if ! action "Activating VGs:" $VGCHANGE -ayl
then
success
echo
else
rtrn=$?
failure
echo
fi
fi
fi
done
@@ -81,49 +66,28 @@ stop()
then
for vg in $LVM_VGS
do
echo -n "Deactivating lvm $vg:"
if $VGCHANGE -anl $vg > /dev/null 2>&1
if ! action "Deactivating VG $vg:" $VGCHANGE -anl $vg
then
success
echo
else
rtrn=$?
failure
echo
fi
done
else
echo -n "Deactivating lvms:"
if $VGCHANGE -anl > /dev/null 2>&1
then
success
echo
else
rtrn=$?
failure
echo
fi
# Hack to only deactivate clustered volumes
clustervgs=`$VGDISPLAY \`$VGS --noheadings -o name\` | awk 'BEGIN {RS="VG Name"} {if (/Clustered/) print $1;}'`
for vg in $clustervgs; do
if ! action "Deactivating VG $vg:" $VGCHANGE -anl $vg
then
rtrn=$?
fi
done
fi
[ $rtrn -ne 0 ] && break
echo -n "Stopping clvm:"
pid=$(pidof clvmd)
if [ -n "$pid" ]
then
while kill $pid > /dev/null 2>&1
do
sleep 1
done
fi
if [ $rtrn -eq 0 ]
then
success
echo
else
failure
echo
fi
killproc clvmd -TERM
rtrn=$?
echo
done
return $rtrn
@@ -146,8 +110,10 @@ case "$1" in
;;
restart)
$0 stop
$0 start
if stop
then
start
fi
rtrn=$?
;;

View File

@@ -21,7 +21,6 @@ ifeq ("@FSADM@", "yes")
endif
SOURCES =\
archiver.c \
dumpconfig.c \
formats.c \
lvchange.c \

View File

@@ -491,6 +491,7 @@ xx(pvs,
"\t[--nosuffix]\n"
"\t[-o|--options [+]Field[,Field]]\n"
"\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n"
"\t[--segments]\n"
"\t[--separator Separator]\n"
"\t[--unbuffered]\n"
"\t[--units hsbkmgtHKMGT]\n"
@@ -499,8 +500,8 @@ xx(pvs,
"\t[PhysicalVolume [PhysicalVolume...]]\n",
aligned_ARG, all_ARG, ignorelockingfailure_ARG, noheadings_ARG,
nolocking_ARG, nosuffix_ARG, options_ARG, separator_ARG, sort_ARG,
unbuffered_ARG, units_ARG)
nolocking_ARG, nosuffix_ARG, options_ARG, segments_ARG, separator_ARG,
sort_ARG, unbuffered_ARG, units_ARG)
xx(pvscan,
"List all physical volumes",
@@ -569,13 +570,15 @@ xx(vgchange,
"\t -c|--clustered {y|n} |" "\n"
"\t -x|--resizeable {y|n} |" "\n"
"\t -l|--logicalvolume MaxLogicalVolumes |" "\n"
"\t -s|--physicalextentsize PhysicalExtentSize[kKmMgGtT] |" "\n"
"\t --addtag Tag |\n"
"\t --deltag Tag}\n"
"\t[VolumeGroupName...]\n",
addtag_ARG, alloc_ARG, allocation_ARG, autobackup_ARG, available_ARG,
clustered_ARG, deltag_ARG, ignorelockingfailure_ARG, logicalvolume_ARG,
partial_ARG, resizeable_ARG, resizable_ARG, test_ARG, uuid_ARG)
partial_ARG, physicalextentsize_ARG, resizeable_ARG, resizable_ARG,
test_ARG, uuid_ARG)
xx(vgck,
"Check the consistency of volume group(s)",
@@ -717,9 +720,12 @@ xx(vgmknodes,
"vgmknodes\n"
"\t[-d|--debug]\n"
"\t[-h|--help]\n"
"\t[--ignorelockingfailure]\n"
"\t[-v|--verbose]\n"
"\t[--version]" "\n"
"\t[VolumeGroupName...]\n" )
"\t[VolumeGroupName...]\n",
ignorelockingfailure_ARG)
xx(vgreduce,
"Remove physical volume(s) from a volume group",

View File

@@ -13,6 +13,9 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
#include "libdevmapper.h"
#include "log.h"
@@ -24,6 +27,9 @@
#include <errno.h>
#include <unistd.h>
#include <libgen.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/param.h>
#ifdef HAVE_GETOPTLONG
# include <getopt.h>
@@ -38,6 +44,15 @@ extern char *optarg;
# define OPTIND_INIT 1
#endif
#ifndef TEMP_FAILURE_RETRY
# define TEMP_FAILURE_RETRY(expression) \
(__extension__ \
({ long int __result; \
do __result = (long int) (expression); \
while (__result == -1L && errno == EINTR); \
__result; }))
#endif
#ifdef linux
# include "kdev_t.h"
#else
@@ -47,6 +62,7 @@ extern char *optarg;
#endif
#define LINE_SIZE 1024
#define ARGS_MAX 256
#define err(msg, x...) fprintf(stderr, msg "\n", ##x)
@@ -56,12 +72,14 @@ extern char *optarg;
enum {
READ_ONLY = 0,
COLS_ARG,
EXEC_ARG,
MAJOR_ARG,
MINOR_ARG,
NOHEADINGS_ARG,
NOOPENCOUNT_ARG,
NOTABLE_ARG,
OPTIONS_ARG,
TARGET_ARG,
UUID_ARG,
VERBOSE_ARG,
VERSION_ARG,
@@ -72,6 +90,8 @@ static int _switches[NUM_SWITCHES];
static int _values[NUM_SWITCHES];
static char *_uuid;
static char *_fields;
static char *_target;
static char *_command;
/*
* Commands
@@ -598,6 +618,102 @@ static int _process_all(int argc, char **argv,
return r;
}
static void _display_dev(struct dm_task *dmt, char *name)
{
struct dm_info info;
if (dm_task_get_info(dmt, &info))
printf("%s\t(%u, %u)\n", name, info.major, info.minor);
}
static int _mknodes_single(char *name)
{
struct dm_task *dmt;
int r = 0;
if (!(dmt = dm_task_create(DM_DEVICE_MKNODES)))
return 0;
if (!_set_task_device(dmt, name, 1))
goto out;
if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
goto out;
if (!dm_task_run(dmt))
goto out;
r = 1;
out:
dm_task_destroy(dmt);
return r;
}
static int _mknodes(int argc, char **argv, void *data)
{
return _mknodes_single(argc > 1 ? argv[1] : NULL);
}
static int _exec_command(char *name)
{
int n;
static char path[PATH_MAX];
static char *args[ARGS_MAX + 1];
static int argc = 0;
char *c;
pid_t pid;
if (argc < 0)
return 0;
if (!_mknodes_single(name))
return 0;
n = snprintf(path, sizeof(path), "%s/%s", dm_dir(), name);
if (n < 0 || n > sizeof(path) - 1)
return 0;
if (!argc) {
c = _command;
while (argc < ARGS_MAX) {
while (*c && isspace(*c))
c++;
if (!*c)
break;
args[argc++] = c;
while (*c && !isspace(*c))
c++;
if (*c)
*c++ = '\0';
}
if (!argc) {
argc = -1;
return 0;
}
if (argc == ARGS_MAX) {
err("Too many args to --exec\n");
argc = -1;
return 0;
}
args[argc++] = path;
args[argc] = NULL;
}
if (!(pid = fork())) {
execvp(args[0], args);
exit(127);
} else if (pid < (pid_t) 0)
return 0;
TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
return 1;
}
static int _status(int argc, char **argv, void *data)
{
int r = 0;
@@ -609,6 +725,8 @@ static int _status(int argc, char **argv, void *data)
int cmd;
struct dm_names *names = (struct dm_names *) data;
char *name = NULL;
int matched = 0;
int ls_only = 0;
if (data)
name = names->name;
@@ -624,6 +742,9 @@ static int _status(int argc, char **argv, void *data)
else
cmd = DM_DEVICE_STATUS;
if (!strcmp(argv[0], "ls"))
ls_only = 1;
if (!(dmt = dm_task_create(cmd)))
return 0;
@@ -636,31 +757,45 @@ static int _status(int argc, char **argv, void *data)
if (!dm_task_run(dmt))
goto out;
if (_switches[VERBOSE_ARG])
_display_info(dmt);
/* Fetch targets and print 'em */
do {
next = dm_get_next_target(dmt, next, &start, &length,
&target_type, &params);
if (data && !_switches[VERBOSE_ARG])
printf("%s: ", name);
if (target_type) {
printf("%" PRIu64 " %" PRIu64 " %s %s",
start, length, target_type, params);
/* Skip if target type doesn't match */
if (_switches[TARGET_ARG] && target_type &&
strcmp(target_type, _target))
continue;
if (ls_only) {
if (!_switches[EXEC_ARG] || !_command ||
_switches[VERBOSE_ARG])
_display_dev(dmt, name);
next = NULL;
} else if (!_switches[EXEC_ARG] || !_command ||
_switches[VERBOSE_ARG]) {
if (!matched && _switches[VERBOSE_ARG])
_display_info(dmt);
if (data && !_switches[VERBOSE_ARG])
printf("%s: ", name);
if (target_type) {
printf("%" PRIu64 " %" PRIu64 " %s %s",
start, length, target_type, params);
}
printf("\n");
}
printf("\n");
matched = 1;
} while (next);
if (data && _switches[VERBOSE_ARG])
if (data && _switches[VERBOSE_ARG] && matched && !ls_only)
printf("\n");
if (matched && _switches[EXEC_ARG] && _command && !_exec_command(name))
goto out;
r = 1;
out:
dm_task_destroy(dmt);
return r;
}
/* Show target names and their version numbers */
@@ -697,30 +832,6 @@ static int _targets(int argc, char **argv, void *data)
}
static int _mknodes(int argc, char **argv, void *data)
{
struct dm_task *dmt;
int r = 0;
if (!(dmt = dm_task_create(DM_DEVICE_MKNODES)))
return 0;
if (!_set_task_device(dmt, argc > 1 ? argv[1] : NULL, 1))
goto out;
if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
goto out;
if (!dm_task_run(dmt))
goto out;
r = 1;
out:
dm_task_destroy(dmt);
return r;
}
static int _info(int argc, char **argv, void *data)
{
int r = 0;
@@ -835,7 +946,11 @@ static int _display_name(int argc, char **argv, void *data)
static int _ls(int argc, char **argv, void *data)
{
return _process_all(argc, argv, _display_name);
if ((_switches[TARGET_ARG] && _target) ||
(_switches[EXEC_ARG] && _command))
return _status(argc, argv, data);
else
return _process_all(argc, argv, _display_name);
}
/*
@@ -864,11 +979,11 @@ static struct command _commands[] = {
{"reload", "<device> [<table_file>]", 0, 2, _load},
{"rename", "<device> <new_name>", 1, 2, _rename},
{"message", "<device> <sector> <message>", 2, -1, _message},
{"ls", "", 0, 0, _ls},
{"ls", "[--target <target_type>] [--exec <command>]", 0, 0, _ls},
{"info", "[<device>]", 0, 1, _info},
{"deps", "[<device>]", 0, 1, _deps},
{"status", "[<device>]", 0, 1, _status},
{"table", "[<device>]", 0, 1, _status},
{"status", "[<device>] [--target <target_type>]", 0, 1, _status},
{"table", "[<device>] [--target <target_type>]", 0, 1, _status},
{"wait", "<device> [<event_nr>]", 0, 2, _wait},
{"mknodes", "[<device>]", 0, 1, _mknodes},
{"targets", "", 0, 0, _targets},
@@ -905,22 +1020,24 @@ static struct command *_find_command(const char *name)
static int _process_switches(int *argc, char ***argv)
{
char *base, *namebase;
int ind;
static int ind;
int c;
#ifdef HAVE_GETOPTLONG
static struct option long_options[] = {
{"readonly", 0, NULL, READ_ONLY},
{"columns", 0, NULL, COLS_ARG},
{"major", 1, NULL, MAJOR_ARG},
{"minor", 1, NULL, MINOR_ARG},
{"noheadings", 0, NULL, NOHEADINGS_ARG},
{"noopencount", 0, NULL, NOOPENCOUNT_ARG},
{"notable", 0, NULL, NOTABLE_ARG},
{"options", 1, NULL, OPTIONS_ARG},
{"uuid", 1, NULL, UUID_ARG},
{"verbose", 1, NULL, VERBOSE_ARG},
{"version", 0, NULL, VERSION_ARG},
{"readonly", 0, &ind, READ_ONLY},
{"columns", 0, &ind, COLS_ARG},
{"exec", 1, &ind, EXEC_ARG},
{"major", 1, &ind, MAJOR_ARG},
{"minor", 1, &ind, MINOR_ARG},
{"noheadings", 0, &ind, NOHEADINGS_ARG},
{"noopencount", 0, &ind, NOOPENCOUNT_ARG},
{"notable", 0, &ind, NOTABLE_ARG},
{"options", 1, &ind, OPTIONS_ARG},
{"target", 1, &ind, TARGET_ARG},
{"uuid", 1, &ind, UUID_ARG},
{"verbose", 1, &ind, VERBOSE_ARG},
{"version", 0, &ind, VERSION_ARG},
{"", 0, NULL, 0}
};
#else
@@ -969,8 +1086,8 @@ static int _process_switches(int *argc, char ***argv)
optarg = 0;
optind = OPTIND_INIT;
while ((c = GETOPTLONG_FN(*argc, *argv, "cCj:m:no:ru:v",
long_options, &ind)) != -1) {
while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCj:m:no:ru:v",
long_options, NULL)) != -1) {
if (c == 'c' || c == 'C' || ind == COLS_ARG)
_switches[COLS_ARG]++;
if (c == 'r' || ind == READ_ONLY)
@@ -995,6 +1112,14 @@ static int _process_switches(int *argc, char ***argv)
_switches[UUID_ARG]++;
_uuid = optarg;
}
if ((ind == EXEC_ARG)) {
_switches[EXEC_ARG]++;
_command = optarg;
}
if ((ind == TARGET_ARG)) {
_switches[TARGET_ARG]++;
_target = optarg;
}
if ((ind == NOHEADINGS_ARG))
_switches[NOHEADINGS_ARG]++;
if ((ind == NOOPENCOUNT_ARG))
@@ -1061,8 +1186,5 @@ int main(int argc, char **argv)
exit(1);
}
dm_lib_release();
dm_lib_exit();
return 0;
}

View File

@@ -246,7 +246,7 @@ static int _read_params(struct lvcreate_params *lp, struct cmd_context *cmd,
if (arg_count(cmd, stripes_ARG) && lp->stripes == 1)
log_print("Redundant stripes argument: default is 1");
if (arg_count(cmd, snapshot_ARG) || (lp->segtype->flags & SEG_SNAPSHOT))
if (arg_count(cmd, snapshot_ARG) || seg_is_snapshot(lp))
lp->snapshot = 1;
if (lp->snapshot) {
@@ -498,7 +498,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
return 0;
}
if (!(lp->segtype->flags & SEG_VIRTUAL) &&
if (!seg_is_virtual(lp) &&
vg->free_count < lp->extents) {
log_error("Insufficient free extents (%u) in volume group %s: "
"%u required", vg->free_count, vg->name, lp->extents);
@@ -512,13 +512,20 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
return 0;
}
if (!(lv = lv_create_empty(vg->fid, lp->lv_name, "lvol%d",
status, lp->alloc, vg))) {
if (!(lv = lv_create_empty(vg->fid, lp->lv_name, "lvol%d", NULL,
status, lp->alloc, 0, vg))) {
stack;
return 0;
}
if (!lv_extend(vg->fid, lv, lp->segtype, lp->stripes, lp->stripe_size,
/* The snapshot segment gets created later */
if (lp->snapshot)
if (!(lp->segtype = get_segtype_from_string(cmd, "striped"))) {
stack;
return 0;
}
if (!lv_extend(lv, lp->segtype, lp->stripes, lp->stripe_size,
lp->mirrors, lp->extents, NULL, 0u, 0u, pvh, lp->alloc)) {
stack;
return 0;
@@ -609,8 +616,8 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
return 0;
}
if (!vg_add_snapshot(org, lv, 1, NULL, org->le_count,
lp->chunk_size)) {
if (!vg_add_snapshot(vg->fid, NULL, org, lv, NULL,
org->le_count, lp->chunk_size)) {
log_err("Couldn't create snapshot.");
return 0;
}

View File

@@ -54,7 +54,7 @@ extern char *optarg;
*/
struct arg the_args[ARG_COUNT + 1] = {
#define arg(a, b, c, d) {b, "--" c, d, 0, NULL, 0, 0, INT64_C(0), UINT64_C(0), 0, NULL},
#define arg(a, b, c, d) {b, "", "--" c, d, 0, NULL, 0, 0, INT64_C(0), UINT64_C(0), 0, NULL},
#include "args.h"
#undef arg
@@ -758,8 +758,8 @@ static void _apply_settings(struct cmd_context *cmd)
init_msg_prefix(cmd->default_settings.msg_prefix);
init_cmd_name(cmd->default_settings.cmd_name);
archive_enable(cmd->current_settings.archive);
backup_enable(cmd->current_settings.backup);
archive_enable(cmd, cmd->current_settings.archive);
backup_enable(cmd, cmd->current_settings.backup);
set_activation(cmd->current_settings.activation);
@@ -912,69 +912,6 @@ static void _init_rand(void)
srand((unsigned int) time(NULL) + (unsigned int) getpid());
}
static int _init_backup(struct cmd_context *cmd, struct config_tree *cft)
{
uint32_t days, min;
char default_dir[PATH_MAX];
const char *dir;
if (!cmd->sys_dir) {
log_warn("WARNING: Metadata changes will NOT be backed up");
backup_init("");
archive_init("", 0, 0);
return 1;
}
/* set up archiving */
cmd->default_settings.archive =
find_config_bool(cmd->cft->root, "backup/archive",
DEFAULT_ARCHIVE_ENABLED);
days = (uint32_t) find_config_int(cmd->cft->root, "backup/retain_days",
DEFAULT_ARCHIVE_DAYS);
min = (uint32_t) find_config_int(cmd->cft->root, "backup/retain_min",
DEFAULT_ARCHIVE_NUMBER);
if (lvm_snprintf
(default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir,
DEFAULT_ARCHIVE_SUBDIR) == -1) {
log_err("Couldn't create default archive path '%s/%s'.",
cmd->sys_dir, DEFAULT_ARCHIVE_SUBDIR);
return 0;
}
dir = find_config_str(cmd->cft->root, "backup/archive_dir",
default_dir);
if (!archive_init(dir, days, min)) {
log_debug("backup_init failed.");
return 0;
}
/* set up the backup */
cmd->default_settings.backup =
find_config_bool(cmd->cft->root, "backup/backup",
DEFAULT_BACKUP_ENABLED);
if (lvm_snprintf
(default_dir, sizeof(default_dir), "%s/%s", cmd->sys_dir,
DEFAULT_BACKUP_SUBDIR) == -1) {
log_err("Couldn't create default backup path '%s/%s'.",
cmd->sys_dir, DEFAULT_BACKUP_SUBDIR);
return 0;
}
dir = find_config_str(cmd->cft->root, "backup/backup_dir", default_dir);
if (!backup_init(dir)) {
log_debug("backup_init failed.");
return 0;
}
return 1;
}
static void _close_stray_fds(void)
{
struct rlimit rlim;
@@ -1012,9 +949,6 @@ static struct cmd_context *_init_lvm(void)
_init_rand();
if (!_init_backup(cmd, cmd->cft))
return NULL;
_apply_settings(cmd);
return cmd;
@@ -1032,10 +966,7 @@ static void _fin_commands(struct cmd_context *cmd)
static void _fin(struct cmd_context *cmd)
{
archive_exit();
backup_exit();
_fin_commands(cmd);
destroy_toolcontext(cmd);
}

View File

@@ -70,14 +70,14 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
if (lv_is_cow(lv)) {
log_verbose("Removing snapshot %s", lv->name);
if (!vg_remove_snapshot(lv->vg, lv)) {
if (!vg_remove_snapshot(lv)) {
stack;
return ECMD_FAILED;
}
}
log_verbose("Releasing logical volume \"%s\"", lv->name);
if (!lv_remove(vg, lv)) {
if (!lv_remove(lv)) {
log_error("Error releasing logical volume \"%s\"", lv->name);
return ECMD_FAILED;
}

View File

@@ -115,7 +115,7 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
{
struct volume_group *vg;
struct logical_volume *lv;
struct snapshot *snap;
struct lv_segment *snap_seg;
struct lvinfo info;
uint32_t stripesize_extents = 0;
uint32_t seg_stripes = 0, seg_stripesize = 0, seg_size = 0;
@@ -180,11 +180,6 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
return ECMD_FAILED;
}
if (lv_is_origin(lv)) {
log_error("Snapshot origin volumes cannot be resized yet.");
return ECMD_FAILED;
}
alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, lv->alloc);
if (lp->size) {
@@ -245,7 +240,7 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
if ((lp->extents > lv->le_count) &&
!(lp->stripes == 1 || (lp->stripes > 1 && lp->stripe_size))) {
list_iterate_items(seg, &lv->segments) {
if (!(seg->segtype->flags & SEG_AREAS_STRIPED))
if (!seg_is_striped(seg))
continue;
sz = seg->stripe_size;
@@ -293,7 +288,7 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
list_iterate_items(seg, &lv->segments) {
seg_extents = seg->len;
if (seg->segtype->flags & SEG_AREAS_STRIPED) {
if (seg_is_striped(seg)) {
seg_stripesize = seg->stripe_size;
seg_stripes = seg->area_count;
}
@@ -352,6 +347,23 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
lp->resize = LV_EXTEND;
}
if (lv_is_origin(lv)) {
if (lp->resize == LV_REDUCE) {
log_error("Snapshot origin volumes cannot be reduced "
"in size yet.");
return ECMD_FAILED;
}
memset(&info, 0, sizeof(info));
if (lv_info(lv, &info, 0) && info.exists) {
log_error("Snapshot origin volumes can be resized "
"only while inactive: try lvchange -an");
return ECMD_FAILED;
}
}
if (lp->resize == LV_REDUCE) {
if (lp->argc)
log_print("Ignoring PVs on command line when reducing");
@@ -439,14 +451,14 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
SIZE_SHORT));
if (lp->resize == LV_REDUCE) {
if (!lv_reduce(vg->fid, lv, lv->le_count - lp->extents)) {
if (!lv_reduce(lv, lv->le_count - lp->extents)) {
stack;
return ECMD_FAILED;
}
} else if (!lv_extend(vg->fid, lv, lp->segtype, lp->stripes,
lp->stripe_size, 0u,
lp->extents - lv->le_count,
NULL, 0u, 0u, pvh, alloc)) {
} else if (!lv_extend(lv, lp->segtype, lp->stripes,
lp->stripe_size, 0u,
lp->extents - lv->le_count,
NULL, 0u, 0u, pvh, alloc)) {
stack;
return ECMD_FAILED;
}
@@ -460,8 +472,8 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
backup(vg);
/* If snapshot, must suspend all associated devices */
if ((snap = find_cow(lv)))
lock_lvid = snap->origin->lvid.s;
if ((snap_seg = find_cow(lv)))
lock_lvid = snap_seg->origin->lvid.s;
else
lock_lvid = lv->lvid.s;

View File

@@ -72,6 +72,8 @@ static int _check_mirror_status(struct cmd_context *cmd,
float segment_percent = 0.0, overall_percent = 0.0;
uint32_t event_nr = 0;
void *x;
/* By default, caller should not retry */
*finished = 1;
@@ -97,6 +99,9 @@ static int _check_mirror_status(struct cmd_context *cmd,
else
log_verbose("%s: Moved: %.1f%%", name, overall_percent);
x = pool_alloc(cmd->mem, 1);
pool_free(cmd->mem, x);
if (segment_percent < 100.0) {
/* The only case the caller *should* try again later */
*finished = 0;

View File

@@ -140,10 +140,9 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
struct lv_list *lvl;
/* FIXME Cope with non-contiguous => splitting existing segments */
/* FIXME Pass 'alloc' down to lv_extend */
if (!(lv_mirr = lv_create_empty(vg->fid, NULL, "pvmove%d",
if (!(lv_mirr = lv_create_empty(vg->fid, NULL, "pvmove%d", NULL,
LVM_READ | LVM_WRITE,
ALLOC_CONTIGUOUS, vg))) {
ALLOC_CONTIGUOUS, 0, vg))) {
log_error("Creation of temporary pvmove LV failed");
return NULL;
}
@@ -160,7 +159,8 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
/* Find segments to be moved and set up mirrors */
list_iterate_items(lvl, &vg->lvs) {
lv = lvl->lv;
if ((lv == lv_mirr) || (lv_name && strcmp(lv->name, lv_name)))
if ((lv == lv_mirr) ||
(lv_name && strcmp(lv->name, lv_name)))
continue;
if (lv_is_origin(lv) || lv_is_cow(lv)) {
log_print("Skipping snapshot-related LV %s", lv->name);
@@ -175,7 +175,8 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
continue;
}
if (!insert_pvmove_mirrors(cmd, lv_mirr, source_pvl, lv,
allocatable_pvs, *lvs_changed)) {
allocatable_pvs, alloc,
*lvs_changed)) {
stack;
return NULL;
}
@@ -438,7 +439,7 @@ static int _finish_pvmove(struct cmd_context *cmd, struct volume_group *vg,
}
log_verbose("Removing temporary pvmove LV");
if (!lv_remove(vg, lv_mirr)) {
if (!lv_remove(lv_mirr)) {
log_error("ABORTING: Removal of temporary pvmove LV failed");
return 0;
}

View File

@@ -24,16 +24,18 @@ static int _vgs_single(struct cmd_context *cmd, const char *vg_name,
return ECMD_FAILED;
}
if (!report_object(handle, vg, NULL, NULL, NULL))
if (!report_object(handle, vg, NULL, NULL, NULL, NULL))
return ECMD_FAILED;
check_current_backup(vg);
return ECMD_PROCESSED;
}
static int _lvs_single(struct cmd_context *cmd, struct logical_volume *lv,
void *handle)
{
if (!report_object(handle, lv->vg, lv, NULL, NULL))
if (!report_object(handle, lv->vg, lv, NULL, NULL, NULL))
return ECMD_FAILED;
return ECMD_PROCESSED;
@@ -42,18 +44,50 @@ static int _lvs_single(struct cmd_context *cmd, struct logical_volume *lv,
static int _segs_single(struct cmd_context *cmd, struct lv_segment *seg,
void *handle)
{
if (!report_object(handle, seg->lv->vg, seg->lv, NULL, seg))
if (!report_object(handle, seg->lv->vg, seg->lv, NULL, seg, NULL))
return ECMD_FAILED;
return ECMD_PROCESSED;
}
static int _pvsegs_sub_single(struct cmd_context *cmd, struct volume_group *vg,
struct pv_segment *pvseg, void *handle)
{
int consistent = 0;
struct physical_volume *pv = pvseg->pv;
int ret = ECMD_PROCESSED;
if (!lock_vol(cmd, pv->vg_name, LCK_VG_READ)) {
log_error("Can't lock %s: skipping", pv->vg_name);
return ECMD_FAILED;
}
if (!(vg = vg_read(cmd, pv->vg_name, &consistent))) {
log_error("Can't read %s: skipping", pv->vg_name);
unlock_vg(cmd, pv->vg_name);
return ECMD_FAILED;
}
if (!report_object(handle, vg, NULL, pv, NULL, pvseg))
ret = ECMD_FAILED;
unlock_vg(cmd, pv->vg_name);
return ret;
}
static int _lvsegs_single(struct cmd_context *cmd, struct logical_volume *lv,
void *handle)
{
return process_each_segment_in_lv(cmd, lv, handle, _segs_single);
}
static int _pvsegs_single(struct cmd_context *cmd, struct volume_group *vg,
struct physical_volume *pv, void *handle)
{
return process_each_segment_in_pv(cmd, vg, pv, handle,
_pvsegs_sub_single);
}
static int _pvs_single(struct cmd_context *cmd, struct volume_group *vg,
struct physical_volume *pv, void *handle)
{
@@ -73,7 +107,7 @@ static int _pvs_single(struct cmd_context *cmd, struct volume_group *vg,
}
}
if (!report_object(handle, vg, NULL, pv, NULL))
if (!report_object(handle, vg, NULL, pv, NULL, NULL))
ret = ECMD_FAILED;
if (pv->vg_name)
@@ -151,6 +185,18 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
"report/segs_cols_verbose",
DEFAULT_SEGS_COLS_VERB);
break;
case PVSEGS:
keys = find_config_str(cmd->cft->root, "report/pvsegs_sort",
DEFAULT_PVSEGS_SORT);
if (!arg_count(cmd, verbose_ARG))
options = find_config_str(cmd->cft->root,
"report/pvsegs_cols",
DEFAULT_PVSEGS_COLS);
else
options = find_config_str(cmd->cft->root,
"report/pvsegs_cols_verbose",
DEFAULT_PVSEGS_COLS_VERB);
break;
}
/* If -o supplied use it, else use default for report_type */
@@ -208,6 +254,10 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
r = process_each_lv(cmd, argc, argv, LCK_VG_READ, report_handle,
&_lvsegs_single);
break;
case PVSEGS:
r = process_each_pv(cmd, argc, argv, NULL, report_handle,
&_pvsegs_single);
break;
}
report_output(report_handle);
@@ -235,5 +285,12 @@ int vgs(struct cmd_context *cmd, int argc, char **argv)
int pvs(struct cmd_context *cmd, int argc, char **argv)
{
return _report(cmd, argc, argv, PVS);
report_type_t type;
if (arg_count(cmd, segments_ARG))
type = PVSEGS;
else
type = PVS;
return _report(cmd, argc, argv, type);
}

View File

@@ -60,6 +60,9 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
}
list_iterate_items(lvl, &vg->lvs) {
if (lvl->lv->status & SNAPSHOT)
continue;
/* Should we process this LV? */
if (process_all)
process_lv = 1;
@@ -285,6 +288,28 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
return ret_max;
}
int process_each_segment_in_pv(struct cmd_context *cmd,
struct volume_group *vg,
struct physical_volume *pv,
void *handle,
int (*process_single) (struct cmd_context * cmd,
struct volume_group * vg,
struct pv_segment * pvseg,
void *handle))
{
struct pv_segment *pvseg;
int ret_max = 0;
int ret;
list_iterate_items(pvseg, &pv->segments) {
ret = process_single(cmd, vg, pvseg, handle);
if (ret > ret_max)
ret_max = ret;
}
return ret_max;
}
int process_each_segment_in_lv(struct cmd_context *cmd,
struct logical_volume *lv,
void *handle,
@@ -472,6 +497,7 @@ static int _process_all_devs(struct cmd_context *cmd, void *handle,
if (!(pv = pv_read(cmd, dev_name(dev), NULL, NULL, 0))) {
memset(&pv_dummy, 0, sizeof(pv_dummy));
list_init(&pv_dummy.tags);
list_init(&pv_dummy.segments);
pv_dummy.dev = dev;
pv_dummy.fmt = NULL;
pv = &pv_dummy;

View File

@@ -40,6 +40,14 @@ int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
struct volume_group * vg,
struct physical_volume * pv,
void *handle));
int process_each_segment_in_pv(struct cmd_context *cmd,
struct volume_group *vg,
struct physical_volume *pv,
void *handle,
int (*process_single) (struct cmd_context * cmd,
struct volume_group * vg,
struct pv_segment * pvseg,
void *handle));
int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
int lock_type, void *handle,

View File

@@ -89,7 +89,9 @@ enum {
/* a global table of possible arguments */
struct arg {
const char short_arg;
char _padding[7];
const char *long_arg;
int (*fn) (struct cmd_context * cmd, struct arg * a);
unsigned int count;

View File

@@ -76,7 +76,7 @@ static int vg_backup_single(struct cmd_context *cmd, const char *vg_name,
}
/* just use the normal backup code */
backup_enable(1); /* force a backup */
backup_enable(cmd, 1); /* force a backup */
if (!backup(vg)) {
stack;
return ECMD_FAILED;

View File

@@ -27,7 +27,7 @@ static int _activate_lvs_in_vg(struct cmd_context *cmd,
lv = lvl->lv;
/* Only request activation of snapshot origin devices */
if (lv_is_cow(lv))
if ((lv->status & SNAPSHOT) || lv_is_cow(lv))
continue;
/* Can't deactive a pvmove LV */
@@ -89,6 +89,10 @@ static int _vgchange_available(struct cmd_context *cmd, struct volume_group *vg)
return ECMD_FAILED;
}
/* FIXME Move into library where clvmd can use it */
if (activate && !lockingfailed())
check_current_backup(vg);
if (activate && (active = lvs_in_vg_activated(vg)))
log_verbose("%d logical volume(s) in volume group \"%s\" "
"already active", active, vg->name);
@@ -251,6 +255,64 @@ static int _vgchange_logicalvolume(struct cmd_context *cmd,
return ECMD_PROCESSED;
}
static int _vgchange_pesize(struct cmd_context *cmd, struct volume_group *vg)
{
uint32_t extent_size;
if (!(vg->status & RESIZEABLE_VG)) {
log_error("Volume group \"%s\" must be resizeable "
"to change PE size", vg->name);
return ECMD_FAILED;
}
if (arg_sign_value(cmd, physicalextentsize_ARG, 0) == SIGN_MINUS) {
log_error("Physical extent size may not be negative");
return EINVALID_CMD_LINE;
}
extent_size = arg_uint_value(cmd, physicalextentsize_ARG, 0) * 2;
if (!extent_size) {
log_error("Physical extent size may not be zero");
return EINVALID_CMD_LINE;
}
if (extent_size == vg->extent_size) {
log_error("Physical extent size of VG %s is already %s",
vg->name, display_size(cmd, extent_size, SIZE_SHORT));
return ECMD_PROCESSED;
}
if (extent_size & (extent_size - 1)) {
log_error("Physical extent size must be a power of 2.");
return EINVALID_CMD_LINE;
}
if (extent_size > vg->extent_size) {
if ((uint64_t) vg->extent_size * vg->extent_count % extent_size) {
/* FIXME Adjust used PV sizes instead */
log_error("New extent size is not a perfect fit");
return EINVALID_CMD_LINE;
}
}
if (!archive(vg))
return ECMD_FAILED;
if (!vg_change_pesize(cmd, vg, extent_size)) {
stack;
return ECMD_FAILED;
}
if (!vg_write(vg) || !vg_commit(vg))
return ECMD_FAILED;
backup(vg);
log_print("Volume group \"%s\" successfully changed", vg->name);
return ECMD_PROCESSED;
}
static int _vgchange_tag(struct cmd_context *cmd, struct volume_group *vg,
int arg)
{
@@ -369,6 +431,9 @@ static int vgchange_single(struct cmd_context *cmd, const char *vg_name,
else if (arg_count(cmd, deltag_ARG))
r = _vgchange_tag(cmd, vg, deltag_ARG);
else if (arg_count(cmd, physicalextentsize_ARG))
r = _vgchange_pesize(cmd, vg);
else if (arg_count(cmd, uuid_ARG))
r = _vgchange_uuid(cmd, vg);
@@ -387,9 +452,10 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
(arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
arg_count(cmd, resizeable_ARG) + arg_count(cmd, deltag_ARG) +
arg_count(cmd, addtag_ARG) + arg_count(cmd, uuid_ARG) +
arg_count(cmd, physicalextentsize_ARG) +
arg_count(cmd, clustered_ARG) + arg_count(cmd, alloc_ARG))) {
log_error("One of -a, -c, -l, -x, --alloc, --addtag, --deltag "
"or --uuid required");
log_error("One of -a, -c, -l, -s, -x, --uuid, --alloc, --addtag or "
"--deltag required");
return EINVALID_CMD_LINE;
}
@@ -397,8 +463,9 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
if (arg_count(cmd, available_ARG) + arg_count(cmd, logicalvolume_ARG) +
arg_count(cmd, resizeable_ARG) + arg_count(cmd, deltag_ARG) +
arg_count(cmd, addtag_ARG) + arg_count(cmd, alloc_ARG) +
arg_count(cmd, uuid_ARG) + arg_count(cmd, clustered_ARG) > 1) {
log_error("Only one of -a, -c, -l, -x, --uuid, --alloc, "
arg_count(cmd, uuid_ARG) + arg_count(cmd, clustered_ARG) +
arg_count(cmd, physicalextentsize_ARG) > 1) {
log_error("Only one of -a, -c, -l, -s, -x, --uuid, --alloc, "
"--addtag or --deltag allowed");
return EINVALID_CMD_LINE;
}

View File

@@ -92,6 +92,8 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
if (cmd->fmt->features & FMT_RESTRICTED_LVIDS) {
list_iterate_items(lvl, &vg->lvs) {
lv = lvl->lv;
if (lv->status & SNAPSHOT)
continue;
if (lvnum_from_lvid(&lv->lvid) < MAX_RESTRICTED_LVS)
continue;
if (lv_info(lv, &info, 0) && info.exists) {

View File

@@ -53,6 +53,8 @@ static int vgdisplay_single(struct cmd_context *cmd, const char *vg_name,
process_each_pv_in_vg(cmd, vg, NULL, NULL, &pvdisplay_short);
}
check_current_backup(vg);
return ECMD_PROCESSED;
}

View File

@@ -49,9 +49,9 @@ static int _remove_pv(struct volume_group *vg, struct pv_list *pvl)
static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv,
int *list_unsafe)
{
struct snapshot *snap;
struct snapshot_list *snl;
struct list *snaplist;
struct lv_segment *snap_seg;
struct list *snh, *snht;
struct logical_volume *cow;
log_verbose("%s/%s has missing extents: removing (including "
"dependencies)", lv->vg->name, lv->name);
@@ -65,36 +65,34 @@ static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv,
log_error("Failed to deactivate LV %s", lv->name);
return 0;
}
} else if ((snap = find_cow(lv))) {
} else if ((snap_seg = find_cow(lv))) {
log_verbose("Deactivating (if active) logical volume %s "
"(origin of %s)", snap->origin->name, lv->name);
"(origin of %s)", snap_seg->origin->name, lv->name);
if (!deactivate_lv(cmd, snap->origin->lvid.s)) {
if (!deactivate_lv(cmd, snap_seg->origin->lvid.s)) {
log_error("Failed to deactivate LV %s",
snap->origin->name);
snap_seg->origin->name);
return 0;
}
/* Use the origin LV */
lv = snap->origin;
lv = snap_seg->origin;
}
/* Remove snapshot dependencies */
if (!(snaplist = find_snapshots(lv))) {
stack;
return 0;
}
/* List may be empty */
list_iterate_items(snl, snaplist) {
list_iterate_safe(snh, snht, &lv->snapshot_segs) {
snap_seg = list_struct_base(snh, struct lv_segment,
origin_list);
cow = snap_seg->cow;
*list_unsafe = 1; /* May remove caller's lvht! */
snap = snl->snapshot;
if (!vg_remove_snapshot(lv->vg, snap->cow)) {
if (!vg_remove_snapshot(cow)) {
stack;
return 0;
}
log_verbose("Removing LV %s from VG %s", snap->cow->name,
log_verbose("Removing LV %s from VG %s", cow->name,
lv->vg->name);
if (!lv_remove(lv->vg, snap->cow)) {
if (!lv_remove(cow)) {
stack;
return 0;
}
@@ -102,7 +100,7 @@ static int _remove_lv(struct cmd_context *cmd, struct logical_volume *lv,
/* Remove the LV itself */
log_verbose("Removing LV %s from VG %s", lv->name, lv->vg->name);
if (!lv_remove(lv->vg, lv)) {
if (!lv_remove(lv)) {
stack;
return 0;
}
@@ -136,7 +134,7 @@ static int _make_vg_consistent(struct cmd_context *cmd, struct volume_group *vg)
/* FIXME Also check for segs on deleted LVs */
pv = seg->area[s].u.pv.pv;
pv = seg->area[s].u.pv.pvseg->pv;
if (!pv || !pv->dev) {
if (!_remove_lv(cmd, lv, &list_unsafe)) {
stack;
@@ -192,6 +190,13 @@ static int _vgreduce_single(struct cmd_context *cmd, struct volume_group *vg,
list_del(&pvl->list);
pv->vg_name = ORPHAN;
pv->status = ALLOCATABLE_PV;
if (!dev_get_size(pv->dev, &pv->size)) {
log_error("%s: Couldn't get size.", dev_name(pv->dev));
return ECMD_FAILED;
}
vg->pv_count--;
vg->free_count -= pv->pe_count - pv->pe_alloc_count;
vg->extent_count -= pv->pe_count;

View File

@@ -56,6 +56,14 @@ static int vgremove_single(struct cmd_context *cmd, const char *vg_name,
log_verbose("Removing physical volume \"%s\" from "
"volume group \"%s\"", dev_name(pv->dev), vg_name);
pv->vg_name = ORPHAN;
pv->status = ALLOCATABLE_PV;
if (!dev_get_size(pv->dev, &pv->size)) {
log_error("%s: Couldn't get size.", dev_name(pv->dev));
ret = ECMD_FAILED;
continue;
}
/* FIXME Write to same sector label was read from */
if (!pv_write(cmd, pv, NULL, INT64_C(-1))) {
log_error("Failed to remove physical volume \"%s\""
@@ -65,7 +73,7 @@ static int vgremove_single(struct cmd_context *cmd, const char *vg_name,
}
}
backup_remove(vg_name);
backup_remove(cmd, vg_name);
if (ret == ECMD_PROCESSED)
log_print("Volume group \"%s\" successfully removed", vg_name);

View File

@@ -36,6 +36,8 @@ static int vgscan_single(struct cmd_context *cmd, const char *vg_name,
(vg->status & EXPORTED_VG) ? "exported " : "", vg_name,
vg->fid->fmt->name);
check_current_backup(vg);
return ECMD_PROCESSED;
}

View File

@@ -44,6 +44,19 @@ static int _move_pv(struct volume_group *vg_from, struct volume_group *vg_to,
return 1;
}
/* FIXME Why not (lv->vg == vg) ? */
static int _lv_is_in_vg(struct volume_group *vg, struct logical_volume *lv)
{
struct lv_list *lvl;
list_iterate_items(lvl, &vg->lvs)
if (lv == lvl->lv)
return 1;
return 0;
}
static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to)
{
struct list *lvh, *lvht;
@@ -56,6 +69,9 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to)
list_iterate_safe(lvh, lvht, &vg_from->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if ((lv->status & SNAPSHOT))
continue;
/* Ensure all the PVs used by this LV remain in the same */
/* VG as each other */
vg_with = NULL;
@@ -65,7 +81,7 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to)
if (seg->area[s].type != AREA_PV)
continue;
pv = seg->area[s].u.pv.pv;
pv = seg->area[s].u.pv.pvseg->pv;
if (vg_with) {
if (!pv_is_in_vg(vg_with, pv)) {
log_error("Logical Volume %s "
@@ -89,8 +105,9 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to)
dev_name(pv->dev));
return 0;
}
}
}
if (vg_with == vg_from)
continue;
@@ -107,39 +124,38 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to)
return 1;
}
static int _lv_is_in_vg(struct volume_group *vg, struct logical_volume *lv)
{
struct lv_list *lvl;
list_iterate_items(lvl, &vg->lvs)
if (lv == lvl->lv)
return 1;
return 0;
}
static int _move_snapshots(struct volume_group *vg_from,
struct volume_group *vg_to)
{
struct list *slh, *slth;
struct snapshot *snap;
int cow_from, origin_from;
struct list *lvh, *lvht;
struct logical_volume *lv;
struct lv_segment *seg;
int cow_from = 0;
int origin_from = 0;
list_iterate_safe(slh, slth, &vg_from->snapshots) {
snap = list_item(slh, struct snapshot_list)->snapshot;
cow_from = _lv_is_in_vg(vg_from, snap->cow);
origin_from = _lv_is_in_vg(vg_from, snap->origin);
if (cow_from && origin_from)
return 1;
if ((!cow_from && origin_from) || (cow_from && !origin_from)) {
log_error("Snapshot %s split", snap->cow->name);
return 0;
list_iterate_safe(lvh, lvht, &vg_from->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if (!(lv->status & SNAPSHOT))
continue;
list_iterate_items(seg, &lv->segments) {
cow_from = _lv_is_in_vg(vg_from, seg->cow);
origin_from = _lv_is_in_vg(vg_from, seg->origin);
}
if (cow_from && origin_from)
continue;
if ((!cow_from && origin_from) || (cow_from && !origin_from)) {
log_error("Snapshot %s split", seg->cow->name);
return 0;
}
/* Move this snapshot */
list_del(lvh);
list_add(&vg_to->lvs, lvh);
vg_from->snapshot_count--;
vg_to->snapshot_count++;
list_del(slh);
list_add(&vg_to->snapshots, slh);
}
return 1;