xref: /illumos-gate/usr/src/uts/common/fs/zfs/vdev_queue.c (revision 4de2612967d06c4fdbf524a62556a1e8118a006f)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/zfs_context.h>
30 #include <sys/spa.h>
31 #include <sys/vdev_impl.h>
32 #include <sys/zio.h>
33 #include <sys/avl.h>
34 
35 /*
36  * Virtual device vector for disk I/O scheduling.
37  */
38 int
39 vdev_queue_deadline_compare(const void *x1, const void *x2)
40 {
41 	const zio_t *z1 = x1;
42 	const zio_t *z2 = x2;
43 
44 	if (z1->io_deadline < z2->io_deadline)
45 		return (-1);
46 	if (z1->io_deadline > z2->io_deadline)
47 		return (1);
48 
49 	if (z1->io_offset < z2->io_offset)
50 		return (-1);
51 	if (z1->io_offset > z2->io_offset)
52 		return (1);
53 
54 	if (z1 < z2)
55 		return (-1);
56 	if (z1 > z2)
57 		return (1);
58 
59 	return (0);
60 }
61 
62 int
63 vdev_queue_offset_compare(const void *x1, const void *x2)
64 {
65 	const zio_t *z1 = x1;
66 	const zio_t *z2 = x2;
67 
68 	if (z1->io_offset < z2->io_offset)
69 		return (-1);
70 	if (z1->io_offset > z2->io_offset)
71 		return (1);
72 
73 	if (z1 < z2)
74 		return (-1);
75 	if (z1 > z2)
76 		return (1);
77 
78 	return (0);
79 }
80 
81 void
82 vdev_queue_init(vdev_t *vd)
83 {
84 	vdev_queue_t *vq = &vd->vdev_queue;
85 
86 	mutex_init(&vq->vq_lock, NULL, MUTEX_DEFAULT, NULL);
87 
88 	avl_create(&vq->vq_deadline_tree, vdev_queue_deadline_compare,
89 	    sizeof (zio_t), offsetof(struct zio, io_deadline_node));
90 
91 	avl_create(&vq->vq_read_tree, vdev_queue_offset_compare,
92 	    sizeof (zio_t), offsetof(struct zio, io_offset_node));
93 
94 	avl_create(&vq->vq_write_tree, vdev_queue_offset_compare,
95 	    sizeof (zio_t), offsetof(struct zio, io_offset_node));
96 
97 	avl_create(&vq->vq_pending_tree, vdev_queue_offset_compare,
98 	    sizeof (zio_t), offsetof(struct zio, io_offset_node));
99 }
100 
101 void
102 vdev_queue_fini(vdev_t *vd)
103 {
104 	vdev_queue_t *vq = &vd->vdev_queue;
105 
106 	avl_destroy(&vq->vq_deadline_tree);
107 	avl_destroy(&vq->vq_read_tree);
108 	avl_destroy(&vq->vq_write_tree);
109 	avl_destroy(&vq->vq_pending_tree);
110 
111 	mutex_destroy(&vq->vq_lock);
112 }
113 
114 static void
115 vdev_queue_agg_io_done(zio_t *aio)
116 {
117 	zio_t *dio;
118 	uint64_t offset = 0;
119 
120 	while ((dio = aio->io_delegate_list) != NULL) {
121 		if (aio->io_type == ZIO_TYPE_READ)
122 			bcopy((char *)aio->io_data + offset, dio->io_data,
123 			    dio->io_size);
124 		offset += dio->io_size;
125 		aio->io_delegate_list = dio->io_delegate_next;
126 		dio->io_delegate_next = NULL;
127 		dio->io_error = aio->io_error;
128 		zio_next_stage(dio);
129 	}
130 	ASSERT3U(offset, ==, aio->io_size);
131 
132 	zio_buf_free(aio->io_data, aio->io_size);
133 }
134 
135 #define	IS_ADJACENT(io, nio) \
136 	((io)->io_offset + (io)->io_size == (nio)->io_offset)
137 
138 typedef void zio_issue_func_t(zio_t *);
139 
140 static zio_t *
141 vdev_queue_io_to_issue(vdev_queue_t *vq, uint64_t pending_limit,
142 	zio_issue_func_t **funcp)
143 {
144 	zio_t *fio, *lio, *aio, *dio;
145 	avl_tree_t *tree;
146 	uint64_t size;
147 
148 	ASSERT(MUTEX_HELD(&vq->vq_lock));
149 
150 	*funcp = NULL;
151 
152 	if (avl_numnodes(&vq->vq_pending_tree) >= pending_limit ||
153 	    avl_numnodes(&vq->vq_deadline_tree) == 0)
154 		return (NULL);
155 
156 	fio = lio = avl_first(&vq->vq_deadline_tree);
157 
158 	tree = fio->io_vdev_tree;
159 	size = fio->io_size;
160 
161 	while ((dio = AVL_PREV(tree, fio)) != NULL && IS_ADJACENT(dio, fio) &&
162 	    size + dio->io_size <= vq->vq_agg_limit) {
163 		dio->io_delegate_next = fio;
164 		fio = dio;
165 		size += dio->io_size;
166 	}
167 
168 	while ((dio = AVL_NEXT(tree, lio)) != NULL && IS_ADJACENT(lio, dio) &&
169 	    size + dio->io_size <= vq->vq_agg_limit) {
170 		lio->io_delegate_next = dio;
171 		lio = dio;
172 		size += dio->io_size;
173 	}
174 
175 	if (fio != lio) {
176 		char *buf = zio_buf_alloc(size);
177 		uint64_t offset = 0;
178 		int nagg = 0;
179 
180 		ASSERT(size <= vq->vq_agg_limit);
181 
182 		aio = zio_vdev_child_io(fio, NULL, fio->io_vd,
183 		    fio->io_offset, buf, size, fio->io_type,
184 		    ZIO_PRIORITY_NOW, ZIO_FLAG_DONT_QUEUE |
185 		    ZIO_FLAG_DONT_CACHE | ZIO_FLAG_DONT_PROPAGATE,
186 		    vdev_queue_agg_io_done, NULL);
187 
188 		aio->io_delegate_list = fio;
189 
190 		for (dio = fio; dio != NULL; dio = dio->io_delegate_next) {
191 			ASSERT(dio->io_type == aio->io_type);
192 			if (dio->io_type == ZIO_TYPE_WRITE)
193 				bcopy(dio->io_data, buf + offset, dio->io_size);
194 			offset += dio->io_size;
195 			avl_remove(&vq->vq_deadline_tree, dio);
196 			avl_remove(tree, dio);
197 			zio_vdev_io_bypass(dio);
198 			nagg++;
199 		}
200 
201 		ASSERT(offset == size);
202 
203 		dprintf("%5s  T=%llu  off=%8llx  agg=%3d  "
204 		    "old=%5llx  new=%5llx\n",
205 		    zio_type_name[fio->io_type],
206 		    fio->io_deadline, fio->io_offset, nagg, fio->io_size, size);
207 
208 		avl_add(&vq->vq_pending_tree, aio);
209 
210 		*funcp = zio_nowait;
211 		return (aio);
212 	}
213 
214 	avl_remove(&vq->vq_deadline_tree, fio);
215 	avl_remove(tree, fio);
216 
217 	avl_add(&vq->vq_pending_tree, fio);
218 
219 	*funcp = zio_next_stage;
220 
221 	return (fio);
222 }
223 
224 zio_t *
225 vdev_queue_io(zio_t *zio)
226 {
227 	vdev_queue_t *vq = &zio->io_vd->vdev_queue;
228 	zio_t *nio;
229 	zio_issue_func_t *func;
230 
231 	ASSERT(zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE);
232 
233 	if (zio->io_flags & ZIO_FLAG_DONT_QUEUE)
234 		return (zio);
235 
236 	zio->io_flags |= ZIO_FLAG_DONT_CACHE | ZIO_FLAG_DONT_QUEUE;
237 
238 	if (zio->io_type == ZIO_TYPE_READ)
239 		zio->io_vdev_tree = &vq->vq_read_tree;
240 	else
241 		zio->io_vdev_tree = &vq->vq_write_tree;
242 
243 	mutex_enter(&vq->vq_lock);
244 
245 	zio->io_deadline = (zio->io_timestamp >> vq->vq_time_shift) +
246 	    zio->io_priority;
247 
248 	avl_add(&vq->vq_deadline_tree, zio);
249 	avl_add(zio->io_vdev_tree, zio);
250 
251 	nio = vdev_queue_io_to_issue(vq, vq->vq_min_pending, &func);
252 
253 	mutex_exit(&vq->vq_lock);
254 
255 	if (nio == NULL || func != zio_nowait)
256 		return (nio);
257 
258 	func(nio);
259 	return (NULL);
260 }
261 
262 void
263 vdev_queue_io_done(zio_t *zio)
264 {
265 	vdev_queue_t *vq = &zio->io_vd->vdev_queue;
266 	zio_t *nio;
267 	zio_issue_func_t *func;
268 	int i;
269 
270 	mutex_enter(&vq->vq_lock);
271 
272 	avl_remove(&vq->vq_pending_tree, zio);
273 
274 	for (i = 0; i < vq->vq_ramp_rate; i++) {
275 		nio = vdev_queue_io_to_issue(vq, vq->vq_max_pending, &func);
276 		if (nio == NULL)
277 			break;
278 		mutex_exit(&vq->vq_lock);
279 		if (func == zio_next_stage)
280 			zio_vdev_io_reissue(nio);
281 		func(nio);
282 		mutex_enter(&vq->vq_lock);
283 	}
284 
285 	mutex_exit(&vq->vq_lock);
286 }
287