1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-09-24 21:44:22 +03:00

Compare commits

...

24 Commits

Author SHA1 Message Date
Patrick Caulfield
cbe3e5991b Add locking to PV commands. 2001-12-07 09:37:18 +00:00
Patrick Caulfield
3335b34c44 Add locking to VG commands 2001-12-06 15:19:32 +00:00
Patrick Caulfield
6ffc854f9c Made active/open messages print with log_verbose rather than log_very_verbose
and made them a little more user-friendly. This is the way users will be told
which nodes an LV/VG is open on.
2001-12-06 15:17:37 +00:00
Patrick Caulfield
cbe47da378 Add return code to vg_unlock so it knows whether or not to reload the metadata.
Add locking to lvrename.
2001-12-06 13:13:07 +00:00
Patrick Caulfield
dd34a165a1 Add an extra parameter to the unlock functions to tell the cluster not to reload
the metadata at unlock time. We use this if the command failed.
2001-12-06 09:58:51 +00:00
Patrick Caulfield
b2a6905722 Lock LVs by vg/lv name 2001-12-05 14:57:41 +00:00
Patrick Caulfield
3af6e3b294 Return open count correctly when run locally. 2001-12-05 11:56:11 +00:00
Patrick Caulfield
43a6ba01b9 Locking for lvremove and a couple of typo fixes. 2001-12-05 11:55:45 +00:00
Patrick Caulfield
74646b92fb ADd locking to lvresize 2001-12-05 10:11:56 +00:00
Patrick Caulfield
09453f276f Lock by name rather than UUID. (just as well really, the UUIDs are too long for
SLM to lock by)
2001-12-03 14:27:29 +00:00
Patrick Caulfield
2ddd6ebf79 Add local lockfile-based locking 2001-12-03 11:06:13 +00:00
Patrick Caulfield
4da649182f Put back prototypes that got lost in the last merge I did. 2001-11-26 15:52:34 +00:00
Patrick Caulfield
fb38dc166f Add routines for checking for LV and VG activity around the cluster 2001-11-26 15:49:56 +00:00
Patrick Caulfield
3213274526 Send UUIDs round the cluster. Hmmm, need to resolve these at t'other end. 2001-11-23 13:59:25 +00:00
Patrick Caulfield
010c1715c4 Bring forward a few more changes so my tree works with the current devmapper 2001-11-23 13:53:23 +00:00
Patrick Caulfield
67a5321134 Bring Alasdairs 64bit fixes into this tree. 2001-11-23 12:00:52 +00:00
Patrick Caulfield
b590ecf83a Make shared library 2001-11-22 09:37:35 +00:00
Patrick Caulfield
cc296900ae Use new simplified API 2001-11-21 16:09:43 +00:00
Patrick Caulfield
89d9ee62d7 Simplify the API a fair bit and add some actual suspend/resume calls for local
use.
2001-11-21 16:08:46 +00:00
Patrick Caulfield
4cc7c16037 Add a couple of suspend API functions. 2001-11-21 16:07:05 +00:00
Patrick Caulfield
8032fb64cd The first command to call the locking API.
In fact the biggest diff here is to make sure the error path always calls unlock
as stated in the previous checkin. Southerners please take note(!)
2001-11-20 14:23:28 +00:00
Patrick Caulfield
75ef8629d5 - Add suspend flag to the locking API as we don't always want to suspend the
target LV.

- Removed lvm_ prefix from all functions because Joe told me to.

- Added super-high-level functions that keep the mainline code clean - comands
  now just call lock_lvm() and unlock_lvm() [lock/unlock are too glib!] and the
  library takes care of whether we are clustered or not.

It's important that client routines call unlock before finishing not because the
API can't clean up afterwards (it does) but because multiple LVM commands can be
issued from one lvm invocation and thus they are the same client as far as the
CLVMD is concerned.

The local locking paths currently don't do anything.

Thought: it might be worth renaming this bit of the lib "locking" to make it
less obvious that we have clustering code (of sorts) in here. Or maybe that's
just job security through obscurity.
2001-11-20 14:20:49 +00:00
Patrick Caulfield
7a6d29f5d2 Add cmgr into list of include files and objects to build. 2001-11-19 14:54:19 +00:00
Patrick Caulfield
1c1770003f Add cluster manager library. 2001-11-19 14:40:32 +00:00
23 changed files with 1276 additions and 94 deletions

View File

@@ -20,3 +20,4 @@
../lib/mm/xlate.h
../lib/regex/matcher.h
../lib/uuid/uuid.h
../lib/cmgr/cmgr.h

View File

@@ -37,9 +37,10 @@ SOURCES=\
regex/matcher.c \
regex/parse_rx.c \
regex/ttree.c \
cmgr/cmgr.c \
uuid/uuid.c
TARGETS=liblvm.a
TARGETS=liblvm.a $(SLIB_SOV) $(SLIB_SOM) $(SLIB_SO)
include ../make.tmpl
@@ -48,3 +49,12 @@ liblvm.a: $(OBJECTS)
$(AR) r $@ $(OBJECTS)
$(RANLIB) $@
$(SLIB_SOV): $(POBJECTS)
$(CC) -shared -Wl,-soname,$(SLIB_SOM) -o $(SLIB_SOV) $(POBJECTS)
$(SLIB_SOM): $(SLIB_SOV)
ln -sf $(SLIB_SOV) $(SLIB_SOM)
$(SLIB_SO): $(SLIB_SOV)
ln -sf $(SLIB_SOV) $(SLIB_SO)

View File

