]> www.infradead.org Git - users/mchehab/rasdaemon.git/commitdiff
add abrt suppport for rasdaemon
authorJunliang Li <lijunliang.dna@gmail.com>
Thu, 13 Feb 2014 02:39:53 +0000 (10:39 +0800)
committerMauro Carvalho Chehab <m.chehab@samsung.com>
Thu, 13 Feb 2014 20:24:37 +0000 (05:24 +0900)
Adds abrt as another error mechanism for the rasdaemon.
This patch does:

1) read ras event (mc,mce and aer)

2) setup a abrt-server unix socket

3) write messages follow ABRT server protocol, set event
   info into backtrace zone.

4) commit report.

For now, it depends on ABRT to limit flood reports.

Signed-off-by: Junliang Li <lijunliang.dna@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Makefile.am
configure.ac
ras-aer-handler.c
ras-events.h
ras-mc-handler.c
ras-mce-handler.c
ras-report.c [new file with mode: 0644]
ras-report.h [new file with mode: 0644]

index 473ce9832af80ae619b7b530117d38a28a2d04cc..c1668b4d939d253b70bcac446f77b40e687cfc3c 100644 (file)
@@ -17,10 +17,13 @@ if WITH_MCE
                        mce-intel-dunnington.c mce-intel-tulsa.c \
                        mce-intel-sb.c mce-intel-ivb.c
 endif
+if WITH_ABRT_REPORT
+   rasdaemon_SOURCES += ras-report.c
+endif
 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-aer-handler.h ras-mce-handler.h ras-record.h bitfield.h ras-report.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
index 4fe6ef2e5411b33fa4764ad247495a01cfc1ce00..0ea962e6f0eaa94e7d97fc975329fb5f70e21fd9 100644 (file)
@@ -53,6 +53,15 @@ AS_IF([test "x$enable_mce" = "xyes"], [
 ])
 AM_CONDITIONAL([WITH_MCE], [test x$enable_mce = xyes])
 
+AC_ARG_ENABLE([abrt_report],
+    AS_HELP_STRING([--enable-abrt-report], [enable report event to ABRT (currently experimental)]))
+
+AS_IF([test "x$enable_abrt_report" = "xyes"], [
+  AC_DEFINE(HAVE_ABRT_REPORT,1,"have report event to ABRT")
+  AC_SUBST([WITH_ABRT_REPORT])
+])
+AM_CONDITIONAL([WITH_ABRT_REPORT], [test x$enable_abrt_report = xyes])
+
 test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc
 
 CFLAGS="$CFLAGS -Wall -Wmissing-prototypes -Wstrict-prototypes"
index e5abaca43b4f183ccd88884561db739627d80e2f..50526afa935a5334e1c6d55e44738aa2e264d2fb 100644 (file)
@@ -24,6 +24,7 @@
 #include "ras-record.h"
 #include "ras-logger.h"
 #include "bitfield.h"
