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