From patchwork Tue Apr 17 14:18:45 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronak Desai X-Patchwork-Id: 899325 X-Patchwork-Delegate: david.oberhollenzer@sigma-star.at Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=rockwellcollins.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="rRVl+XEJ"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40QS6y3Rf7z9s0n for ; Wed, 18 Apr 2018 00:19:22 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:List-Subscribe:List-Help: List-Post:List-Archive:List-Unsubscribe:List-Id:Message-Id:Date:Subject:To: From:Reply-To:Cc:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=KB8gFbZIiuy3Bi76QYMNDkDXa5jwnwAAhnAtqdNPGNM=; b=rRVl+XEJbBHO6B 2aMgcxb497nvQH5uSUf1kfc3rFBfy0E5pWC1dMkLJw6XsXnd88XJgeM33FZ4+gmPiNDcsO9Fu21QH ZhzhP2EJHEI9N5qZkSA9u50Duu2ymj324CVtW0XUzxIzsYUPWANw4zMwpW77E4wBQkiRdAtiVmlT+ ZcnrScuoC5FQrr4Cp6LgF92o12LnDc223+ClaPT+LR2RPVoKNFn4hjdPE8/r5uOoQAKvpy03oCaho JOE3ObgkStqbU7JcPTqXmbcwGFnw4c1tUZqW+MRloxWn0wyiK5on+CjoDV0TdgzPARjWnqvmsj+7f 1beBMgtPklKg6PB5ZaMg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1f8RRt-0002Li-0J; Tue, 17 Apr 2018 14:19:09 +0000 Received: from secvs01.rockwellcollins.com ([205.175.225.240]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1f8RRp-0002Ko-6m for linux-mtd@lists.infradead.org; Tue, 17 Apr 2018 14:19:07 +0000 Received: from ofwgwc03.rockwellcollins.com (HELO dtulimr02.rockwellcollins.com) ([205.175.225.12]) by secvs01.rockwellcollins.com with ESMTP; 17 Apr 2018 09:18:50 -0500 X-Received: from largo.rockwellcollins.com (unknown [192.168.140.76]) by dtulimr02.rockwellcollins.com (Postfix) with ESMTP id 3E9322006A for ; Tue, 17 Apr 2018 09:18:50 -0500 (CDT) From: Ronak Desai To: linux-mtd@lists.infradead.org Subject: [PATCH] ubihealthd : Updated ubihealthd to handle large UBI volumes and fix some issues Date: Tue, 17 Apr 2018 09:18:45 -0500 Message-Id: <1523974725-9860-1-git-send-email-ronak.desai@rockwellcollins.com> X-Mailer: git-send-email 1.9.1 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180417_071905_376867_DA312F39 X-CRM114-Status: GOOD ( 15.57 ) X-Spam-Score: -5.0 (-----) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-5.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/, high trust [205.175.225.240 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org 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. 5) Added some sleep in loops so that processor can have scheduling time. 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 --- ubihealthd.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 14 deletions(-) diff --git a/ubihealthd.c b/ubihealthd.c index 4be15d5..c82c077 100644 --- a/ubihealthd.c +++ b/ubihealthd.c @@ -55,6 +55,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; @@ -215,6 +218,9 @@ static int init_stats(int fd, struct list_head *head, int pnum) { int i, err = 0; size_t req_size = pnum * sizeof(struct ubi_stats_entry); + struct timespec wait; + wait.tv_sec = 0; + wait.tv_nsec = 2; /* 2ns */ struct ubi_stats_req *req = malloc(sizeof(struct ubi_stats_req) + req_size); if (!req) { log_err("Could not alloc ubi_stats_req: %s", strerror(errno)); @@ -253,6 +259,7 @@ static int init_stats(int fd, struct list_head *head, int pnum) } p->peb = peb; list_add_tail(&p->list, head); + (void)nanosleep(&wait, NULL); } free(req); return 0; @@ -273,6 +280,9 @@ static void free_list(struct peb_list *head) static int update_stats(int fd, struct peb_list *head, int pnum) { + struct timespec wait; + wait.tv_sec = 0; + wait.tv_nsec = 2; /* 2ns */ if (list_empty(&head->list)) { log_fatal("PEB list not initialized"); return -1; @@ -295,8 +305,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; @@ -319,6 +344,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; } @@ -326,8 +363,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; @@ -339,8 +377,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; @@ -427,6 +466,9 @@ static int read_stats_file(const char *filename, struct peb_list *peb_head, stru uint64_t magic_version; FILE *file = fopen(filename, "rb"); ssize_t i; + struct timespec wait; + wait.tv_sec = 0; + wait.tv_nsec = 2; /* 2ns */ if (file == NULL) return -1; fread(&magic_version, sizeof(magic_version), 1, file); @@ -438,20 +480,20 @@ 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; } + (void)nanosleep(&wait, NULL); } /* init read and scrub lists */ struct peb_list *p = NULL; @@ -460,6 +502,7 @@ static int read_stats_file(const char *filename, struct peb_list *peb_head, stru schedule_peb(&sched_read_head->list, p->peb, SCHED_READ); if (p->peb->peb_num >= next_scrub_peb) schedule_peb(&sched_scrub_head->list, p->peb, SCHED_SCRUB); + (void)nanosleep(&wait, NULL); } p = NULL; list_for_each_entry(p, &peb_head->list, list) { @@ -467,6 +510,7 @@ static int read_stats_file(const char *filename, struct peb_list *peb_head, stru schedule_peb(&sched_read_head->list, p->peb, SCHED_READ); if (p->peb->peb_num < next_scrub_peb) schedule_peb(&sched_scrub_head->list, p->peb, SCHED_SCRUB); + (void)nanosleep(&wait, NULL); } return 0; @@ -506,6 +550,9 @@ int main(int argc, char **argv) struct peb_list *peb_head; const char *stats_file = "/tmp/ubihealth_stats"; const char *ubi_dev = "/dev/ubi0"; + struct timespec wait; + wait.tv_sec = 0; + wait.tv_nsec = 2; /* 2 ns */ log_level = 4; while ((c = getopt_long(argc, argv, opt_string, options, &i)) != -1) { @@ -597,6 +644,7 @@ int main(int argc, char **argv) list_for_each_entry(p, &peb_head->list, list) { schedule_peb(&sched_read_head->list, p->peb, SCHED_READ); schedule_peb(&sched_scrub_head->list, p->peb, SCHED_SCRUB); + (void)nanosleep(&wait, NULL); } } @@ -652,7 +700,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 */ @@ -671,13 +719,20 @@ 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; + } } + (void)nanosleep(&wait, NULL); } } /* 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 */ @@ -687,7 +742,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 */