]> sourceware.org Git - lvm2.git/blame - tools/polldaemon.c
thin: tighten discard string conversions
[lvm2.git] / tools / polldaemon.c
CommitLineData
cb919290 1/*
67cdbd7e 2 * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
be684599 3 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
cb919290
AK
4 *
5 * This file is part of LVM2.
6 *
7 * This copyrighted material is made available to anyone wishing to use,
8 * modify, copy, or redistribute it subject to the terms and conditions
be684599 9 * of the GNU Lesser General Public License v.2.1.
cb919290 10 *
be684599 11 * You should have received a copy of the GNU Lesser General Public License
cb919290
AK
12 * along with this program; if not, write to the Free Software Foundation,
13 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 */
15
16#include "tools.h"
17#include "polldaemon.h"
94d4a90f 18#include "lvm2cmdline.h"
cb919290
AK
19#include <signal.h>
20#include <sys/wait.h>
21
08f1ddea 22static void _sigchld_handler(int sig __attribute__((unused)))
cb919290
AK
23{
24 while (wait4(-1, NULL, WNOHANG | WUNTRACED, NULL) > 0) ;
25}
26
94d4a90f
MS
27/*
28 * returns:
29 * -1 if the fork failed
30 * 0 if the parent
31 * 1 if the child
32 */
cb919290
AK
33static int _become_daemon(struct cmd_context *cmd)
34{
6f8bd07b
ZK
35 static const char devnull[] = "/dev/null";
36 int null_fd;
cb919290
AK
37 pid_t pid;
38 struct sigaction act = {
39 {_sigchld_handler},
40 .sa_flags = SA_NOCLDSTOP,
41 };
42
43 log_verbose("Forking background process");
44
45 sigaction(SIGCHLD, &act, NULL);
46
a8de2765 47 sync_local_dev_names(cmd); /* Flush ops and reset dm cookie */
ad50450a 48
cb919290
AK
49 if ((pid = fork()) == -1) {
50 log_error("fork failed: %s", strerror(errno));
94d4a90f 51 return -1;
cb919290
AK
52 }
53
54 /* Parent */
55 if (pid > 0)
56 return 0;
57
58 /* Child */
59 if (setsid() == -1)
60 log_error("Background process failed to setsid: %s",
61 strerror(errno));
cb919290 62
6f8bd07b
ZK
63 /* For poll debugging it's best to disable for compilation */
64#if 1
65 if ((null_fd = open(devnull, O_RDWR)) == -1) {
66 log_sys_error("open", devnull);
67 _exit(ECMD_FAILED);
68 }
69
6ddce3b6
ZK
70 if ((dup2(null_fd, STDIN_FILENO) < 0) || /* reopen stdin */
71 (dup2(null_fd, STDOUT_FILENO) < 0) || /* reopen stdout */
72 (dup2(null_fd, STDERR_FILENO) < 0)) { /* reopen stderr */
6f8bd07b
ZK
73 log_sys_error("dup2", "redirect");
74 (void) close(null_fd);
75 _exit(ECMD_FAILED);
76 }
cb919290 77
6f8bd07b
ZK
78 if (null_fd > STDERR_FILENO)
79 (void) close(null_fd);
80
81 init_verbose(VERBOSE_BASE_LEVEL);
82#endif
c9f27b1c 83 strncpy(*cmd->argv, "(lvm2)", strlen(*cmd->argv));
cb919290
AK
84
85 reset_locking();
de0ae6a1
ZK
86 if (!lvmcache_init())
87 /* FIXME Clean up properly here */
88 _exit(ECMD_FAILED);
cb919290
AK
89 dev_close_all();
90
91 return 1;
92}
93
42dd692b
AK
94progress_t poll_mirror_progress(struct cmd_context *cmd,
95 struct logical_volume *lv, const char *name,
96 struct daemon_parms *parms)
97{
8191fe4f 98 percent_t segment_percent = PERCENT_0, overall_percent = PERCENT_0;
42dd692b
AK
99 uint32_t event_nr = 0;
100
6ec8c522
JEB
101 if (!lv_is_mirrored(lv) ||
102 !lv_mirror_percent(cmd, lv, !parms->interval, &segment_percent,
8191fe4f
PR
103 &event_nr) ||
104 (segment_percent == PERCENT_INVALID)) {
42dd692b
AK
105 log_error("ABORTING: Mirror percentage check failed.");
106 return PROGRESS_CHECK_FAILED;
107 }
108
8191fe4f 109 overall_percent = copy_percent(lv);
42dd692b
AK
110 if (parms->progress_display)
111 log_print("%s: %s: %.1f%%", name, parms->progress_title,
8191fe4f 112 percent_to_float(overall_percent));
42dd692b
AK
113 else
114 log_verbose("%s: %s: %.1f%%", name, parms->progress_title,
8191fe4f 115 percent_to_float(overall_percent));
42dd692b 116
8191fe4f 117 if (segment_percent != PERCENT_100)
42dd692b
AK
118 return PROGRESS_UNFINISHED;
119
8191fe4f 120 if (overall_percent == PERCENT_100)
42dd692b
AK
121 return PROGRESS_FINISHED_ALL;
122
123 return PROGRESS_FINISHED_SEGMENT;
124}
125
724de279
AK
126static int _check_lv_status(struct cmd_context *cmd,
127 struct volume_group *vg,
128 struct logical_volume *lv,
129 const char *name, struct daemon_parms *parms,
130 int *finished)
cb919290 131{
2c44337b 132 struct dm_list *lvs_changed;
42dd692b 133 progress_t progress;
cb919290
AK
134
135 /* By default, caller should not retry */
136 *finished = 1;
137
138 if (parms->aborting) {
724de279 139 if (!(lvs_changed = lvs_using_lv(cmd, vg, lv))) {
cb919290
AK
140 log_error("Failed to generate list of copied LVs: "
141 "can't abort.");
142 return 0;
143 }
e9848871
MB
144 if (!parms->poll_fns->finish_copy(cmd, vg, lv, lvs_changed))
145 return_0;
146
147 return 1;
cb919290
AK
148 }
149
4b12fa13 150 progress = parms->poll_fns->poll_progress(cmd, lv, name, parms);
42dd692b
AK
151 if (progress == PROGRESS_CHECK_FAILED)
152 return_0;
cb919290 153
42dd692b 154 if (progress == PROGRESS_UNFINISHED) {
cb919290
AK
155 /* The only case the caller *should* try again later */
156 *finished = 0;
157 return 1;
158 }
159
724de279 160 if (!(lvs_changed = lvs_using_lv(cmd, vg, lv))) {
cb919290
AK
161 log_error("ABORTING: Failed to generate list of copied LVs");
162 return 0;
163 }
164
165 /* Finished? Or progress to next segment? */
42dd692b 166 if (progress == PROGRESS_FINISHED_ALL) {
724de279 167 if (!parms->poll_fns->finish_copy(cmd, vg, lv, lvs_changed))
45afc155 168 return_0;
cb919290 169 } else {
c9f27b1c
MS
170 if (parms->poll_fns->update_metadata &&
171 !parms->poll_fns->update_metadata(cmd, vg, lv, lvs_changed, 0)) {
cb919290 172 log_error("ABORTING: Segment progression failed.");
724de279 173 parms->poll_fns->finish_copy(cmd, vg, lv, lvs_changed);
cb919290
AK
174 return 0;
175 }
176 *finished = 0; /* Another segment */
177 }
178
179 return 1;
180}
181
43d99aab
MS
182static void _sleep_and_rescan_devices(struct daemon_parms *parms)
183{
184 /* FIXME Use alarm for regular intervals instead */
185 if (parms->interval && !parms->aborting) {
186 sleep(parms->interval);
187 /* Devices might have changed while we slept */
188 init_full_scan_done(0);
189 }
190}
191
724de279 192static int _wait_for_single_lv(struct cmd_context *cmd, const char *name, const char *uuid,
43d99aab 193 struct daemon_parms *parms)
cb919290
AK
194{
195 struct volume_group *vg;
724de279 196 struct logical_volume *lv;
cb919290
AK
197 int finished = 0;
198
724de279 199 /* Poll for completion */
cb919290 200 while (!finished) {
43d99aab
MS
201 if (parms->wait_before_testing)
202 _sleep_and_rescan_devices(parms);
cb919290
AK
203
204 /* Locks the (possibly renamed) VG again */
b8b3508c
DW
205 vg = parms->poll_fns->get_copy_vg(cmd, name, uuid);
206 if (vg_read_error(vg)) {
077a6755 207 release_vg(vg);
cb919290
AK
208 log_error("ABORTING: Can't reread VG for %s", name);
209 /* What more could we do here? */
210 return 0;
211 }
212
74863007
MB
213 lv = parms->poll_fns->get_copy_lv(cmd, vg, name, uuid, parms->lv_type);
214
215 if (!lv && parms->lv_type == PVMOVE) {
216 log_print("%s: no pvmove in progress - already finished or aborted.",
217 name);
077a6755 218 unlock_and_release_vg(cmd, vg, vg->name);
74863007
MB
219 return 1;
220 }
221
222 if (!lv) {
c9f27b1c 223 log_error("ABORTING: Can't find LV in %s for %s",
cb919290 224 vg->name, name);
077a6755 225 unlock_and_release_vg(cmd, vg, vg->name);
cb919290
AK
226 return 0;
227 }
228
724de279 229 if (!_check_lv_status(cmd, vg, lv, name, parms, &finished)) {
077a6755 230 unlock_and_release_vg(cmd, vg, vg->name);
45afc155 231 return_0;
cb919290
AK
232 }
233
077a6755 234 unlock_and_release_vg(cmd, vg, vg->name);
43d99aab
MS
235
236 /*
237 * FIXME Sleeping after testing, while preferred, also works around
238 * unreliable "finished" state checking in _percent_run. If the
239 * above _check_lv_status is deferred until after the first sleep it
240 * may be that a polldaemon will run without ever completing.
241 *
242 * This happens when one snapshot-merge polldaemon is racing with
243 * another (polling the same LV). The first to see the LV status
244 * reach the "finished" state will alter the LV that the other
245 * polldaemon(s) are polling. These other polldaemon(s) can then
246 * continue polling an LV that doesn't have a "status".
247 */
248 if (!parms->wait_before_testing)
249 _sleep_and_rescan_devices(parms);
cb919290
AK
250 }
251
252 return 1;
253}
254
255static int _poll_vg(struct cmd_context *cmd, const char *vgname,
13e8c7e4 256 struct volume_group *vg, void *handle)
cb919290
AK
257{
258 struct daemon_parms *parms = (struct daemon_parms *) handle;
259 struct lv_list *lvl;
724de279 260 struct logical_volume *lv;
cb919290
AK
261 const char *name;
262 int finished;
263
2c44337b 264 dm_list_iterate_items(lvl, &vg->lvs) {
724de279
AK
265 lv = lvl->lv;
266 if (!(lv->status & parms->lv_type))
cb919290 267 continue;
cf704d22
MB
268 name = parms->poll_fns->get_copy_name_from_lv(lv);
269 if (!name && !parms->aborting)
cb919290 270 continue;
cf704d22 271
67cdbd7e 272 /* FIXME Need to do the activation from _set_up_pvmove here
cb919290 273 * if it's not running and we're not aborting */
724de279
AK
274 if (_check_lv_status(cmd, vg, lv, name, parms, &finished) &&
275 !finished)
cb919290
AK
276 parms->outstanding_count++;
277 }
278
279 return ECMD_PROCESSED;
280
281}
282
283static void _poll_for_all_vgs(struct cmd_context *cmd,
284 struct daemon_parms *parms)
285{
286 while (1) {
287 parms->outstanding_count = 0;
13e8c7e4 288 process_each_vg(cmd, 0, NULL, READ_FOR_UPDATE, parms, _poll_vg);
cb919290
AK
289 if (!parms->outstanding_count)
290 break;
291 sleep(parms->interval);
292 }
293}
294
94d4a90f
MS
295/*
296 * Only allow *one* return from poll_daemon() (the parent).
297 * If there is a child it must exit (ignoring the memory leak messages).
298 * - 'background' is advisory so a child polldaemon may not be used even
299 * if it was requested.
300 */
31f55a07
MB
301int poll_daemon(struct cmd_context *cmd, const char *name, const char *uuid,
302 unsigned background,
2ef5b7cc 303 uint64_t lv_type, struct poll_functions *poll_fns,
ba0c495d 304 const char *progress_title)
cb919290
AK
305{
306 struct daemon_parms parms;
94d4a90f
MS
307 int daemon_mode = 0;
308 int ret = ECMD_PROCESSED;
43d99aab 309 sign_t interval_sign;
cb919290 310
a8fb89ad 311 parms.aborting = arg_is_set(cmd, abort_ARG);
cb919290 312 parms.background = background;
fbf6b89a 313 interval_sign = arg_sign_value(cmd, interval_ARG, SIGN_NONE);
43d99aab
MS
314 if (interval_sign == SIGN_MINUS)
315 log_error("Argument to --interval cannot be negative");
59131572
AK
316 parms.interval = arg_uint_value(cmd, interval_ARG,
317 find_config_tree_int(cmd, "activation/polling_interval",
318 DEFAULT_INTERVAL));
43d99aab 319 parms.wait_before_testing = (interval_sign == SIGN_PLUS);
cb919290 320 parms.progress_display = 1;
ba0c495d 321 parms.progress_title = progress_title;
cb919290
AK
322 parms.lv_type = lv_type;
323 parms.poll_fns = poll_fns;
324
325 if (parms.interval && !parms.aborting)
43d99aab
MS
326 log_verbose("Checking progress %s waiting every %u seconds",
327 (parms.wait_before_testing ? "after" : "before"),
cb919290
AK
328 parms.interval);
329
330 if (!parms.interval) {
331 parms.progress_display = 0;
332
333 /* FIXME Disabled multiple-copy wait_event */
334 if (!name)
59131572
AK
335 parms.interval = find_config_tree_int(cmd, "activation/polling_interval",
336 DEFAULT_INTERVAL);
cb919290
AK
337 }
338
339 if (parms.background) {
94d4a90f
MS
340 daemon_mode = _become_daemon(cmd);
341 if (daemon_mode == 0)
342 return ECMD_PROCESSED; /* Parent */
343 else if (daemon_mode == 1)
344 parms.progress_display = 0; /* Child */
cb919290
AK
345 /* FIXME Use wait_event (i.e. interval = 0) and */
346 /* fork one daemon per copy? */
347 }
348
724de279
AK
349 /*
350 * Process one specific task or all incomplete tasks?
351 */
cb919290 352 if (name) {
724de279 353 if (!_wait_for_single_lv(cmd, name, uuid, &parms)) {
651ff9b3 354 stack;
94d4a90f 355 ret = ECMD_FAILED;
651ff9b3 356 }
cb919290
AK
357 } else
358 _poll_for_all_vgs(cmd, &parms);
359
94d4a90f
MS
360 if (parms.background && daemon_mode == 1) {
361 /*
362 * child was successfully forked:
363 * background polldaemon must not return to the caller
364 * because it will redundantly continue performing the
365 * caller's task (that the parent already performed)
366 */
367 /* FIXME Attempt proper cleanup */
368 _exit(lvm_return_code(ret));
369 }
370
371 return ret;
cb919290 372}
This page took 0.114089 seconds and 5 git commands to generate.