+#include "ras-report.h"
 
 static const char *aer_errors[32] = {
        /* Correctable errors */
@@ -115,5 +116,10 @@ int ras_aer_event_handler(struct trace_seq *s,
        ras_store_aer_event(ras, &ev);
 #endif
 
+#ifdef HAVE_ABRT_REPORT
+       /* Report event to ABRT */
+       ras_report_aer_event(ras, &ev);
+#endif
+
        return 0;
 }
index 554a95e69727b441aef06c5769785f6c1af1e1cd..64e045a6b819c1d0f3b83ea3f511587fb40a3fd0 100644 (file)
@@ -47,6 +47,9 @@ struct ras_events {
 
        /* For the mce handler */
        struct mce_priv *mce_priv;
+
+       /* For ABRT socket*/
+       int socketfd;
 };
 
 struct pthread_data {
index 5c24f658b117ad06679b078b97ea8c554c37035e..ffb3805181f940d0de336e861238c278b8f8494d 100644 (file)
@@ -23,6 +23,7 @@
 #include "ras-mc-handler.h"
 #include "ras-record.h"
 #include "ras-logger.h"
+#include "ras-report.h"
 
 int ras_mc_event_handler(struct trace_seq *s,
                         struct pevent_record *record,
@@ -189,6 +190,12 @@ int ras_mc_event_handler(struct trace_seq *s,
        /* Insert data into the SGBD */
 
        ras_store_mc_event(ras, &ev);
+
+#ifdef HAVE_ABRT_REPORT
+       /* Report event to ABRT */
+       ras_report_mc_event(ras, &ev);
+#endif
+
        return 0;
 
 parse_error:
index 59e8d057ff0cf4df756bcdab3fb726353c63c275..1431049068d740699e492a3e8b83a0b3c5cf0972 100644 (file)
@@ -26,6 +26,7 @@
 #include "ras-mce-handler.h"
 #include "ras-record.h"
 #include "ras-logger.h"
+#include "ras-report.h"
 
 /*
  * The code below were adapted from Andi Kleen/Intel/SuSe mcelog code,
@@ -401,5 +402,10 @@ int ras_mce_event_handler(struct trace_seq *s,
        ras_store_mce_record(ras, &e);
 #endif
 
+#ifdef HAVE_ABRT_REPORT
+       /* Report event to ABRT */
+       ras_report_mce_event(ras, &e);
+#endif
+
        return 0;
 }
diff --git a/ras-report.c b/ras-report.c
new file mode 100644 (file)
index 0000000..d3e4a79
--- /dev/null
@@ -0,0 +1,429 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "ras-report.h"
+
+static int setup_report_socket(void){
+       int sockfd = -1;
+       int rc = -1;
+       struct sockaddr_un addr;
+
+       sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (sockfd < 0){
+               return -1;
+       }
+
+       memset(&addr, 0, sizeof(struct sockaddr_un));
+       addr.sun_family = AF_UNIX;
+       strncpy(addr.sun_path, ABRT_SOCKET, strlen(ABRT_SOCKET));
+
+       rc = connect(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un));
+       if (rc < 0){
+               return -1;
+       }
+
+       return sockfd;
+}
+
+static int commit_report_basic(int sockfd){
+       char buf[INPUT_BUFFER_SIZE];
+       struct utsname un;
+       int rc = -1;
+
+       if(sockfd < 0){
+               return rc;
+       }
+
+       memset(buf, 0, INPUT_BUFFER_SIZE);
+       memset(&un, 0, sizeof(struct utsname));
+
+       rc = uname(&un);
+       if(rc < 0){
+               return rc;
+       }
+
+       /*
+        * ABRT server protocol
+        */
+       sprintf(buf, "PUT / HTTP/1.1\r\n\r\n");
+       rc = write(sockfd, buf, strlen(buf) + 1);
+       if(rc < strlen(buf) + 1){
+               return -1;
+       }
+
+       sprintf(buf, "PID=%d", (int)getpid());
+       rc = write(sockfd, buf, strlen(buf) + 1);
+       if(rc < strlen(buf) + 1){
+               return -1;
+       }
+
+       sprintf(buf, "EXECUTABLE=/boot/vmlinuz-%s", un.release);
+       rc = write(sockfd, buf, strlen(buf) + 1);
+       if(rc < strlen(buf) + 1){
+               return -1;
+       }
+
+       sprintf(buf, "BASENAME=%s", "rasdaemon");
+       rc = write(sockfd, buf, strlen(buf) + 1);
+       if(rc < strlen(buf) + 1){
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ *  add "DONE" string to finish message.
+ */
+static int commit_report_done(int sockfd){
+       int rc = -1;
+
+       if(sockfd < 0){
+               return -1;
+       }
+
+       rc = write(sockfd, "DONE\0", strlen("DONE\0"));
+       if(rc < strlen("DONE\0")){
+               return -1;
+       }
+
+       return 0;
+}
+
+static int set_mc_event_backtrace(char *buf, struct ras_mc_event *ev){
+       char bt_buf[MAX_BACKTRACE_SIZE];
+
+       if(!buf || !ev)
+               return -1;
+
+       sprintf(bt_buf, "BACKTRACE= "   \
+                                               "timestamp=%s\n"        \
+                                               "error_count=%d\n"      \
+                                               "error_type=%s\n"       \
+                                               "msg=%s\n"      \
+                                               "label=%s\n"    \
+                                               "mc_index=%c\n" \
+                                               "top_layer=%c\n"        \
+                                               "middle_layer=%c\n"     \
+                                               "lower_layer=%c\n"      \
+                                               "address=%llu\n"        \
+                                               "grain=%llu\n"  \
+                                               "syndrome=%llu\n"       \
+                                               "driver_detail=%s\n",   \
+                                               ev->timestamp,  \
+                                               ev->error_count,        \
+                                               ev->error_type, \
+                                               ev->msg,        \
+                                               ev->label,      \
+                                               ev->mc_index,   \
+                                               ev->top_layer,  \
+                                               ev->middle_layer,       \
+                                               ev->lower_layer,        \
+                                               ev->address,    \
+                                               ev->grain,      \
+                                               ev->syndrome,   \
+                                               ev->driver_detail);
+
+       strcat(buf, bt_buf);
+
+       return 0;
+}
+
+static int set_mce_event_backtrace(char *buf, struct mce_event *ev){
+       char bt_buf[MAX_BACKTRACE_SIZE];
+
+       if(!buf || !ev)
+               return -1;
+
+       sprintf(bt_buf, "BACKTRACE="    \
+                                               "timestamp=%s\n"        \
+                                               "bank_name=%s\n"        \
+                                               "error_msg=%s\n"        \
+                                               "mcgstatus_msg=%s\n"    \
+                                               "mcistatus_msg=%s\n"    \
+                                               "mcastatus_msg=%s\n"    \
+                                               "user_action=%s\n"      \
+                                               "mc_location=%s\n"      \
+                                               "mcgcap=%lu\n"  \
+                                               "mcgstatus=%lu\n"       \
+                                               "status=%lu\n"  \
+                                               "addr=%lu\n"    \
+                                               "misc=%lu\n"    \
+                                               "ip=%lu\n"      \
+                                               "tsc=%lu\n"     \
+                                               "walltime=%lu\n"        \
+                                               "cpu=%u\n"      \
+                                               "cpuid=%u\n"    \
+                                               "apicid=%u\n"   \
+                                               "socketid=%u\n" \
+                                               "cs=%d\n"       \
+                                               "bank=%d\n"     \
+                                               "cpuvendor=%d\n",       \
+                                               ev->timestamp,  \
+                                               ev->bank_name,  \
+                                               ev->error_msg,  \
+                                               ev->mcgstatus_msg,      \
+                                               ev->mcistatus_msg,      \
+                                               ev->mcastatus_msg,      \
+                                               ev->user_action,        \
+                                               ev->mc_location,        \
+                                               ev->mcgcap,     \
+                                               ev->mcgstatus,  \
+                                               ev->status,     \
+                                               ev->addr,       \
+                                               ev->misc,       \
+                                               ev->ip, \
+                                               ev->tsc,        \
+                                               ev->walltime,   \
+                                               ev->cpu,        \
+                                               ev->cpuid,      \
+                                               ev->apicid,     \
+                                               ev->socketid,   \
+                                               ev->cs, \
+                                               ev->bank,       \
+                                               ev->cpuvendor);
+
+       strcat(buf, bt_buf);
+
+       return 0;
+}
+
+static int set_aer_event_backtrace(char *buf, struct ras_aer_event *ev){
+       char bt_buf[MAX_BACKTRACE_SIZE];
+
+       if(!buf || !ev)
+               return -1;
+
+       sprintf(bt_buf, "BACKTRACE="    \
+                                               "timestamp=%s\n"        \
+                                               "error_type=%s\n"       \
+                                               "dev_name=%s\n" \
+                                               "msg=%s\n",     \
+                                               ev->timestamp,  \
+                                               ev->error_type, \
+                                               ev->dev_name,   \
+                                               ev->msg);
+
+       strcat(buf, bt_buf);
+
+       return 0;
+}
+
+static int commit_report_backtrace(int sockfd, int type, void *ev){
+       char buf[MAX_BACKTRACE_SIZE];
+       char *pbuf = buf;
+       int rc = -1;
+       int buf_len = 0;
+
+       if(sockfd < 0 || !ev){
+               return -1;
+       }
+
+       memset(buf, 0, MAX_BACKTRACE_SIZE);
+
+       switch(type){
+       case MC_EVENT:
+               rc = set_mc_event_backtrace(buf, (struct ras_mc_event *)ev);
+               break;
+       case AER_EVENT:
+               rc = set_aer_event_backtrace(buf, (struct ras_aer_event *)ev);
+               break;
+       case MCE_EVENT:
+               rc = set_mce_event_backtrace(buf, (struct mce_event *)ev);
+               break;
+       default:
+               return -1;
+       }
+
+       if(rc < 0){
+               return -1;
+       }
+
+       buf_len = strlen(buf);
+
+       for(;buf_len > INPUT_BUFFER_SIZE - 1; buf_len -= (INPUT_BUFFER_SIZE - 1)){
+               rc = write(sockfd, pbuf, INPUT_BUFFER_SIZE - 1);
+               if(rc < INPUT_BUFFER_SIZE - 1){
+                       return -1;
+               }
+
+               pbuf = pbuf + INPUT_BUFFER_SIZE - 1;
+       }
+
+       rc = write(sockfd, pbuf, buf_len + 1);
+       if(rc < buf_len){
+               return -1;
+       }
+
+       return 0;
+}
+
+int ras_report_mc_event(struct ras_events *ras, struct ras_mc_event *ev){
+       char buf[MAX_MESSAGE_SIZE];
+       int sockfd = -1;
+       int done = 0;
+       int rc = -1;
+
+       memset(buf, 0, sizeof(buf));
+
+       sockfd = setup_report_socket();
+       if(sockfd < 0){
+               return -1;
+       }
+
+       rc = commit_report_basic(sockfd);
+       if(rc < 0){
+               goto mc_fail;
+       }
+
+       rc = commit_report_backtrace(sockfd, MC_EVENT, ev);
+       if(rc < 0){
+               goto mc_fail;
+       }
+
+       sprintf(buf, "ANALYZER=%s", "rasdaemon-mc");
+       rc = write(sockfd, buf, strlen(buf) + 1);
+       if(rc < strlen(buf) + 1){
+               goto mc_fail;
+       }
+
+       sprintf(buf, "REASON=%s", "EDAC driver report problem");
+       rc = write(sockfd, buf, strlen(buf) + 1);
+       if(rc < strlen(buf) + 1){
+               goto mc_fail;
+       }
+
+       rc = commit_report_done(sockfd);
+       if(rc < 0){
+               goto mc_fail;
+       }
+
+       done = 1;
+
+mc_fail:
+
+       if(sockfd > 0){
+               close(sockfd);
+       }
+
+       if(done){
+               return 0;
+       }else{
+               return -1;
+       }
+}
+
+int ras_report_aer_event(struct ras_events *ras, struct ras_aer_event *ev){
+       char buf[MAX_MESSAGE_SIZE];
+       int sockfd = 0;
+       int done = 0;
+       int rc = -1;
+
+       memset(buf, 0, sizeof(buf));
+
+       sockfd = setup_report_socket();
+       if(sockfd < 0){
+               return -1;
+       }
+
+       rc = commit_report_basic(sockfd);
+       if(rc < 0){
+               goto aer_fail;
+       }
+
+       rc = commit_report_backtrace(sockfd, AER_EVENT, ev);
+       if(rc < 0){
+               goto aer_fail;
+       }
+
+       sprintf(buf, "ANALYZER=%s", "rasdaemon-aer");
+       rc = write(sockfd, buf, strlen(buf) + 1);
+       if(rc < strlen(buf) + 1){
+               goto aer_fail;
+       }
+
+       sprintf(buf, "REASON=%s", "PCIe AER driver report problem");
+       rc = write(sockfd, buf, strlen(buf) + 1);
+       if(rc < strlen(buf) + 1){
+               goto aer_fail;
+       }
+
+       rc = commit_report_done(sockfd);
+       if(rc < 0){
+               goto aer_fail;
+       }
+
+       done = 1;
+
+aer_fail:
+
+       if(sockfd > 0){
+               close(sockfd);
+       }
+
+       if(done){
+               return 0;
+       }else{
+               return -1;
+       }
+}
+
+int ras_report_mce_event(struct ras_events *ras, struct mce_event *ev){
+       char buf[MAX_MESSAGE_SIZE];
+       int sockfd = 0;
+       int done = 0;
+       int rc = -1;
+
+       memset(buf, 0, sizeof(buf));
+
+       sockfd = setup_report_socket();
+       if(sockfd < 0){
+               return -1;
+       }
+
+       rc = commit_report_basic(sockfd);
+       if(rc < 0){
+               goto mce_fail;
+       }
+
+       rc = commit_report_backtrace(sockfd, MCE_EVENT, ev);
+       if(rc < 0){
+               goto mce_fail;
+       }
+
+       sprintf(buf, "ANALYZER=%s", "rasdaemon-mce");
+       rc = write(sockfd, buf, strlen(buf) + 1);
+       if(rc < strlen(buf) + 1){
+               goto mce_fail;
+       }
+
+       sprintf(buf, "REASON=%s", "Machine Check driver report problem");
+       rc = write(sockfd, buf, strlen(buf) + 1);
+       if(rc < strlen(buf) + 1){
+               goto mce_fail;
+       }
+
+       rc = commit_report_done(sockfd);
+       if(rc < 0){
+               goto mce_fail;
+       }
+
+       done = 1;
+
+mce_fail:
+
+       if(sockfd > 0){
+               close(sockfd);
+       }
+
+       if(done){
+               return 0;
+       }else{
+               return -1;
+       }
+}
diff --git a/ras-report.h b/ras-report.h
new file mode 100644 (file)
index 0000000..7920cdf
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __RAS_REPORT_H
+#define __RAS_REPORT_H
+
+#include "ras-record.h"
+#include "ras-events.h"
+#include "ras-mc-handler.h"
+#include "ras-mce-handler.h"
+#include "ras-aer-handler.h"
+
+/* Maximal length of backtrace. */
+#define MAX_BACKTRACE_SIZE (1024*1024)
+/* Amount of data received from one client for a message before reporting error. */
+#define MAX_MESSAGE_SIZE (4*MAX_BACKTRACE_SIZE)
+/* Maximal number of characters read from socket at once. */
+#define INPUT_BUFFER_SIZE (8*1024)
+/* ABRT socket file */
+#define ABRT_SOCKET "/var/run/abrt/abrt.socket"
+
+enum {
+       MC_EVENT,
+       MCE_EVENT,
+       AER_EVENT
+};
+
+#ifdef HAVE_ABRT_REPORT
+
+int ras_report_mc_event(struct ras_events *ras, struct ras_mc_event *ev);
+int ras_report_aer_event(struct ras_events *ras, struct ras_aer_event *ev);
+int ras_report_mce_event(struct ras_events *ras, struct mce_event *ev);
+
+#else
+
+static inline int ras_report_mc_event(struct ras_events *ras, struct ras_mc_event *ev) { return 0; };
+static inline int ras_report_aer_event(struct ras_events *ras, struct ras_aer_event *ev) { return 0; };
+static inline int ras_report_mce_event(struct ras_events *ras, struct mce_event *ev) { return 0; };
+
+#endif
+
+#endif