diff --git a/daemons/clvmd/clvmd-cman.c b/daemons/clvmd/clvmd-cman.c index 751f4ddf4..a21515e63 100644 --- a/daemons/clvmd/clvmd-cman.c +++ b/daemons/clvmd/clvmd-cman.c @@ -337,7 +337,7 @@ static void get_members() } nodelist.max_members = count_nodes; nodelist.nodes = nodes; - + num_nodes = ioctl(cluster_sock, SIOCCLUSTER_GETMEMBERS, &nodelist); if (num_nodes <= 0) { perror("get node details"); @@ -441,6 +441,7 @@ int sync_lock(const char *resource, int mode, int flags, int *lockid) return -1; } + DEBUGLOG("sync_lock: '%s' mode:%d flags=%d\n", resource,mode,flags); /* Conversions need the lockid in the LKSB */ if (flags & LKF_CONVERT) lwait.lksb.sb_lkid = *lockid; @@ -466,6 +467,7 @@ int sync_lock(const char *resource, int mode, int flags, int *lockid) *lockid = lwait.lksb.sb_lkid; errno = lwait.lksb.sb_status; + DEBUGLOG("sync_lock: returning lkid %x\n", *lockid); if (lwait.lksb.sb_status) return -1; else @@ -477,6 +479,8 @@ int sync_unlock(const char *resource /* UNUSED */, int lockid) int status; struct lock_wait lwait; + DEBUGLOG("sync_unlock: '%s' lkid:%x\n", resource, lockid); + pthread_cond_init(&lwait.cond, NULL); pthread_mutex_init(&lwait.mutex, NULL); pthread_mutex_lock(&lwait.mutex); diff --git a/daemons/clvmd/clvmd-command.c b/daemons/clvmd/clvmd-command.c index db41fe3e8..cabeaf160 100644 --- a/daemons/clvmd/clvmd-command.c +++ b/daemons/clvmd/clvmd-command.c @@ -66,6 +66,7 @@ #include #include "list.h" +#include "hash.h" #include "locking.h" #include "log.h" #include "lvm-functions.h" @@ -135,6 +136,61 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen, } +static int lock_vg(struct local_client *client) +{ + struct hash_table *lock_hash; + struct clvm_header *header = + (struct clvm_header *) client->bits.localsock.cmd; + unsigned char lock_cmd; + unsigned char lock_flags; + char *args = header->node + strlen(header->node) + 1; + int lkid; + int status = 0; + char *lockname; + + /* Keep a track of VG locks in our own hash table. In current + practice there should only ever be more than two VGs locked + if a user tries to merge lots of them at once */ + if (client->bits.localsock.private) { + lock_hash = (struct hash_table *)client->bits.localsock.private; + } + else { + lock_hash = hash_create(3); + if (!lock_hash) + return ENOMEM; + client->bits.localsock.private = (void *)lock_hash; + } + + lock_cmd = args[0]; + lock_flags = args[1]; + lockname = &args[2]; + DEBUGLOG("doing PRE command LOCK_VG '%s' at %x (client=%p)\n", lockname, lock_cmd, client); + + if (lock_cmd == LCK_UNLOCK) { + + lkid = (int)(long)hash_lookup(lock_hash, lockname); + if (lkid == 0) + return EINVAL; + + status = sync_unlock(lockname, lkid); + if (status) + status = errno; + else + hash_remove(lock_hash, lockname); + } + else { + + status = sync_lock(lockname, (int)lock_cmd, (int)lock_flags, &lkid); + if (status) + status = errno; + else + hash_insert(lock_hash, lockname, (void *)lkid); + } + + return status; +} + + /* Pre-command is a good place to get locks that are needed only for the duration of the commands around the cluster (don't forget to free them in post-command), and to sanity check the command arguments */ @@ -156,22 +212,7 @@ int do_pre_command(struct local_client *client) break; case CLVMD_CMD_LOCK_VG: - lock_cmd = args[0]; - lock_flags = args[1]; - lockname = &args[2]; - DEBUGLOG("doing PRE command LOCK_VG %s at %x\n", lockname, - lock_cmd); - if (lock_cmd == LCK_UNLOCK) { - status = sync_unlock(lockname, (int) (long) client->bits.localsock.private); - if (status) - status = errno; - } else { - status = sync_lock(lockname, (int) lock_cmd, (int) lock_flags, &lockid); - if (status) - status = errno; - else - client->bits.localsock.private = (void *) lockid; - } + status = lock_vg(client); break; case CLVMD_CMD_LOCK_LV: @@ -204,6 +245,7 @@ int do_post_command(struct local_client *client) case CLVMD_CMD_TEST: status = sync_unlock("CLVMD_TEST", (int) (long) client->bits.localsock.private); + client->bits.localsock.private = 0; break; case CLVMD_CMD_LOCK_VG: @@ -219,3 +261,25 @@ int do_post_command(struct local_client *client) } return status; } + + +/* Called when the client is about to be deleted */ +void cmd_client_cleanup(struct local_client *client) +{ + if (client->bits.localsock.private) { + + struct hash_node *v; + struct hash_table *lock_hash = + (struct hash_table *)client->bits.localsock.private; + + hash_iterate(v, lock_hash) { + int lkid = (int)(long)hash_get_data(lock_hash, v); + + DEBUGLOG("cleanup: Unlocking lkid %x\n", lkid); + sync_unlock("DUMMY", lkid); + } + + hash_destroy(lock_hash); + client->bits.localsock.private = 0; + } +} diff --git a/daemons/clvmd/clvmd.c b/daemons/clvmd/clvmd.c index 8b5e5c833..cb936426c 100644 --- a/daemons/clvmd/clvmd.c +++ b/daemons/clvmd/clvmd.c @@ -303,6 +303,7 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf, newfd->bits.localsock.threadid = 0; newfd->bits.localsock.finished = 0; newfd->bits.localsock.pipe_client = NULL; + newfd->bits.localsock.private = NULL; newfd->bits.localsock.all_success = 1; DEBUGLOG("Got new connection on fd %d\n", newfd->fd); *new_client = newfd; @@ -496,6 +497,7 @@ static void main_loop(int local_sock, int cmd_timeout) lastfd->next = thisfd->next; free_fd = thisfd; thisfd = lastfd; + cmd_client_cleanup(free_fd); free(free_fd); break; } @@ -717,6 +719,7 @@ static int read_from_local_sock(struct local_client *thisfd) struct local_client *newfd; char csid[MAX_CSID_LEN]; struct clvm_header *inheader; + int status; inheader = (struct clvm_header *) buffer; @@ -863,8 +866,10 @@ static int read_from_local_sock(struct local_client *thisfd) /* Run the pre routine */ thisfd->bits.localsock.in_progress = TRUE; thisfd->bits.localsock.state = PRE_COMMAND; - pthread_create(&thisfd->bits.localsock.threadid, NULL, + DEBUGLOG("Creating pre&post thread\n"); + status = pthread_create(&thisfd->bits.localsock.threadid, NULL, pre_and_post_thread, thisfd); + DEBUGLOG("Created pre&post thread, state = %d\n", status); } return len; } diff --git a/daemons/clvmd/clvmd.h b/daemons/clvmd/clvmd.h index 46e53c4b0..50be3b588 100644 --- a/daemons/clvmd/clvmd.h +++ b/daemons/clvmd/clvmd.h @@ -111,7 +111,7 @@ extern int do_command(struct local_client *client, struct clvm_header *msg, /* Pre and post command routines are called only on the local node */ extern int do_pre_command(struct local_client *client); extern int do_post_command(struct local_client *client); - +extern void cmd_client_cleanup(struct local_client *client); extern int add_client(struct local_client *new_client); extern void clvmd_cluster_init_completed(void); diff --git a/daemons/clvmd/cnxman-socket.h b/daemons/clvmd/cnxman-socket.h index 08740280e..1aaa0bc1b 100644 --- a/daemons/clvmd/cnxman-socket.h +++ b/daemons/clvmd/cnxman-socket.h @@ -105,6 +105,7 @@ #define MSG_MULTICAST 0x080000 /* Message was sent to all nodes in the cluster */ #define MSG_ALLINT 0x100000 /* Send out of all interfaces */ +#define MSG_REPLYEXP 0x200000 /* Reply is expected */ typedef enum { NODESTATE_REMOTEMEMBER, NODESTATE_JOINING, NODESTATE_MEMBER, NODESTATE_DEAD } nodestate_t;