4 * Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
7 * This file is part of LVM2.
9 * This copyrighted material is made available to anyone wishing to use,
10 * modify, copy, or redistribute it subject to the terms and conditions
11 * of the GNU Lesser General Public License v.2.1.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "polldaemon.h"
23 static void _sigchld_handler(int sig
__attribute((unused
)))
25 while (wait4(-1, NULL
, WNOHANG
| WUNTRACED
, NULL
) > 0) ;
28 static int _become_daemon(struct cmd_context
*cmd
)
31 struct sigaction act
= {
33 .sa_flags
= SA_NOCLDSTOP
,
36 log_verbose("Forking background process");
38 sigaction(SIGCHLD
, &act
, NULL
);
40 if ((pid
= fork()) == -1) {
41 log_error("fork failed: %s", strerror(errno
));
51 log_error("Background process failed to setsid: %s",
53 init_verbose(VERBOSE_BASE_LEVEL
);
59 strncpy(*cmd
->argv
, "(lvm2copyd)", strlen(*cmd
->argv
));
68 progress_t
poll_mirror_progress(struct cmd_context
*cmd
,
69 struct logical_volume
*lv
, const char *name
,
70 struct daemon_parms
*parms
)
72 float segment_percent
= 0.0, overall_percent
= 0.0;
73 percent_range_t percent_range
, overall_percent_range
;
74 uint32_t event_nr
= 0;
76 if (!lv_mirror_percent(cmd
, lv
, !parms
->interval
, &segment_percent
,
77 &percent_range
, &event_nr
) ||
78 (percent_range
== PERCENT_INVALID
)) {
79 log_error("ABORTING: Mirror percentage check failed.");
80 return PROGRESS_CHECK_FAILED
;
83 overall_percent
= copy_percent(lv
, &overall_percent_range
);
84 if (parms
->progress_display
)
85 log_print("%s: %s: %.1f%%", name
, parms
->progress_title
,
88 log_verbose("%s: %s: %.1f%%", name
, parms
->progress_title
,
91 if (percent_range
!= PERCENT_100
)
92 return PROGRESS_UNFINISHED
;
94 if (overall_percent_range
== PERCENT_100
)
95 return PROGRESS_FINISHED_ALL
;
97 return PROGRESS_FINISHED_SEGMENT
;
100 static int _check_lv_status(struct cmd_context
*cmd
,
101 struct volume_group
*vg
,
102 struct logical_volume
*lv
,
103 const char *name
, struct daemon_parms
*parms
,
106 struct dm_list
*lvs_changed
;
109 /* By default, caller should not retry */
112 if (parms
->aborting
) {
113 if (!(lvs_changed
= lvs_using_lv(cmd
, vg
, lv
))) {
114 log_error("Failed to generate list of copied LVs: "
118 parms
->poll_fns
->finish_copy(cmd
, vg
, lv
, lvs_changed
);
122 progress
= parms
->poll_fns
->poll_progress(cmd
, lv
, name
, parms
);
123 if (progress
== PROGRESS_CHECK_FAILED
)
126 if (progress
== PROGRESS_UNFINISHED
) {
127 /* The only case the caller *should* try again later */
132 if (!(lvs_changed
= lvs_using_lv(cmd
, vg
, lv
))) {
133 log_error("ABORTING: Failed to generate list of copied LVs");
137 /* Finished? Or progress to next segment? */
138 if (progress
== PROGRESS_FINISHED_ALL
) {
139 if (!parms
->poll_fns
->finish_copy(cmd
, vg
, lv
, lvs_changed
))
142 if (!parms
->poll_fns
->update_metadata(cmd
, vg
, lv
, lvs_changed
,
144 log_error("ABORTING: Segment progression failed.");
145 parms
->poll_fns
->finish_copy(cmd
, vg
, lv
, lvs_changed
);
148 *finished
= 0; /* Another segment */
154 static int _wait_for_single_lv(struct cmd_context
*cmd
, const char *name
, const char *uuid
,
155 struct daemon_parms
*parms
)
157 struct volume_group
*vg
;
158 struct logical_volume
*lv
;
161 /* Poll for completion */
163 /* FIXME Also needed in vg/lvchange -ay? */
164 /* FIXME Use alarm for regular intervals instead */
165 if (parms
->interval
&& !parms
->aborting
) {
166 sleep(parms
->interval
);
167 /* Devices might have changed while we slept */
168 init_full_scan_done(0);
171 /* Locks the (possibly renamed) VG again */
172 vg
= parms
->poll_fns
->get_copy_vg(cmd
, name
, uuid
);
173 if (vg_read_error(vg
)) {
175 log_error("ABORTING: Can't reread VG for %s", name
);
176 /* What more could we do here? */
180 if (!(lv
= parms
->poll_fns
->get_copy_lv(cmd
, vg
, name
, uuid
,
182 log_error("ABORTING: Can't find mirror LV in %s for %s",
184 unlock_and_release_vg(cmd
, vg
, vg
->name
);
188 if (!_check_lv_status(cmd
, vg
, lv
, name
, parms
, &finished
)) {
189 unlock_and_release_vg(cmd
, vg
, vg
->name
);
193 unlock_and_release_vg(cmd
, vg
, vg
->name
);
199 static int _poll_vg(struct cmd_context
*cmd
, const char *vgname
,
200 struct volume_group
*vg
, void *handle
)
202 struct daemon_parms
*parms
= (struct daemon_parms
*) handle
;
204 struct logical_volume
*lv
;
208 dm_list_iterate_items(lvl
, &vg
->lvs
) {
210 if (!(lv
->status
& parms
->lv_type
))
212 if (!(name
= parms
->poll_fns
->get_copy_name_from_lv(lv
)))
214 /* FIXME Need to do the activation from _set_up_pvmove here
215 * if it's not running and we're not aborting */
216 if (_check_lv_status(cmd
, vg
, lv
, name
, parms
, &finished
) &&
218 parms
->outstanding_count
++;
221 return ECMD_PROCESSED
;
225 static void _poll_for_all_vgs(struct cmd_context
*cmd
,
226 struct daemon_parms
*parms
)
229 parms
->outstanding_count
= 0;
230 process_each_vg(cmd
, 0, NULL
, READ_FOR_UPDATE
, parms
, _poll_vg
);
231 if (!parms
->outstanding_count
)
233 sleep(parms
->interval
);
237 int poll_daemon(struct cmd_context
*cmd
, const char *name
, const char *uuid
,
239 uint32_t lv_type
, struct poll_functions
*poll_fns
,
240 const char *progress_title
)
242 struct daemon_parms parms
;
244 parms
.aborting
= arg_is_set(cmd
, abort_ARG
);
245 parms
.background
= background
;
246 parms
.interval
= arg_uint_value(cmd
, interval_ARG
, DEFAULT_INTERVAL
);
247 parms
.progress_display
= 1;
248 parms
.progress_title
= progress_title
;
249 parms
.lv_type
= lv_type
;
250 parms
.poll_fns
= poll_fns
;
252 if (parms
.interval
&& !parms
.aborting
)
253 log_verbose("Checking progress every %u seconds",
256 if (!parms
.interval
) {
257 parms
.progress_display
= 0;
259 /* FIXME Disabled multiple-copy wait_event */
261 parms
.interval
= DEFAULT_INTERVAL
;
264 if (parms
.background
) {
265 if (!_become_daemon(cmd
))
266 return ECMD_PROCESSED
; /* Parent */
267 parms
.progress_display
= 0;
268 /* FIXME Use wait_event (i.e. interval = 0) and */
269 /* fork one daemon per copy? */
273 * Process one specific task or all incomplete tasks?
276 if (!_wait_for_single_lv(cmd
, name
, uuid
, &parms
)) {
281 _poll_for_all_vgs(cmd
, &parms
);
283 return ECMD_PROCESSED
;