1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #ifndef _WINDOWS
21 
22 #include "common.h"
23 #include "diskdevices.h"
24 #include "stats.h"
25 #include "log.h"
26 #include "mutexs.h"
27 
28 extern zbx_mutex_t		diskstats_lock;
29 #define LOCK_DISKSTATS		zbx_mutex_lock(diskstats_lock)
30 #define UNLOCK_DISKSTATS	zbx_mutex_unlock(diskstats_lock)
31 
apply_diskstat(ZBX_SINGLE_DISKDEVICE_DATA * device,time_t now,zbx_uint64_t * dstat)32 static void	apply_diskstat(ZBX_SINGLE_DISKDEVICE_DATA *device, time_t now, zbx_uint64_t *dstat)
33 {
34 	register int	i;
35 	time_t		clock[ZBX_AVG_COUNT], sec;
36 	int		index[ZBX_AVG_COUNT];
37 
38 	assert(device);
39 
40 	device->index++;
41 
42 	if (MAX_COLLECTOR_HISTORY == device->index)
43 		device->index = 0;
44 
45 	device->clock[device->index] = now;
46 	device->r_sect[device->index] = dstat[ZBX_DSTAT_R_SECT];
47 	device->r_oper[device->index] = dstat[ZBX_DSTAT_R_OPER];
48 	device->r_byte[device->index] = dstat[ZBX_DSTAT_R_BYTE];
49 	device->w_sect[device->index] = dstat[ZBX_DSTAT_W_SECT];
50 	device->w_oper[device->index] = dstat[ZBX_DSTAT_W_OPER];
51 	device->w_byte[device->index] = dstat[ZBX_DSTAT_W_BYTE];
52 
53 	clock[ZBX_AVG1] = clock[ZBX_AVG5] = clock[ZBX_AVG15] = now + 1;
54 	index[ZBX_AVG1] = index[ZBX_AVG5] = index[ZBX_AVG15] = -1;
55 
56 	for (i = 0; i < MAX_COLLECTOR_HISTORY; i++)
57 	{
58 		if (0 == device->clock[i])
59 			continue;
60 
61 #define DISKSTAT(t)\
62 		if ((device->clock[i] >= (now - (t * 60))) && (clock[ZBX_AVG ## t] > device->clock[i]))\
63 		{\
64 			clock[ZBX_AVG ## t] = device->clock[i];\
65 			index[ZBX_AVG ## t] = i;\
66 		}
67 
68 		DISKSTAT(1);
69 		DISKSTAT(5);
70 		DISKSTAT(15);
71 	}
72 
73 #define SAVE_DISKSTAT(t)\
74 	if (-1 == index[ZBX_AVG ## t] || 0 == now - device->clock[index[ZBX_AVG ## t]])\
75 	{\
76 		device->r_sps[ZBX_AVG ## t] = 0;\
77 		device->r_ops[ZBX_AVG ## t] = 0;\
78 		device->r_bps[ZBX_AVG ## t] = 0;\
79 		device->w_sps[ZBX_AVG ## t] = 0;\
80 		device->w_ops[ZBX_AVG ## t] = 0;\
81 		device->w_bps[ZBX_AVG ## t] = 0;\
82 	}\
83 	else\
84 	{\
85 		sec = now - device->clock[index[ZBX_AVG ## t]];\
86 		device->r_sps[ZBX_AVG ## t] = (dstat[ZBX_DSTAT_R_SECT] - device->r_sect[index[ZBX_AVG ## t]]) / (double)sec;\
87 		device->r_ops[ZBX_AVG ## t] = (dstat[ZBX_DSTAT_R_OPER] - device->r_oper[index[ZBX_AVG ## t]]) / (double)sec;\
88 		device->r_bps[ZBX_AVG ## t] = (dstat[ZBX_DSTAT_R_BYTE] - device->r_byte[index[ZBX_AVG ## t]]) / (double)sec;\
89 		device->w_sps[ZBX_AVG ## t] = (dstat[ZBX_DSTAT_W_SECT] - device->w_sect[index[ZBX_AVG ## t]]) / (double)sec;\
90 		device->w_ops[ZBX_AVG ## t] = (dstat[ZBX_DSTAT_W_OPER] - device->w_oper[index[ZBX_AVG ## t]]) / (double)sec;\
91 		device->w_bps[ZBX_AVG ## t] = (dstat[ZBX_DSTAT_W_BYTE] - device->w_byte[index[ZBX_AVG ## t]]) / (double)sec;\
92 	}
93 
94 	SAVE_DISKSTAT(1);
95 	SAVE_DISKSTAT(5);
96 	SAVE_DISKSTAT(15);
97 }
98 
process_diskstat(ZBX_SINGLE_DISKDEVICE_DATA * device)99 static void	process_diskstat(ZBX_SINGLE_DISKDEVICE_DATA *device)
100 {
101 	time_t		now;
102 	zbx_uint64_t	dstat[ZBX_DSTAT_MAX];
103 
104 	now = time(NULL);
105 	if (FAIL == get_diskstat(device->name, dstat))
106 		return;
107 
108 	apply_diskstat(device, now, dstat);
109 
110 	device->ticks_since_polled++;
111 }
112 
collect_stats_diskdevices(void)113 void	collect_stats_diskdevices(void)
114 {
115 	int	i;
116 
117 	LOCK_DISKSTATS;
118 	diskstat_shm_reattach();
119 
120 	for (i = 0; i < diskdevices->count; i++)
121 	{
122 		process_diskstat(&diskdevices->device[i]);
123 
124 		/* remove device from collector if not being polled for long time */
125 		if (DISKDEVICE_TTL <= diskdevices->device[i].ticks_since_polled)
126 		{
127 			if ((diskdevices->count - 1) > i)
128 			{
129 				memcpy(diskdevices->device + i, diskdevices->device + i + 1,
130 					sizeof(ZBX_SINGLE_DISKDEVICE_DATA) * (diskdevices->count - i));
131 			}
132 
133 			diskdevices->count--;
134 			i--;
135 		}
136 	}
137 
138 	UNLOCK_DISKSTATS;
139 }
140 
collector_diskdevice_get(const char * devname)141 ZBX_SINGLE_DISKDEVICE_DATA	*collector_diskdevice_get(const char *devname)
142 {
143 	int				i;
144 	ZBX_SINGLE_DISKDEVICE_DATA	*device = NULL;
145 
146 	assert(devname);
147 
148 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() devname:'%s'", __func__, devname);
149 
150 	LOCK_DISKSTATS;
151 	if (0 == DISKDEVICE_COLLECTOR_STARTED(collector))
152 		diskstat_shm_init();
153 	else
154 		diskstat_shm_reattach();
155 
156 	for (i = 0; i < diskdevices->count; i++)
157 	{
158 		if (0 == strcmp(devname, diskdevices->device[i].name))
159 		{
160 			device = &diskdevices->device[i];
161 			device->ticks_since_polled = 0;
162 			zabbix_log(LOG_LEVEL_DEBUG, "%s() device '%s' found", __func__, devname);
163 			break;
164 		}
165 	}
166 	UNLOCK_DISKSTATS;
167 
168 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)device);
169 
170 	return device;
171 }
172 
collector_diskdevice_add(const char * devname)173 ZBX_SINGLE_DISKDEVICE_DATA	*collector_diskdevice_add(const char *devname)
174 {
175 	ZBX_SINGLE_DISKDEVICE_DATA	*device = NULL;
176 
177 	assert(devname);
178 
179 	zabbix_log(LOG_LEVEL_DEBUG, "In %s() devname:'%s'", __func__, devname);
180 
181 	LOCK_DISKSTATS;
182 	if (0 == DISKDEVICE_COLLECTOR_STARTED(collector))
183 		diskstat_shm_init();
184 	else
185 		diskstat_shm_reattach();
186 
187 	if (diskdevices->count == MAX_DISKDEVICES)
188 	{
189 		zabbix_log(LOG_LEVEL_DEBUG, "%s() collector is full", __func__);
190 		goto end;
191 	}
192 
193 	if (diskdevices->count == diskdevices->max_diskdev)
194 		diskstat_shm_extend();
195 
196 	device = &(diskdevices->device[diskdevices->count]);
197 	memset(device, 0, sizeof(ZBX_SINGLE_DISKDEVICE_DATA));
198 	zbx_strlcpy(device->name, devname, sizeof(device->name));
199 	device->index = -1;
200 	device->ticks_since_polled = 0;
201 	(diskdevices->count)++;
202 
203 	process_diskstat(device);
204 end:
205 	UNLOCK_DISKSTATS;
206 
207 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __func__, (void *)device);
208 
209 	return device;
210 }
211 
212 #endif	/* _WINDOWS */
213