1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22#include <sys/zfs_context.h>
23#include <sys/spa_impl.h>
24#include <sys/vdev_impl.h>
25#include <sys/spa.h>
26#include <zfs_comutil.h>
27
28/*
29 * Keeps stats on last N reads per spa_t, disabled by default.
30 */
31int zfs_read_history = 0;
32
33/*
34 * Include cache hits in history, disabled by default.
35 */
36int zfs_read_history_hits = 0;
37
38/*
39 * Keeps stats on the last 100 txgs by default.
40 */
41int zfs_txg_history = 100;
42
43/*
44 * Keeps stats on the last N MMP updates, disabled by default.
45 */
46int zfs_multihost_history = 0;
47
48/*
49 * ==========================================================================
50 * SPA Read History Routines
51 * ==========================================================================
52 */
53
54/*
55 * Read statistics - Information exported regarding each arc_read call
56 */
57typedef struct spa_read_history {
58	hrtime_t	start;		/* time read completed */
59	uint64_t	objset;		/* read from this objset */
60	uint64_t	object;		/* read of this object number */
61	uint64_t	level;		/* block's indirection level */
62	uint64_t	blkid;		/* read of this block id */
63	char		origin[24];	/* read originated from here */
64	uint32_t	aflags;		/* ARC flags (cached, prefetch, etc.) */
65	pid_t		pid;		/* PID of task doing read */
66	char		comm[16];	/* process name of task doing read */
67	procfs_list_node_t	srh_node;
68} spa_read_history_t;
69
70static int
71spa_read_history_show_header(struct seq_file *f)
72{
73	seq_printf(f, "%-8s %-16s %-8s %-8s %-8s %-8s %-8s "
74	    "%-24s %-8s %-16s\n", "UID", "start", "objset", "object",
75	    "level", "blkid", "aflags", "origin", "pid", "process");
76
77	return (0);
78}
79
80static int
81spa_read_history_show(struct seq_file *f, void *data)
82{
83	spa_read_history_t *srh = (spa_read_history_t *)data;
84
85	seq_printf(f, "%-8llu %-16llu 0x%-6llx "
86	    "%-8lli %-8lli %-8lli 0x%-6x %-24s %-8i %-16s\n",
87	    (u_longlong_t)srh->srh_node.pln_id, srh->start,
88	    (longlong_t)srh->objset, (longlong_t)srh->object,
89	    (longlong_t)srh->level, (longlong_t)srh->blkid,
90	    srh->aflags, srh->origin, srh->pid, srh->comm);
91
92	return (0);
93}
94
95/* Remove oldest elements from list until there are no more than 'size' left */
96static void
97spa_read_history_truncate(spa_history_list_t *shl, unsigned int size)
98{
99	spa_read_history_t *srh;
100	while (shl->size > size) {
101		srh = list_remove_head(&shl->procfs_list.pl_list);
102		ASSERT3P(srh, !=, NULL);
103		kmem_free(srh, sizeof (spa_read_history_t));
104		shl->size--;
105	}
106
107	if (size == 0)
108		ASSERT(list_is_empty(&shl->procfs_list.pl_list));
109}
110
111static int
112spa_read_history_clear(procfs_list_t *procfs_list)
113{
114	spa_history_list_t *shl = procfs_list->pl_private;
115	mutex_enter(&procfs_list->pl_lock);
116	spa_read_history_truncate(shl, 0);
117	mutex_exit(&procfs_list->pl_lock);
118	return (0);
119}
120
121static void
122spa_read_history_init(spa_t *spa)
123{
124	spa_history_list_t *shl = &spa->spa_stats.read_history;
125
126	shl->size = 0;
127	shl->procfs_list.pl_private = shl;
128	procfs_list_install("zfs",
129	    spa_name(spa),
130	    "reads",
131	    0600,
132	    &shl->procfs_list,
133	    spa_read_history_show,
134	    spa_read_history_show_header,
135	    spa_read_history_clear,
136	    offsetof(spa_read_history_t, srh_node));
137}
138
139static void
140spa_read_history_destroy(spa_t *spa)
141{
142	spa_history_list_t *shl = &spa->spa_stats.read_history;
143	procfs_list_uninstall(&shl->procfs_list);
144	spa_read_history_truncate(shl, 0);
145	procfs_list_destroy(&shl->procfs_list);
146}
147
148void
149spa_read_history_add(spa_t *spa, const zbookmark_phys_t *zb, uint32_t aflags)
150{
151	spa_history_list_t *shl = &spa->spa_stats.read_history;
152	spa_read_history_t *srh;
153
154	ASSERT3P(spa, !=, NULL);
155	ASSERT3P(zb,  !=, NULL);
156
157	if (zfs_read_history == 0 && shl->size == 0)
158		return;
159
160	if (zfs_read_history_hits == 0 && (aflags & ARC_FLAG_CACHED))
161		return;
162
163	srh = kmem_zalloc(sizeof (spa_read_history_t), KM_SLEEP);
164	strlcpy(srh->comm, getcomm(), sizeof (srh->comm));
165	srh->start  = gethrtime();
166	srh->objset = zb->zb_objset;
167	srh->object = zb->zb_object;
168	srh->level  = zb->zb_level;
169	srh->blkid  = zb->zb_blkid;
170	srh->aflags = aflags;
171	srh->pid    = getpid();
172
173	mutex_enter(&shl->procfs_list.pl_lock);
174
175	procfs_list_add(&shl->procfs_list, srh);
176	shl->size++;
177
178	spa_read_history_truncate(shl, zfs_read_history);
179
180	mutex_exit(&shl->procfs_list.pl_lock);
181}
182
183/*
184 * ==========================================================================
185 * SPA TXG History Routines
186 * ==========================================================================
187 */
188
189/*
190 * Txg statistics - Information exported regarding each txg sync
191 */
192
193typedef struct spa_txg_history {
194	uint64_t	txg;		/* txg id */
195	txg_state_t	state;		/* active txg state */
196	uint64_t	nread;		/* number of bytes read */
197	uint64_t	nwritten;	/* number of bytes written */
198	uint64_t	reads;		/* number of read operations */
199	uint64_t	writes;		/* number of write operations */
200	uint64_t	ndirty;		/* number of dirty bytes */
201	hrtime_t	times[TXG_STATE_COMMITTED]; /* completion times */
202	procfs_list_node_t	sth_node;
203} spa_txg_history_t;
204
205static int
206spa_txg_history_show_header(struct seq_file *f)
207{
208	seq_printf(f, "%-8s %-16s %-5s %-12s %-12s %-12s "
209	    "%-8s %-8s %-12s %-12s %-12s %-12s\n", "txg", "birth", "state",
210	    "ndirty", "nread", "nwritten", "reads", "writes",
211	    "otime", "qtime", "wtime", "stime");
212	return (0);
213}
214
215static int
216spa_txg_history_show(struct seq_file *f, void *data)
217{
218	spa_txg_history_t *sth = (spa_txg_history_t *)data;
219	uint64_t open = 0, quiesce = 0, wait = 0, sync = 0;
220	char state;
221
222	switch (sth->state) {
223		case TXG_STATE_BIRTH:		state = 'B';	break;
224		case TXG_STATE_OPEN:		state = 'O';	break;
225		case TXG_STATE_QUIESCED:	state = 'Q';	break;
226		case TXG_STATE_WAIT_FOR_SYNC:	state = 'W';	break;
227		case TXG_STATE_SYNCED:		state = 'S';	break;
228		case TXG_STATE_COMMITTED:	state = 'C';	break;
229		default:			state = '?';	break;
230	}
231
232	if (sth->times[TXG_STATE_OPEN])
233		open = sth->times[TXG_STATE_OPEN] -
234		    sth->times[TXG_STATE_BIRTH];
235
236	if (sth->times[TXG_STATE_QUIESCED])
237		quiesce = sth->times[TXG_STATE_QUIESCED] -
238		    sth->times[TXG_STATE_OPEN];
239
240	if (sth->times[TXG_STATE_WAIT_FOR_SYNC])
241		wait = sth->times[TXG_STATE_WAIT_FOR_SYNC] -
242		    sth->times[TXG_STATE_QUIESCED];
243
244	if (sth->times[TXG_STATE_SYNCED])
245		sync = sth->times[TXG_STATE_SYNCED] -
246		    sth->times[TXG_STATE_WAIT_FOR_SYNC];
247
248	seq_printf(f, "%-8llu %-16llu %-5c %-12llu "
249	    "%-12llu %-12llu %-8llu %-8llu %-12llu %-12llu %-12llu %-12llu\n",
250	    (longlong_t)sth->txg, sth->times[TXG_STATE_BIRTH], state,
251	    (u_longlong_t)sth->ndirty,
252	    (u_longlong_t)sth->nread, (u_longlong_t)sth->nwritten,
253	    (u_longlong_t)sth->reads, (u_longlong_t)sth->writes,
254	    (u_longlong_t)open, (u_longlong_t)quiesce, (u_longlong_t)wait,
255	    (u_longlong_t)sync);
256
257	return (0);
258}
259
260/* Remove oldest elements from list until there are no more than 'size' left */
261static void
262spa_txg_history_truncate(spa_history_list_t *shl, unsigned int size)
263{
264	spa_txg_history_t *sth;
265	while (shl->size > size) {
266		sth = list_remove_head(&shl->procfs_list.pl_list);
267		ASSERT3P(sth, !=, NULL);
268		kmem_free(sth, sizeof (spa_txg_history_t));
269		shl->size--;
270	}
271
272	if (size == 0)
273		ASSERT(list_is_empty(&shl->procfs_list.pl_list));
274
275}
276
277static int
278spa_txg_history_clear(procfs_list_t *procfs_list)
279{
280	spa_history_list_t *shl = procfs_list->pl_private;
281	mutex_enter(&procfs_list->pl_lock);
282	spa_txg_history_truncate(shl, 0);
283	mutex_exit(&procfs_list->pl_lock);
284	return (0);
285}
286
287static void
288spa_txg_history_init(spa_t *spa)
289{
290	spa_history_list_t *shl = &spa->spa_stats.txg_history;
291
292	shl->size = 0;
293	shl->procfs_list.pl_private = shl;
294	procfs_list_install("zfs",
295	    spa_name(spa),
296	    "txgs",
297	    0644,
298	    &shl->procfs_list,
299	    spa_txg_history_show,
300	    spa_txg_history_show_header,
301	    spa_txg_history_clear,
302	    offsetof(spa_txg_history_t, sth_node));
303}
304
305static void
306spa_txg_history_destroy(spa_t *spa)
307{
308	spa_history_list_t *shl = &spa->spa_stats.txg_history;
309	procfs_list_uninstall(&shl->procfs_list);
310	spa_txg_history_truncate(shl, 0);
311	procfs_list_destroy(&shl->procfs_list);
312}
313
314/*
315 * Add a new txg to historical record.
316 */
317void
318spa_txg_history_add(spa_t *spa, uint64_t txg, hrtime_t birth_time)
319{
320	spa_history_list_t *shl = &spa->spa_stats.txg_history;
321	spa_txg_history_t *sth;
322
323	if (zfs_txg_history == 0 && shl->size == 0)
324		return;
325
326	sth = kmem_zalloc(sizeof (spa_txg_history_t), KM_SLEEP);
327	sth->txg = txg;
328	sth->state = TXG_STATE_OPEN;
329	sth->times[TXG_STATE_BIRTH] = birth_time;
330
331	mutex_enter(&shl->procfs_list.pl_lock);
332	procfs_list_add(&shl->procfs_list, sth);
333	shl->size++;
334	spa_txg_history_truncate(shl, zfs_txg_history);
335	mutex_exit(&shl->procfs_list.pl_lock);
336}
337
338/*
339 * Set txg state completion time and increment current state.
340 */
341int
342spa_txg_history_set(spa_t *spa, uint64_t txg, txg_state_t completed_state,
343    hrtime_t completed_time)
344{
345	spa_history_list_t *shl = &spa->spa_stats.txg_history;
346	spa_txg_history_t *sth;
347	int error = ENOENT;
348
349	if (zfs_txg_history == 0)
350		return (0);
351
352	mutex_enter(&shl->procfs_list.pl_lock);
353	for (sth = list_tail(&shl->procfs_list.pl_list); sth != NULL;
354	    sth = list_prev(&shl->procfs_list.pl_list, sth)) {
355		if (sth->txg == txg) {
356			sth->times[completed_state] = completed_time;
357			sth->state++;
358			error = 0;
359			break;
360		}
361	}
362	mutex_exit(&shl->procfs_list.pl_lock);
363
364	return (error);
365}
366
367/*
368 * Set txg IO stats.
369 */
370static int
371spa_txg_history_set_io(spa_t *spa, uint64_t txg, uint64_t nread,
372    uint64_t nwritten, uint64_t reads, uint64_t writes, uint64_t ndirty)
373{
374	spa_history_list_t *shl = &spa->spa_stats.txg_history;
375	spa_txg_history_t *sth;
376	int error = ENOENT;
377
378	if (zfs_txg_history == 0)
379		return (0);
380
381	mutex_enter(&shl->procfs_list.pl_lock);
382	for (sth = list_tail(&shl->procfs_list.pl_list); sth != NULL;
383	    sth = list_prev(&shl->procfs_list.pl_list, sth)) {
384		if (sth->txg == txg) {
385			sth->nread = nread;
386			sth->nwritten = nwritten;
387			sth->reads = reads;
388			sth->writes = writes;
389			sth->ndirty = ndirty;
390			error = 0;
391			break;
392		}
393	}
394	mutex_exit(&shl->procfs_list.pl_lock);
395
396	return (error);
397}
398
399txg_stat_t *
400spa_txg_history_init_io(spa_t *spa, uint64_t txg, dsl_pool_t *dp)
401{
402	txg_stat_t *ts;
403
404	if (zfs_txg_history == 0)
405		return (NULL);
406
407	ts = kmem_alloc(sizeof (txg_stat_t), KM_SLEEP);
408
409	spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
410	vdev_get_stats(spa->spa_root_vdev, &ts->vs1);
411	spa_config_exit(spa, SCL_CONFIG, FTAG);
412
413	ts->txg = txg;
414	ts->ndirty = dp->dp_dirty_pertxg[txg & TXG_MASK];
415
416	spa_txg_history_set(spa, txg, TXG_STATE_WAIT_FOR_SYNC, gethrtime());
417
418	return (ts);
419}
420
421void
422spa_txg_history_fini_io(spa_t *spa, txg_stat_t *ts)
423{
424	if (ts == NULL)
425		return;
426
427	if (zfs_txg_history == 0) {
428		kmem_free(ts, sizeof (txg_stat_t));
429		return;
430	}
431
432	spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
433	vdev_get_stats(spa->spa_root_vdev, &ts->vs2);
434	spa_config_exit(spa, SCL_CONFIG, FTAG);
435
436	spa_txg_history_set(spa, ts->txg, TXG_STATE_SYNCED, gethrtime());
437	spa_txg_history_set_io(spa, ts->txg,
438	    ts->vs2.vs_bytes[ZIO_TYPE_READ] - ts->vs1.vs_bytes[ZIO_TYPE_READ],
439	    ts->vs2.vs_bytes[ZIO_TYPE_WRITE] - ts->vs1.vs_bytes[ZIO_TYPE_WRITE],
440	    ts->vs2.vs_ops[ZIO_TYPE_READ] - ts->vs1.vs_ops[ZIO_TYPE_READ],
441	    ts->vs2.vs_ops[ZIO_TYPE_WRITE] - ts->vs1.vs_ops[ZIO_TYPE_WRITE],
442	    ts->ndirty);
443
444	kmem_free(ts, sizeof (txg_stat_t));
445}
446
447/*
448 * ==========================================================================
449 * SPA TX Assign Histogram Routines
450 * ==========================================================================
451 */
452
453/*
454 * Tx statistics - Information exported regarding dmu_tx_assign time.
455 */
456
457/*
458 * When the kstat is written zero all buckets.  When the kstat is read
459 * count the number of trailing buckets set to zero and update ks_ndata
460 * such that they are not output.
461 */
462static int
463spa_tx_assign_update(kstat_t *ksp, int rw)
464{
465	spa_t *spa = ksp->ks_private;
466	spa_history_kstat_t *shk = &spa->spa_stats.tx_assign_histogram;
467	int i;
468
469	if (rw == KSTAT_WRITE) {
470		for (i = 0; i < shk->count; i++)
471			((kstat_named_t *)shk->priv)[i].value.ui64 = 0;
472	}
473
474	for (i = shk->count; i > 0; i--)
475		if (((kstat_named_t *)shk->priv)[i-1].value.ui64 != 0)
476			break;
477
478	ksp->ks_ndata = i;
479	ksp->ks_data_size = i * sizeof (kstat_named_t);
480
481	return (0);
482}
483
484static void
485spa_tx_assign_init(spa_t *spa)
486{
487	spa_history_kstat_t *shk = &spa->spa_stats.tx_assign_histogram;
488	char *name;
489	kstat_named_t *ks;
490	kstat_t *ksp;
491	int i;
492
493	mutex_init(&shk->lock, NULL, MUTEX_DEFAULT, NULL);
494
495	shk->count = 42; /* power of two buckets for 1ns to 2,199s */
496	shk->size = shk->count * sizeof (kstat_named_t);
497	shk->priv = kmem_alloc(shk->size, KM_SLEEP);
498
499	name = kmem_asprintf("zfs/%s", spa_name(spa));
500
501	for (i = 0; i < shk->count; i++) {
502		ks = &((kstat_named_t *)shk->priv)[i];
503		ks->data_type = KSTAT_DATA_UINT64;
504		ks->value.ui64 = 0;
505		(void) snprintf(ks->name, KSTAT_STRLEN, "%llu ns",
506		    (u_longlong_t)1 << i);
507	}
508
509	ksp = kstat_create(name, 0, "dmu_tx_assign", "misc",
510	    KSTAT_TYPE_NAMED, 0, KSTAT_FLAG_VIRTUAL);
511	shk->kstat = ksp;
512
513	if (ksp) {
514		ksp->ks_lock = &shk->lock;
515		ksp->ks_data = shk->priv;
516		ksp->ks_ndata = shk->count;
517		ksp->ks_data_size = shk->size;
518		ksp->ks_private = spa;
519		ksp->ks_update = spa_tx_assign_update;
520		kstat_install(ksp);
521	}
522	kmem_strfree(name);
523}
524
525static void
526spa_tx_assign_destroy(spa_t *spa)
527{
528	spa_history_kstat_t *shk = &spa->spa_stats.tx_assign_histogram;
529	kstat_t *ksp;
530
531	ksp = shk->kstat;
532	if (ksp)
533		kstat_delete(ksp);
534
535	kmem_free(shk->priv, shk->size);
536	mutex_destroy(&shk->lock);
537}
538
539void
540spa_tx_assign_add_nsecs(spa_t *spa, uint64_t nsecs)
541{
542	spa_history_kstat_t *shk = &spa->spa_stats.tx_assign_histogram;
543	uint64_t idx = 0;
544
545	while (((1ULL << idx) < nsecs) && (idx < shk->size - 1))
546		idx++;
547
548	atomic_inc_64(&((kstat_named_t *)shk->priv)[idx].value.ui64);
549}
550
551/*
552 * ==========================================================================
553 * SPA MMP History Routines
554 * ==========================================================================
555 */
556
557/*
558 * MMP statistics - Information exported regarding attempted MMP writes
559 *   For MMP writes issued, fields used as per comments below.
560 *   For MMP writes skipped, an entry represents a span of time when
561 *      writes were skipped for same reason (error from mmp_random_leaf).
562 *      Differences are:
563 *      timestamp	time first write skipped, if >1 skipped in a row
564 *      mmp_delay	delay value at timestamp
565 *      vdev_guid	number of writes skipped
566 *      io_error	one of enum mmp_error
567 *      duration	time span (ns) of skipped writes
568 */
569
570typedef struct spa_mmp_history {
571	uint64_t	mmp_node_id;	/* unique # for updates */
572	uint64_t	txg;		/* txg of last sync */
573	uint64_t	timestamp;	/* UTC time MMP write issued */
574	uint64_t	mmp_delay;	/* mmp_thread.mmp_delay at timestamp */
575	uint64_t	vdev_guid;	/* unique ID of leaf vdev */
576	char		*vdev_path;
577	int		vdev_label;	/* vdev label */
578	int		io_error;	/* error status of MMP write */
579	hrtime_t	error_start;	/* hrtime of start of error period */
580	hrtime_t	duration;	/* time from submission to completion */
581	procfs_list_node_t	smh_node;
582} spa_mmp_history_t;
583
584static int
585spa_mmp_history_show_header(struct seq_file *f)
586{
587	seq_printf(f, "%-10s %-10s %-10s %-6s %-10s %-12s %-24s "
588	    "%-10s %s\n", "id", "txg", "timestamp", "error", "duration",
589	    "mmp_delay", "vdev_guid", "vdev_label", "vdev_path");
590	return (0);
591}
592
593static int
594spa_mmp_history_show(struct seq_file *f, void *data)
595{
596	spa_mmp_history_t *smh = (spa_mmp_history_t *)data;
597	char skip_fmt[] = "%-10llu %-10llu %10llu %#6llx %10lld %12llu %-24llu "
598	    "%-10lld %s\n";
599	char write_fmt[] = "%-10llu %-10llu %10llu %6lld %10lld %12llu %-24llu "
600	    "%-10lld %s\n";
601
602	seq_printf(f, (smh->error_start ? skip_fmt : write_fmt),
603	    (u_longlong_t)smh->mmp_node_id, (u_longlong_t)smh->txg,
604	    (u_longlong_t)smh->timestamp, (longlong_t)smh->io_error,
605	    (longlong_t)smh->duration, (u_longlong_t)smh->mmp_delay,
606	    (u_longlong_t)smh->vdev_guid, (u_longlong_t)smh->vdev_label,
607	    (smh->vdev_path ? smh->vdev_path : "-"));
608
609	return (0);
610}
611
612/* Remove oldest elements from list until there are no more than 'size' left */
613static void
614spa_mmp_history_truncate(spa_history_list_t *shl, unsigned int size)
615{
616	spa_mmp_history_t *smh;
617	while (shl->size > size) {
618		smh = list_remove_head(&shl->procfs_list.pl_list);
619		if (smh->vdev_path)
620			kmem_strfree(smh->vdev_path);
621		kmem_free(smh, sizeof (spa_mmp_history_t));
622		shl->size--;
623	}
624
625	if (size == 0)
626		ASSERT(list_is_empty(&shl->procfs_list.pl_list));
627
628}
629
630static int
631spa_mmp_history_clear(procfs_list_t *procfs_list)
632{
633	spa_history_list_t *shl = procfs_list->pl_private;
634	mutex_enter(&procfs_list->pl_lock);
635	spa_mmp_history_truncate(shl, 0);
636	mutex_exit(&procfs_list->pl_lock);
637	return (0);
638}
639
640static void
641spa_mmp_history_init(spa_t *spa)
642{
643	spa_history_list_t *shl = &spa->spa_stats.mmp_history;
644
645	shl->size = 0;
646
647	shl->procfs_list.pl_private = shl;
648	procfs_list_install("zfs",
649	    spa_name(spa),
650	    "multihost",
651	    0644,
652	    &shl->procfs_list,
653	    spa_mmp_history_show,
654	    spa_mmp_history_show_header,
655	    spa_mmp_history_clear,
656	    offsetof(spa_mmp_history_t, smh_node));
657}
658
659static void
660spa_mmp_history_destroy(spa_t *spa)
661{
662	spa_history_list_t *shl = &spa->spa_stats.mmp_history;
663	procfs_list_uninstall(&shl->procfs_list);
664	spa_mmp_history_truncate(shl, 0);
665	procfs_list_destroy(&shl->procfs_list);
666}
667
668/*
669 * Set duration in existing "skip" record to how long we have waited for a leaf
670 * vdev to become available.
671 *
672 * Important that we start search at the tail of the list where new
673 * records are inserted, so this is normally an O(1) operation.
674 */
675int
676spa_mmp_history_set_skip(spa_t *spa, uint64_t mmp_node_id)
677{
678	spa_history_list_t *shl = &spa->spa_stats.mmp_history;
679	spa_mmp_history_t *smh;
680	int error = ENOENT;
681
682	if (zfs_multihost_history == 0 && shl->size == 0)
683		return (0);
684
685	mutex_enter(&shl->procfs_list.pl_lock);
686	for (smh = list_tail(&shl->procfs_list.pl_list); smh != NULL;
687	    smh = list_prev(&shl->procfs_list.pl_list, smh)) {
688		if (smh->mmp_node_id == mmp_node_id) {
689			ASSERT3U(smh->io_error, !=, 0);
690			smh->duration = gethrtime() - smh->error_start;
691			smh->vdev_guid++;
692			error = 0;
693			break;
694		}
695	}
696	mutex_exit(&shl->procfs_list.pl_lock);
697
698	return (error);
699}
700
701/*
702 * Set MMP write duration and error status in existing record.
703 * See comment re: search order above spa_mmp_history_set_skip().
704 */
705int
706spa_mmp_history_set(spa_t *spa, uint64_t mmp_node_id, int io_error,
707    hrtime_t duration)
708{
709	spa_history_list_t *shl = &spa->spa_stats.mmp_history;
710	spa_mmp_history_t *smh;
711	int error = ENOENT;
712
713	if (zfs_multihost_history == 0 && shl->size == 0)
714		return (0);
715
716	mutex_enter(&shl->procfs_list.pl_lock);
717	for (smh = list_tail(&shl->procfs_list.pl_list); smh != NULL;
718	    smh = list_prev(&shl->procfs_list.pl_list, smh)) {
719		if (smh->mmp_node_id == mmp_node_id) {
720			ASSERT(smh->io_error == 0);
721			smh->io_error = io_error;
722			smh->duration = duration;
723			error = 0;
724			break;
725		}
726	}
727	mutex_exit(&shl->procfs_list.pl_lock);
728
729	return (error);
730}
731
732/*
733 * Add a new MMP historical record.
734 * error == 0 : a write was issued.
735 * error != 0 : a write was not issued because no leaves were found.
736 */
737void
738spa_mmp_history_add(spa_t *spa, uint64_t txg, uint64_t timestamp,
739    uint64_t mmp_delay, vdev_t *vd, int label, uint64_t mmp_node_id,
740    int error)
741{
742	spa_history_list_t *shl = &spa->spa_stats.mmp_history;
743	spa_mmp_history_t *smh;
744
745	if (zfs_multihost_history == 0 && shl->size == 0)
746		return;
747
748	smh = kmem_zalloc(sizeof (spa_mmp_history_t), KM_SLEEP);
749	smh->txg = txg;
750	smh->timestamp = timestamp;
751	smh->mmp_delay = mmp_delay;
752	if (vd) {
753		smh->vdev_guid = vd->vdev_guid;
754		if (vd->vdev_path)
755			smh->vdev_path = kmem_strdup(vd->vdev_path);
756	}
757	smh->vdev_label = label;
758	smh->mmp_node_id = mmp_node_id;
759
760	if (error) {
761		smh->io_error = error;
762		smh->error_start = gethrtime();
763		smh->vdev_guid = 1;
764	}
765
766	mutex_enter(&shl->procfs_list.pl_lock);
767	procfs_list_add(&shl->procfs_list, smh);
768	shl->size++;
769	spa_mmp_history_truncate(shl, zfs_multihost_history);
770	mutex_exit(&shl->procfs_list.pl_lock);
771}
772
773static void *
774spa_state_addr(kstat_t *ksp, loff_t n)
775{
776	if (n == 0)
777		return (ksp->ks_private);	/* return the spa_t */
778	return (NULL);
779}
780
781static int
782spa_state_data(char *buf, size_t size, void *data)
783{
784	spa_t *spa = (spa_t *)data;
785	(void) snprintf(buf, size, "%s\n", spa_state_to_name(spa));
786	return (0);
787}
788
789/*
790 * Return the state of the pool in /proc/spl/kstat/zfs/<pool>/state.
791 *
792 * This is a lock-less read of the pool's state (unlike using 'zpool', which
793 * can potentially block for seconds).  Because it doesn't block, it can useful
794 * as a pool heartbeat value.
795 */
796static void
797spa_state_init(spa_t *spa)
798{
799	spa_history_kstat_t *shk = &spa->spa_stats.state;
800	char *name;
801	kstat_t *ksp;
802
803	mutex_init(&shk->lock, NULL, MUTEX_DEFAULT, NULL);
804
805	name = kmem_asprintf("zfs/%s", spa_name(spa));
806	ksp = kstat_create(name, 0, "state", "misc",
807	    KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
808
809	shk->kstat = ksp;
810	if (ksp) {
811		ksp->ks_lock = &shk->lock;
812		ksp->ks_data = NULL;
813		ksp->ks_private = spa;
814		ksp->ks_flags |= KSTAT_FLAG_NO_HEADERS;
815		kstat_set_raw_ops(ksp, NULL, spa_state_data, spa_state_addr);
816		kstat_install(ksp);
817	}
818
819	kmem_strfree(name);
820}
821
822static void
823spa_health_destroy(spa_t *spa)
824{
825	spa_history_kstat_t *shk = &spa->spa_stats.state;
826	kstat_t *ksp = shk->kstat;
827	if (ksp)
828		kstat_delete(ksp);
829
830	mutex_destroy(&shk->lock);
831}
832
833static spa_iostats_t spa_iostats_template = {
834	{ "trim_extents_written",		KSTAT_DATA_UINT64 },
835	{ "trim_bytes_written",			KSTAT_DATA_UINT64 },
836	{ "trim_extents_skipped",		KSTAT_DATA_UINT64 },
837	{ "trim_bytes_skipped",			KSTAT_DATA_UINT64 },
838	{ "trim_extents_failed",		KSTAT_DATA_UINT64 },
839	{ "trim_bytes_failed",			KSTAT_DATA_UINT64 },
840	{ "autotrim_extents_written",		KSTAT_DATA_UINT64 },
841	{ "autotrim_bytes_written",		KSTAT_DATA_UINT64 },
842	{ "autotrim_extents_skipped",		KSTAT_DATA_UINT64 },
843	{ "autotrim_bytes_skipped",		KSTAT_DATA_UINT64 },
844	{ "autotrim_extents_failed",		KSTAT_DATA_UINT64 },
845	{ "autotrim_bytes_failed",		KSTAT_DATA_UINT64 },
846	{ "simple_trim_extents_written",	KSTAT_DATA_UINT64 },
847	{ "simple_trim_bytes_written",		KSTAT_DATA_UINT64 },
848	{ "simple_trim_extents_skipped",	KSTAT_DATA_UINT64 },
849	{ "simple_trim_bytes_skipped",		KSTAT_DATA_UINT64 },
850	{ "simple_trim_extents_failed",		KSTAT_DATA_UINT64 },
851	{ "simple_trim_bytes_failed",		KSTAT_DATA_UINT64 },
852};
853
854#define	SPA_IOSTATS_ADD(stat, val) \
855    atomic_add_64(&iostats->stat.value.ui64, (val));
856
857void
858spa_iostats_trim_add(spa_t *spa, trim_type_t type,
859    uint64_t extents_written, uint64_t bytes_written,
860    uint64_t extents_skipped, uint64_t bytes_skipped,
861    uint64_t extents_failed, uint64_t bytes_failed)
862{
863	spa_history_kstat_t *shk = &spa->spa_stats.iostats;
864	kstat_t *ksp = shk->kstat;
865	spa_iostats_t *iostats;
866
867	if (ksp == NULL)
868		return;
869
870	iostats = ksp->ks_data;
871	if (type == TRIM_TYPE_MANUAL) {
872		SPA_IOSTATS_ADD(trim_extents_written, extents_written);
873		SPA_IOSTATS_ADD(trim_bytes_written, bytes_written);
874		SPA_IOSTATS_ADD(trim_extents_skipped, extents_skipped);
875		SPA_IOSTATS_ADD(trim_bytes_skipped, bytes_skipped);
876		SPA_IOSTATS_ADD(trim_extents_failed, extents_failed);
877		SPA_IOSTATS_ADD(trim_bytes_failed, bytes_failed);
878	} else if (type == TRIM_TYPE_AUTO) {
879		SPA_IOSTATS_ADD(autotrim_extents_written, extents_written);
880		SPA_IOSTATS_ADD(autotrim_bytes_written, bytes_written);
881		SPA_IOSTATS_ADD(autotrim_extents_skipped, extents_skipped);
882		SPA_IOSTATS_ADD(autotrim_bytes_skipped, bytes_skipped);
883		SPA_IOSTATS_ADD(autotrim_extents_failed, extents_failed);
884		SPA_IOSTATS_ADD(autotrim_bytes_failed, bytes_failed);
885	} else {
886		SPA_IOSTATS_ADD(simple_trim_extents_written, extents_written);
887		SPA_IOSTATS_ADD(simple_trim_bytes_written, bytes_written);
888		SPA_IOSTATS_ADD(simple_trim_extents_skipped, extents_skipped);
889		SPA_IOSTATS_ADD(simple_trim_bytes_skipped, bytes_skipped);
890		SPA_IOSTATS_ADD(simple_trim_extents_failed, extents_failed);
891		SPA_IOSTATS_ADD(simple_trim_bytes_failed, bytes_failed);
892	}
893}
894
895static int
896spa_iostats_update(kstat_t *ksp, int rw)
897{
898	if (rw == KSTAT_WRITE) {
899		memcpy(ksp->ks_data, &spa_iostats_template,
900		    sizeof (spa_iostats_t));
901	}
902
903	return (0);
904}
905
906static void
907spa_iostats_init(spa_t *spa)
908{
909	spa_history_kstat_t *shk = &spa->spa_stats.iostats;
910
911	mutex_init(&shk->lock, NULL, MUTEX_DEFAULT, NULL);
912
913	char *name = kmem_asprintf("zfs/%s", spa_name(spa));
914	kstat_t *ksp = kstat_create(name, 0, "iostats", "misc",
915	    KSTAT_TYPE_NAMED, sizeof (spa_iostats_t) / sizeof (kstat_named_t),
916	    KSTAT_FLAG_VIRTUAL);
917
918	shk->kstat = ksp;
919	if (ksp) {
920		int size = sizeof (spa_iostats_t);
921		ksp->ks_lock = &shk->lock;
922		ksp->ks_private = spa;
923		ksp->ks_update = spa_iostats_update;
924		ksp->ks_data = kmem_alloc(size, KM_SLEEP);
925		memcpy(ksp->ks_data, &spa_iostats_template, size);
926		kstat_install(ksp);
927	}
928
929	kmem_strfree(name);
930}
931
932static void
933spa_iostats_destroy(spa_t *spa)
934{
935	spa_history_kstat_t *shk = &spa->spa_stats.iostats;
936	kstat_t *ksp = shk->kstat;
937	if (ksp) {
938		kmem_free(ksp->ks_data, sizeof (spa_iostats_t));
939		kstat_delete(ksp);
940	}
941
942	mutex_destroy(&shk->lock);
943}
944
945void
946spa_stats_init(spa_t *spa)
947{
948	spa_read_history_init(spa);
949	spa_txg_history_init(spa);
950	spa_tx_assign_init(spa);
951	spa_mmp_history_init(spa);
952	spa_state_init(spa);
953	spa_iostats_init(spa);
954}
955
956void
957spa_stats_destroy(spa_t *spa)
958{
959	spa_iostats_destroy(spa);
960	spa_health_destroy(spa);
961	spa_tx_assign_destroy(spa);
962	spa_txg_history_destroy(spa);
963	spa_read_history_destroy(spa);
964	spa_mmp_history_destroy(spa);
965}
966
967/* BEGIN CSTYLED */
968ZFS_MODULE_PARAM(zfs, zfs_, read_history, INT, ZMOD_RW,
969    "Historical statistics for the last N reads");
970
971ZFS_MODULE_PARAM(zfs, zfs_, read_history_hits, INT, ZMOD_RW,
972    "Include cache hits in read history");
973
974ZFS_MODULE_PARAM(zfs_txg, zfs_txg_, history, INT, ZMOD_RW,
975    "Historical statistics for the last N txgs");
976
977ZFS_MODULE_PARAM(zfs_multihost, zfs_multihost_, history, INT, ZMOD_RW,
978    "Historical statistics for last N multihost writes");
979/* END CSTYLED */
980