-
Notifications
You must be signed in to change notification settings - Fork 82
/
ras-diskerror-handler.c
122 lines (103 loc) · 3.04 KB
/
ras-diskerror-handler.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2019 Cong Wang <[email protected]>
*/
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/sysmacros.h>
#include <traceevent/kbuffer.h>
#include "ras-diskerror-handler.h"
#include "ras-logger.h"
#include "ras-report.h"
#include "types.h"
#ifndef __dev_t_defined
#include <sys/types.h>
#endif /* __dev_t_defined */
static const struct {
int error;
const char *name;
} blk_errors[] = {
{ -EOPNOTSUPP, "operation not supported error" },
{ -ETIMEDOUT, "timeout error" },
{ -ENOSPC, "critical space allocation error" },
{ -ENOLINK, "recoverable transport error" },
{ -EREMOTEIO, "critical target error" },
{ -EBADE, "critical nexus error" },
{ -ENODATA, "critical medium error" },
{ -EILSEQ, "protection error" },
{ -ENOMEM, "kernel resource error" },
{ -EBUSY, "device resource error" },
{ -EAGAIN, "nonblocking retry error" },
{ -EREMCHG, "dm internal retry error" },
{ -EIO, "I/O error" },
};
static const char *get_blk_error(int err)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(blk_errors); i++)
if (blk_errors[i].error == err)
return blk_errors[i].name;
return "unknown block error";
}
int ras_diskerror_event_handler(struct trace_seq *s,
struct tep_record *record,
struct tep_event *event, void *context)
{
unsigned long long val;
int len;
struct ras_events *ras = context;
time_t now;
struct tm *tm;
struct diskerror_event ev;
dev_t dev;
/*
* 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);
trace_seq_printf(s, "%s ", ev.timestamp);
if (tep_get_field_val(s, event, "dev", record, &val, 1) < 0)
return -1;
dev = (dev_t)val;
if (asprintf(&ev.dev, "%u:%u", major(dev), minor(dev)) < 0)
return -1;
if (tep_get_field_val(s, event, "sector", record, &val, 1) < 0)
return -1;
ev.sector = val;
if (tep_get_field_val(s, event, "nr_sector", record, &val, 1) < 0)
return -1;
ev.nr_sector = (unsigned int)val;
if (tep_get_field_val(s, event, "error", record, &val, 1) < 0)
return -1;
ev.error = get_blk_error((int)val);
ev.rwbs = tep_get_field_raw(s, event, "rwbs", record, &len, 1);
if (!ev.rwbs)
return -1;
ev.cmd = tep_get_field_raw(s, event, "cmd", record, &len, 1);
if (!ev.cmd)
return -1;
/* Insert data into the SGBD */
#ifdef HAVE_SQLITE3
ras_store_diskerror_event(ras, &ev);
#endif
#ifdef HAVE_ABRT_REPORT
/* Report event to ABRT */
ras_report_diskerror_event(ras, &ev);
#endif
free(ev.dev);
return 0;
}