@@ -10,8 +10,6 @@
#include "log.h"
#include "fs.h"
#include <devmapper/libdevmapper.h>
static void _build_lv_name(char *buffer, size_t s, struct logical_volume *lv)
{
snprintf(buffer, s, "%s_%s", lv->vg->name, lv->name);
@@ -33,8 +31,9 @@ static struct dm_task *_setup_task(struct logical_volume *lv, int task)
return dmt;
}
static struct dm_task *_info(struct logical_volume *lv)
int lv_info(struct logical_volume *lv, struct dm_info *info)
{
int r = 0;
struct dm_task *dmt;
if (!(dmt = _setup_task(lv, DM_DEVICE_INFO))) {
@@ -44,54 +43,44 @@ static struct dm_task *_info(struct logical_volume *lv)
if (!dm_task_run(dmt)) {
stack;
goto bad;
goto out;
}
return dmt;
if (!dm_task_get_info(dmt, info)) {
stack;
goto out;
}
r = 1;
bad:
out:
dm_task_destroy(dmt);
return NULL;
return r;
}
int lv_active(struct logical_volume *lv)
{
int r = -1;
struct dm_task *dmt;
struct dm_info info;
if (!(dmt = _info(lv))) {
if (!lv_info(lv, &info)) {
stack;
return r;
}
if (!dm_task_exists(dmt, &r)) {
stack;
goto out;
}
out:
dm_task_destroy(dmt);
return r;
return info.exists;
}
int lv_open_count(struct logical_volume *lv)
{
int r = -1;
struct dm_task *dmt;
struct dm_info info;
if (!(dmt = _info(lv))) {
if (!lv_info(lv, &info)) {
stack;
return r;
}
if (!dm_task_open_count(dmt, &r)) {
stack;
goto out;
}
out:
dm_task_destroy(dmt);
return r;
return info.open_count;
}
/*
@@ -113,8 +102,12 @@ static int _emit_target(struct dm_task *dmt, struct logical_volume *lv,
if (!first)
first = pes;
else if (first->pv != pes->pv || first->pe != pes->pe + 1)
break; /* no longer contig. */
/*
* check that we're still contiguous.
*/
else if ((pes->pv != first->pv) ||
(pes->pe != first->pe + count))
break;
count++;
}
@@ -158,6 +151,8 @@ int _load(struct logical_volume *lv, int task)
if (!(r = dm_task_run(dmt)))
stack;
log_verbose("Logical volume %s activated", lv->name);
out:
dm_task_destroy(dmt);
return r;
@@ -226,6 +221,27 @@ int lv_deactivate(struct logical_volume *lv)
return r;
}
int lv_suspend(struct logical_volume *lv, int sus)
{
return _suspend(lv, sus);
}
int suspend_lvs_in_vg(struct volume_group *vg, int sus)
{
struct list *lvh;
struct logical_volume *lv;
int count = 0;
list_iterate(lvh, &vg->lvs) {
lv = &(list_item(lvh, struct lv_list)->lv);
count += (_suspend(lv, sus));
}
return count;
}
int activate_lvs_in_vg(struct volume_group *vg)
{
struct list *lvh;

View File

@@ -7,14 +7,18 @@
#ifndef LVM_ACTIVATE_H
#define LVM_ACTIVATE_H
#include <libdevmapper.h>
/* FIXME Snapshot handling? */
int lv_active(struct logical_volume *lv);
int lv_open_count(struct logical_volume *lv);
int lv_info(struct logical_volume *lv, struct dm_info *info);
int lv_activate(struct logical_volume *lv);
int lv_reactivate(struct logical_volume *lv);
int lv_deactivate(struct logical_volume *lv);
int lv_suspend(struct logical_volume *lv, int sus);
/*
* Return number of LVs in the VG that are
@@ -40,4 +44,10 @@ int activate_lvs_in_vg(struct volume_group *vg);
*/
int deactivate_lvs_in_vg(struct volume_group *vg);
/*
*
* Suspend/resume
*/
int suspend_lvs_in_vg(struct volume_group *vg, int sus);
#endif

46
lib/cmgr/clvm.h Normal file
View File

@@ -0,0 +1,46 @@
/* Definitions for CLVMD server and clients */
/* The protocol spoken over the cluster and across the local
socket
*/
struct clvm_header
{
unsigned char cmd; /* See below */
unsigned char flags; /* See below */
unsigned short pad; /* To keep alignment sane */
unsigned int clientid; /* Only used in Daemon->Daemon comms */
int status; /* For replies, whether the request suceeded or not */
unsigned int arglen; /* Length of argument below. if >1500 then it will be passed around the
cluster in the system LV */
char node[1]; /* Actually a NUL-terminated string, node name, if this is empty then
the command is forwarded to all cluster nodes unless FLAG_LOCAL is
also set. */
char args[1]; /* Arguments for the command follow the node name, This member is only
valid if the node name is empty */
} __attribute__((packed));
/* Flags */
#define CLVMD_FLAG_LOCAL 1 /* Only do this on the local node */
#define CLVMD_FLAG_SYSTEMLV 2 /* Data is in system LV under my node name */
/* Name of the local socket to communicate between libclvm and clvmd */
#define CLVMD_SOCKNAME "/var/run/clvmd"
/* Command numbers */
#define CLVMD_CMD_TEST 4
/* Lock/Unlock commands */
#define CLVMD_CMD_LOCK 30
#define CLVMD_CMD_UNLOCK 31
#define CLVMD_CMD_LOCK_SUSPEND 32
#define CLVMD_CMD_UNLOCK_RESUME 33
/* Info Commands */
#define CLVMD_CMD_LVDISPLAY 40
#define CLVMD_CMD_LVCHECK 41
#define CLVMD_CMD_VGDISPLAY 42
#define CLVMD_CMD_VGCHECK 43

874
lib/cmgr/cmgr.c Normal file
View File

@@ -0,0 +1,874 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
/* Locking functions for LVM
* The main purpose of this part of the library is to serialise LVM
* management operations (across a cluster if necessary)
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
#include <syslog.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <search.h>
#include <errno.h>
#include "metadata.h"
#include "activate.h"
#include "log.h"
#include "clvm.h"
#include "cmgr.h"
/* This gets stuck at the start of memory we allocate so we
can sanity-check it at deallocation time */
#define LVM_SIGNATURE 0x434C564D
#define MAX_CLUSTER_MEMBER_NAME_LEN 255
#define LVM_GLOBAL_LOCK "LVM_GLOBAL"
#define LOCKFILE_DIR "/var/lock/lvm"
/* NOTE: the LVMD uses the socket FD as the client ID, this means
that any client that calls fork() will inherit the context of
it's parent. */
static int clvmd_sock = -1;
/* Open connection to the Cluster Manager daemon */
static int open_local_sock(void)
{
int local_socket;
struct sockaddr_un sockaddr;
/* Open local socket */
local_socket = socket(PF_UNIX, SOCK_STREAM, 0);
if (local_socket < 0)
{
perror("Can't create local socket");
return -1;
}
fcntl(local_socket, F_SETFD, !FD_CLOEXEC);
strcpy(sockaddr.sun_path, CLVMD_SOCKNAME);
sockaddr.sun_family = AF_UNIX;
if (connect(local_socket, (struct sockaddr *)&sockaddr, sizeof(sockaddr)))
{
int saved_errno = errno;
close(local_socket);
errno = saved_errno;
return -1;
}
return local_socket;
}
/* Send a request and return the status */
static int send_request(char *inbuf, int inlen, char **retbuf)
{
char outbuf[PIPE_BUF];
struct clvm_header *outheader = (struct clvm_header *)outbuf;
int len;
int off;
fd_set fds;
FD_ZERO(&fds);
FD_SET(clvmd_sock, &fds);
/* Send it to CLVMD */
if (write(clvmd_sock, inbuf, inlen) != inlen)
{
perror("Error writing to CLVMD");
return -1;
}
/* Get the response */
if ( (len = read(clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0)
{
perror("Error reading CLVMD");
return -1;
}
if (len == 0)
{
fprintf(stderr, "EOF reading CLVMD");
errno = ENOTCONN;
return -1;
}
/* Allocate buffer */
*retbuf = malloc(len + outheader->arglen);
if (!*retbuf)
{
errno = ENOMEM;
return -1;
}
/* Copy the header */
memcpy(*retbuf, outbuf, len);
outheader = (struct clvm_header *)*retbuf;
/* Read the returned values */
off = 1; /* we've already read the first byte */
while (off < outheader->arglen && len > 0)
{
len = read(clvmd_sock, outheader->args+off, PIPE_BUF);
if (len > 0)
off += len;
}
/* Was it an error ? */
if (outheader->status < 0)
{
errno = -outheader->status;
return -2;
}
return 0;
}
/* Build the structure header and parse-out wildcard node names */
static void build_header(struct clvm_header *head, int cmd, char *node, void *data, int len)
{
head->cmd = cmd;
head->status = 0;
head->flags = 0;
head->clientid = 0;
head->arglen = len;
if (node)
{
/* Allow a couple of special node names:
"*" for all nodes,
"." for the local node only
*/
if (strcmp(node, "*") == 0)
{
head->node[0] = '\0';
}
else if (strcmp(node, ".") == 0)
{
head->node[0] = '\0';
head->flags = CLVMD_FLAG_LOCAL;
}
else
{
strcpy(head->node, node);
}
}
else
{
head->node[0] = '\0';
}
}
/* Send a message to a(or all) node(s) in the cluster */
int cluster_write(char cmd, char *node, void *data, int len)
{
char outbuf[sizeof(struct clvm_header)+len+strlen(node)+1];
char *retbuf = NULL;
int status;
struct clvm_header *head = (struct clvm_header *)outbuf;
if (clvmd_sock == -1)
clvmd_sock = open_local_sock();
if (clvmd_sock == -1)
return -1;
build_header(head, cmd, node, data, len);
memcpy(head->node+strlen(head->node)+1, data, len);
status = send_request(outbuf, sizeof(struct clvm_header)+strlen(head->node)+len, &retbuf);
if (retbuf) free(retbuf);
return status;
}
/* API: Send a message to a(or all) node(s) in the cluster
and wait for replies */
int cluster_request(char cmd, char *node, void *data, int len,
lvm_response_t **response, int *num)
{
char outbuf[sizeof(struct clvm_header)+len+strlen(node)+1];
int *outptr;
char *inptr;
char *retbuf = NULL;
int status;
int i;
int num_responses=0;
struct clvm_header *head = (struct clvm_header *)outbuf;
lvm_response_t *rarray;
*num = 0;
if (clvmd_sock == -1)
clvmd_sock = open_local_sock();
if (clvmd_sock == -1)
return -1;
build_header(head, cmd, node, data, len);
memcpy(head->node+strlen(head->node)+1, data, len);
status = send_request(outbuf, sizeof(struct clvm_header)+strlen(head->node)+len, &retbuf);
if (status == 0 || status == -2)
{
/* Count the number of responses we got */
head = (struct clvm_header *)retbuf;
inptr = head->args;
while (inptr[0])
{
num_responses++;
inptr += strlen(inptr)+1;
inptr += sizeof(int);
inptr += strlen(inptr)+1;
}
/* Allocate response array. With an extra pair of INTs on the front to sanity
check the pointer when we are given it back to free */
outptr = malloc(sizeof(lvm_response_t) * num_responses + sizeof(int)*2);
if (!outptr)
{
if (retbuf) free(retbuf);
errno = ENOMEM;
return -1;
}
*response = (lvm_response_t *)(outptr+2);
outptr[0] = LVM_SIGNATURE;
outptr[1] = num_responses;
rarray = *response;
/* Unpack the response into an lvm_response_t array */
inptr = head->args;
i = 0;
while (inptr[0])
{
strcpy(rarray[i].node, inptr);
inptr += strlen(inptr)+1;
rarray[i].status = *(int *)inptr;
inptr += sizeof(int);
rarray[i].response = malloc(strlen(inptr)+1);
if (rarray[i].response == NULL)
{
/* Free up everything else and return error */
int j;
for (j=0; j<i; j++)
free(rarray[i].response);
free(outptr);
errno = ENOMEM;
return -1;
}
strcpy(rarray[i].response, inptr);
rarray[i].len = strlen(inptr);
inptr += strlen(inptr)+1;
i++;
}
*num = num_responses;
*response = rarray;
}
if (retbuf) free(retbuf);
return status;
}
/* API: Free reply array */
int cluster_free_request(lvm_response_t *response)
{
int *ptr = (int *)response-2;
int i;
int num;
/* Check it's ours to free */
if (response == NULL || *ptr != LVM_SIGNATURE)
{
errno = EINVAL;
return -1;
}
num = ptr[1];
for (i = 0; i<num; i++)
{
free(response[i].response);
}
free(ptr);
return 0;
}
static pid_t locked_by(char *lockfile_name)
{
/* Check lock is not stale - the file should contain
the owners PID */
FILE *f = fopen(lockfile_name, "r");
pid_t pid = 0;
if (f)
{
char proc_pid[PATH_MAX];
struct stat st;
/* Normal practice to to kill -0 the process at this point
but we may not have the privilege */
fscanf(f, "%d\n", &pid);
fclose(f);
snprintf(proc_pid, sizeof(proc_pid), "/proc/%d", pid);
if (stat(proc_pid, &st) == 0)
{
/* Process exists - lock is valid. */
return pid;
}
/* Remove stale lock file */
unlink(lockfile_name);
}
/* Not locked */
return -1;
}
/* LOCK resource using a file */
static int lock_resource(char *resource, int mode, int flags, int *lockid)
{
struct stat;
int fd;
char lockfile_name[PATH_MAX];
mode_t old_umask;
FILE *pidfile;
int ret = -1;
int ret_errno;
if (mode != LKM_EXMODE)
{
ret_errno = EINVAL;
goto lock_finish;
}
old_umask = umask(000);
ret_errno = -EPERM;
if (mkdir(LOCKFILE_DIR, 0777) != 0)
if (errno != EEXIST)
goto lock_finish;
/* Make the lockfile name */
snprintf(lockfile_name, sizeof(lockfile_name), LOCKFILE_DIR "/%s", resource);
/* Keep trying to lock untill we succeed
unless LKM_NONBLOCK was requested */
do
{
fd = open(lockfile_name, O_CREAT|O_EXCL|O_WRONLY, 0666);
if (fd == -1)
{
pid_t owner_pid;
/* Is the permission on the directory correct ? */
if (errno == EPERM)
goto lock_finish;
owner_pid = locked_by(lockfile_name);
/* If it's locked and the caller doesn't want to block then return */
if (owner_pid > 0 && (flags & O_NONBLOCK))
{
ret_errno = EAGAIN;
goto lock_finish;
}
/* If it's locked, then wait and try again in a second,
Ugh, need directrory notification */
if (owner_pid > 0)
{
sleep(1);
}
}
}
while (fd < 0);
/* OK - lock it */
pidfile = fdopen(fd, "w");
if (pidfile)
{
fprintf(pidfile, "%d\n", getpid());
fclose(pidfile);
ret = 0;
}
lock_finish:
umask(old_umask);
errno = ret_errno;
return ret;
}
static int unlock_resource(char *resource, int lockid)
{
char lockfile_name[PATH_MAX];
pid_t owner_pid;
snprintf(lockfile_name, sizeof(lockfile_name), LOCKFILE_DIR "/%s", resource);
owner_pid = locked_by(lockfile_name);
/* Is it locked by us ? */
if (owner_pid != getpid())
{
errno = EINVAL;
return -1;
}
unlink(lockfile_name);
return 0;
}
/* These are a "higher-level" API providing black-box lock/unlock
functions for cluster LVM...maybe */
/* Set by lock(), used by unlock() */
static int num_responses;
static lvm_response_t *response;
int lock_for_cluster(char scope, char *name, int namelen, int suspend)
{
int status;
int i;
char *args;
int len;
int cmd;
/* Validate scope */
if (scope != 'V' && scope != 'L' && scope != 'G')
{
errno = EINVAL;
return -1;
}
/* Allow for NULL in name field */
if (name && namelen)
{
len = namelen + 2;
args = alloca(namelen);
memcpy(args+1, name, namelen);
}
else
{
len = 2;
args = alloca(len);
args[1] = '\0';
}
args[0] = scope;
cmd = (suspend)?CLVMD_CMD_LOCK_SUSPEND:CLVMD_CMD_LOCK;
status = cluster_request(cmd,
"", args, len,
&response, &num_responses);
/* If any nodes were down then display them and return an error */
for (i=0; i<num_responses; i++)
{
if (response[i].status == -EHOSTDOWN)
{
log_verbose("clvmd not running on node %s\n", response[i].node);
status = -1;
}
}
/* If there was an error then free the memory now as the caller won't
want to do the unlock */
if (status)
{
int saved_errno = errno;
cluster_free_request(response);
num_responses = 0;
errno = saved_errno;
}
return status;
}
int unlock_for_cluster(char scope, char *name, int namelen, int suspend)
{
int status;
int i;
int len;
int failed;
int cmd;
int num_unlock_responses;
char *args;
lvm_response_t *unlock_response;
/* We failed - this should not have been called */
if (num_responses == 0)
return 0;
/* Validate scope */
if (scope != 'V' && scope != 'L' && scope != 'G' &&
scope != 'v' && scope != 'l' && scope != 'g')
{
errno = EINVAL;
return -1;
}
/* Allow for NULL in name field */
if (name && namelen)
{
len = namelen + 2;
args = alloca(namelen);
memcpy(args+1, name, namelen);
}
else
{
len = 2;
args = alloca(len);
args[1] = '\0';
}
args[0] = scope;
cmd = (suspend)?CLVMD_CMD_UNLOCK_RESUME:CLVMD_CMD_UNLOCK;
/* See if it failed anywhere */
failed = 0;
for (i=0; i<num_responses; i++)
{
if (response[i].status != 0)
failed++;
}
/* If it failed on any nodes then we only unlock on
the nodes that succeeded */
if (failed)
{
for (i=0; i<num_responses; i++)
{
/* Unlock the ones that succeeded */
if (response[i].status == 0)
{
status = cluster_request(cmd,
response[i].node,
args, len,
&unlock_response, &num_unlock_responses);
if (status)
{
log_verbose("cluster command to node %s failed: %s\n",
response[i].node, strerror(errno));
}
else if (unlock_response[0].status != 0)
{
log_verbose("unlock on node %s failed: %s\n",
response[i].node, strerror(unlock_response[0].status));
}
cluster_free_request(unlock_response);
}
else
{
log_verbose("command on node %s failed: '%s' - will be left locked\n",
response[i].node, strerror(response[i].status));
}
}
}
else
{
/* All OK, we can do a full cluster unlock */
status = cluster_request(cmd,
"",
args, len,
&unlock_response, &num_unlock_responses);
if (status)
{
log_verbose("cluster command failed: %s\n",
strerror(errno));
}
else
{
for (i=0; i<num_unlock_responses; i++)
{
if (unlock_response[i].status != 0)
{
log_verbose("unlock on node %s failed: %s\n",
response[i].node, strerror(unlock_response[0].status));
}
}
}
cluster_free_request(unlock_response);
}
cluster_free_request(response);
return 0;
}
/* Keep track of the current request state */
static int clustered = 0;
static int suspended = 0;
static int lockid;
/* Lock the whole system */
int lock_lvm(int suspend)
{
int status;
suspended = suspend;
status = lock_for_cluster('G', NULL, 0, suspend);
if (status == -1)
{
/* ENOENT means clvmd is not running - assume we are not clustered */
/* TODO: May need some way of forcing this to fail in the future */
if (errno == ENOENT)
{
clustered = 0;
status = lock_resource(LVM_GLOBAL_LOCK, LKM_EXMODE, 0, &lockid);
if (!status)
return status;
/* TODO: suspend? */
return 0;
}
clustered = 1;
return -1;
}
clustered = 1;
return status;
}
int unlock_lvm(int cmd_status)
{
if (!clustered)
{
/* TODO: resume? */
return unlock_resource(LVM_GLOBAL_LOCK, lockid);
}
else
{
char cmd = (cmd_status==0)?'G':'g';
return unlock_for_cluster(cmd, NULL, 0, suspended);
}
}
/* Lock a whole Volume group and all its LVs */
int lock_vg(struct volume_group *vg, int suspend)
{
int status;
suspended = suspend;
status = lock_for_cluster('V', vg->name, strlen(vg->name)+1, suspend);
if (status == -1)
{
/* ENOENT means clvmd is not running - assume we are not clustered */
/* TODO: May need some way of forcing this to fail in the future */
if (errno == ENOENT)
{
clustered = 0;
/* Get LVM lock */
status = lock_resource(LVM_GLOBAL_LOCK, LKM_EXMODE, 0, &lockid);
if (!status)
return status;
if (suspend) suspend_lvs_in_vg(vg, 1);
return 0;
}
clustered = 1;
return -1;
}
clustered = 1;
return status;
}
int unlock_vg(struct volume_group *vg, int cmd_status)
{
if (!clustered)
{
activate_lvs_in_vg(vg);
return unlock_resource(LVM_GLOBAL_LOCK, lockid);
}
else
{
char cmd = (cmd_status==0)?'V':'v';
return unlock_for_cluster(cmd, vg->name, strlen(vg->name)+1, suspended);
}
}
/* Just lock a Logical volume */
int lock_lv(struct logical_volume *lv, int suspend)
{
int status;
char full_lv_name[strlen(lv->name)+strlen(lv->vg->name)+2];
sprintf(full_lv_name, "%s/%s", lv->vg->name, lv->name);
suspended = suspend;
status = lock_for_cluster('L', full_lv_name, strlen(full_lv_name)+1, suspend);
if (status == -1)
{
/* ENOENT means clvmd is not running - assume we are not clustered */
/* TODO: May need some way of forcing this to fail in the future */
if (errno == ENOENT)
{
clustered = 0;
/* Get LVM lock */
status = lock_resource(LVM_GLOBAL_LOCK, LKM_EXMODE, 0, &lockid);
if (!status)
return status;
if (suspend) lv_suspend(lv, 1);
return 0;
}
clustered = 1;
return -1;
}
clustered = 1;
return status;
}
int unlock_lv(struct logical_volume *lv, int cmd_status)
{
char full_lv_name[strlen(lv->name)+strlen(lv->vg->name)+2];
sprintf(full_lv_name, "%s/%s", lv->vg->name, lv->name);
if (!clustered)
{
lv_reactivate(lv);
return unlock_resource(LVM_GLOBAL_LOCK, lockid);
}
else
{
char cmd = (cmd_status==0)?'L':'l';
return unlock_for_cluster(cmd, full_lv_name, strlen(full_lv_name)+1, suspended);
}
}
/*
Maybe should replace lv_open_count() (Which we use!)
*/
int get_lv_open_count(struct logical_volume *lv, int *open_count)
{
int status;
int num_lv_responses;
lvm_response_t *lv_response;
int count = 0;
int i;
/* Do cluster check */
status = cluster_request(CLVMD_CMD_LVCHECK, "",
lv->name, strlen(lv->name)+1,
&lv_response, &num_lv_responses);
/* Are we sngle-node only ?*/
if (status == -1 && errno == ENOENT)
{
*open_count = lv_open_count(lv);
return 0;
}
if (status)
{
int saved_errno = errno;
cluster_free_request(lv_response);
errno = saved_errno;
return status;
}
for (i=0; i<num_lv_responses; i++)
{
if (lv_response[i].status != 0)
{
log_verbose("lv_open_count on node %s failed: %s\n",
lv_response[i].node, strerror(lv_response[i].status));
}
else
{
if (lv_response[i].response[0] != '\0')
{
count++;
log_verbose("Logical volume %s is open on node %s\n",
lv->name, lv_response[i].node);
}
}
}
cluster_free_request(lv_response);
*open_count = count;
return 0;
}
/*
Get the number of nodes the VG is active on.
*/
int get_vg_active_count(struct volume_group *vg, int *active_count)
{
int status;
int num_vg_responses;
lvm_response_t *vg_response;
int count = 0;
int i;
/* Do cluster check */
status = cluster_request(CLVMD_CMD_VGCHECK, "",
vg->name, strlen(vg->name)+1,
&vg_response, &num_vg_responses);
/* Are we sngle-node only ?*/
if (status == -1 && errno == ENOENT)
{
*active_count = 1; //vg_active(vg);
return 0;
}
if (status)
{
int saved_errno = errno;
cluster_free_request(vg_response);
errno = saved_errno;
return status;
}
for (i=0; i<num_vg_responses; i++)
{
if (vg_response[i].status != 0)
{
log_verbose("vg_active_count on node %s failed: %s\n",
vg_response[i].node, strerror(vg_response[i].status));
}
else
{
if (vg_response[i].response[0] != '\0')
{
count++;
log_verbose("Volume group %s is active on node %s\n",
vg->name, vg_response[i].node);
}
}
}
cluster_free_request(vg_response);
*active_count = count;
return 0;
}

52
lib/cmgr/cmgr.h Normal file
View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
*
* This is the interface to the locking and cluster manager
*/
typedef struct lvm_response
{
char node[255];
char *response;
int status;
int len;
} lvm_response_t;
/* The "direct to cluster manager" API */
extern int cluster_request(char cmd, char *node, void *data, int len,
lvm_response_t **response, int *num);
extern int cluster_write(char cmd, char *node, void *data, int len);
extern int cluster_free_request(lvm_response_t *response);
/* The "high-level" API */
extern int lock_for_cluster(char scope, char *name, int namelen, int suspend);
extern int unlock_for_cluster(char scope, char *name, int namelen, int suspend);
/* The "even higher-level" API that also copes with
non-clustered environment. */
extern int lock_lvm(int suspend);
extern int unlock_lvm(int cmd_status);
extern int lock_lv(struct logical_volume *lv, int suspend);
extern int unlock_lv(struct logical_volume *lv, int cmd_status);
extern int lock_vg(struct volume_group *vg, int suspend);
extern int unlock_vg(struct volume_group *vg, int cmd_status);
/* The system must be locked by one of the above calls before
using these */
extern int get_lv_open_count(struct logical_volume *lv, int *open_count);
extern int get_vg_active_count(struct volume_group *vg, int *active_count);
/* Lock modes: these are taken from the IBM DLM,
but we only support EX! */
#define LKM_NLMODE 0 /* null lock */
#define LKM_CRMODE 1 /* concurrent read */
#define LKM_CWMODE 2 /* concurrent write */
#define LKM_PRMODE 3 /* protected read */
#define LKM_PWMODE 4 /* protected write */
#define LKM_EXMODE 5 /* exclusive */

View File

@@ -43,13 +43,22 @@ mandir = @mandir@
OWNER=@OWNER@
GROUP=@GROUP@
#
# Shared library versions
# TODO: Substitute version numbers
SLIB_NAME = liblvm
SLIB_SOV = $(SLIB_NAME).so.2.0
SLIB_SOM = $(SLIB_NAME).so.0
SLIB_SO = $(SLIB_NAME).so
# The number of jobs to run, if blank, defaults to the make standard
ifndef MAKEFLAGS
MAKEFLAGS = @JOBS@
endif
SUFFIXES=
SUFFIXES=.c .d .o
SUFFIXES=.c .d .o .po
CFLAGS+=-Wall
#CFLAGS+=-O2
@@ -69,6 +78,7 @@ ifeq ("@READLINE@", "yes")
endif
OBJECTS=$(SOURCES:%.c=%.o)
POBJECTS=$(SOURCES:%.c=%.po)
SUBDIRS.install := $(SUBDIRS:=.install)
SUBDIRS.clean := $(SUBDIRS:=.clean)
@@ -96,6 +106,9 @@ $(SUBDIRS.distclean):
%.o: %.c
$(CC) -c $(INCLUDES) $(CFLAGS) $< -o $@
%.po: %.c
$(CC) -c $(INCLUDES) $(CFLAGS) -fPIC $< -o $@
%.d: %.c
set -e; FILE=`echo $@ | sed 's/\\//\\\\\\//g;s/\\.d//g'`; \
INC_LNS=`echo $(INC_LNS) | sed -e 's/\\//\\\\\\//g'`; \
@@ -104,7 +117,7 @@ $(SUBDIRS.distclean):
[ -s $@ ] || $(RM) $@
clean: $(SUBDIRS.clean)
$(RM) $(OBJECTS) $(TARGETS) $(SOURCES:%.c=%.d)
$(RM) $(POBJECTS) $(OBJECTS) $(TARGETS) $(SOURCES:%.c=%.d)
distclean: $(SUBDIRS.distclean)
$(RM) $(OBJECTS) $(TARGETS) $(SOURCES:%.c=%.d)

View File

@@ -62,7 +62,7 @@ xx(uuid_ARG, 'u', "uuid", NULL)
xx(uuidlist_ARG, 'U', "uuidlist", NULL)
xx(verbose_ARG, 'v', "verbose", NULL)
xx(volumegroup_ARG, 'V', "volumegroup", NULL)
xx(version_ARG, '\0', "version", NULL)
xx(version_ARG, (char) 0x1, "version", NULL)
xx(allocation_ARG, 'x', "allocation", yes_no_arg)
xx(yes_ARG, 'y', "yes", NULL)
xx(zero_ARG, 'Z', "zero", yes_no_arg)

View File

@@ -15,6 +15,7 @@ int lvcreate(int argc, char **argv)
int stripes = 1;
int stripesize = 0;
int ret;
int opt = 0;
uint32_t status = 0;
uint32_t size = 0;
@@ -127,19 +128,27 @@ int lvcreate(int argc, char **argv)
return ECMD_FAILED;
}
/* Prevent other commands from interleaving */
if (lock_vg(vg, 0) != 0) {
log_error("error locking volume group");
return ECMD_FAILED;
}
if (argc) {
ret = ECMD_FAILED;
/* Build up list of PVs */
if (!(pvh = pool_alloc(fid->cmd->mem, sizeof(struct list)))) {
log_error("pvh list allocation failed");
return ECMD_FAILED;
goto finish;
}
list_init(pvh);
ret = EINVALID_CMD_LINE;
for (; opt < argc; opt++) {
if (!(pvl = find_pv_in_vg(vg, argv[opt]))) {
log_error("Physical Volume %s not found in "
"Volume Group %s", argv[opt],
vg->name);
return EINVALID_CMD_LINE;
goto finish;
}
if (list_item(pvl, struct pv_list)->pv.pe_count ==
list_item(pvl, struct pv_list)->pv.pe_allocated) {
@@ -163,7 +172,8 @@ int lvcreate(int argc, char **argv)
if (argc && argc != stripes) {
log_error("Incorrect number of physical volumes on "
"command line for %d-way striping", stripes);
return EINVALID_CMD_LINE;
ret = EINVALID_CMD_LINE;
goto finish;
}
/******** FIXME Inside lv_create stripes
@@ -221,8 +231,9 @@ int lvcreate(int argc, char **argv)
}
*************/
ret = ECMD_FAILED;
if (!(lv = lv_create(lv_name, status, stripes, stripesize, extents,
vg, pvh))) return ECMD_FAILED;
vg, pvh))) goto finish;
if (arg_count(readahead_ARG)) {
log_verbose("Setting read ahead sectors");
@@ -231,12 +242,17 @@ int lvcreate(int argc, char **argv)
/* store vg on disk(s) */
if (!fid->ops->vg_write(fid, vg))
return ECMD_FAILED;
goto finish;
log_print("Logical volume %s created", lv->name);
if (!lv_activate(lv))
return ECMD_FAILED;
goto finish;
ret = 0;
finish:
/* TODO: Actually - this will do the activate as well */
unlock_vg(vg, ret);
if (zero) {
struct device *dev;
@@ -257,7 +273,7 @@ int lvcreate(int argc, char **argv)
return ECMD_FAILED;
}
if (!(dev_open(dev, O_WRONLY)))
return ECMD_FAILED;
return ECMD_FAILED;
dev_zero(dev, 0, 4096);
dev_close(dev);
@@ -269,5 +285,5 @@ int lvcreate(int argc, char **argv)
return ret;
***********/
return 0;
return ret;
}

View File

@@ -390,7 +390,7 @@ static void add_getopt_arg(int arg, char **ptr, struct option **o)
(*o)->name = a->long_arg + 2;
(*o)->has_arg = a->fn ? 1 : 0;
(*o)->flag = NULL;
(*o)->val = a->short_arg ? a->short_arg : (int) a;
(*o)->val = a->short_arg;
(*o)++;
}
}
@@ -460,7 +460,7 @@ static struct arg *find_arg(struct command *com, int opt)
for (i = 0; i < com->num_args; i++) {
a = the_args + com->valid_args[i];
if ((opt == a->short_arg) || (opt == (int) a))
if (opt == a->short_arg)
return a;
}
@@ -721,6 +721,7 @@ static int init(void)
/* FIXME: Override from config file. (Append trailing slash if reqd) */
cmd->dev_dir = "/dev/";
dm_set_dev_dir(cmd->dev_dir);
if (!(cmd->cf = create_config_file())) {
stack;
@@ -744,6 +745,8 @@ static int init(void)
__init_log(cmd->cf);
}
dm_log_init(print_log);
if (!dev_cache_setup(cmd->cf)) {
goto out;
}

View File

@@ -34,6 +34,9 @@ int lvremove(int argc, char **argv)
static int lvremove_single(struct volume_group *vg, struct logical_volume *lv)
{
int ret = 0;
int count;
if (!(vg->status & ACTIVE)) {
log_error("Volume group %s must be active before removing a "
"logical volume", vg->name);
@@ -64,10 +67,28 @@ static int lvremove_single(struct volume_group *vg, struct logical_volume *lv)
}
}
/* Prevent other commands from interleaving */
if (lock_vg(vg, 0) != 0) {
log_error("error locking volume group");
return ECMD_FAILED;
}
ret = ECMD_FAILED;
/* Check open count (maybe across the cluster) */
if (get_lv_open_count(lv, &count) != 0) {
log_error("error getting open count");
goto finish;
}
if (count > 0) {
log_print("logical volume %s is open, not removed", lv->name);
goto finish;
}
log_verbose("Releasing logical volume %s", lv->name);
if (!lv_remove(vg, lv)) {
log_error("Error releasing logical volume %s", lv->name);
return ECMD_FAILED;
goto finish;
}
/********* FIXME
@@ -78,13 +99,17 @@ static int lvremove_single(struct volume_group *vg, struct logical_volume *lv)
/* store it on disks */
if (fid->ops->vg_write(fid, vg))
return ECMD_FAILED;
goto finish;
/******** FIXME
if ((ret = do_autobackup(vg->name, vg)))
return ret;
goto finish;
**********/
log_print("logical volume %s successfully removed", lv->name);
return 0;
ret = 0;
finish:
unlock_vg(vg, ret);
return ret;
}

