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