2 * Copyright (C) 2005-2010 Red Hat, Inc. All rights reserved.
4 * This file is part of LVM2.
6 * This copyrighted material is made available to anyone wishing to use,
7 * modify, copy, or redistribute it subject to the terms and conditions
8 * of the GNU Lesser General Public License v.2.1.
10 * You should have received a copy of the GNU Lesser General Public License
11 * along with this program; if not, write to the Free Software Foundation,
12 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "libdevmapper-event.h"
20 #include "dmeventd_lvm.h"
22 #include <syslog.h> /* FIXME Replace syslog with multilog */
23 /* FIXME Missing openlog? */
24 /* FIXME Replace most syslogs with log_error() style messages and add complete context. */
25 /* FIXME Reformat to 80 char lines. */
31 static int _process_status_code(const char status_code, const char *dev_name,
32 const char *dev_type, int r)
35 * A => Alive - No failures
36 * D => Dead - A write failure occurred leaving mirror out-of-sync
38 * S => Sync - A sychronization failure occurred, mirror out-of-sync
39 * R => Read - A read failure occurred, mirror data unaffected
40 * U => Unclassified failure (bug)
42 if (status_code == 'F') {
43 syslog(LOG_ERR, "%s device %s flush failed.",
46 } else if (status_code == 'S')
47 syslog(LOG_ERR, "%s device %s sync failed.",
49 else if (status_code == 'R')
50 syslog(LOG_ERR, "%s device %s read failed.",
52 else if (status_code != 'A') {
53 syslog(LOG_ERR, "%s device %s has failed (%c).",
54 dev_type, dev_name, status_code);
61 static int _get_mirror_event(char *params)
69 int log_argc, num_devs;
72 * dm core parms: 0 409600 mirror
73 * Mirror core parms: 2 253:4 253:5 400/400
74 * New-style failure params: 1 AA
75 * New-style log params: 3 cluster 253:3 A
80 /* number of devices */
81 if (!dm_split_words(params, 1, 0, &p))
84 if (!(num_devs = atoi(p)))
88 /* devices names + "400/400" + "1 AA" + 1 or 3 log parms + NULL */
89 args = dm_malloc((num_devs + 7) * sizeof(char *));
90 if (!args || dm_split_words(p, num_devs + 7, 0, args) < num_devs + 5)
93 dev_status_str = args[2 + num_devs];
94 log_argc = atoi(args[3 + num_devs]);
95 log_status_str = args[3 + num_devs + log_argc];
96 sync_str = args[num_devs];
98 /* Check for bad mirror devices */
99 for (i = 0; i < num_devs; i++)
100 r = _process_status_code(dev_status_str[i], args[i],
101 i ? "Secondary mirror" : "Primary mirror", r);
103 /* Check for bad disk log device */
105 r = _process_status_code(log_status_str[0],
106 args[2 + num_devs + log_argc],
112 p = strstr(sync_str, "/");
115 if (strcmp(sync_str, p+1))
127 syslog(LOG_ERR, "Unable to parse mirror status string.");
131 static int _remove_failed_devices(const char *device)
134 #define CMD_SIZE 256 /* FIXME Use system restriction */
135 char cmd_str[CMD_SIZE];
136 char *vg = NULL, *lv = NULL, *layer = NULL;
138 if (strlen(device) > 200) /* FIXME Use real restriction */
139 return -ENAMETOOLONG; /* FIXME These return code distinctions are not used so remove them! */
141 if (!dm_split_lvm_name(dmeventd_lvm2_pool(), device, &vg, &lv, &layer)) {
142 syslog(LOG_ERR, "Unable to determine VG name from %s.",
144 return -ENOMEM; /* FIXME Replace with generic error return - reason for failure has already got logged */
147 /* strip off the mirror component designations */
148 layer = strstr(lv, "_mlog");
152 /* FIXME Is any sanity-checking required on %s? */
153 if (CMD_SIZE <= snprintf(cmd_str, CMD_SIZE, "lvconvert --config devices{ignore_suspended_devices=1} --repair --use-policies %s/%s", vg, lv)) {
154 /* this error should be caught above, but doesn't hurt to check again */
155 syslog(LOG_ERR, "Unable to form LVM command: Device name too long.");
156 return -ENAMETOOLONG; /* FIXME Replace with generic error return - reason for failure has already got logged */
159 r = dmeventd_lvm2_run(cmd_str);
161 syslog(LOG_INFO, "Repair of mirrored LV %s/%s %s.", vg, lv,
162 (r == ECMD_PROCESSED) ? "finished successfully" : "failed");
164 return (r == ECMD_PROCESSED) ? 0 : -1;
167 void process_event(struct dm_task *dmt,
168 enum dm_event_mask event __attribute__((unused)),
169 void **unused __attribute__((unused)))
172 uint64_t start, length;
173 char *target_type = NULL;
175 const char *device = dm_task_get_name(dmt);
177 dmeventd_lvm2_lock();
180 next = dm_get_next_target(dmt, next, &start, &length,
181 &target_type, ¶ms);
184 syslog(LOG_INFO, "%s mapping lost.", device);
188 if (strcmp(target_type, "mirror")) {
189 syslog(LOG_INFO, "%s has unmirrored portion.", device);
193 switch(_get_mirror_event(params)) {
195 /* FIXME: all we really know is that this
196 _part_ of the device is in sync
197 Also, this is not an error
199 syslog(LOG_NOTICE, "%s is now in-sync.", device);
202 syslog(LOG_ERR, "Device failure in %s.", device);
203 if (_remove_failed_devices(device))
204 /* FIXME Why are all the error return codes unused? Get rid of them? */
205 syslog(LOG_ERR, "Failed to remove faulty devices in %s.",
207 /* Should check before warning user that device is now linear
209 syslog(LOG_NOTICE, "%s is now a linear device.\n",
216 /* FIXME Provide value then! */
217 syslog(LOG_INFO, "Unknown event received.");
221 dmeventd_lvm2_unlock();
224 int register_device(const char *device,
225 const char *uuid __attribute__((unused)),
226 int major __attribute__((unused)),
227 int minor __attribute__((unused)),
228 void **unused __attribute__((unused)))
230 int r = dmeventd_lvm2_init();
231 syslog(LOG_INFO, "Monitoring mirror device %s for events.", device);
235 int unregister_device(const char *device,
236 const char *uuid __attribute__((unused)),
237 int major __attribute__((unused)),
238 int minor __attribute__((unused)),
239 void **unused __attribute__((unused)))
241 syslog(LOG_INFO, "No longer monitoring mirror device %s for events.",
243 dmeventd_lvm2_exit();