Home | History | Annotate | Line # | Download | only in clvmd
      1 /*	$NetBSD: clvmd-command.c,v 1.1.1.2 2009/12/02 00:27:06 haad Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
      5  * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
      6  *
      7  * This file is part of LVM2.
      8  *
      9  * This copyrighted material is made available to anyone wishing to use,
     10  * modify, copy, or redistribute it subject to the terms and conditions
     11  * of the GNU General Public License v.2.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program; if not, write to the Free Software Foundation,
     15  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     16  */
     17 
     18 /*
     19 
     20   CLVMD Cluster LVM daemon command processor.
     21 
     22   To add commands to the daemon simply add a processor in do_command and return
     23   and messages back in buf and the length in *retlen. The initial value of
     24   buflen is the maximum size of the buffer. if buf is not large enough then it
     25   may be reallocated by the functions in here to a suitable size bearing in
     26   mind that anything larger than the passed-in size will have to be returned
     27   using the system LV and so performance will suffer.
     28 
     29   The status return will be negated and passed back to the originating node.
     30 
     31   pre- and post- command routines are called only on the local node. The
     32   purpose is primarily to get and release locks, though the pre- routine should
     33   also do any other local setups required by the command (if any) and can
     34   return a failure code that prevents the command from being distributed around
     35   the cluster
     36 
     37   The pre- and post- routines are run in their own thread so can block as long
     38   they like, do_command is run in the main clvmd thread so should not block for
     39   too long. If the pre-command returns an error code (!=0) then the command
     40   will not be propogated around the cluster but the post-command WILL be called
     41 
     42   Also note that the pre and post routine are *always* called on the local
     43   node, even if the command to be executed was only requested to run on a
     44   remote node. It may peek inside the client structure to check the status of
     45   the command.
     46 
     47   The clients of the daemon must, naturally, understand the return messages and
     48   codes.
     49 
     50   Routines in here may only READ the values in the client structure passed in
     51   apart from client->private which they are free to do what they like with.
     52 
     53 */
     54 
     55 #define _GNU_SOURCE
     56 #define _FILE_OFFSET_BITS 64
     57 
     58 #include <configure.h>
     59 #include <pthread.h>
     60 #include <sys/types.h>
     61 #include <sys/utsname.h>
     62 #include <sys/ioctl.h>
     63 #include <sys/socket.h>
     64 #include <sys/stat.h>
     65 #include <stdio.h>
     66 #include <stdlib.h>
     67 #include <stdint.h>
     68 #include <fcntl.h>
     69 #include <string.h>
     70 #include <stddef.h>
     71 #include <unistd.h>
     72 #include <errno.h>
     73 #include <libdevmapper.h>
     74 #include <libdlm.h>
     75 
     76 #include "locking.h"
     77 #include "lvm-logging.h"
     78 #include "lvm-functions.h"
     79 #include "clvmd-comms.h"
     80 #include "clvm.h"
     81 #include "clvmd.h"
     82 
     83 extern debug_t debug;
     84 extern struct cluster_ops *clops;
     85 
     86 /* This is where all the real work happens:
     87    NOTE: client will be NULL when this is executed on a remote node */
     88 int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
     89 	       char **buf, int buflen, int *retlen)
     90 {
     91 	char *args = msg->node + strlen(msg->node) + 1;
     92 	int arglen = msglen - sizeof(struct clvm_header) - strlen(msg->node);
     93 	int status = 0;
     94 	char *lockname;
     95 	const char *locktype;
     96 	struct utsname nodeinfo;
     97 	unsigned char lock_cmd;
     98 	unsigned char lock_flags;
     99 
    100 	/* Do the command */
    101 	switch (msg->cmd) {
    102 		/* Just a test message */
    103 	case CLVMD_CMD_TEST:
    104 		if (arglen > buflen) {
    105 			char *new_buf;
    106 			buflen = arglen + 200;
    107 			new_buf = realloc(*buf, buflen);
    108 			if (new_buf == NULL) {
    109 				status = errno;
    110 				free (*buf);
    111 			}
    112 			*buf = new_buf;
    113 		}
    114 		if (*buf) {
    115 			uname(&nodeinfo);
    116 			*retlen = 1 + snprintf(*buf, buflen,
    117 					       "TEST from %s: %s v%s",
    118 					       nodeinfo.nodename, args,
    119 					       nodeinfo.release);
    120 		}
    121 		break;
    122 
    123 	case CLVMD_CMD_LOCK_VG:
    124 		lockname = &args[2];
    125 		/* Check to see if the VG is in use by LVM1 */
    126 		status = do_check_lvm1(lockname);
    127 		/* P_#global causes a full cache refresh */
    128 		if (!strcmp(lockname, "P_" VG_GLOBAL))
    129 			do_refresh_cache();
    130 		else
    131 			drop_metadata(lockname + 2);
    132 
    133 		break;
    134 
    135 	case CLVMD_CMD_LOCK_LV:
    136 		/* This is the biggie */
    137 		lock_cmd = args[0] & 0x3F;
    138 		lock_flags = args[1];
    139 		lockname = &args[2];
    140 		status = do_lock_lv(lock_cmd, lock_flags, lockname);
    141 		/* Replace EIO with something less scary */
    142 		if (status == EIO) {
    143 			*retlen =
    144 			    1 + snprintf(*buf, buflen, "%s",
    145 					 get_last_lvm_error());
    146 			return EIO;
    147 		}
    148 		break;
    149 
    150 	case CLVMD_CMD_LOCK_QUERY:
    151 		lockname = &args[2];
    152 		if (buflen < 3)
    153 			return EIO;
    154 		if ((locktype = do_lock_query(lockname)))
    155 			*retlen = 1 + snprintf(*buf, buflen, "%s", locktype);
    156 		break;
    157 
    158 	case CLVMD_CMD_REFRESH:
    159 		do_refresh_cache();
    160 		break;
    161 
    162 	case CLVMD_CMD_SET_DEBUG:
    163 		debug = args[0];
    164 		break;
    165 
    166 	case CLVMD_CMD_GET_CLUSTERNAME:
    167 		status = clops->get_cluster_name(*buf, buflen);
    168 		if (!status)
    169 			*retlen = strlen(*buf)+1;
    170 		break;
    171 
    172 	case CLVMD_CMD_VG_BACKUP:
    173 		/*
    174 		 * Do not run backup on local node, caller should do that.
    175 		 */
    176 		if (!client)
    177 			lvm_do_backup(&args[2]);
    178 		break;
    179 
    180 	default:
    181 		/* Won't get here because command is validated in pre_command */
    182 		break;
    183 	}
    184 
    185 	/* Check the status of the command and return the error text */
    186 	if (status) {
    187 		*retlen = 1 + snprintf(*buf, buflen, "%s", strerror(status));
    188 	}
    189 
    190 	return status;
    191 
    192 }
    193 
    194 static int lock_vg(struct local_client *client)
    195 {
    196     struct dm_hash_table *lock_hash;
    197     struct clvm_header *header =
    198 	(struct clvm_header *) client->bits.localsock.cmd;
    199     unsigned char lock_cmd;
    200     unsigned char lock_flags;
    201     char *args = header->node + strlen(header->node) + 1;
    202     int lkid;
    203     int status = 0;
    204     char *lockname;
    205 
    206     /* Keep a track of VG locks in our own hash table. In current
    207        practice there should only ever be more than two VGs locked
    208        if a user tries to merge lots of them at once */
    209     if (client->bits.localsock.private) {
    210 	lock_hash = (struct dm_hash_table *)client->bits.localsock.private;
    211     }
    212     else {
    213 	lock_hash = dm_hash_create(3);
    214 	if (!lock_hash)
    215 	    return ENOMEM;
    216 	client->bits.localsock.private = (void *)lock_hash;
    217     }
    218 
    219     lock_cmd = args[0] & 0x3F;
    220     lock_flags = args[1];
    221     lockname = &args[2];
    222     DEBUGLOG("doing PRE command LOCK_VG '%s' at %x (client=%p)\n", lockname, lock_cmd, client);
    223 
    224     if (lock_cmd == LCK_UNLOCK) {
    225 
    226 	lkid = (int)(long)dm_hash_lookup(lock_hash, lockname);
    227 	if (lkid == 0)
    228 	    return EINVAL;
    229 
    230 	status = sync_unlock(lockname, lkid);
    231 	if (status)
    232 	    status = errno;
    233 	else
    234 	    dm_hash_remove(lock_hash, lockname);
    235     }
    236     else {
    237 	/* Read locks need to be PR; other modes get passed through */
    238 	if ((lock_cmd & LCK_TYPE_MASK) == LCK_READ) {
    239 	    lock_cmd &= ~LCK_TYPE_MASK;
    240 	    lock_cmd |= LCK_PREAD;
    241 	}
    242 	status = sync_lock(lockname, (int)lock_cmd, (lock_flags & LCK_NONBLOCK) ? LKF_NOQUEUE : 0, &lkid);
    243 	if (status)
    244 	    status = errno;
    245 	else
    246 	    dm_hash_insert(lock_hash, lockname, (void *)(long)lkid);
    247     }
    248 
    249     return status;
    250 }
    251 
    252 
    253 /* Pre-command is a good place to get locks that are needed only for the duration
    254    of the commands around the cluster (don't forget to free them in post-command),
    255    and to sanity check the command arguments */
    256 int do_pre_command(struct local_client *client)
    257 {
    258 	struct clvm_header *header =
    259 	    (struct clvm_header *) client->bits.localsock.cmd;
    260 	unsigned char lock_cmd;
    261 	unsigned char lock_flags;
    262 	char *args = header->node + strlen(header->node) + 1;
    263 	int lockid;
    264 	int status = 0;
    265 	char *lockname;
    266 
    267 	switch (header->cmd) {
    268 	case CLVMD_CMD_TEST:
    269 		status = sync_lock("CLVMD_TEST", LKM_EXMODE, 0, &lockid);
    270 		client->bits.localsock.private = (void *)(long)lockid;
    271 		break;
    272 
    273 	case CLVMD_CMD_LOCK_VG:
    274 		lockname = &args[2];
    275 		/* We take out a real lock unless LCK_CACHE was set */
    276 		if (!strncmp(lockname, "V_", 2) ||
    277 		    !strncmp(lockname, "P_#", 3))
    278 			status = lock_vg(client);
    279 		break;
    280 
    281 	case CLVMD_CMD_LOCK_LV:
    282 		lock_cmd = args[0];
    283 		lock_flags = args[1];
    284 		lockname = &args[2];
    285 		status = pre_lock_lv(lock_cmd, lock_flags, lockname);
    286 		break;
    287 
    288 	case CLVMD_CMD_REFRESH:
    289 	case CLVMD_CMD_GET_CLUSTERNAME:
    290 	case CLVMD_CMD_SET_DEBUG:
    291 	case CLVMD_CMD_VG_BACKUP:
    292 	case CLVMD_CMD_LOCK_QUERY:
    293 		break;
    294 
    295 	default:
    296 		log_error("Unknown command %d received\n", header->cmd);
    297 		status = EINVAL;
    298 	}
    299 	return status;
    300 }
    301 
    302 /* Note that the post-command routine is called even if the pre-command or the real command
    303    failed */
    304 int do_post_command(struct local_client *client)
    305 {
    306 	struct clvm_header *header =
    307 	    (struct clvm_header *) client->bits.localsock.cmd;
    308 	int status = 0;
    309 	unsigned char lock_cmd;
    310 	unsigned char lock_flags;
    311 	char *args = header->node + strlen(header->node) + 1;
    312 	char *lockname;
    313 
    314 	switch (header->cmd) {
    315 	case CLVMD_CMD_TEST:
    316 		status =
    317 		    sync_unlock("CLVMD_TEST", (int) (long) client->bits.localsock.private);
    318 		client->bits.localsock.private = 0;
    319 		break;
    320 
    321 	case CLVMD_CMD_LOCK_VG:
    322 	case CLVMD_CMD_VG_BACKUP:
    323 	case CLVMD_CMD_LOCK_QUERY:
    324 		/* Nothing to do here */
    325 		break;
    326 
    327 	case CLVMD_CMD_LOCK_LV:
    328 		lock_cmd = args[0];
    329 		lock_flags = args[1];
    330 		lockname = &args[2];
    331 		status = post_lock_lv(lock_cmd, lock_flags, lockname);
    332 		break;
    333 	}
    334 	return status;
    335 }
    336 
    337 
    338 /* Called when the client is about to be deleted */
    339 void cmd_client_cleanup(struct local_client *client)
    340 {
    341     if (client->bits.localsock.private) {
    342 
    343 	struct dm_hash_node *v;
    344 	struct dm_hash_table *lock_hash =
    345 	    (struct dm_hash_table *)client->bits.localsock.private;
    346 
    347 	dm_hash_iterate(v, lock_hash) {
    348 		int lkid = (int)(long)dm_hash_get_data(lock_hash, v);
    349 		char *lockname = dm_hash_get_key(lock_hash, v);
    350 
    351 		DEBUGLOG("cleanup: Unlocking lock %s %x\n", lockname, lkid);
    352 		sync_unlock(lockname, lkid);
    353 	}
    354 
    355 	dm_hash_destroy(lock_hash);
    356 	client->bits.localsock.private = 0;
    357     }
    358 }
    359