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 */
do_command(struct local_client * client,struct clvm_header * msg,int msglen,char ** buf,int buflen,int * retlen)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 
lock_vg(struct local_client * client)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 */
do_pre_command(struct local_client * client)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 */
do_post_command(struct local_client * client)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 */
cmd_client_cleanup(struct local_client * client)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