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