View File

@@ -26,6 +26,7 @@ int lvrename(int argc, char **argv)
char *lv_name_old, *lv_name_new;
char *vg_name, *vg_name_new;
char *st;
int ret = ECMD_FAILED;
struct volume_group *vg;
struct logical_volume *lv;
@@ -89,35 +90,41 @@ int lvrename(int argc, char **argv)
return ECMD_FAILED;
}
/* Prevent other commands from interleaving */
if (lock_vg(vg, 0) != 0) {
log_error("error locking volume group");
return ECMD_FAILED;
}
if (!(vg->status & ACTIVE)) {
log_error("Volume group %s must be active before changing a "
"logical volume", vg_name);
return ECMD_FAILED;
goto finish;
}
if ((lvh = find_lv_in_vg(vg, lv_name_new))) {
log_error("Logical volume %s already exists in "
"volume group %s", lv_name_new, vg_name);
return ECMD_FAILED;
goto finish;
}
if (!(lvh = find_lv_in_vg(vg, lv_name_old))) {
log_error("Existing logical volume %s not found in "
"volume group %s", lv_name_old, vg_name);
return ECMD_FAILED;
goto finish;
}
lv = &list_item(lvh, struct lv_list)->lv;
if (!(lv->name = pool_strdup(fid->cmd->mem, lv_name_new))) {
log_error("Failed to allocate space for new name");
return ECMD_FAILED;
goto finish;
}
/* store it on disks */
log_verbose("Writing out updated volume group");
if (!(fid->ops->vg_write(fid, vg))) {
return ECMD_FAILED;
goto finish;
}
/* FIXME Update symlink. lv_reactivate? */
@@ -126,6 +133,8 @@ int lvrename(int argc, char **argv)
log_print("Renamed %s to %s in volume group %s%s",
lv_name_old, lv_name_new, fid->cmd->dev_dir, vg_name);
return 0;
ret = 0;
finish:
unlock_vg(vg, ret);
return ret;
}

