File: ras-diskerror-handler.c

package info (click to toggle)
rasdaemon 0.8.4-1
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 2,832 kB
  • sloc: ansic: 17,870; sh: 4,983; perl: 2,383; makefile: 212
file content (118 lines) | stat: -rw-r--r-- 3,069 bytes parent folder | download
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
// SPDX-License-Identifier: GPL-2.0-or-later

/*
 * Copyright (C) 2019 Cong Wang <xiyou.wangcong@gmail.com>
 */

#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <traceevent/kbuffer.h>

#include "ras-diskerror-handler.h"
#include "ras-logger.h"
#include "ras-report.h"
#include "types.h"

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;
	uint32_t dev;

	trace_seq_printf(s, "%s ", loglevel_str[LOGLEVEL_ERR]);
	/*
	 * 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 = (uint32_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;
}