1*7c604eeaShaad /* $NetBSD: polldaemon.c,v 1.1.1.2 2009/12/02 00:25:53 haad Exp $ */
256a34939Shaad
356a34939Shaad /*
456a34939Shaad * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
556a34939Shaad * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
656a34939Shaad *
756a34939Shaad * This file is part of LVM2.
856a34939Shaad *
956a34939Shaad * This copyrighted material is made available to anyone wishing to use,
1056a34939Shaad * modify, copy, or redistribute it subject to the terms and conditions
1156a34939Shaad * of the GNU Lesser General Public License v.2.1.
1256a34939Shaad *
1356a34939Shaad * You should have received a copy of the GNU Lesser General Public License
1456a34939Shaad * along with this program; if not, write to the Free Software Foundation,
1556a34939Shaad * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1656a34939Shaad */
1756a34939Shaad
1856a34939Shaad #include "tools.h"
1956a34939Shaad #include "polldaemon.h"
2056a34939Shaad #include <signal.h>
2156a34939Shaad #include <sys/wait.h>
2256a34939Shaad
_sigchld_handler(int sig __attribute ((unused)))2356a34939Shaad static void _sigchld_handler(int sig __attribute((unused)))
2456a34939Shaad {
2556a34939Shaad while (wait4(-1, NULL, WNOHANG | WUNTRACED, NULL) > 0) ;
2656a34939Shaad }
2756a34939Shaad
_become_daemon(struct cmd_context * cmd)2856a34939Shaad static int _become_daemon(struct cmd_context *cmd)
2956a34939Shaad {
3056a34939Shaad pid_t pid;
3156a34939Shaad struct sigaction act = {
3256a34939Shaad {_sigchld_handler},
3356a34939Shaad .sa_flags = SA_NOCLDSTOP,
3456a34939Shaad };
3556a34939Shaad
3656a34939Shaad log_verbose("Forking background process");
3756a34939Shaad
3856a34939Shaad sigaction(SIGCHLD, &act, NULL);
3956a34939Shaad
4056a34939Shaad if ((pid = fork()) == -1) {
4156a34939Shaad log_error("fork failed: %s", strerror(errno));
4256a34939Shaad return 1;
4356a34939Shaad }
4456a34939Shaad
4556a34939Shaad /* Parent */
4656a34939Shaad if (pid > 0)
4756a34939Shaad return 0;
4856a34939Shaad
4956a34939Shaad /* Child */
5056a34939Shaad if (setsid() == -1)
5156a34939Shaad log_error("Background process failed to setsid: %s",
5256a34939Shaad strerror(errno));
5356a34939Shaad init_verbose(VERBOSE_BASE_LEVEL);
5456a34939Shaad
5556a34939Shaad close(STDIN_FILENO);
5656a34939Shaad close(STDOUT_FILENO);
5756a34939Shaad close(STDERR_FILENO);
5856a34939Shaad
5956a34939Shaad strncpy(*cmd->argv, "(lvm2copyd)", strlen(*cmd->argv));
6056a34939Shaad
6156a34939Shaad reset_locking();
62*7c604eeaShaad lvmcache_init();
6356a34939Shaad dev_close_all();
6456a34939Shaad
6556a34939Shaad return 1;
6656a34939Shaad }
6756a34939Shaad
poll_mirror_progress(struct cmd_context * cmd,struct logical_volume * lv,const char * name,struct daemon_parms * parms)68*7c604eeaShaad progress_t poll_mirror_progress(struct cmd_context *cmd,
69*7c604eeaShaad struct logical_volume *lv, const char *name,
70*7c604eeaShaad struct daemon_parms *parms)
7156a34939Shaad {
7256a34939Shaad float segment_percent = 0.0, overall_percent = 0.0;
73*7c604eeaShaad percent_range_t percent_range, overall_percent_range;
7456a34939Shaad uint32_t event_nr = 0;
7556a34939Shaad
76*7c604eeaShaad if (!lv_mirror_percent(cmd, lv, !parms->interval, &segment_percent,
77*7c604eeaShaad &percent_range, &event_nr) ||
78*7c604eeaShaad (percent_range == PERCENT_INVALID)) {
7956a34939Shaad log_error("ABORTING: Mirror percentage check failed.");
80*7c604eeaShaad return PROGRESS_CHECK_FAILED;
8156a34939Shaad }
8256a34939Shaad
83*7c604eeaShaad overall_percent = copy_percent(lv, &overall_percent_range);
8456a34939Shaad if (parms->progress_display)
8556a34939Shaad log_print("%s: %s: %.1f%%", name, parms->progress_title,
8656a34939Shaad overall_percent);
8756a34939Shaad else
8856a34939Shaad log_verbose("%s: %s: %.1f%%", name, parms->progress_title,
8956a34939Shaad overall_percent);
9056a34939Shaad
91*7c604eeaShaad if (percent_range != PERCENT_100)
92*7c604eeaShaad return PROGRESS_UNFINISHED;
93*7c604eeaShaad
94*7c604eeaShaad if (overall_percent_range == PERCENT_100)
95*7c604eeaShaad return PROGRESS_FINISHED_ALL;
96*7c604eeaShaad
97*7c604eeaShaad return PROGRESS_FINISHED_SEGMENT;
98*7c604eeaShaad }
99*7c604eeaShaad
_check_lv_status(struct cmd_context * cmd,struct volume_group * vg,struct logical_volume * lv,const char * name,struct daemon_parms * parms,int * finished)100*7c604eeaShaad static int _check_lv_status(struct cmd_context *cmd,
101*7c604eeaShaad struct volume_group *vg,
102*7c604eeaShaad struct logical_volume *lv,
103*7c604eeaShaad const char *name, struct daemon_parms *parms,
104*7c604eeaShaad int *finished)
105*7c604eeaShaad {
106*7c604eeaShaad struct dm_list *lvs_changed;
107*7c604eeaShaad progress_t progress;
108*7c604eeaShaad
109*7c604eeaShaad /* By default, caller should not retry */
110*7c604eeaShaad *finished = 1;
111*7c604eeaShaad
112*7c604eeaShaad if (parms->aborting) {
113*7c604eeaShaad if (!(lvs_changed = lvs_using_lv(cmd, vg, lv))) {
114*7c604eeaShaad log_error("Failed to generate list of copied LVs: "
115*7c604eeaShaad "can't abort.");
116*7c604eeaShaad return 0;
117*7c604eeaShaad }
118*7c604eeaShaad parms->poll_fns->finish_copy(cmd, vg, lv, lvs_changed);
119*7c604eeaShaad return 0;
120*7c604eeaShaad }
121*7c604eeaShaad
122*7c604eeaShaad progress = parms->poll_fns->poll_progress(cmd, lv, name, parms);
123*7c604eeaShaad if (progress == PROGRESS_CHECK_FAILED)
124*7c604eeaShaad return_0;
125*7c604eeaShaad
126*7c604eeaShaad if (progress == PROGRESS_UNFINISHED) {
12756a34939Shaad /* The only case the caller *should* try again later */
12856a34939Shaad *finished = 0;
12956a34939Shaad return 1;
13056a34939Shaad }
13156a34939Shaad
132*7c604eeaShaad if (!(lvs_changed = lvs_using_lv(cmd, vg, lv))) {
13356a34939Shaad log_error("ABORTING: Failed to generate list of copied LVs");
13456a34939Shaad return 0;
13556a34939Shaad }
13656a34939Shaad
13756a34939Shaad /* Finished? Or progress to next segment? */
138*7c604eeaShaad if (progress == PROGRESS_FINISHED_ALL) {
139*7c604eeaShaad if (!parms->poll_fns->finish_copy(cmd, vg, lv, lvs_changed))
14056a34939Shaad return 0;
14156a34939Shaad } else {
142*7c604eeaShaad if (!parms->poll_fns->update_metadata(cmd, vg, lv, lvs_changed,
143*7c604eeaShaad 0)) {
14456a34939Shaad log_error("ABORTING: Segment progression failed.");
145*7c604eeaShaad parms->poll_fns->finish_copy(cmd, vg, lv, lvs_changed);
14656a34939Shaad return 0;
14756a34939Shaad }
14856a34939Shaad *finished = 0; /* Another segment */
14956a34939Shaad }
15056a34939Shaad
15156a34939Shaad return 1;
15256a34939Shaad }
15356a34939Shaad
_wait_for_single_lv(struct cmd_context * cmd,const char * name,const char * uuid,struct daemon_parms * parms)154*7c604eeaShaad static int _wait_for_single_lv(struct cmd_context *cmd, const char *name, const char *uuid,
15556a34939Shaad struct daemon_parms *parms)
15656a34939Shaad {
15756a34939Shaad struct volume_group *vg;
158*7c604eeaShaad struct logical_volume *lv;
15956a34939Shaad int finished = 0;
16056a34939Shaad
161*7c604eeaShaad /* Poll for completion */
16256a34939Shaad while (!finished) {
16356a34939Shaad /* FIXME Also needed in vg/lvchange -ay? */
16456a34939Shaad /* FIXME Use alarm for regular intervals instead */
16556a34939Shaad if (parms->interval && !parms->aborting) {
16656a34939Shaad sleep(parms->interval);
16756a34939Shaad /* Devices might have changed while we slept */
16856a34939Shaad init_full_scan_done(0);
16956a34939Shaad }
17056a34939Shaad
17156a34939Shaad /* Locks the (possibly renamed) VG again */
172*7c604eeaShaad vg = parms->poll_fns->get_copy_vg(cmd, name, uuid);
173*7c604eeaShaad if (vg_read_error(vg)) {
174*7c604eeaShaad vg_release(vg);
17556a34939Shaad log_error("ABORTING: Can't reread VG for %s", name);
17656a34939Shaad /* What more could we do here? */
17756a34939Shaad return 0;
17856a34939Shaad }
17956a34939Shaad
180*7c604eeaShaad if (!(lv = parms->poll_fns->get_copy_lv(cmd, vg, name, uuid,
18156a34939Shaad parms->lv_type))) {
18256a34939Shaad log_error("ABORTING: Can't find mirror LV in %s for %s",
18356a34939Shaad vg->name, name);
184*7c604eeaShaad unlock_and_release_vg(cmd, vg, vg->name);
18556a34939Shaad return 0;
18656a34939Shaad }
18756a34939Shaad
188*7c604eeaShaad if (!_check_lv_status(cmd, vg, lv, name, parms, &finished)) {
189*7c604eeaShaad unlock_and_release_vg(cmd, vg, vg->name);
19056a34939Shaad return 0;
19156a34939Shaad }
19256a34939Shaad
193*7c604eeaShaad unlock_and_release_vg(cmd, vg, vg->name);
19456a34939Shaad }
19556a34939Shaad
19656a34939Shaad return 1;
19756a34939Shaad }
19856a34939Shaad
_poll_vg(struct cmd_context * cmd,const char * vgname,struct volume_group * vg,void * handle)19956a34939Shaad static int _poll_vg(struct cmd_context *cmd, const char *vgname,
200*7c604eeaShaad struct volume_group *vg, void *handle)
20156a34939Shaad {
20256a34939Shaad struct daemon_parms *parms = (struct daemon_parms *) handle;
20356a34939Shaad struct lv_list *lvl;
204*7c604eeaShaad struct logical_volume *lv;
20556a34939Shaad const char *name;
20656a34939Shaad int finished;
20756a34939Shaad
20856a34939Shaad dm_list_iterate_items(lvl, &vg->lvs) {
209*7c604eeaShaad lv = lvl->lv;
210*7c604eeaShaad if (!(lv->status & parms->lv_type))
21156a34939Shaad continue;
212*7c604eeaShaad if (!(name = parms->poll_fns->get_copy_name_from_lv(lv)))
21356a34939Shaad continue;
21456a34939Shaad /* FIXME Need to do the activation from _set_up_pvmove here
21556a34939Shaad * if it's not running and we're not aborting */
216*7c604eeaShaad if (_check_lv_status(cmd, vg, lv, name, parms, &finished) &&
217*7c604eeaShaad !finished)
21856a34939Shaad parms->outstanding_count++;
21956a34939Shaad }
22056a34939Shaad
22156a34939Shaad return ECMD_PROCESSED;
22256a34939Shaad
22356a34939Shaad }
22456a34939Shaad
_poll_for_all_vgs(struct cmd_context * cmd,struct daemon_parms * parms)22556a34939Shaad static void _poll_for_all_vgs(struct cmd_context *cmd,
22656a34939Shaad struct daemon_parms *parms)
22756a34939Shaad {
22856a34939Shaad while (1) {
22956a34939Shaad parms->outstanding_count = 0;
230*7c604eeaShaad process_each_vg(cmd, 0, NULL, READ_FOR_UPDATE, parms, _poll_vg);
23156a34939Shaad if (!parms->outstanding_count)
23256a34939Shaad break;
23356a34939Shaad sleep(parms->interval);
23456a34939Shaad }
23556a34939Shaad }
23656a34939Shaad
poll_daemon(struct cmd_context * cmd,const char * name,const char * uuid,unsigned background,uint32_t lv_type,struct poll_functions * poll_fns,const char * progress_title)237*7c604eeaShaad int poll_daemon(struct cmd_context *cmd, const char *name, const char *uuid,
238*7c604eeaShaad unsigned background,
23956a34939Shaad uint32_t lv_type, struct poll_functions *poll_fns,
24056a34939Shaad const char *progress_title)
24156a34939Shaad {
24256a34939Shaad struct daemon_parms parms;
24356a34939Shaad
244*7c604eeaShaad parms.aborting = arg_is_set(cmd, abort_ARG);
24556a34939Shaad parms.background = background;
24656a34939Shaad parms.interval = arg_uint_value(cmd, interval_ARG, DEFAULT_INTERVAL);
24756a34939Shaad parms.progress_display = 1;
24856a34939Shaad parms.progress_title = progress_title;
24956a34939Shaad parms.lv_type = lv_type;
25056a34939Shaad parms.poll_fns = poll_fns;
25156a34939Shaad
25256a34939Shaad if (parms.interval && !parms.aborting)
25356a34939Shaad log_verbose("Checking progress every %u seconds",
25456a34939Shaad parms.interval);
25556a34939Shaad
25656a34939Shaad if (!parms.interval) {
25756a34939Shaad parms.progress_display = 0;
25856a34939Shaad
25956a34939Shaad /* FIXME Disabled multiple-copy wait_event */
26056a34939Shaad if (!name)
26156a34939Shaad parms.interval = DEFAULT_INTERVAL;
26256a34939Shaad }
26356a34939Shaad
26456a34939Shaad if (parms.background) {
26556a34939Shaad if (!_become_daemon(cmd))
26656a34939Shaad return ECMD_PROCESSED; /* Parent */
26756a34939Shaad parms.progress_display = 0;
26856a34939Shaad /* FIXME Use wait_event (i.e. interval = 0) and */
26956a34939Shaad /* fork one daemon per copy? */
27056a34939Shaad }
27156a34939Shaad
272*7c604eeaShaad /*
273*7c604eeaShaad * Process one specific task or all incomplete tasks?
274*7c604eeaShaad */
27556a34939Shaad if (name) {
276*7c604eeaShaad if (!_wait_for_single_lv(cmd, name, uuid, &parms)) {
277*7c604eeaShaad stack;
27856a34939Shaad return ECMD_FAILED;
279*7c604eeaShaad }
28056a34939Shaad } else
28156a34939Shaad _poll_for_all_vgs(cmd, &parms);
28256a34939Shaad
28356a34939Shaad return ECMD_PROCESSED;
28456a34939Shaad }
285