commit 4f1fc1e5a7fe01f5d355ae3219b931a389f6bdbe Author: overweight <5324761+overweight@user.noreply.gitee.com> Date: Mon Sep 30 11:16:11 2019 -0400 Package init diff --git a/add-rbtree-support-for-page-record.patch b/add-rbtree-support-for-page-record.patch new file mode 100644 index 0000000..efd8742 --- /dev/null +++ b/add-rbtree-support-for-page-record.patch @@ -0,0 +1,601 @@ +From 3d5d5b581e92cf4240485a1c0fb92d35da0dfb7f Mon Sep 17 00:00:00 2001 +From: lvying +Date: Sat, 26 Jan 2019 15:19:16 +0800 +Subject: [PATCH] add rbtree support for page record + +--- + Makefile.am | 4 +- + rbtree.c | 385 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + rbtree.h | 166 ++++++++++++++++++++++ + 3 files changed, 553 insertions(+), 2 deletions(-) + create mode 100644 rbtree.c + create mode 100644 rbtree.h + +diff --git a/Makefile.am b/Makefile.am +index 843b538..2ff742d 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -17,7 +17,7 @@ all-local: $(SYSTEMD_SERVICES) + + sbin_PROGRAMS = rasdaemon + rasdaemon_SOURCES = rasdaemon.c ras-events.c ras-mc-handler.c \ +- bitfield.c ++ bitfield.c rbtree.c + if WITH_SQLITE3 + rasdaemon_SOURCES += ras-record.c + endif +@@ -59,7 +59,7 @@ rasdaemon_LDADD = -lpthread $(SQLITE3_LIBS) libtrace/libtrace.a + include_HEADERS = config.h ras-events.h ras-logger.h ras-mc-handler.h \ + ras-aer-handler.h ras-mce-handler.h ras-record.h bitfield.h ras-report.h \ + ras-extlog-handler.h ras-arm-handler.h ras-non-standard-handler.h \ +- ras-devlink-handler.h ras-diskerror-handler.h ++ ras-devlink-handler.h ras-diskerror-handler.h rbtree.h + + # This rule can't be called with more than one Makefile job (like make -j8) + # I can't figure out a way to fix that +diff --git a/rbtree.c b/rbtree.c +new file mode 100644 +index 0000000..0bc6267 +--- /dev/null ++++ b/rbtree.c +@@ -0,0 +1,385 @@ ++/* ++ Red Black Trees ++ (C) 1999 Andrea Arcangeli ++ (C) 2002 David Woodhouse ++ Taken from the Linux 2.6.30 source with some minor modificatons. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ ++ linux/lib/rbtree.c ++*/ ++ ++#include "rbtree.h" ++ ++static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) ++{ ++ struct rb_node *right = node->rb_right; ++ struct rb_node *parent = rb_parent(node); ++ ++ if ((node->rb_right = right->rb_left)) ++ rb_set_parent(right->rb_left, node); ++ right->rb_left = node; ++ ++ rb_set_parent(right, parent); ++ ++ if (parent) ++ { ++ if (node == parent->rb_left) ++ parent->rb_left = right; ++ else ++ parent->rb_right = right; ++ } ++ else ++ root->rb_node = right; ++ rb_set_parent(node, right); ++} ++ ++static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) ++{ ++ struct rb_node *left = node->rb_left; ++ struct rb_node *parent = rb_parent(node); ++ ++ if ((node->rb_left = left->rb_right)) ++ rb_set_parent(left->rb_right, node); ++ left->rb_right = node; ++ ++ rb_set_parent(left, parent); ++ ++ if (parent) ++ { ++ if (node == parent->rb_right) ++ parent->rb_right = left; ++ else ++ parent->rb_left = left; ++ } ++ else ++ root->rb_node = left; ++ rb_set_parent(node, left); ++} ++ ++void rb_insert_color(struct rb_node *node, struct rb_root *root) ++{ ++ struct rb_node *parent, *gparent; ++ ++ while ((parent = rb_parent(node)) && rb_is_red(parent)) ++ { ++ gparent = rb_parent(parent); ++ ++ if (parent == gparent->rb_left) ++ { ++ { ++ register struct rb_node *uncle = gparent->rb_right; ++ if (uncle && rb_is_red(uncle)) ++ { ++ rb_set_black(uncle); ++ rb_set_black(parent); ++ rb_set_red(gparent); ++ node = gparent; ++ continue; ++ } ++ } ++ ++ if (parent->rb_right == node) ++ { ++ struct rb_node *tmp; ++ __rb_rotate_left(parent, root); ++ tmp = parent; ++ parent = node; ++ node = tmp; ++ } ++ ++ rb_set_black(parent); ++ rb_set_red(gparent); ++ __rb_rotate_right(gparent, root); ++ } else { ++ { ++ struct rb_node *uncle = gparent->rb_left; ++ if (uncle && rb_is_red(uncle)) ++ { ++ rb_set_black(uncle); ++ rb_set_black(parent); ++ rb_set_red(gparent); ++ node = gparent; ++ continue; ++ } ++ } ++ ++ if (parent->rb_left == node) ++ { ++ struct rb_node *tmp; ++ __rb_rotate_right(parent, root); ++ tmp = parent; ++ parent = node; ++ node = tmp; ++ } ++ ++ rb_set_black(parent); ++ rb_set_red(gparent); ++ __rb_rotate_left(gparent, root); ++ } ++ } ++ ++ rb_set_black(root->rb_node); ++} ++ ++static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, ++ struct rb_root *root) ++{ ++ struct rb_node *other; ++ ++ while ((!node || rb_is_black(node)) && node != root->rb_node) ++ { ++ if (parent->rb_left == node) ++ { ++ other = parent->rb_right; ++ if (rb_is_red(other)) ++ { ++ rb_set_black(other); ++ rb_set_red(parent); ++ __rb_rotate_left(parent, root); ++ other = parent->rb_right; ++ } ++ if ((!other->rb_left || rb_is_black(other->rb_left)) && ++ (!other->rb_right || rb_is_black(other->rb_right))) ++ { ++ rb_set_red(other); ++ node = parent; ++ parent = rb_parent(node); ++ } ++ else ++ { ++ if (!other->rb_right || rb_is_black(other->rb_right)) ++ { ++ rb_set_black(other->rb_left); ++ rb_set_red(other); ++ __rb_rotate_right(other, root); ++ other = parent->rb_right; ++ } ++ rb_set_color(other, rb_color(parent)); ++ rb_set_black(parent); ++ rb_set_black(other->rb_right); ++ __rb_rotate_left(parent, root); ++ node = root->rb_node; ++ break; ++ } ++ } ++ else ++ { ++ other = parent->rb_left; ++ if (rb_is_red(other)) ++ { ++ rb_set_black(other); ++ rb_set_red(parent); ++ __rb_rotate_right(parent, root); ++ other = parent->rb_left; ++ } ++ if ((!other->rb_left || rb_is_black(other->rb_left)) && ++ (!other->rb_right || rb_is_black(other->rb_right))) ++ { ++ rb_set_red(other); ++ node = parent; ++ parent = rb_parent(node); ++ } ++ else ++ { ++ if (!other->rb_left || rb_is_black(other->rb_left)) ++ { ++ rb_set_black(other->rb_right); ++ rb_set_red(other); ++ __rb_rotate_left(other, root); ++ other = parent->rb_left; ++ } ++ rb_set_color(other, rb_color(parent)); ++ rb_set_black(parent); ++ rb_set_black(other->rb_left); ++ __rb_rotate_right(parent, root); ++ node = root->rb_node; ++ break; ++ } ++ } ++ } ++ if (node) ++ rb_set_black(node); ++} ++ ++void rb_erase(struct rb_node *node, struct rb_root *root) ++{ ++ struct rb_node *child, *parent; ++ int color; ++ ++ if (!node->rb_left) ++ child = node->rb_right; ++ else if (!node->rb_right) ++ child = node->rb_left; ++ else ++ { ++ struct rb_node *old = node, *left; ++ ++ node = node->rb_right; ++ while ((left = node->rb_left) != NULL) ++ node = left; ++ child = node->rb_right; ++ parent = rb_parent(node); ++ color = rb_color(node); ++ ++ if (child) ++ rb_set_parent(child, parent); ++ if (parent == old) { ++ parent->rb_right = child; ++ parent = node; ++ } else ++ parent->rb_left = child; ++ ++ node->rb_parent_color = old->rb_parent_color; ++ node->rb_right = old->rb_right; ++ node->rb_left = old->rb_left; ++ ++ if (rb_parent(old)) ++ { ++ if (rb_parent(old)->rb_left == old) ++ rb_parent(old)->rb_left = node; ++ else ++ rb_parent(old)->rb_right = node; ++ } else ++ root->rb_node = node; ++ ++ rb_set_parent(old->rb_left, node); ++ if (old->rb_right) ++ rb_set_parent(old->rb_right, node); ++ goto color; ++ } ++ ++ parent = rb_parent(node); ++ color = rb_color(node); ++ ++ if (child) ++ rb_set_parent(child, parent); ++ if (parent) ++ { ++ if (parent->rb_left == node) ++ parent->rb_left = child; ++ else ++ parent->rb_right = child; ++ } ++ else ++ root->rb_node = child; ++ ++ color: ++ if (color == RB_BLACK) ++ __rb_erase_color(child, parent, root); ++} ++ ++/* ++ * This function returns the first node (in sort order) of the tree. ++ */ ++struct rb_node *rb_first(const struct rb_root *root) ++{ ++ struct rb_node *n; ++ ++ n = root->rb_node; ++ if (!n) ++ return NULL; ++ while (n->rb_left) ++ n = n->rb_left; ++ return n; ++} ++ ++struct rb_node *rb_last(const struct rb_root *root) ++{ ++ struct rb_node *n; ++ ++ n = root->rb_node; ++ if (!n) ++ return NULL; ++ while (n->rb_right) ++ n = n->rb_right; ++ return n; ++} ++ ++struct rb_node *rb_next(const struct rb_node *node) ++{ ++ struct rb_node *parent; ++ ++ if (rb_parent(node) == node) ++ return NULL; ++ ++ /* If we have a right-hand child, go down and then left as far ++ as we can. */ ++ if (node->rb_right) { ++ node = node->rb_right; ++ while (node->rb_left) ++ node=node->rb_left; ++ return (struct rb_node *)node; ++ } ++ ++ /* No right-hand children. Everything down and left is ++ smaller than us, so any 'next' node must be in the general ++ direction of our parent. Go up the tree; any time the ++ ancestor is a right-hand child of its parent, keep going ++ up. First time it's a left-hand child of its parent, said ++ parent is our 'next' node. */ ++ while ((parent = rb_parent(node)) && node == parent->rb_right) ++ node = parent; ++ ++ return parent; ++} ++ ++struct rb_node *rb_prev(const struct rb_node *node) ++{ ++ struct rb_node *parent; ++ ++ if (rb_parent(node) == node) ++ return NULL; ++ ++ /* If we have a left-hand child, go down and then right as far ++ as we can. */ ++ if (node->rb_left) { ++ node = node->rb_left; ++ while (node->rb_right) ++ node=node->rb_right; ++ return (struct rb_node *)node; ++ } ++ ++ /* No left-hand children. Go up till we find an ancestor which ++ is a right-hand child of its parent */ ++ while ((parent = rb_parent(node)) && node == parent->rb_left) ++ node = parent; ++ ++ return parent; ++} ++ ++void rb_replace_node(struct rb_node *victim, struct rb_node *new, ++ struct rb_root *root) ++{ ++ struct rb_node *parent = rb_parent(victim); ++ ++ /* Set the surrounding nodes to point to the replacement */ ++ if (parent) { ++ if (victim == parent->rb_left) ++ parent->rb_left = new; ++ else ++ parent->rb_right = new; ++ } else { ++ root->rb_node = new; ++ } ++ if (victim->rb_left) ++ rb_set_parent(victim->rb_left, new); ++ if (victim->rb_right) ++ rb_set_parent(victim->rb_right, new); ++ ++ /* Copy the pointers/colour from the victim to the replacement */ ++ *new = *victim; ++} ++ +diff --git a/rbtree.h b/rbtree.h +new file mode 100644 +index 0000000..8f232ae +--- /dev/null ++++ b/rbtree.h +@@ -0,0 +1,166 @@ ++/* ++ Red Black Trees ++ (C) 1999 Andrea Arcangeli ++ Taken from the Linux 2.6.30 source. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ ++ linux/include/linux/rbtree.h ++ ++ To use rbtrees you'll have to implement your own insert and search cores. ++ This will avoid us to use callbacks and to drop drammatically performances. ++ I know it's not the cleaner way, but in C (not in C++) to get ++ performances and genericity... ++ ++ Some example of insert and search follows here. The search is a plain ++ normal search over an ordered tree. The insert instead must be implemented ++ int two steps: as first thing the code must insert the element in ++ order as a red leaf in the tree, then the support library function ++ rb_insert_color() must be called. Such function will do the ++ not trivial work to rebalance the rbtree if necessary. ++ ++----------------------------------------------------------------------- ++static inline struct page * rb_search_page_cache(struct inode * inode, ++ unsigned long offset) ++{ ++ struct rb_node * n = inode->i_rb_page_cache.rb_node; ++ struct page * page; ++ ++ while (n) ++ { ++ page = rb_entry(n, struct page, rb_page_cache); ++ ++ if (offset < page->offset) ++ n = n->rb_left; ++ else if (offset > page->offset) ++ n = n->rb_right; ++ else ++ return page; ++ } ++ return NULL; ++} ++ ++static inline struct page * __rb_insert_page_cache(struct inode * inode, ++ unsigned long offset, ++ struct rb_node * node) ++{ ++ struct rb_node ** p = &inode->i_rb_page_cache.rb_node; ++ struct rb_node * parent = NULL; ++ struct page * page; ++ ++ while (*p) ++ { ++ parent = *p; ++ page = rb_entry(parent, struct page, rb_page_cache); ++ ++ if (offset < page->offset) ++ p = &(*p)->rb_left; ++ else if (offset > page->offset) ++ p = &(*p)->rb_right; ++ else ++ return page; ++ } ++ ++ rb_link_node(node, parent, p); ++ ++ return NULL; ++} ++ ++static inline struct page * rb_insert_page_cache(struct inode * inode, ++ unsigned long offset, ++ struct rb_node * node) ++{ ++ struct page * ret; ++ if ((ret = __rb_insert_page_cache(inode, offset, node))) ++ goto out; ++ rb_insert_color(node, &inode->i_rb_page_cache); ++ out: ++ return ret; ++} ++----------------------------------------------------------------------- ++*/ ++ ++#ifndef _LINUX_RBTREE_H ++#define _LINUX_RBTREE_H ++ ++#include ++ ++#define container_of(ptr, type, member) ({ \ ++ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ++ (type *)( (char *)__mptr - offsetof(type,member) );}) ++ ++struct rb_node ++{ ++ unsigned long rb_parent_color; ++#define RB_RED 0 ++#define RB_BLACK 1 ++ struct rb_node *rb_right; ++ struct rb_node *rb_left; ++} __attribute__((aligned(sizeof(long)))); ++ /* The alignment might seem pointless, but allegedly CRIS needs it */ ++ ++struct rb_root ++{ ++ struct rb_node *rb_node; ++}; ++ ++ ++#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3)) ++#define rb_color(r) ((r)->rb_parent_color & 1) ++#define rb_is_red(r) (!rb_color(r)) ++#define rb_is_black(r) rb_color(r) ++#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0) ++#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0) ++ ++static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) ++{ ++ rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p; ++} ++static inline void rb_set_color(struct rb_node *rb, int color) ++{ ++ rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; ++} ++ ++#define RB_ROOT (struct rb_root) { NULL, } ++#define rb_entry(ptr, type, member) container_of(ptr, type, member) ++ ++#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) ++#define RB_EMPTY_NODE(node) (rb_parent(node) == node) ++#define RB_CLEAR_NODE(node) (rb_set_parent(node, node)) ++ ++extern void rb_insert_color(struct rb_node *, struct rb_root *); ++extern void rb_erase(struct rb_node *, struct rb_root *); ++ ++/* Find logical next and previous nodes in a tree */ ++extern struct rb_node *rb_next(const struct rb_node *); ++extern struct rb_node *rb_prev(const struct rb_node *); ++extern struct rb_node *rb_first(const struct rb_root *); ++extern struct rb_node *rb_last(const struct rb_root *); ++ ++/* Fast replacement of a single node without remove/rebalance/add/rebalance */ ++extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, ++ struct rb_root *root); ++ ++static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, ++ struct rb_node ** rb_link) ++{ ++ node->rb_parent_color = (unsigned long )parent; ++ node->rb_left = node->rb_right = NULL; ++ ++ *rb_link = node; ++} ++ ++#endif /* _LINUX_RBTREE_H */ ++ +-- +2.19.1 + diff --git a/bugfix-fix-fd-check.patch b/bugfix-fix-fd-check.patch new file mode 100644 index 0000000..6c81cb8 --- /dev/null +++ b/bugfix-fix-fd-check.patch @@ -0,0 +1,18 @@ +From d59e4d224b3271cf7a7fe53cd7c5d539b58eac32 Mon Sep 17 00:00:00 2001 +From: lvying +Date: Sat, 26 Jan 2019 15:54:17 +0800 +Subject: [PATCH] rasdaemon:fix fd check + +reason:fix fd check + +--- rasdaemon-0.4.1/ras-events.c 2018-04-12 04:05:05.000000000 -0400 ++++ rasdaemon-0.4.1/ras-events.c 2018-04-12 04:11:44.000000000 -0400 +@@ -544,7 +544,7 @@ + + /* Select uptime tracing */ + fd = open_trace(ras, "trace_clock", O_WRONLY); +- if (!fd) { ++ if (fd < 0) { + log(TERM, LOG_ERR, + "Kernel didn't allow writing to trace_clock\n"); + return 0; diff --git a/bugfix-ras-events-memory-leak.patch b/bugfix-ras-events-memory-leak.patch new file mode 100644 index 0000000..e78651f --- /dev/null +++ b/bugfix-ras-events-memory-leak.patch @@ -0,0 +1,18 @@ +From d59e4d224b3271cf7a7fe53cd7c5d539b58eac32 Mon Sep 17 00:00:00 2001 +From: lvying +Date: Sat, 26 Jan 2019 15:54:17 +0800 +Subject: [PATCH] rasdaemon:fix ras events memory leak + +reason:fix ras events memory leak + +diff -uprN a/ras-events.c b/ras-events.c +--- a/ras-events.c 2018-06-22 14:20:42.880878700 +0800 ++++ b/ras-events.c 2018-06-22 14:38:24.420726900 +0800 +@@ -262,6 +262,7 @@ static void parse_ras_data(struct pthrea + fflush(stdout); + pevent_print_event(pdata->ras->pevent, &s, &record); + trace_seq_do_printf(&s); ++ trace_seq_destroy(&s); + printf("\n"); + } + diff --git a/bugfix-rasdaemon-wait-for-file-access.patch b/bugfix-rasdaemon-wait-for-file-access.patch new file mode 100644 index 0000000..2991e98 --- /dev/null +++ b/bugfix-rasdaemon-wait-for-file-access.patch @@ -0,0 +1,50 @@ +From d59e4d224b3271cf7a7fe53cd7c5d539b58eac32 Mon Sep 17 00:00:00 2001 +From: lvying +Date: Sat, 26 Jan 2019 15:54:17 +0800 +Subject: [PATCH] rasdaemon:fix rasdaemon wait for file access + +reason:fix fix rasdaemon wait for file access + +--- rasdaemon-0.4.1/ras-events.c 2018-04-08 04:05:18.755000000 -0400 ++++ rasdaemon-0.4.1/ras-events.c 2018-04-08 04:05:46.879000000 -0400 +@@ -89,15 +89,39 @@ + return ENOENT; + } + ++static int wait_access(char *path, int ms) ++{ ++ int i; ++ for (i = 0; i < ms; i++) { ++ if (access(path, F_OK) == 0) ++ return 0; ++ usleep(1000); ++ } ++ ++ log(ALL, LOG_WARNING, "wait_access() failed, %s not created in %d ms\n", path, ms); ++ return -1; ++} ++ + static int open_trace(struct ras_events *ras, char *name, int flags) + { ++ int ret = 0; + char fname[MAX_PATH + 1]; + + strcpy(fname, ras->tracing); + strcat(fname, "/"); + strcat(fname, name); + +- return open(fname, flags); ++ ret = wait_access(fname, 100); ++ if (ret != 0) { ++ /* use -1 to keep same error value with open() */ ++ return -1; ++ } ++ ++ ret = open(fname, flags); ++ if (ret == -1) ++ log(ALL, LOG_WARNING, "open_trace()->open() failed, fname=%s ret=%d errno=%d\n", fname, ret, errno); ++ ++ return ret; + } + + static int get_tracing_dir(struct ras_events *ras) diff --git a/feature-mc-support-page-isolation.patch b/feature-mc-support-page-isolation.patch new file mode 100644 index 0000000..80a5a1d --- /dev/null +++ b/feature-mc-support-page-isolation.patch @@ -0,0 +1,524 @@ +From 35b8410151f253f2c924ebd15feb1b601da9167c Mon Sep 17 00:00:00 2001 +From: lvying +Date: Sat, 26 Jan 2019 15:22:29 +0800 +Subject: [PATCH] rasdaemon:mc support page isolation + +reason: mc support page isolation +--- + Makefile.am | 4 +- + misc/rasdaemon.env | 29 ++++ + misc/rasdaemon.service.in | 1 + + ras-events.c | 4 + + ras-mc-handler.c | 5 + + ras-page-isolation.c | 308 ++++++++++++++++++++++++++++++++++++++ + ras-page-isolation.h | 68 +++++++++ + 7 files changed, 417 insertions(+), 2 deletions(-) + create mode 100644 misc/rasdaemon.env + create mode 100644 ras-page-isolation.c + create mode 100644 ras-page-isolation.h + +diff --git a/Makefile.am b/Makefile.am +index 2ff742d..6fc39f2 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -17,7 +17,7 @@ all-local: $(SYSTEMD_SERVICES) + + sbin_PROGRAMS = rasdaemon + rasdaemon_SOURCES = rasdaemon.c ras-events.c ras-mc-handler.c \ +- bitfield.c rbtree.c ++ bitfield.c rbtree.c ras-page-isolation.c + if WITH_SQLITE3 + rasdaemon_SOURCES += ras-record.c + endif +@@ -59,7 +59,7 @@ rasdaemon_LDADD = -lpthread $(SQLITE3_LIBS) libtrace/libtrace.a + include_HEADERS = config.h ras-events.h ras-logger.h ras-mc-handler.h \ + ras-aer-handler.h ras-mce-handler.h ras-record.h bitfield.h ras-report.h \ + ras-extlog-handler.h ras-arm-handler.h ras-non-standard-handler.h \ +- ras-devlink-handler.h ras-diskerror-handler.h rbtree.h ++ ras-devlink-handler.h ras-diskerror-handler.h rbtree.h ras-page-isolation.h + + # This rule can't be called with more than one Makefile job (like make -j8) + # I can't figure out a way to fix that +diff --git a/misc/rasdaemon.env b/misc/rasdaemon.env +new file mode 100644 +index 0000000..c327353 +--- /dev/null ++++ b/misc/rasdaemon.env +@@ -0,0 +1,29 @@ ++# Page Isolation ++# Note: Run-time configuration is unsupported, service restart needed. ++ ++# Specify the threshold of isolating buggy pages. ++# ++# Format: ++# [0-9]+[unit] ++# WARNING: please make sure perfectly match this format. ++# ++# Supported units: ++# PAGE_CE_REFRESH_CYCLE: D|d (day), H|h (hour), M|m (min), default is in hour ++# PAGE_CE_THRESHOLD: K|k (x1000), M|m (x1000k), default is none ++# ++# The two configs will only take no effect when PAGE_CE_ACTION is "off". ++PAGE_CE_REFRESH_CYCLE="24h" ++PAGE_CE_THRESHOLD="50" ++ ++# Specify the internal action in rasdaemon to exceeding a page error threshold. ++# ++# off no action ++# account only account errors ++# soft try to soft-offline page without killing any processes ++# This requires an uptodate kernel. Might not be successfull. ++# hard try to hard-offline page by killing processes ++# Requires an uptodate kernel. Might not be successfull. ++# soft-then-hard First try to soft offline, then try hard offlining. ++# Note: default offline choice is "soft". ++PAGE_CE_ACTION="soft" ++ +diff --git a/misc/rasdaemon.service.in b/misc/rasdaemon.service.in +index be9ad5a..e73a08a 100644 +--- a/misc/rasdaemon.service.in ++++ b/misc/rasdaemon.service.in +@@ -3,6 +3,7 @@ Description=RAS daemon to log the RAS events + After=syslog.target + + [Service] ++EnvironmentFile=/etc/sysconfig/rasdaemon + ExecStart=@sbindir@/rasdaemon -f -r + ExecStartPost=@sbindir@/rasdaemon --enable + ExecStop=@sbindir@/rasdaemon --disable +diff --git a/ras-events.c b/ras-events.c +index 4cc2cee..70b02e5 100644 +--- a/ras-events.c ++++ b/ras-events.c +@@ -37,6 +37,7 @@ + #include "ras-diskerror-handler.h" + #include "ras-record.h" + #include "ras-logger.h" ++#include "ras-page-isolation.h" + + /* + * Polling time, if read() doesn't block. Currently, trace_pipe_raw never +@@ -760,6 +761,9 @@ int handle_ras_events(int record_events) + ras->page_size = page_size; + ras->record_events = record_events; + ++ /* FIXME: enable memory isolation unconditionally */ ++ ras_page_account_init(); ++ + rc = add_event_handler(ras, pevent, page_size, "ras", "mc_event", + ras_mc_event_handler, NULL, MC_EVENT); + if (!rc) +diff --git a/ras-mc-handler.c b/ras-mc-handler.c +index deb7e05..bfbe1ef 100644 +--- a/ras-mc-handler.c ++++ b/ras-mc-handler.c +@@ -23,6 +23,7 @@ + #include "ras-mc-handler.h" + #include "ras-record.h" + #include "ras-logger.h" ++#include "ras-page-isolation.h" + #include "ras-report.h" + + int ras_mc_event_handler(struct trace_seq *s, +@@ -183,6 +184,10 @@ int ras_mc_event_handler(struct trace_seq *s, + + ras_store_mc_event(ras, &ev); + ++ /* Account page corrected errors */ ++ if (!strcmp(ev.error_type, "Corrected")) ++ ras_record_page_error(ev.address, ev.error_count, now); ++ + #ifdef HAVE_ABRT_REPORT + /* Report event to ABRT */ + ras_report_mc_event(ras, &ev); +diff --git a/ras-page-isolation.c b/ras-page-isolation.c +new file mode 100644 +index 0000000..1bd04e4 +--- /dev/null ++++ b/ras-page-isolation.c +@@ -0,0 +1,308 @@ ++/* ++ * Copyright (C) 2015 Yun Wu (Abel) ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include "ras-logger.h" ++#include "ras-page-isolation.h" ++ ++static const struct config threshold_units[] = { ++ { "m", 1000 }, ++ { "k", 1000 }, ++ { "", 1 }, ++ {} ++}; ++ ++static const struct config cycle_units[] = { ++ { "d", 24 }, ++ { "h", 60 }, ++ { "m", 60 }, ++ {} ++}; ++ ++static struct isolation threshold = { ++ .name = "PAGE_CE_THRESHOLD", ++ .units = threshold_units, ++ .env = "50", ++ .unit = "", ++}; ++ ++static struct isolation cycle = { ++ .name = "PAGE_CE_REFRESH_CYCLE", ++ .units = cycle_units, ++ .env = "24h", ++ .unit = "h", ++}; ++ ++static const char *kernel_offline[] = { ++ [OFFLINE_SOFT] = "/sys/devices/system/memory/soft_offline_page", ++ [OFFLINE_HARD] = "/sys/devices/system/memory/hard_offline_page", ++ [OFFLINE_SOFT_THEN_HARD] = "/sys/devices/system/memory/soft_offline_page", ++}; ++ ++static const struct config offline_choice[] = { ++ { "off", OFFLINE_OFF }, ++ { "account", OFFLINE_ACCOUNT }, ++ { "soft", OFFLINE_SOFT }, ++ { "hard", OFFLINE_HARD }, ++ { "soft-then-hard", OFFLINE_SOFT_THEN_HARD }, ++ {} ++}; ++ ++static const char *page_state[] = { ++ [PAGE_ONLINE] = "online", ++ [PAGE_OFFLINE] = "offlined", ++ [PAGE_OFFLINE_FAILED] = "offline-failed", ++}; ++ ++static enum otype offline = OFFLINE_SOFT; ++static struct rb_root page_records; ++ ++static void page_offline_init(void) ++{ ++ const char *env = "PAGE_CE_ACTION"; ++ char *choice = getenv(env); ++ const struct config *c = NULL; ++ int matched = 0; ++ ++ if (choice) { ++ for (c = offline_choice; c->name; c++) { ++ if (!strcasecmp(choice, c->name)) { ++ offline = c->val; ++ matched = 1; ++ break; ++ } ++ } ++ } ++ ++ if (!matched) ++ log(TERM, LOG_INFO, "Improper %s, set to default soft\n", env); ++ ++ if (offline > OFFLINE_ACCOUNT && access(kernel_offline[offline], W_OK)) { ++ log(TERM, LOG_INFO, "Kernel does not support page offline interface\n"); ++ offline = OFFLINE_ACCOUNT; ++ } ++ ++ log(TERM, LOG_INFO, "Page offline choice on Corrected Errors is %s\n", ++ offline_choice[offline].name); ++} ++ ++static void parse_isolation_env(struct isolation *config) ++{ ++ char *env = getenv(config->name), *unit = NULL; ++ const struct config *units = NULL; ++ unsigned long value; ++ int no_unit, unit_matched; ++ int last, i; ++ ++reparse: ++ /* Start a new round */ ++ no_unit = unit_matched = 0; ++ ++ /* Environments could be un-configured */ ++ if (!env || !strlen(env)) ++ goto use_default; ++ ++ /* Index of the last char of environment */ ++ last = strlen(env) - 1; ++ unit = env + last; ++ if (isdigit(*unit)) { ++ unit = config->unit; ++ no_unit = 1; ++ } ++ ++ /* Only decimal digit can be accepted */ ++ for (i = 0; i < last; i++) { ++ if (!isdigit(env[i])) ++ goto use_default; ++ } ++ ++ /* Check if value is valid or not */ ++ if (sscanf(env, "%lu", &value) < 1 || !value) ++ goto use_default; ++ ++ for (units = config->units; units->name; units++) { ++ if (!strcasecmp(unit, units->name)) ++ unit_matched = 1; ++ if (unit_matched) ++ value *= units->val; ++ } ++ ++ /* Improper unit */ ++ if (!unit_matched) ++ goto use_default; ++ ++ config->env = env; ++ config->val = value; ++ config->unit = no_unit ? unit : ""; ++ return; ++ ++use_default: ++ log(TERM, LOG_INFO, "Improper %s, set to default %s.\n", ++ config->name, config->env); ++ ++ env = config->env; ++ goto reparse; ++} ++ ++static void page_isolation_init(void) ++{ ++ /** ++ * It's unnecessary to parse threshold configuration when offline ++ * choice is off. ++ */ ++ if (offline == OFFLINE_OFF) ++ return; ++ ++ parse_isolation_env(&threshold); ++ parse_isolation_env(&cycle); ++ log(TERM, LOG_INFO, "Threshold of memory Corrected Errors is %s%s / %s%s\n", ++ threshold.env, threshold.unit, cycle.env, cycle.unit); ++} ++ ++void ras_page_account_init(void) ++{ ++ page_offline_init(); ++ page_isolation_init(); ++} ++ ++static int do_page_offline(unsigned long long addr, enum otype type) ++{ ++ FILE *offline_file; ++ int err; ++ ++ offline_file = fopen(kernel_offline[type], "w"); ++ if (!offline_file) ++ return -1; ++ ++ fprintf(offline_file, "%#llx", addr); ++ err = ferror(offline_file) ? -1 : 0; ++ fclose(offline_file); ++ ++ return err; ++} ++ ++static void page_offline(struct page_record *pr) ++{ ++ unsigned long long addr = pr->addr; ++ int ret; ++ ++ /* Offlining page is not required */ ++ if (offline <= OFFLINE_ACCOUNT) ++ return; ++ ++ /* Ignore offlined pages */ ++ if (pr->offlined != PAGE_ONLINE) ++ return; ++ ++ /* Time to silence this noisy page */ ++ if (offline == OFFLINE_SOFT_THEN_HARD) { ++ ret = do_page_offline(addr, OFFLINE_SOFT); ++ if (ret < 0) ++ ret = do_page_offline(addr, OFFLINE_HARD); ++ } else { ++ ret = do_page_offline(addr, offline); ++ } ++ ++ pr->offlined = ret < 0 ? PAGE_OFFLINE_FAILED : PAGE_OFFLINE; ++ ++ log(TERM, LOG_INFO, "Result of offlining page at %#llx: %s\n", ++ addr, page_state[pr->offlined]); ++} ++ ++static void page_record(struct page_record *pr, unsigned count, time_t time) ++{ ++ unsigned long period = time - pr->start; ++ unsigned long tolerate; ++ ++ if (period >= cycle.val) { ++ /** ++ * Since we don't refresh automatically, it is possible that the period ++ * between two occurences longer than the pre-configured refresh cycle. ++ * In this case, we tolerate the frequency of the whole period up to ++ * the pre-configured threshold. ++ */ ++ tolerate = (period / (double)cycle.val) * threshold.val; ++ pr->count -= (tolerate > pr->count) ? pr->count : tolerate; ++ pr->start = time; ++ pr->excess = 0; ++ } ++ ++ pr->count += count; ++ if (pr->count >= threshold.val) { ++ log(TERM, LOG_INFO, "Corrected Errors at %#llx exceed threshold\n", pr->addr); ++ ++ /** ++ * Backup ce count of current cycle to enable next round, which actually ++ * should never happen if we can disable overflow completely in the same ++ * time unit (but sadly we can't). ++ */ ++ pr->excess += pr->count; ++ pr->count = 0; ++ page_offline(pr); ++ } ++} ++ ++static struct page_record *page_lookup_insert(unsigned long long addr) ++{ ++ struct rb_node **entry = &page_records.rb_node; ++ struct rb_node *parent = NULL; ++ struct page_record *pr = NULL, *find = NULL; ++ ++ while (*entry) { ++ parent = *entry; ++ pr = rb_entry(parent, struct page_record, entry); ++ if (addr == pr->addr) { ++ return pr; ++ } else if (addr < pr->addr) { ++ entry = &(*entry)->rb_left; ++ } else { ++ entry = &(*entry)->rb_right; ++ } ++ } ++ ++ find = calloc(1, sizeof(struct page_record)); ++ if (!find) { ++ log(TERM, LOG_ERR, "No memory for page records\n"); ++ return NULL; ++ } ++ ++ find->addr = addr; ++ rb_link_node(&find->entry, parent, entry); ++ rb_insert_color(&find->entry, &page_records); ++ ++ return find; ++} ++ ++void ras_record_page_error(unsigned long long addr, unsigned count, time_t time) ++{ ++ struct page_record *pr = NULL; ++ ++ if (offline == OFFLINE_OFF) ++ return; ++ ++ pr = page_lookup_insert(addr & PAGE_MASK); ++ if (pr) { ++ if (!pr->start) ++ pr->start = time; ++ page_record(pr, count, time); ++ } ++} +diff --git a/ras-page-isolation.h b/ras-page-isolation.h +new file mode 100644 +index 0000000..6aefa1e +--- /dev/null ++++ b/ras-page-isolation.h +@@ -0,0 +1,68 @@ ++/* ++ * Copyright (C) 2015 Yun Wu (Abel) ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++*/ ++ ++#ifndef __RAS_PAGE_ISOLATION_H ++#define __RAS_PAGE_ISOLATION_H ++ ++#include ++#include "rbtree.h" ++ ++#define PAGE_SHIFT 12 ++#define PAGE_SIZE (1 << PAGE_SHIFT) ++#define PAGE_MASK (~(PAGE_SIZE-1)) ++ ++struct config { ++ char *name; ++ int val; ++}; ++ ++enum otype { ++ OFFLINE_OFF, ++ OFFLINE_ACCOUNT, ++ OFFLINE_SOFT, ++ OFFLINE_HARD, ++ OFFLINE_SOFT_THEN_HARD, ++}; ++ ++enum pstate { ++ PAGE_ONLINE, ++ PAGE_OFFLINE, ++ PAGE_OFFLINE_FAILED, ++}; ++ ++struct page_record { ++ struct rb_node entry; ++ unsigned long long addr; ++ time_t start; ++ enum pstate offlined; ++ unsigned long count; ++ unsigned long excess; ++}; ++ ++struct isolation { ++ char *name; ++ char *env; ++ const struct config *units; ++ unsigned long val; ++ char *unit; ++}; ++ ++void ras_page_account_init(void); ++void ras_record_page_error(unsigned long long addr, unsigned count, time_t time); ++ ++#endif +-- +2.19.1 + diff --git a/feature-report-ARM-processor-info.patch b/feature-report-ARM-processor-info.patch new file mode 100644 index 0000000..0fde36b --- /dev/null +++ b/feature-report-ARM-processor-info.patch @@ -0,0 +1,367 @@ +From 5ae4ad1d71e931fa1639f605c83a0313f641c282 Mon Sep 17 00:00:00 2001 +From: lvying +Date: Wed, 24 Apr 2019 17:50:57 +0800 +Subject: [PATCH] rasdaemon:report ARM processor info + +reason: report ARM processor info + +Signed-off-by: lvying +--- + Makefile.am | 4 +- + ras-arm-ctx-handler.c | 75 ++++++++++++++++++++++++++++++ + ras-arm-ctx-handler.h | 23 +++++++++ + ras-arm-error-info-handler.c | 90 ++++++++++++++++++++++++++++++++++++ + ras-arm-error-info-handler.h | 23 +++++++++ + ras-events.c | 18 ++++++++ + ras-events.h | 2 + + ras-record.h | 19 ++++++++ + 8 files changed, 252 insertions(+), 2 deletions(-) + create mode 100644 ras-arm-ctx-handler.c + create mode 100644 ras-arm-ctx-handler.h + create mode 100644 ras-arm-error-info-handler.c + create mode 100644 ras-arm-error-info-handler.h + +diff --git a/Makefile.am b/Makefile.am +index 6fc39f2..52cd1a2 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -28,7 +28,7 @@ if WITH_NON_STANDARD + rasdaemon_SOURCES += ras-non-standard-handler.c + endif + if WITH_ARM +- rasdaemon_SOURCES += ras-arm-handler.c ++ rasdaemon_SOURCES += ras-arm-handler.c ras-arm-error-info-handler.c ras-arm-ctx-handler.c + endif + if WITH_MCE + rasdaemon_SOURCES += ras-mce-handler.c mce-intel.c mce-amd.c \ +@@ -59,7 +59,7 @@ rasdaemon_LDADD = -lpthread $(SQLITE3_LIBS) libtrace/libtrace.a + include_HEADERS = config.h ras-events.h ras-logger.h ras-mc-handler.h \ + ras-aer-handler.h ras-mce-handler.h ras-record.h bitfield.h ras-report.h \ + ras-extlog-handler.h ras-arm-handler.h ras-non-standard-handler.h \ +- ras-devlink-handler.h ras-diskerror-handler.h rbtree.h ras-page-isolation.h ++ ras-devlink-handler.h ras-diskerror-handler.h rbtree.h ras-page-isolation.h ras-arm-ctx-handler.h ras-arm-error-info-handler.h + + # This rule can't be called with more than one Makefile job (like make -j8) + # I can't figure out a way to fix that +diff --git a/ras-arm-ctx-handler.c b/ras-arm-ctx-handler.c +new file mode 100644 +index 0000000..4abe3a8 +--- /dev/null ++++ b/ras-arm-ctx-handler.c +@@ -0,0 +1,75 @@ ++/* ++ * Copyright (c) 2016, The Linux Foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include "libtrace/kbuffer.h" ++#include "ras-arm-ctx-handler.h" ++#include "ras-record.h" ++#include "ras-logger.h" ++#include "ras-report.h" ++ ++int ras_arm_ctx_handler(struct trace_seq *s, ++ struct pevent_record *record, ++ struct event_format *event, void *context) ++{ ++ unsigned long long val; ++ struct ras_events *ras = context; ++ struct ras_arm_ctx_event ev; ++ time_t now; ++ struct tm *tm = NULL; ++ int len; ++ ++ memset(&ev, 0, sizeof(ev)); ++ ++ /* ++ * Newer kernels (3.10-rc1 or upper) provide an uptime clock. ++ * On previous kernels, the way to properly generate an event would ++ * be to inject a fake one, measure its timestamp and diff it against ++ * gettimeofday. We won't do it here. Instead, let's use uptime, ++ * falling-back to the event report's time, if "uptime" clock is ++ * not available (legacy kernels). ++ */ ++ ++ if (ras->use_uptime) ++ now = record->ts/user_hz + ras->uptime_diff; ++ else ++ now = time(NULL); ++ ++ tm = localtime(&now); ++ if (tm) ++ strftime(ev.timestamp, sizeof(ev.timestamp), ++ "%Y-%m-%d %H:%M:%S %z", tm); ++ ++ if (pevent_get_field_val(s, event, "index", record, &val, 1) < 0) ++ return -1; ++ ev.index = val; ++ trace_seq_printf(s, " Context info structure %d:", ev.index); ++ ++ ev.processor_ctx_info = pevent_get_field_raw(s, event, "processor_ctx_info", record, &len, 1); ++ if (!ev.processor_ctx_info) ++ return -1; ++ ++ if (*ev.processor_ctx_info) { ++ trace_seq_puts(s, "\n"); ++ trace_seq_puts(s, ev.processor_ctx_info); ++ } ++ ++ // TODO: how to design this table: related to ARM event table or sperated table? ++ ++ // TODO: report to ABRT ++ ++ return 0; ++} +diff --git a/ras-arm-ctx-handler.h b/ras-arm-ctx-handler.h +new file mode 100644 +index 0000000..d23a142 +--- /dev/null ++++ b/ras-arm-ctx-handler.h +@@ -0,0 +1,23 @@ ++/* ++ * Copyright (c) 2016, The Linux Foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#ifndef __RAS_ARM_CTX_HANDLER_H ++#define __RAS_ARM_CTX_HANDLER_H ++ ++#include "ras-events.h" ++#include "libtrace/event-parse.h" ++ ++int ras_arm_ctx_handler(struct trace_seq *s, ++ struct pevent_record *record, ++ struct event_format *event, void *context); ++#endif +diff --git a/ras-arm-error-info-handler.c b/ras-arm-error-info-handler.c +new file mode 100644 +index 0000000..afafe89 +--- /dev/null ++++ b/ras-arm-error-info-handler.c +@@ -0,0 +1,90 @@ ++/* ++ * Copyright (c) 2016, The Linux Foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include "libtrace/kbuffer.h" ++#include "ras-arm-error-info-handler.h" ++#include "ras-record.h" ++#include "ras-logger.h" ++#include "ras-report.h" ++ ++int ras_arm_error_info_handler(struct trace_seq *s, ++ struct pevent_record *record, ++ struct event_format *event, void *context) ++{ ++ unsigned long long val; ++ struct ras_events *ras = context; ++ struct ras_arm_err_info_event ev; ++ time_t now; ++ struct tm *tm = NULL; ++ int len; ++ ++ memset(&ev, 0, sizeof(ev)); ++ ++ /* ++ * Newer kernels (3.10-rc1 or upper) provide an uptime clock. ++ * On previous kernels, the way to properly generate an event would ++ * be to inject a fake one, measure its timestamp and diff it against ++ * gettimeofday. We won't do it here. Instead, let's use uptime, ++ * falling-back to the event report's time, if "uptime" clock is ++ * not available (legacy kernels). ++ */ ++ ++ if (ras->use_uptime) ++ now = record->ts/user_hz + ras->uptime_diff; ++ else ++ now = time(NULL); ++ ++ tm = localtime(&now); ++ if (tm) ++ strftime(ev.timestamp, sizeof(ev.timestamp), ++ "%Y-%m-%d %H:%M:%S %z", tm); ++ ++ if (pevent_get_field_val(s, event, "index", record, &val, 1) < 0) ++ return -1; ++ ev.index = val; ++ trace_seq_printf(s, " Error info structure %d:", ev.index); ++ ++ if (pevent_get_field_val(s, event, "multiplie_error", record, &val, 1) < 0) ++ return -1; ++ ev.multiplie_error = val; ++ trace_seq_printf(s, "\n num errors: %d", ev.multiplie_error); ++ ++ ev.processor_error_info = pevent_get_field_raw(s, event, "processor_error_info", record, &len, 1); ++ if (!ev.processor_error_info) ++ return -1; ++ ++ if (*ev.processor_error_info) { ++ trace_seq_puts(s, "\n"); ++ trace_seq_puts(s, ev.processor_error_info); ++ } ++ ++ if (pevent_get_field_val(s, event, "va", record, &val, 1) < 0) ++ return -1; ++ ev.va = val; ++ trace_seq_printf(s, "\n virtual fault address: 0x%lx", ev.va); ++ ++ if (pevent_get_field_val(s, event, "pa", record, &val, 1) < 0) ++ return -1; ++ ev.pa = val; ++ trace_seq_printf(s, "\n physical fault address: 0x%lx", ev.pa); ++ ++ // TODO: how to design this table: related to ARM event table or sperated table? ++ ++ // TODO: report to ABRT ++ ++ return 0; ++} +diff --git a/ras-arm-error-info-handler.h b/ras-arm-error-info-handler.h +new file mode 100644 +index 0000000..9680989 +--- /dev/null ++++ b/ras-arm-error-info-handler.h +@@ -0,0 +1,23 @@ ++/* ++ * Copyright (c) 2016, The Linux Foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#ifndef __RAS_ARM_ERROR_INFO_HANDLER_H ++#define __RAS_ARM_ERROR_INFO_HANDLER_H ++ ++#include "ras-events.h" ++#include "libtrace/event-parse.h" ++ ++int ras_arm_error_info_handler(struct trace_seq *s, ++ struct pevent_record *record, ++ struct event_format *event, void *context); ++#endif +diff --git a/ras-events.c b/ras-events.c +index 70b02e5..a8f7fe9 100644 +--- a/ras-events.c ++++ b/ras-events.c +@@ -27,6 +27,8 @@ + #include + #include "libtrace/kbuffer.h" + #include "libtrace/event-parse.h" ++#include "ras-arm-error-info-handler.h" ++#include "ras-arm-ctx-handler.h" + #include "ras-mc-handler.h" + #include "ras-aer-handler.h" + #include "ras-non-standard-handler.h" +@@ -800,6 +802,22 @@ int handle_ras_events(int record_events) + else + log(ALL, LOG_ERR, "Can't get traces from %s:%s\n", + "ras", "arm_event"); ++ ++ rc = add_event_handler(ras, pevent, page_size, "ras", "arm_err_info_event", ++ ras_arm_error_info_handler, NULL, ARM_ERR_INFO_EVENT); ++ if (!rc) ++ num_events++; ++ else ++ log(ALL, LOG_ERR, "Can't get traces from %s:%s\n", ++ "ras", "arm_err_info_event"); ++ ++ rc = add_event_handler(ras, pevent, page_size, "ras", "arm_ctx_event", ++ ras_arm_ctx_handler, NULL, ARM_CTX_EVENT); ++ if (!rc) ++ num_events++; ++ else ++ log(ALL, LOG_ERR, "Can't get traces from %s:%s\n", ++ "ras", "arm_ctx_event"); + #endif + + cpus = get_num_cpus(ras); +diff --git a/ras-events.h b/ras-events.h +index f028741..6accdd1 100644 +--- a/ras-events.h ++++ b/ras-events.h +@@ -38,6 +38,8 @@ enum { + EXTLOG_EVENT, + DEVLINK_EVENT, + DISKERROR_EVENT, ++ ARM_ERR_INFO_EVENT, ++ ARM_CTX_EVENT, + NR_EVENTS + }; + +diff --git a/ras-record.h b/ras-record.h +index 5311c67..b7d7436 100644 +--- a/ras-record.h ++++ b/ras-record.h +@@ -94,11 +94,30 @@ struct diskerror_event { + const char *cmd; + }; + ++struct ras_arm_err_info_event ++{ ++ char timestamp[64]; ++ uint32_t index; ++ uint16_t multiplie_error; ++ uint64_t va; ++ uint64_t pa; ++ const char *processor_error_info; ++}; ++ ++struct ras_arm_ctx_event ++{ ++ char timestamp[64]; ++ uint32_t index; ++ const char *processor_ctx_info; ++}; ++ + struct ras_mc_event; + struct ras_aer_event; + struct ras_extlog_event; + struct ras_non_standard_event; + struct ras_arm_event; ++struct ras_arm_err_info_event; ++struct ras_arm_ctx_event; + struct mce_event; + struct devlink_event; + struct diskerror_event; +-- +2.19.1 + diff --git a/output-log-timely.patch b/output-log-timely.patch new file mode 100644 index 0000000..bd98453 --- /dev/null +++ b/output-log-timely.patch @@ -0,0 +1,27 @@ +From e426fef8949c4bd7a4e3ebca84db95a0c90fc918 Mon Sep 17 00:00:00 2001 +From: Ying Lv +Date: Mon, 13 May 2019 06:00:40 +0800 +Subject: [PATCH] rasdaemon:output log timely + +reason: output log timely + +Signed-off-by: Ying Lv +--- + ras-events.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/ras-events.c b/ras-events.c +index 615550c..f32d512 100644 +--- a/ras-events.c ++++ b/ras-events.c +@@ -301,6 +301,7 @@ static void parse_ras_data(struct pthread_data *pdata, struct kbuffer *kbuf, + trace_seq_do_printf(&s); + trace_seq_destroy(&s); + printf("\n"); ++ fflush(stdout); + } + + static int get_num_cpus(struct ras_events *ras) +-- +1.8.3.1 + diff --git a/rasdaemon-0.6.3.tar.gz b/rasdaemon-0.6.3.tar.gz new file mode 100644 index 0000000..d3d9073 Binary files /dev/null and b/rasdaemon-0.6.3.tar.gz differ diff --git a/rasdaemon.spec b/rasdaemon.spec new file mode 100644 index 0000000..0ce9cd0 --- /dev/null +++ b/rasdaemon.spec @@ -0,0 +1,77 @@ +Name: rasdaemon +Version: 0.6.3 +Release: 1 +License: GPLv2 +Summary: Utility to get Platform Reliability, Availability and Serviceability (RAS) reports via the Kernel tracing events +URL: https://github.com/mchehab/rasdaemon.git +Source0: %{name}-%{version}.tar.gz + +ExcludeArch: s390 s390x +BuildRequires: gcc, gettext-devel, perl-generators, sqlite-devel, systemd, git, libtool +Provides: bundled(kernel-event-lib) +Requires: hwdata +Requires: perl-DBD-SQLite +%ifarch %{ix86} x86_64 +Requires: dmidecode +%endif + +Requires(post): systemd +Requires(preun): systemd +Requires(postun): systemd + +Patch6000: add-rbtree-support-for-page-record.patch + +Patch9000: bugfix-ras-events-memory-leak.patch +Patch9001: bugfix-rasdaemon-wait-for-file-access.patch +Patch9002: bugfix-fix-fd-check.patch +Patch9003: feature-mc-support-page-isolation.patch +Patch9004: feature-report-ARM-processor-info.patch +Patch9005: output-log-timely.patch + +%description +The rasdaemon program is a daemon which monitors the platform +Reliablity, Availability and Serviceability (RAS) reports from the +Linux kernel trace events. These trace events are logged in +/sys/kernel/debug/tracing, reporting them via syslog/journald. + + +%prep +%autosetup -n %{name}-%{version} -S git + +%build +autoscan +aclocal +autoconf +autoheader +libtoolize --automake --copy --debug --force +automake --add-missing +%ifarch %{arm} aarch64 +%configure --enable-mce --enable-aer --enable-sqlite3 --enable-extlog --enable-abrt-report --enable-devlink --enable-diskerror --enable-non-standard --enable-hisi-ns-decode --enable-arm +%else +%configure --enable-mce --enable-aer --enable-sqlite3 --enable-extlog --enable-abrt-report --enable-devlink --enable-diskerror +%endif +make %{?_smp_mflags} + +%install +make install DESTDIR=%{buildroot} +install -D -p -m 0644 misc/rasdaemon.env %{buildroot}%{_sysconfdir}/sysconfig/%{name} +install -D -p -m 0644 misc/rasdaemon.service %{buildroot}/%{_unitdir}/rasdaemon.service +install -D -p -m 0644 misc/ras-mc-ctl.service %{buildroot}%{_unitdir}/ras-mc-ctl.service +rm INSTALL %{buildroot}/usr/include/*.h + +%files +%doc AUTHORS ChangeLog COPYING README TODO +%{_sbindir}/rasdaemon +%{_sbindir}/ras-mc-ctl +%{_mandir}/*/* +%{_unitdir}/*.service +%{_sharedstatedir}/rasdaemon +%{_sysconfdir}/ras/dimm_labels.d +%config(noreplace) %{_sysconfdir}/sysconfig/%{name} + +%post +/usr/bin/systemctl enable rasdaemon.service >/dev/null 2>&1 || : + +%changelog +* Wed Sep 18 2019 openEuler Buildteam - 0.6.3-1 +- Package init