1*56a34939Shaad /* $NetBSD: polldaemon.c,v 1.1.1.1 2008/12/22 00:19:05 haad Exp $ */ 2*56a34939Shaad 3*56a34939Shaad /* 4*56a34939Shaad * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved. 5*56a34939Shaad * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. 6*56a34939Shaad * 7*56a34939Shaad * This file is part of LVM2. 8*56a34939Shaad * 9*56a34939Shaad * This copyrighted material is made available to anyone wishing to use, 10*56a34939Shaad * modify, copy, or redistribute it subject to the terms and conditions 11*56a34939Shaad * of the GNU Lesser General Public License v.2.1. 12*56a34939Shaad * 13*56a34939Shaad * You should have received a copy of the GNU Lesser General Public License 14*56a34939Shaad * along with this program; if not, write to the Free Software Foundation, 15*56a34939Shaad * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16*56a34939Shaad */ 17*56a34939Shaad 18*56a34939Shaad #include "tools.h" 19*56a34939Shaad #include "polldaemon.h" 20*56a34939Shaad #include <signal.h> 21*56a34939Shaad #include <sys/wait.h> 22*56a34939Shaad 23*56a34939Shaad static void _sigchld_handler(int sig __attribute((unused))) 24*56a34939Shaad { 25*56a34939Shaad while (wait4(-1, NULL, WNOHANG | WUNTRACED, NULL) > 0) ; 26*56a34939Shaad } 27*56a34939Shaad 28*56a34939Shaad static int _become_daemon(struct cmd_context *cmd) 29*56a34939Shaad { 30*56a34939Shaad pid_t pid; 31*56a34939Shaad struct sigaction act = { 32*56a34939Shaad {_sigchld_handler}, 33*56a34939Shaad .sa_flags = SA_NOCLDSTOP, 34*56a34939Shaad }; 35*56a34939Shaad 36*56a34939Shaad log_verbose("Forking background process"); 37*56a34939Shaad 38*56a34939Shaad sigaction(SIGCHLD, &act, NULL); 39*56a34939Shaad 40*56a34939Shaad if ((pid = fork()) == -1) { 41*56a34939Shaad log_error("fork failed: %s", strerror(errno)); 42*56a34939Shaad return 1; 43*56a34939Shaad } 44*56a34939Shaad 45*56a34939Shaad /* Parent */ 46*56a34939Shaad if (pid > 0) 47*56a34939Shaad return 0; 48*56a34939Shaad 49*56a34939Shaad /* Child */ 50*56a34939Shaad if (setsid() == -1) 51*56a34939Shaad log_error("Background process failed to setsid: %s", 52*56a34939Shaad strerror(errno)); 53*56a34939Shaad init_verbose(VERBOSE_BASE_LEVEL); 54*56a34939Shaad 55*56a34939Shaad close(STDIN_FILENO); 56*56a34939Shaad close(STDOUT_FILENO); 57*56a34939Shaad close(STDERR_FILENO); 58*56a34939Shaad 59*56a34939Shaad strncpy(*cmd->argv, "(lvm2copyd)", strlen(*cmd->argv)); 60*56a34939Shaad 61*56a34939Shaad reset_locking(); 62*56a34939Shaad dev_close_all(); 63*56a34939Shaad 64*56a34939Shaad return 1; 65*56a34939Shaad } 66*56a34939Shaad 67*56a34939Shaad static int _check_mirror_status(struct cmd_context *cmd, 68*56a34939Shaad struct volume_group *vg, 69*56a34939Shaad struct logical_volume *lv_mirr, 70*56a34939Shaad const char *name, struct daemon_parms *parms, 71*56a34939Shaad int *finished) 72*56a34939Shaad { 73*56a34939Shaad struct dm_list *lvs_changed; 74*56a34939Shaad float segment_percent = 0.0, overall_percent = 0.0; 75*56a34939Shaad uint32_t event_nr = 0; 76*56a34939Shaad 77*56a34939Shaad /* By default, caller should not retry */ 78*56a34939Shaad *finished = 1; 79*56a34939Shaad 80*56a34939Shaad if (parms->aborting) { 81*56a34939Shaad if (!(lvs_changed = lvs_using_lv(cmd, vg, lv_mirr))) { 82*56a34939Shaad log_error("Failed to generate list of copied LVs: " 83*56a34939Shaad "can't abort."); 84*56a34939Shaad return 0; 85*56a34939Shaad } 86*56a34939Shaad parms->poll_fns->finish_copy(cmd, vg, lv_mirr, lvs_changed); 87*56a34939Shaad return 0; 88*56a34939Shaad } 89*56a34939Shaad 90*56a34939Shaad if (!lv_mirror_percent(cmd, lv_mirr, !parms->interval, &segment_percent, 91*56a34939Shaad &event_nr)) { 92*56a34939Shaad log_error("ABORTING: Mirror percentage check failed."); 93*56a34939Shaad return 0; 94*56a34939Shaad } 95*56a34939Shaad 96*56a34939Shaad overall_percent = copy_percent(lv_mirr); 97*56a34939Shaad if (parms->progress_display) 98*56a34939Shaad log_print("%s: %s: %.1f%%", name, parms->progress_title, 99*56a34939Shaad overall_percent); 100*56a34939Shaad else 101*56a34939Shaad log_verbose("%s: %s: %.1f%%", name, parms->progress_title, 102*56a34939Shaad overall_percent); 103*56a34939Shaad 104*56a34939Shaad if (segment_percent < 100.0) { 105*56a34939Shaad /* The only case the caller *should* try again later */ 106*56a34939Shaad *finished = 0; 107*56a34939Shaad return 1; 108*56a34939Shaad } 109*56a34939Shaad 110*56a34939Shaad if (!(lvs_changed = lvs_using_lv(cmd, vg, lv_mirr))) { 111*56a34939Shaad log_error("ABORTING: Failed to generate list of copied LVs"); 112*56a34939Shaad return 0; 113*56a34939Shaad } 114*56a34939Shaad 115*56a34939Shaad /* Finished? Or progress to next segment? */ 116*56a34939Shaad if (overall_percent >= 100.0) { 117*56a34939Shaad if (!parms->poll_fns->finish_copy(cmd, vg, lv_mirr, 118*56a34939Shaad lvs_changed)) 119*56a34939Shaad return 0; 120*56a34939Shaad } else { 121*56a34939Shaad if (!parms->poll_fns->update_metadata(cmd, vg, lv_mirr, 122*56a34939Shaad lvs_changed, 0)) { 123*56a34939Shaad log_error("ABORTING: Segment progression failed."); 124*56a34939Shaad parms->poll_fns->finish_copy(cmd, vg, lv_mirr, 125*56a34939Shaad lvs_changed); 126*56a34939Shaad return 0; 127*56a34939Shaad } 128*56a34939Shaad *finished = 0; /* Another segment */ 129*56a34939Shaad } 130*56a34939Shaad 131*56a34939Shaad return 1; 132*56a34939Shaad } 133*56a34939Shaad 134*56a34939Shaad static int _wait_for_single_mirror(struct cmd_context *cmd, const char *name, 135*56a34939Shaad struct daemon_parms *parms) 136*56a34939Shaad { 137*56a34939Shaad struct volume_group *vg; 138*56a34939Shaad struct logical_volume *lv_mirr; 139*56a34939Shaad int finished = 0; 140*56a34939Shaad 141*56a34939Shaad /* Poll for mirror completion */ 142*56a34939Shaad while (!finished) { 143*56a34939Shaad /* FIXME Also needed in vg/lvchange -ay? */ 144*56a34939Shaad /* FIXME Use alarm for regular intervals instead */ 145*56a34939Shaad if (parms->interval && !parms->aborting) { 146*56a34939Shaad sleep(parms->interval); 147*56a34939Shaad /* Devices might have changed while we slept */ 148*56a34939Shaad init_full_scan_done(0); 149*56a34939Shaad } 150*56a34939Shaad 151*56a34939Shaad /* Locks the (possibly renamed) VG again */ 152*56a34939Shaad if (!(vg = parms->poll_fns->get_copy_vg(cmd, name))) { 153*56a34939Shaad log_error("ABORTING: Can't reread VG for %s", name); 154*56a34939Shaad /* What more could we do here? */ 155*56a34939Shaad return 0; 156*56a34939Shaad } 157*56a34939Shaad 158*56a34939Shaad if (!(lv_mirr = parms->poll_fns->get_copy_lv(cmd, vg, name, 159*56a34939Shaad parms->lv_type))) { 160*56a34939Shaad log_error("ABORTING: Can't find mirror LV in %s for %s", 161*56a34939Shaad vg->name, name); 162*56a34939Shaad unlock_vg(cmd, vg->name); 163*56a34939Shaad return 0; 164*56a34939Shaad } 165*56a34939Shaad 166*56a34939Shaad if (!_check_mirror_status(cmd, vg, lv_mirr, name, parms, 167*56a34939Shaad &finished)) { 168*56a34939Shaad unlock_vg(cmd, vg->name); 169*56a34939Shaad return 0; 170*56a34939Shaad } 171*56a34939Shaad 172*56a34939Shaad unlock_vg(cmd, vg->name); 173*56a34939Shaad } 174*56a34939Shaad 175*56a34939Shaad return 1; 176*56a34939Shaad } 177*56a34939Shaad 178*56a34939Shaad static int _poll_vg(struct cmd_context *cmd, const char *vgname, 179*56a34939Shaad struct volume_group *vg, int consistent, void *handle) 180*56a34939Shaad { 181*56a34939Shaad struct daemon_parms *parms = (struct daemon_parms *) handle; 182*56a34939Shaad struct lv_list *lvl; 183*56a34939Shaad struct logical_volume *lv_mirr; 184*56a34939Shaad const char *name; 185*56a34939Shaad int finished; 186*56a34939Shaad 187*56a34939Shaad if (!vg) { 188*56a34939Shaad log_error("Couldn't read volume group %s", vgname); 189*56a34939Shaad return ECMD_FAILED; 190*56a34939Shaad } 191*56a34939Shaad 192*56a34939Shaad if (!consistent) { 193*56a34939Shaad log_error("Volume Group %s inconsistent - skipping", vgname); 194*56a34939Shaad /* FIXME Should we silently recover it here or not? */ 195*56a34939Shaad return ECMD_FAILED; 196*56a34939Shaad } 197*56a34939Shaad 198*56a34939Shaad if (!vg_check_status(vg, EXPORTED_VG)) 199*56a34939Shaad return ECMD_FAILED; 200*56a34939Shaad 201*56a34939Shaad dm_list_iterate_items(lvl, &vg->lvs) { 202*56a34939Shaad lv_mirr = lvl->lv; 203*56a34939Shaad if (!(lv_mirr->status & parms->lv_type)) 204*56a34939Shaad continue; 205*56a34939Shaad if (!(name = parms->poll_fns->get_copy_name_from_lv(lv_mirr))) 206*56a34939Shaad continue; 207*56a34939Shaad /* FIXME Need to do the activation from _set_up_pvmove here 208*56a34939Shaad * if it's not running and we're not aborting */ 209*56a34939Shaad if (_check_mirror_status(cmd, vg, lv_mirr, name, 210*56a34939Shaad parms, &finished) && !finished) 211*56a34939Shaad parms->outstanding_count++; 212*56a34939Shaad } 213*56a34939Shaad 214*56a34939Shaad return ECMD_PROCESSED; 215*56a34939Shaad 216*56a34939Shaad } 217*56a34939Shaad 218*56a34939Shaad static void _poll_for_all_vgs(struct cmd_context *cmd, 219*56a34939Shaad struct daemon_parms *parms) 220*56a34939Shaad { 221*56a34939Shaad while (1) { 222*56a34939Shaad parms->outstanding_count = 0; 223*56a34939Shaad process_each_vg(cmd, 0, NULL, LCK_VG_WRITE, 1, parms, _poll_vg); 224*56a34939Shaad if (!parms->outstanding_count) 225*56a34939Shaad break; 226*56a34939Shaad sleep(parms->interval); 227*56a34939Shaad } 228*56a34939Shaad } 229*56a34939Shaad 230*56a34939Shaad int poll_daemon(struct cmd_context *cmd, const char *name, unsigned background, 231*56a34939Shaad uint32_t lv_type, struct poll_functions *poll_fns, 232*56a34939Shaad const char *progress_title) 233*56a34939Shaad { 234*56a34939Shaad struct daemon_parms parms; 235*56a34939Shaad 236*56a34939Shaad parms.aborting = arg_count(cmd, abort_ARG) ? 1 : 0; 237*56a34939Shaad parms.background = background; 238*56a34939Shaad parms.interval = arg_uint_value(cmd, interval_ARG, DEFAULT_INTERVAL); 239*56a34939Shaad parms.progress_display = 1; 240*56a34939Shaad parms.progress_title = progress_title; 241*56a34939Shaad parms.lv_type = lv_type; 242*56a34939Shaad parms.poll_fns = poll_fns; 243*56a34939Shaad 244*56a34939Shaad if (parms.interval && !parms.aborting) 245*56a34939Shaad log_verbose("Checking progress every %u seconds", 246*56a34939Shaad parms.interval); 247*56a34939Shaad 248*56a34939Shaad if (!parms.interval) { 249*56a34939Shaad parms.progress_display = 0; 250*56a34939Shaad 251*56a34939Shaad /* FIXME Disabled multiple-copy wait_event */ 252*56a34939Shaad if (!name) 253*56a34939Shaad parms.interval = DEFAULT_INTERVAL; 254*56a34939Shaad } 255*56a34939Shaad 256*56a34939Shaad if (parms.background) { 257*56a34939Shaad if (!_become_daemon(cmd)) 258*56a34939Shaad return ECMD_PROCESSED; /* Parent */ 259*56a34939Shaad parms.progress_display = 0; 260*56a34939Shaad /* FIXME Use wait_event (i.e. interval = 0) and */ 261*56a34939Shaad /* fork one daemon per copy? */ 262*56a34939Shaad } 263*56a34939Shaad 264*56a34939Shaad if (name) { 265*56a34939Shaad if (!_wait_for_single_mirror(cmd, name, &parms)) 266*56a34939Shaad return ECMD_FAILED; 267*56a34939Shaad } else 268*56a34939Shaad _poll_for_all_vgs(cmd, &parms); 269*56a34939Shaad 270*56a34939Shaad return ECMD_PROCESSED; 271*56a34939Shaad } 272