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