Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / gpl2 / lvm2 / dist / daemons / clvmd / clvmd-command.c
bloba0fb0d1534f39ddb46d3c3a45052cc5968becfb4
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
7 * This file is part of LVM2.
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.
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
20 CLVMD Cluster LVM daemon command processor.
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.
29 The status return will be negated and passed back to the originating node.
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
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
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.
47 The clients of the daemon must, naturally, understand the return messages and
48 codes.
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.
55 #define _GNU_SOURCE
56 #define _FILE_OFFSET_BITS 64
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>
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"
83 extern debug_t debug;
84 extern struct cluster_ops *clops;
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)
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;
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);
112 *buf = new_buf;
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);
121 break;
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);
133 break;
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;
148 break;
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;
158 case CLVMD_CMD_REFRESH:
159 do_refresh_cache();
160 break;
162 case CLVMD_CMD_SET_DEBUG:
163 debug = args[0];
164 break;
166 case CLVMD_CMD_GET_CLUSTERNAME:
167 status = clops->get_cluster_name(*buf, buflen);
168 if (!status)
169 *retlen = strlen(*buf)+1;
170 break;
172 case CLVMD_CMD_VG_BACKUP:
174 * Do not run backup on local node, caller should do that.
176 if (!client)
177 lvm_do_backup(&args[2]);
178 break;
180 default:
181 /* Won't get here because command is validated in pre_command */
182 break;
185 /* Check the status of the command and return the error text */
186 if (status) {
187 *retlen = 1 + snprintf(*buf, buflen, "%s", strerror(status));
190 return status;
194 static int lock_vg(struct local_client *client)
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;
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;
212 else {
213 lock_hash = dm_hash_create(3);
214 if (!lock_hash)
215 return ENOMEM;
216 client->bits.localsock.private = (void *)lock_hash;
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);
224 if (lock_cmd == LCK_UNLOCK) {
226 lkid = (int)(long)dm_hash_lookup(lock_hash, lockname);
227 if (lkid == 0)
228 return EINVAL;
230 status = sync_unlock(lockname, lkid);
231 if (status)
232 status = errno;
233 else
234 dm_hash_remove(lock_hash, lockname);
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;
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);
249 return status;
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)
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;
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;
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;
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;
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;
295 default:
296 log_error("Unknown command %d received\n", header->cmd);
297 status = EINVAL;
299 return status;
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)
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;
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;
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;
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;
334 return status;
338 /* Called when the client is about to be deleted */
339 void cmd_client_cleanup(struct local_client *client)
341 if (client->bits.localsock.private) {
343 struct dm_hash_node *v;
344 struct dm_hash_table *lock_hash =
345 (struct dm_hash_table *)client->bits.localsock.private;
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);
351 DEBUGLOG("cleanup: Unlocking lock %s %x\n", lockname, lkid);
352 sync_unlock(lockname, lkid);
355 dm_hash_destroy(lock_hash);
356 client->bits.localsock.private = 0;