1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-09-28 09:44:18 +03:00

Compare commits

...

33 Commits

Author SHA1 Message Date
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
67 changed files with 3051 additions and 812 deletions

View File

@@ -1 +1 @@
2.01.09-cvs (2005-03-22)
2.01.10-cvs (2005-04-04)

View File

@@ -1,5 +1,23 @@
Version 2.01.09 -
=================================
Version 2.01.10 -
================================
Tidy lv_segment interface.
Initial 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,6 @@
Version 1.01.02 -
=============================
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
ifeq ("@LIB_SUFFIX@","dylib")
LIB_SHARED = libdmeventnoop.dylib
else
LIB_SHARED = libdmeventnoop.so
endif
LDFLAGS += -ldl -ldevmapper -lpthread
include ../make.tmpl
libdmeventnoop.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 -lmultilog -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 -lmultilog $(LIBS)
install: $(INSTALL_TYPE)
.PHONY: install_dynamic
install_dynamic: dmeventd
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) dmeventd $(sbindir)/dmeventd

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

@@ -0,0 +1,137 @@
/*
* 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 <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, char **device, int *reg, int *list)
{
int c;
const char *options = "d:hlru";
while ((c = getopt(argc, argv, options)) != -1) {
switch (c) {
case 'd':
*dso_name = 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 (!*list) {
if (optind >= argc) {
fprintf(stderr, "You need to specify a device.\n");
return 0;
}
*device = argv[optind];
}
return 1;
}
int main(int argc, char **argv)
{
int list = 0, ret, reg = default_reg;
char *device, *dso_name = default_dso_name;
if (!parse_argv(argc, argv, &dso_name, &device, &reg, &list))
exit(EXIT_FAILURE);
if (list) {
do {
ret = dm_get_next_registered_device(&dso_name, &device, &events);
if (!ret) {
printf("%s %s 0x%x\n", dso_name, device, events);
free(dso_name);
free(device);
}
} while (ret);
exit(EXIT_SUCCESS);
}
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));
exit(EXIT_FAILURE);
}
printf("%s %sregistered successfully.\n", device, reg ? "" : "un");
exit(EXIT_SUCCESS);
}
/*
* 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:
*/

1021
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 <stdio.h>
void process_event(char *device, enum event_type event)
{
fprintf(stderr, "[%s] %s(%d) - Device: %s, Event %d\n",
__FILE__, __func__, __LINE__, device, event);
}
int register_device(char *device)
{
fprintf(stderr, "[%s] %s(%d) - Device: %s\n",
__FILE__, __func__, __LINE__, device);
return 1;
}
int unregister_device(char *device)
{
fprintf(stderr, "[%s] %s(%d) - Device: %s\n",
__FILE__, __func__, __LINE__, device);
return 1;
}

View File

@@ -31,6 +31,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

@@ -70,6 +70,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)
@@ -875,22 +894,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 +929,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 +1294,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 +1303,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 +1314,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 +1351,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 +1372,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 +1467,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 +1630,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 +1941,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 +1973,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 +1981,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 +2009,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 +2017,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 +2104,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

@@ -32,17 +32,15 @@ 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;

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

@@ -330,8 +330,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 +346,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 +363,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 +394,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);

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);
@@ -550,7 +536,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,13 @@ int import_pv(struct pool *mem, struct device *dev,
pv->pe_alloc_count = pvd->pe_allocated;
list_init(&pv->tags);
list_init(&pv->segments);
list_init(&pv->free_segments);
if (!alloc_pv_segment_whole_pv(mem, pv)) {
stack;
return 0;
}
return 1;
}
@@ -323,6 +331,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);
@@ -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,55 @@ 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"))) {
stack;
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;
}
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));
le += seg->len;
set_lv_segment_area_pv(seg, 0, lvm->map[le].pv, lvm->map[le].pe);
list_add(&lvm->lv->segments, &seg->list);
le += seg->len;
}
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 +263,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 +277,42 @@ 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++)
set_lv_segment_area_pv(seg, st,
lvm->map[le + st * len].pv,
lvm->map[le + st * len].pe);
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,13 @@ 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);
list_init(&pv->free_segments);
if (!alloc_pv_segment_whole_pv(mem, pv)) {
stack;
return 0;
}
return 1;
}
@@ -200,40 +212,41 @@ 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;
area_len = (usp->devs[0].blocks) / POOL_PE_SIZE;
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++)
set_lv_segment_area_pv(seg, j, usp->devs[j].pv, 0);
/* add the subpool type to the segment tag list */
str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
for (j = 0; j < usp->num_devs; j++) {
if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd,
"striped"))) {
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;
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 +255,35 @@ 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;
set_lv_segment_area_pv(seg, 0, usp->devs[j].pv, 0);
list_add(&lv->segments, &seg->list);
*le_cur += seg->len;
}
return 1;
}
@@ -288,8 +299,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