View File

@@ -33,6 +33,7 @@ int lvresize(int argc, char **argv)
const char *cmd_name;
struct list *lvh, *pvh, *pvl;
int opt = 0;
int ret = 0;
enum {
LV_ANY = 0,
@@ -192,6 +193,13 @@ int lvresize(int argc, char **argv)
resize = LV_EXTEND;
}
/* Prevent other commands from interleaving */
if (lock_vg(vg, 0) != 0) {
log_error("error locking volume group");
return ECMD_FAILED;
}
ret = ECMD_FAILED;
if (resize == LV_REDUCE) {
if (argc)
log_print("Ignoring PVs on command line when reducing");
@@ -214,7 +222,7 @@ int lvresize(int argc, char **argv)
" [y/n]: ", lv_name) == 'n') {
log_print("Logical volume %s NOT reduced",
lv_name);
return ECMD_FAILED;
goto finish;
}
}
@@ -225,7 +233,7 @@ int lvresize(int argc, char **argv)
/* Build up list of PVs */
if (!(pvh = pool_alloc(fid->cmd->mem, sizeof(struct list)))) {
log_error("pvh list allocation failed");
return ECMD_FAILED;
goto finish;
}
list_init(pvh);
for (; opt < argc; opt++) {
@@ -233,7 +241,8 @@ int lvresize(int argc, char **argv)
log_error("Physical Volume %s not found in "
"Volume Group %s", argv[opt],
vg->name);
return EINVALID_CMD_LINE;
ret = EINVALID_CMD_LINE;
goto finish;
}
if (list_item(pvl, struct pv_list)->pv.pe_count ==
list_item(pvl, struct pv_list)->pv.pe_allocated) {
@@ -262,20 +271,23 @@ int lvresize(int argc, char **argv)
/* store vg on disk(s) */
if (!fid->ops->vg_write(fid, vg))
return ECMD_FAILED;
goto finish;
/* FIXME Ensure it always displays errors? */
if (!lv_reactivate(lv))
return ECMD_FAILED;
goto finish;
/********* FIXME Resume *********/
/********* FIXME Backup
/********* FIXME Backup
if ((ret = do_autobackup(vg_name, vg)))
return ret;
goto finish;
************/
log_print("Logical volume %s successfully resized", lv_name);
ret = 0;
return 0;
finish:
unlock_vg(vg, ret);
return ret;
}

