Skip to content
Snippets Groups Projects

Wip/martyn/t7336 speed up ubihealthd shutdown

3 files
+ 183
0
Compare changes
  • Side-by-side
  • Inline
Files
3
From: Govindaraji Sivanantham <Govindaraji.Sivanantham@in.bosch.com>
Date: Tue, 25 Aug 2020 11:23:57 +0000
Subject: ubihealthd : Updated ubihealthd to handle large UBI volumes and fix
some issues
This patch updates ubihealthd for the following things,
1) Do statistic updates in chunk of 500 erase blocks.
2) Updated logic to read stats from the pre-existing stat file.
3) Checked shutdown flag before doing read or scrub work
4) Fixed incorrect value of peb number passing to read_peb and scrub_peb.
Note : This is an update to the work which Richard did in past
(https://lwn.net/Articles/663751/). Without these changes, ubihealthd
will cause heavy CPU load and won't respond to user signals when running
with large UBI volumes. I have tested these changes on target HW
where UBI volume size is greater than 60 GB.
Signed-off-by: Ronak Desai <ronak.desai@rockwellcollins.com>
[Govindaraji Sivanantham: Removed nanosleep calls]
Signed-off-by: Govindaraji Sivanantham <Govindaraji.Sivanantham@in.bosch.com>
[Martyn Welch: Reformatted commit message, added description of Govindaraji's changes]
Signed-off-by: Martyn Welch <martyn.welch@collabora.com>
---
ubi-utils/ubihealthd.c | 65 +++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 51 insertions(+), 14 deletions(-)
diff --git a/ubi-utils/ubihealthd.c b/ubi-utils/ubihealthd.c
index 97ffbac..b46a6fa 100644
--- a/ubi-utils/ubihealthd.c
+++ b/ubi-utils/ubihealthd.c
@@ -35,6 +35,9 @@
#define log_info(M, ...) _log(3, "[INFO]" M, ##__VA_ARGS__);
#define log_debug(M, ...) _log(4, "[DEBUG]" M, ##__VA_ARGS__);
+#define STAT_PEB_CHUNK (500)
+static int peb_start;
+static int peb_end;
int log_level;
@@ -275,8 +278,23 @@ static int update_stats(int fd, struct peb_list *head, int pnum)
return -1;
}
log_debug("Kernel reported stats for %d PEBs", err);
+
+ /* Divide the total number of PEBs in a small chunk(STAT_PEB_CHUNK) for
+ * statistic updates so that statistic updates can be done in parts.
+ */
+ if (err > STAT_PEB_CHUNK)
+ {
+ if ((peb_start + STAT_PEB_CHUNK) < err)
+ peb_end = (peb_start + STAT_PEB_CHUNK);
+ else
+ peb_end = err;
+ }
+ else
+ peb_end = err;
+
+ log_debug("--> peb_start = %d, peb_end = %d PEBs", peb_start, peb_end);
time_t now = time(NULL);
- for (i = 0; i < err; i++) {
+ for (i = peb_start; i < peb_end; i++) {
struct ubi_stats_entry *s = &req->stats[i];
struct peb_list *p = NULL;
struct peb_info *peb = NULL;
@@ -299,6 +317,18 @@ static int update_stats(int fd, struct peb_list *head, int pnum)
peb->prev_read_cnt = peb->read_cnt;
peb->last_stat_update = now;
}
+
+ if (err > STAT_PEB_CHUNK)
+ {
+ if (peb_end == err)
+ {
+ peb_start = 0;
+ peb_end = 0;
+ }
+ else
+ peb_start += STAT_PEB_CHUNK;
+ }
+
free(req);
return 0;
}
@@ -306,8 +336,9 @@ static int update_stats(int fd, struct peb_list *head, int pnum)
static int read_peb(int fd, struct peb_info *peb)
{
time_t now = time(NULL);
+ int32_t peb_num = (int32_t)peb->peb_num;
log_debug("Reading PEB %"PRIu64 , peb->peb_num);
- int err = ioctl(fd, UBI_IOCRPEB, &peb->peb_num);
+ int err = ioctl(fd, UBI_IOCRPEB, &peb_num);
if (err < 0) {
log_err("Error while reading PEB %" PRIu64, peb->peb_num);
return -1;
@@ -319,8 +350,9 @@ static int read_peb(int fd, struct peb_info *peb)
static int scrub_peb(int fd, struct peb_info *peb)
{
time_t now = time(NULL);
+ int32_t peb_num = (int32_t)peb->peb_num;
log_debug("Scrubbing PEB %"PRIu64, peb->peb_num);
- int err = ioctl (fd, UBI_IOCSPEB, &peb->peb_num);
+ int err = ioctl (fd, UBI_IOCSPEB, &peb_num);
if (err < 0) {
log_err("Error while scrubbing PEB %" PRIu64, peb->peb_num);
return -1;
@@ -418,19 +450,18 @@ static int read_stats_file(const char *filename, struct peb_list *peb_head, stru
fread(&num_pebs, sizeof(num_pebs), 1, file);
fread(&next_read_peb, sizeof(next_read_peb), 1, file);
fread(&next_scrub_peb, sizeof(next_scrub_peb), 1, file);
- for (i = 0; i < num_pebs; i++) {
+
+ struct peb_list *q = NULL;
+ list_for_each_entry(q, &peb_head->list, list) {
struct peb_info *peb = malloc(sizeof(struct peb_info));
if (!peb) {
log_err("Could not allocate peb_info");
return -1;
}
- struct peb_list *p = NULL;
fread(peb, sizeof(struct peb_info), 1, file);
- list_for_each_entry(p, &peb_head->list, list) {
- if (p->peb && (p->peb->peb_num == peb->peb_num)) {
- free(p->peb);
- p->peb = peb;
- }
+ if (q->peb && (q->peb->peb_num == peb->peb_num)) {
+ free(q->peb);
+ q->peb = peb;
}
}
/* init read and scrub lists */
@@ -632,7 +663,7 @@ int main(int argc, char **argv)
}
}
/* stats timer */
- if (pfd[1].revents & POLLIN) {
+ if ((pfd[1].revents & POLLIN) && !shutdown) {
uint64_t tmp;
read(stats_timer, &tmp, sizeof(tmp));
/* update stats */
@@ -651,13 +682,19 @@ int main(int argc, char **argv)
/* read whole PEB if number of reads since last check is above threshold */
if (read_stats >= read_threshold) {
log_info("Too many reads for PEB %" PRIu64 " between stats updates, scheduling READ", peb->peb_num);
- read_peb(fd, peb);
+ if (!read_peb(fd, peb))
+ {
+ /* No need to wait to update previous read count as
+ * read is performed successfully.
+ */
+ peb->prev_read_cnt = peb->read_cnt;
+ }
}
}
}
/* read_peb_timer */
- if (pfd[2].revents & POLLIN) {
+ if ((pfd[2].revents & POLLIN) && !shutdown) {
uint64_t tmp;
read(pfd[2].fd, &tmp, sizeof(tmp));
/* do next peb read */
@@ -667,7 +704,7 @@ int main(int argc, char **argv)
}
/* scrub pebs */
- if (pfd[3].revents & POLLIN) {
+ if ((pfd[3].revents & POLLIN) && !shutdown) {
uint64_t tmp;
read(pfd[3].fd, &tmp, sizeof(tmp));
/* do next peb scrub */
Loading