@@ -477,87 +477,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 +548,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,8 @@ static int _read_pv(struct format_instance *fid, struct pool *mem,
}
list_init(&pv->tags);
list_init(&pv->segments);
list_init(&pv->free_segments);
/* Optional tags */
if ((cn = find_config_node(pvn, "tags")) &&
@@ -208,6 +211,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 +291,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;
@@ -361,19 +363,14 @@ 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;
set_lv_segment_area_pv(seg, s, pv, cv->next->v.i);
/*
* 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 +505,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 +560,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 +740,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

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

@@ -61,22 +61,57 @@ 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;
}
void set_lv_segment_area_pv(struct lv_segment *seg, uint32_t area_num,
struct physical_volume *pv, uint32_t pe)
{
seg->area[area_num].type = AREA_PV;
seg->area[area_num].u.pv.pv = pv;
seg->area[area_num].u.pv.pe = pe;
seg->area[area_num].u.pv.pvseg = NULL;
}
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 int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
uint32_t stripe_size,
struct segment_type *segtype,
@@ -98,24 +133,17 @@ static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_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 = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, *ix,
area_len * (striped ? area_count : 1),
0u, stripe_size, area_count, area_len,
0u, 0u))) {
log_error("Couldn't allocate new parallel segment.");
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;
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;
set_lv_segment_area_pv(seg, s, pva->map->pvl->pv, pva->start);
consume_pv_area(pva, area_len);
}
@@ -221,34 +249,31 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t *ix,
{
uint32_t count, remaining;
struct lv_segment *seg;
struct segment_type *segtype;
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"))) {
if (!(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;
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, *ix,
count, 0, 0, 1, count, 0, 0))) {
log_error("Couldn't allocate new stripe segment.");
return 0;
}
set_lv_segment_area_pv(seg, 0, map->pvl->pv, pva->start);
list_add(&lv->segments, &seg->list);
consume_pv_area(pva, count);
*ix += count;
consume_pv_area(pva, seg->len);
*ix += seg->len;
return 1;
}
@@ -266,30 +291,21 @@ static int _alloc_mirrored_area(struct logical_volume *lv, uint32_t *ix,
if (count > remaining)
count = remaining;
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, 2))) {
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, segtype, lv, *ix,
count, 0, 0, 2, count, 0, 0))) {
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;
set_lv_segment_area_pv(seg, 0, mirrored_pv, mirrored_pe);
set_lv_segment_area_pv(seg, 1, map->pvl->pv, pva->start);
list_add(&lv->segments, &seg->list);
consume_pv_area(pva, count);
*ix += count;
consume_pv_area(pva, seg->len);
*ix += seg->len;
return 1;
}
@@ -421,25 +437,44 @@ 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.
*/
@@ -543,8 +578,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 +602,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 +630,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,7 +645,9 @@ 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;

View File

@@ -98,11 +98,17 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
}
/* 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;
}
/* FIXME Avoid the memcpy */
len = sizeof(*seg) + (seg->area_count * sizeof(seg->area[0]));
memcpy(split_seg, seg, len);

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)
@@ -109,6 +111,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_to->free_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 +274,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 +301,153 @@ 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;
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 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.pe, lv->name,
" area start", 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 +510,8 @@ struct physical_volume *pv_create(const struct format_type *fmt,
pv->fmt = fmt;
list_init(&pv->tags);
list_init(&pv->segments);
list_init(&pv->free_segments);
if (!fmt->ops->pv_setup(fmt, pe_start, existing_extent_count,
existing_extent_size,
@@ -507,6 +708,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 +730,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 +818,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 +849,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 +861,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 +887,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 +902,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 +931,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 +946,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 +976,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 +1019,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 +1131,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 +1147,29 @@ 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);
list_init(&pv->free_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,20 @@ 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 list freelist; /* Member of pv->free_segments */
};
struct physical_volume {
struct id id;
struct device *dev;
@@ -113,6 +128,8 @@ struct physical_volume {
uint32_t pe_count;
uint32_t pe_alloc_count;
struct list segments; /* Ordered pv_segments covering complete PV */
struct list free_segments; /* Free pv_segments for this PV */
struct list tags;
};
@@ -124,6 +141,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 +160,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 +207,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 +230,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;
@@ -222,6 +243,7 @@ struct lv_segment {
struct {
struct physical_volume *pv;
uint32_t pe;
struct pv_segment *pvseg;
} pv;
struct {
struct logical_volume *lv;
@@ -246,21 +268,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 +299,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 +388,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,13 +424,17 @@ 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,
@@ -440,6 +461,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);
@@ -493,12 +516,11 @@ 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);

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.
@@ -153,9 +154,7 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
"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;
@@ -225,9 +224,9 @@ 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;
set_lv_segment_area_pv(seg, s,
mir_seg->area[c].u.pv.pv,
mir_seg->area[c].u.pv.pe);
/* Replace mirror with old area */
if (!

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

@@ -0,0 +1,22 @@
/*
* 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_free_new,
struct list *peg_old);
#endif

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

@@ -0,0 +1,83 @@
/*
* 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"
static struct pv_segment *_alloc_pv_segment(struct pool *mem,
struct physical_volume *pv,
uint32_t pe, uint32_t len)
{
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 = NULL;
peg->lv_area = 0;
list_init(&peg->list);
list_init(&peg->freelist);
return peg;
}
int alloc_pv_segment_whole_pv(struct pool *mem, struct physical_volume *pv)
{
struct pv_segment *peg;
/* FIXME Cope with holes in PVs */
if (!(peg = _alloc_pv_segment(mem, pv, 0, pv->pe_count))) {
stack;
return 0;
}
list_add(&pv->segments, &peg->list);
list_add(&pv->free_segments, &peg->freelist);
return 1;
}
int peg_dup(struct pool *mem, struct list *peg_new, struct list *peg_free_new,
struct list *peg_old)
{
struct pv_segment *peg, *pego;
list_init(peg_new);
list_init(peg_free_new);
list_iterate_items(pego, peg_old) {
if (!(peg = _alloc_pv_segment(mem, pego->pv, pego->pe,
pego->len))) {
stack;
return 0;
}
peg->lvseg = pego->lvseg;
peg->lv_area = pego->lv_area;
list_add(peg_new, &peg->list);
if (!peg->lvseg)
list_add(peg_free_new, &peg->freelist);
}
return 1;
}

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)
{
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(vg, 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;
vg->snapshot_count--;
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

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

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

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

@@ -0,0 +1,83 @@
/*
* 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_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;
char *client_path;
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)
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_next_registered_device(char **dso_name, char **device,
enum event_type *events);
#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

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

@@ -512,8 +512,8 @@ 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;
}
@@ -609,8 +609,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

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

@@ -141,9 +141,9 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
/* 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 +160,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);

View File

@@ -24,7 +24,7 @@ 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;
return ECMD_PROCESSED;
@@ -33,7 +33,7 @@ static int _vgs_single(struct cmd_context *cmd, const char *vg_name,
static int _lvs_single(struct cmd_context *cmd, struct logical_volume *lv,
void *handle)
{
if (!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 +42,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 +105,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 +183,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 +252,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 +283,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,8 @@ 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);
list_init(&pv_dummy.free_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

@@ -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 */
@@ -251,6 +251,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 +427,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 +448,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 +459,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

@@ -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(lv->vg, 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(lv->vg, cow)) {
stack;
return 0;
}

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