View File

@@ -27,6 +27,7 @@ int pvchange(int argc, char **argv)
int opt = 0;
int done = 0;
int total = 0;
int ret = ECMD_FAILED;
struct physical_volume *pv;
char *pv_name;
@@ -48,6 +49,12 @@ int pvchange(int argc, char **argv)
return EINVALID_CMD_LINE;
}
/* Prevent other commands from interleaving */
if (lock_lvm(0) != 0) {
log_error("error locking lvm");
return ECMD_FAILED;
}
if (argc) {
log_verbose("Using physical volume(s) on command line");
for (; opt < argc; opt++) {
@@ -63,7 +70,7 @@ int pvchange(int argc, char **argv)
} else {
log_verbose("Scanning for physical volume names");
if (!(pvs = fid->ops->get_pvs(fid))) {
return ECMD_FAILED;
goto finish;
}
list_iterate(pvh, pvs) {
@@ -80,8 +87,11 @@ int pvchange(int argc, char **argv)
log_print("%d physical volume(s) changed / %d physical volume(s) "
"not changed", done, total - done);
ret = 0;
finish:
unlock_lvm(ret);
return 0;
return ret;
}
int pvchange_single(struct physical_volume *pv)
@@ -96,7 +106,7 @@ int pvchange_single(struct physical_volume *pv)
/* If in a VG, must change using volume group. Pointless. */
/* FIXME: Provide a direct pv_write_pv that *only* touches PV structs*/
if (*pv->vg_name) {
log_verbose("Finding volume group of physical volume %s",
log_verbose("Finding volume group of physical volume %s",
pv_name);
if (!(vg = fid->ops->vg_read(fid, pv->vg_name))) {
log_error("Unable to find volume group of %s", pv_name);
@@ -144,7 +154,7 @@ int pvchange_single(struct physical_volume *pv)
}
} else {
if (!(fid->ops->pv_write(fid, pv))) {
log_error("Failed to store physical volume %s",
log_error("Failed to store physical volume %s",
pv_name);
return 0;
}

View File

@@ -106,6 +106,7 @@ static void pvcreate_single(const char *pv_name)
int pvcreate(int argc, char **argv)
{
int i;
int ret = ECMD_FAILED;
if (!argc) {
log_error("Please enter a physical volume path");
@@ -117,10 +118,20 @@ int pvcreate(int argc, char **argv)
return EINVALID_CMD_LINE;
}
/* Prevent other commands from interleaving */
if (lock_lvm(0) != 0) {
log_error("error locking lvm");
return ECMD_FAILED;
}
for (i = 0; i < argc; i++) {
pvcreate_single(argv[i]);
pool_empty(fid->cmd->mem);
}
return 0;
ret = 0;
finish:
unlock_lvm(ret);
return ret;
}

View File

@@ -44,6 +44,7 @@
#include "format1.h"
#include "toollib.h"
#include "activate.h"
#include "cmgr.h"
#define CMD_LEN 256
#define MAX_ARGS 64

View File

@@ -27,6 +27,8 @@ void vgchange_logicalvolume(struct volume_group *vg);
int vgchange(int argc, char **argv)
{
int ret;
if (!(arg_count(available_ARG) + arg_count(logicalvolume_ARG) +
arg_count(allocation_ARG))) {
log_error("One of -a, -l or -x options required");
@@ -44,7 +46,17 @@ int vgchange(int argc, char **argv)
return EINVALID_CMD_LINE;
}
return process_each_vg(argc, argv, &vgchange_single);
/* Prevent other commands from interleaving */
if (lock_lvm(0) != 0) {
log_error("error locking lvm");
return ECMD_FAILED;
}
ret = process_each_vg(argc, argv, &vgchange_single);
unlock_lvm(ret);
return ret;
}
static int vgchange_single(const char *vg_name)
@@ -103,12 +115,12 @@ void vgchange_available(struct volume_group *vg)
if (available) {
vg->status |= ACTIVE;
list_iterate(pvh, &vg->pvs)
list_item(pvh, struct pv_list)->pv.status
list_item(pvh, struct pv_list)->pv.status
|= ACTIVE;
} else {
vg->status &= ~ACTIVE;
list_iterate(pvh, &vg->pvs)
list_item(pvh, struct pv_list)->pv.status
list_item(pvh, struct pv_list)->pv.status
&= ~ACTIVE;
}

View File

@@ -32,6 +32,7 @@ int vgcreate(int argc, char **argv)
uint32_t extent_size;
char *vg_name;
struct volume_group *vg;
int ret = ECMD_FAILED;
if (!argc) {
log_error("Please provide volume group name and "
@@ -55,12 +56,12 @@ int vgcreate(int argc, char **argv)
log_error("maxlogicalvolumes too low");
return EINVALID_CMD_LINE;
}
if (max_pv < 1) {
log_error("maxphysicalvolumes too low");
return EINVALID_CMD_LINE;
}
/* Strip dev_dir if present */
if (!strncmp(vg_name, fid->cmd->dev_dir, strlen(fid->cmd->dev_dir)))
vg_name += strlen(fid->cmd->dev_dir);
@@ -71,22 +72,28 @@ int vgcreate(int argc, char **argv)
return ECMD_FAILED;
}
/* create the new vg */
if (!(vg = vg_create(fid, vg_name, extent_size, max_pv, max_lv,
argc - 1, argv + 1)))
return ECMD_FAILED;
/* Prevent other commands from interleaving */
if (lock_lvm(0) != 0) {
log_error("error locking lvm");
return ECMD_FAILED;
}
if (max_lv != vg->max_lv)
log_error("Warning: Setting maxlogicalvolumes to %d",
/* create the new vg */
if (!(vg = vg_create(fid, vg_name, extent_size, max_pv, max_lv,
argc - 1, argv + 1)))
goto finish;
if (max_lv != vg->max_lv)
log_error("Warning: Setting maxlogicalvolumes to %d",
vg->max_lv);
if (max_pv != vg->max_pv)
log_error("Warning: Setting maxphysicalvolumes to %d",
if (max_pv != vg->max_pv)
log_error("Warning: Setting maxphysicalvolumes to %d",
vg->max_pv);
/* store vg on disk(s) */
if (!fid->ops->vg_write(fid, vg))
return ECMD_FAILED;
goto finish;
/* FIXME Create /dev/vg */
/* FIXME Activate */
@@ -94,5 +101,8 @@ int vgcreate(int argc, char **argv)
log_print("Volume group %s successfully created and activated",
vg_name);
return 0;
ret = 0;
finish:
unlock_lvm(ret);
return ret;
}

View File

@@ -24,6 +24,7 @@ int vgextend(int argc, char **argv)
{
char *vg_name;
struct volume_group *vg = NULL;
int ret = ECMD_FAILED;
if (!argc) {
log_error("Please enter volume group name and "
@@ -63,9 +64,15 @@ int vgextend(int argc, char **argv)
dummy = NULL;
**********/
/* Prevent other commands from interleaving */
if (lock_lvm(0) != 0) {
log_error("error locking lvm");
return ECMD_FAILED;
}
/* extend vg */
if (!vg_extend(fid, vg, argc, argv))
return ECMD_FAILED;
goto finish;
/* ret > 0 */
log_verbose("Volume group '%s' will be extended by %d new "
@@ -73,7 +80,7 @@ int vgextend(int argc, char **argv)
/* store vg on disk(s) */
if (!fid->ops->vg_write(fid, vg))
return ECMD_FAILED;
goto finish;
/********* FIXME
if ((ret = do_autobackup(vg_name, vg)))
@@ -81,6 +88,9 @@ int vgextend(int argc, char **argv)
*********/
log_print("Volume group '%s' successfully extended", vg_name);
ret = 0;
return 0;
finish:
unlock_lvm(ret);
return ret;
}

View File

@@ -26,6 +26,7 @@ int vgreduce(int argc, char **argv)
{
struct volume_group *vg;
char *vg_name;
int ret = ECMD_FAILED;
if (!argc) {
log_error("Please give volume group name and "
@@ -64,13 +65,19 @@ int vgreduce(int argc, char **argv)
return ECMD_FAILED;
}
/* Prevent other commands from interleaving */
if (lock_lvm(0) != 0) {
log_error("error locking lvm");
return ECMD_FAILED;
}
/* FIXME: Pass private structure through to all these functions */
/* and update in batch here? */
return process_each_pv(argc, argv, vg, vgreduce_single);
ret = process_each_pv(argc, argv, vg, vgreduce_single);
/******* FIXME
log_error ("no empty physical volumes found in volume group \"%s\"", vg_name);
log_verbose
("volume group \"%s\" will be reduced by %d physical volume%s",
vg_name, np, np > 1 ? "s" : "");
@@ -81,7 +88,9 @@ int vgreduce(int argc, char **argv)
vg_name, error > 0 ? "NOT " : "", p > 1 ? "s" : "");
log_print("%s", pv_this[p]->pv_name);
********/
unlock_lvm(ret);
return ret;
}
/* Or take pv_name instead? */

View File

@@ -24,7 +24,18 @@ static int vgremove_single(const char *vg_name);
int vgremove(int argc, char **argv)
{
return process_each_vg(argc, argv, &vgremove_single);
int ret;
/* Prevent other commands from interleaving */
if (lock_lvm(0) != 0) {
log_error("error locking lvm");
return ECMD_FAILED;
}
ret = process_each_vg(argc, argv, &vgremove_single);
unlock_lvm(ret);
return ret;
}
static int vgremove_single(const char *vg_name)
@@ -33,6 +44,7 @@ static int vgremove_single(const char *vg_name)
struct physical_volume *pv;
struct list *pvh;
int ret = 0;
int count;
log_verbose("Checking for volume group %s", vg_name);
if (!(vg = fid->ops->vg_read(fid, vg_name))) {
@@ -40,6 +52,17 @@ static int vgremove_single(const char *vg_name)
return ECMD_FAILED;
}
/* Check cluster active count if appropriate */
if (get_vg_active_count(vg, &count)) {
log_error("Error getting active count for volume group %s", vg_name);
return ECMD_FAILED;
}
if (count > 0) {
log_error("Volume group %s is still active", vg_name);
return ECMD_FAILED;
}
if (vg->status & ACTIVE) {
log_error("Volume group %s is still active", vg_name);
return ECMD_FAILED;
@@ -66,7 +89,7 @@ static int vgremove_single(const char *vg_name)
*pv->vg_name = '\0';
if (!(fid->ops->pv_write(fid, pv))) {
log_error("Failed to remove physical volume %s from "
"volume group %s", dev_name(pv->dev),
"volume group %s", dev_name(pv->dev),
vg_name);
ret = ECMD_FAILED;
}

View File

@@ -24,6 +24,7 @@ int vgrename(int argc, char **argv)
{
char *dev_dir;
int length;
int ret = ECMD_FAILED;
char *vg_name_old, *vg_name_new;
@@ -90,7 +91,13 @@ int vgrename(int argc, char **argv)
/* Change the volume group name */
strcpy(vg_old->name, vg_name_new);
/* FIXME Should vg_write fix these implicitly? It has to check them. */
/* Prevent other commands from interleaving */
if (lock_lvm(0) != 0) {
log_error("error locking lvm");
return ECMD_FAILED;
}
/* FIXME Should vg_write fix these implicitly? It has to check them. */
list_iterate(pvh, &vg_old->pvs) {
strcpy(list_item(pvh, struct pv_list)->pv.vg_name,
vg_name_new);
@@ -109,13 +116,13 @@ int vgrename(int argc, char **argv)
if (rename(old_path, new_path)) {
log_error("Renaming %s to %s failed: %s",
old_path, new_path, strerror(errno));
return ECMD_FAILED;
goto finish;
}
/* store it on disks */
log_verbose("Writing out updated volume group");
if (!(fid->ops->vg_write(fid, vg_old))) {
return ECMD_FAILED;
goto finish;
}
/***********
@@ -127,8 +134,10 @@ int vgrename(int argc, char **argv)
vg_name_old, vg_name_new);
/* FIXME: Deallocations */
return 0;
ret = 0;
finish:
unlock_lvm(ret);
return ret;
}
/* FIXME: Moved into vg_write now */