5 #include "err_protos.h"
9 #define ONEHOUR (60*ONEMINUTE)
10 #define ONEDAY (24*ONEHOUR)
11 #define ONEWEEK (7*ONEDAY)
22 N_("allocation groups"),
23 #define TYPE_AGI_BUCKET 4
24 N_("AGI unlinked buckets"),
25 #define TYPE_EXTENTS 5
27 #define TYPE_RTEXTENTS 6
28 N_("realtime extents"),
29 #define TYPE_UNLINKED_LIST 7
37 N_(" - %02d:%02d:%02d: %s - %llu of %llu %s done\n"),
39 N_(" - %02d:%02d:%02d: %s - %llu %s done\n"),
42 typedef struct progress_rpt_s
{
50 progress_rpt_t progress_rpt_reports
[] = {
51 {FMT1
, N_("scanning filesystem freespace"), /* 0 */
52 &rpt_fmts
[FMT1
], &rpt_types
[TYPE_AG
]},
53 {FMT1
, N_("scanning agi unlinked lists"), /* 1 */
54 &rpt_fmts
[FMT1
], &rpt_types
[TYPE_AG
]},
55 {FMT2
, N_("check uncertain AG inodes"), /* 2 */
56 &rpt_fmts
[FMT2
], &rpt_types
[TYPE_AGI_BUCKET
]},
57 {FMT1
, N_("process known inodes and inode discovery"), /* 3 */
58 &rpt_fmts
[FMT1
], &rpt_types
[TYPE_INODE
]},
59 {FMT1
, N_("process newly discovered inodes"), /* 4 */
60 &rpt_fmts
[FMT1
], &rpt_types
[TYPE_AG
]},
61 {FMT1
, N_("setting up duplicate extent list"), /* 5 */
62 &rpt_fmts
[FMT1
], &rpt_types
[TYPE_AG
]},
63 {FMT1
, N_("initialize realtime bitmap"), /* 6 */
64 &rpt_fmts
[FMT1
], &rpt_types
[TYPE_BLOCK
]},
65 {FMT1
, N_("reset realtime bitmaps"), /* 7 */
66 &rpt_fmts
[FMT1
], &rpt_types
[TYPE_AG
]},
67 {FMT1
, N_("check for inodes claiming duplicate blocks"), /* 8 */
68 &rpt_fmts
[FMT1
], &rpt_types
[TYPE_INODE
]},
69 {FMT1
, N_("rebuild AG headers and trees"), /* 9 */
70 &rpt_fmts
[FMT1
], &rpt_types
[TYPE_AG
]},
71 {FMT1
, N_("traversing filesystem"), /* 10 */
72 &rpt_fmts
[FMT1
], &rpt_types
[TYPE_AG
]},
73 {FMT2
, N_("traversing all unattached subtrees"), /* 11 */
74 &rpt_fmts
[FMT2
], &rpt_types
[TYPE_DIR
]},
75 {FMT2
, N_("moving disconnected inodes to lost+found"), /* 12 */
76 &rpt_fmts
[FMT2
], &rpt_types
[TYPE_INODE
]},
77 {FMT1
, N_("verify and correct link counts"), /* 13 */
78 &rpt_fmts
[FMT1
], &rpt_types
[TYPE_AG
]},
79 {FMT1
, N_("verify link counts"), /* 14 */
80 &rpt_fmts
[FMT1
], &rpt_types
[TYPE_AG
]}
83 pthread_t report_thread
;
85 typedef struct msg_block_s
{
86 pthread_mutex_t mutex
;
87 progress_rpt_t
*format
;
93 static msg_block_t global_msgs
;
95 typedef struct phase_times_s
{
99 uint64_t item_counts
[4];
101 static phase_times_t phase_times
[8];
103 static void *progress_rpt_thread(void *);
104 static int current_phase
;
106 static uint64_t prog_rpt_total
;
109 init_progress_rpt (void)
113 * allocate the done vector
116 if ((prog_rpt_done
= (uint64_t *)
117 malloc(sizeof(uint64_t)*glob_agcount
)) == NULL
) {
118 do_error(_("cannot malloc pointer to done vector\n"));
120 bzero(prog_rpt_done
, sizeof(uint64_t)*glob_agcount
);
123 * Setup comm block, start the thread
126 pthread_mutex_init(&global_msgs
.mutex
, NULL
);
127 global_msgs
.format
= NULL
;
128 global_msgs
.count
= glob_agcount
;
129 global_msgs
.interval
= report_interval
;
130 global_msgs
.done
= prog_rpt_done
;
131 global_msgs
.total
= &prog_rpt_total
;
133 if (pthread_create (&report_thread
, NULL
,
134 progress_rpt_thread
, (void *)&global_msgs
))
135 do_error(_("unable to create progress report thread\n"));
141 stop_progress_rpt(void)
145 * Tell msg thread to shutdown,
146 * wait for all threads to finished
150 pthread_kill (report_thread
, SIGHUP
);
151 pthread_join (report_thread
, NULL
);
157 progress_rpt_thread (void *p
)
162 sigset_t sigs_to_catch
;
166 struct itimerspec timespec
;
170 msg_block_t
*msgp
= (msg_block_t
*)p
;
173 /* It's possible to get here very early w/ no progress msg set */
177 if ((msgbuf
= (char *)malloc(DURATION_BUF_SIZE
)) == NULL
)
178 do_error (_("progress_rpt: cannot malloc progress msg buffer\n"));
183 * Specify a repeating timer that fires each MSG_INTERVAL seconds.
186 memset(×pec
, 0, sizeof(timespec
));
187 timespec
.it_value
.tv_sec
= msgp
->interval
;
188 timespec
.it_interval
.tv_sec
= msgp
->interval
;
190 if (timer_create (CLOCK_REALTIME
, NULL
, &timerid
))
191 do_error(_("progress_rpt: cannot create timer\n"));
193 if (timer_settime (timerid
, 0, ×pec
, NULL
))
194 do_error(_("progress_rpt: cannot set timer\n"));
197 * Main loop - output messages based on periodic signal arrival
198 * set this thread's signal mask to block out all other signals
201 sigemptyset (&sigs_to_catch
);
202 sigaddset (&sigs_to_catch
, SIGALRM
);
203 sigaddset (&sigs_to_catch
, SIGHUP
);
204 sigwait (&sigs_to_catch
, &caught
);
206 while (caught
!= SIGHUP
) {
208 * Allow the mainline to hold off messages by holding
209 * the lock. We don't want to just skip a period in case the
210 * reporting interval is very long... people get nervous. But,
211 * if the interval is very short, we can't let the timer go
212 * off again without sigwait'ing for it. So disarm the timer
213 * while we try to get the lock and giveup the cpu... the
214 * mainline shouldn't take that long.
217 if (pthread_mutex_lock(&msgp
->mutex
)) {
218 do_error(_("progress_rpt: cannot lock progress mutex\n"));
225 tmp
= localtime ((const time_t *) &now
);
233 for (i
= 0; i
< msgp
->count
; i
++) {
238 switch(msgp
->format
->format
) {
241 percent
= (sum
* 100) / ( *msgp
->total
);
242 sprintf (msgbuf
, *msgp
->format
->fmt
,
243 tmp
->tm_hour
, tmp
->tm_min
, tmp
->tm_sec
,
244 msgp
->format
->msg
, sum
,
245 *msgp
->total
, *msgp
->format
->type
);
248 sprintf (msgbuf
, *msgp
->format
->fmt
,
249 tmp
->tm_hour
, tmp
->tm_min
, tmp
->tm_sec
,
250 msgp
->format
->msg
, sum
,
251 *msgp
->format
->type
);
255 do_log(_("%s"), msgbuf
);
256 elapsed
= now
- phase_times
[current_phase
].start
;
257 if ((msgp
->format
->format
== FMT1
) && sum
&& elapsed
&&
258 ((current_phase
== 3) ||
259 (current_phase
== 4) ||
260 (current_phase
== 7))) {
261 /* for inode phase report % complete */
263 _("\t- %02d:%02d:%02d: Phase %d: elapsed time %s - processed %d %s per minute\n"),
264 tmp
->tm_hour
, tmp
->tm_min
, tmp
->tm_sec
,
265 current_phase
, duration(elapsed
, msgbuf
),
266 (int) (60*sum
/(elapsed
)), *msgp
->format
->type
);
268 _("\t- %02d:%02d:%02d: Phase %d: %" PRIu64
"%% done - estimated remaining time %s\n"),
269 tmp
->tm_hour
, tmp
->tm_min
, tmp
->tm_sec
,
270 current_phase
, percent
,
271 duration((int) ((*msgp
->total
- sum
) * (elapsed
)/sum
), msgbuf
));
274 if (pthread_mutex_unlock(&msgp
->mutex
) != 0) {
276 _("progress_rpt: error unlock msg mutex\n"));
278 sigwait (&sigs_to_catch
, &caught
);
281 if (timer_delete (timerid
))
282 do_warn(_("cannot delete timer\n"));
289 set_progress_msg(int report
, uint64_t total
)
295 if (pthread_mutex_lock(&global_msgs
.mutex
))
296 do_error(_("set_progress_msg: cannot lock progress mutex\n"));
298 prog_rpt_total
= total
;
299 global_msgs
.format
= &progress_rpt_reports
[report
];
301 /* reset all the accumulative totals */
303 bzero(prog_rpt_done
, sizeof(uint64_t)*glob_agcount
);
305 if (pthread_mutex_unlock(&global_msgs
.mutex
))
306 do_error(_("set_progress_msg: cannot unlock progress mutex\n"));
312 print_final_rpt(void)
319 msg_block_t
*msgp
= &global_msgs
;
320 char msgbuf
[DURATION_BUF_SIZE
];
325 if (pthread_mutex_lock(&global_msgs
.mutex
))
326 do_error(_("print_final_rpt: cannot lock progress mutex\n"));
328 bzero(&msgbuf
, sizeof(msgbuf
));
331 tmp
= localtime ((const time_t *) &now
);
339 for (i
= 0; i
< msgp
->count
; i
++) {
343 if (report_interval
) {
344 switch(msgp
->format
->format
) {
346 sprintf (msgbuf
, _(*msgp
->format
->fmt
),
347 tmp
->tm_hour
, tmp
->tm_min
, tmp
->tm_sec
,
348 _(msgp
->format
->msg
), sum
,
349 *msgp
->total
, _(*msgp
->format
->type
));
352 sprintf (msgbuf
, _(*msgp
->format
->fmt
),
353 tmp
->tm_hour
, tmp
->tm_min
, tmp
->tm_sec
,
354 _(msgp
->format
->msg
), sum
,
355 _(*msgp
->format
->type
));
358 do_log(_("%s"), msgbuf
);
361 if (pthread_mutex_unlock(&global_msgs
.mutex
))
362 do_error(_("print_final_rpt: cannot unlock progress mutex\n"));
370 phase_times
[phase
].duration
=
371 phase_times
[phase
].end
- phase_times
[phase
].start
;
376 ** Get the time and save in the phase time
380 timestamp(int end
, int phase
, char *buf
)
387 cache_report(stderr
, "libxfs_bcache", libxfs_bcache
);
392 phase_times
[phase
].end
= now
;
395 /* total time in slot zero */
396 phase_times
[0].end
= now
;
400 phase_times
[phase
+1].start
= now
;
401 current_phase
= phase
+ 1;
405 phase_times
[phase
].start
= now
;
406 current_phase
= phase
;
410 tmp
= localtime((const time_t *)&now
);
411 sprintf(buf
, _("%02d:%02d:%02d"), tmp
->tm_hour
, tmp
->tm_min
, tmp
->tm_sec
);
417 duration(int length
, char *buf
)
428 weeks
= days
= hours
= minutes
= seconds
= sum
= 0;
429 if (length
>= ONEWEEK
) {
430 weeks
= length
/ ONEWEEK
;
431 sum
= (weeks
* ONEWEEK
);
433 sprintf(buf
, _("%d week"), weeks
);
434 if (weeks
> 1) strcat(buf
, _("s"));
435 if ((length
-sum
) == 0)
439 if (length
>= ONEDAY
) {
440 days
= (length
- sum
) / ONEDAY
;
441 sum
+= (days
* ONEDAY
);
443 sprintf(temp
, _("%d day"), days
);
444 if (days
> 1) strcat(temp
, _("s"));
445 if (((length
-sum
) == 0) && (!weeks
)) {
450 strcat(buf
, _(", "));
455 if (length
>= ONEHOUR
) {
456 hours
= (length
- sum
) / ONEHOUR
;
457 sum
+= (hours
* ONEHOUR
);
459 sprintf(temp
, _("%d hour"), hours
);
460 if (hours
> 1) strcat(temp
, _("s"));
461 if (((length
-sum
) == 0) &&
462 (!weeks
) && (!days
)) {
466 else if ((weeks
) || (days
)) {
467 strcat(buf
, _(", "));
473 if (length
>= ONEMINUTE
) {
474 minutes
= (length
- sum
) / ONEMINUTE
;
475 sum
+= (minutes
* ONEMINUTE
);
477 sprintf(temp
, _("%d minute"), minutes
);
478 if (minutes
> 1) strcat(temp
, _("s"));
479 if (((length
-sum
) == 0) &&
480 (!weeks
) && (!days
) && (!hours
)) {
484 else if ((weeks
)||(days
)||(hours
)) {
485 strcat(buf
, _(", "));
490 seconds
= length
- sum
;
492 sprintf(temp
, _("%d second"), seconds
);
493 if (seconds
> 1) strcat(temp
, _("s"));
494 if ((weeks
)||(days
)||(hours
)||(minutes
))
495 strcat(buf
, _(", "));
509 char msgbuf
[DURATION_BUF_SIZE
];
513 do_log(_("\n XFS_REPAIR Summary %s\n"),
514 ctime((const time_t *)&now
));
515 do_log(_("Phase\t\tStart\t\tEnd\t\tDuration\n"));
516 for (i
= 1; i
< 8; i
++) {
517 localtime_r((const time_t *)&phase_times
[i
].start
, &start
);
518 localtime_r((const time_t *)&phase_times
[i
].end
, &end
);
519 if ((no_modify
) && (i
== 5)) {
520 do_log(_("Phase %d:\tSkipped\n"), i
);
522 else if ((bad_ino_btree
) && ((i
== 6) || (i
== 7))) {
523 do_log(_("Phase %d:\tSkipped\n"), i
);
527 _("Phase %d:\t%02d/%02d %02d:%02d:%02d\t%02d/%02d %02d:%02d:%02d\t%s\n"), i
,
528 start
.tm_mon
+1, start
.tm_mday
, start
.tm_hour
, start
.tm_min
, start
.tm_sec
,
529 end
.tm_mon
+1, end
.tm_mday
, end
.tm_hour
, end
.tm_min
, end
.tm_sec
,
530 duration(phase_times
[i
].duration
, msgbuf
));
533 do_log(_("\nTotal run time: %s\n"), duration(phase_times
[0].duration
, msgbuf
));