mirror of
git://sourceware.org/git/lvm2.git
synced 2025-09-24 21:44:22 +03:00
Compare commits
24 Commits
v1_01_01
...
CLUSTER_TA
Author | SHA1 | Date | |
---|---|---|---|
|
cbe3e5991b | ||
|
3335b34c44 | ||
|
6ffc854f9c | ||
|
cbe47da378 | ||
|
dd34a165a1 | ||
|
b2a6905722 | ||
|
3af6e3b294 | ||
|
43a6ba01b9 | ||
|
74646b92fb | ||
|
09453f276f | ||
|
2ddd6ebf79 | ||
|
4da649182f | ||
|
fb38dc166f | ||
|
3213274526 | ||
|
010c1715c4 | ||
|
67a5321134 | ||
|
b590ecf83a | ||
|
cc296900ae | ||
|
89d9ee62d7 | ||
|
4cc7c16037 | ||
|
8032fb64cd | ||
|
75ef8629d5 | ||
|
7a6d29f5d2 | ||
|
1c1770003f |
@@ -20,3 +20,4 @@
|
||||
../lib/mm/xlate.h
|
||||
../lib/regex/matcher.h
|
||||
../lib/uuid/uuid.h
|
||||
../lib/cmgr/cmgr.h
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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
46
lib/cmgr/clvm.h
Normal 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
874
lib/cmgr/cmgr.c
Normal 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
52
lib/cmgr/cmgr.h
Normal 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 */
|
17
make.tmpl.in
17
make.tmpl.in
@@ -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)
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -44,6 +44,7 @@
|
||||
#include "format1.h"
|
||||
#include "toollib.h"
|
||||
#include "activate.h"
|
||||
#include "cmgr.h"
|
||||
|
||||
#define CMD_LEN 256
|
||||
#define MAX_ARGS 64
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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? */
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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 */
|
||||
|
Reference in New Issue
Block a user