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 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/zfs_context.h> 29 #include <sys/spa.h> 30 #include <sys/vdev_impl.h> 31 #include <sys/zio.h> 32 #include <sys/avl.h> 33 34 /* 35 * Virtual device vector for disk I/O scheduling. 36 */ 37 int 38 vdev_queue_deadline_compare(const void *x1, const void *x2) 39 { 40 const zio_t *z1 = x1; 41 const zio_t *z2 = x2; 42 43 if (z1->io_deadline < z2->io_deadline) 44 return (-1); 45 if (z1->io_deadline > z2->io_deadline) 46 return (1); 47 48 if (z1->io_offset < z2->io_offset) 49 return (-1); 50 if (z1->io_offset > z2->io_offset) 51 return (1); 52 53 if (z1 < z2) 54 return (-1); 55 if (z1 > z2) 56 return (1); 57 58 return (0); 59 } 60 61 int 62 vdev_queue_offset_compare(const void *x1, const void *x2) 63 { 64 const zio_t *z1 = x1; 65 const zio_t *z2 = x2; 66 67 if (z1->io_offset < z2->io_offset) 68 return (-1); 69 if (z1->io_offset > z2->io_offset) 70 return (1); 71 72 if (z1 < z2) 73 return (-1); 74 if (z1 > z2) 75 return (1); 76 77 return (0); 78 } 79 80 void 81 vdev_queue_init(vdev_t *vd) 82 { 83 vdev_queue_t *vq = &vd->vdev_queue; 84 85 mutex_init(&vq->vq_lock, NULL, MUTEX_DEFAULT, NULL); 86 87 avl_create(&vq->vq_deadline_tree, vdev_queue_deadline_compare, 88 sizeof (zio_t), offsetof(struct zio, io_deadline_node)); 89 90 avl_create(&vq->vq_read_tree, vdev_queue_offset_compare, 91 sizeof (zio_t), offsetof(struct zio, io_offset_node)); 92 93 avl_create(&vq->vq_write_tree, vdev_queue_offset_compare, 94 sizeof (zio_t), offsetof(struct zio, io_offset_node)); 95 96 avl_create(&vq->vq_pending_tree, vdev_queue_offset_compare, 97 sizeof (zio_t), offsetof(struct zio, io_offset_node)); 98 } 99 100 void 101 vdev_queue_fini(vdev_t *vd) 102 { 103 vdev_queue_t *vq = &vd->vdev_queue; 104 105 ASSERT(vq->vq_scrub_count == 0); 106 107 avl_destroy(&vq->vq_deadline_tree); 108 avl_destroy(&vq->vq_read_tree); 109 avl_destroy(&vq->vq_write_tree); 110 avl_destroy(&vq->vq_pending_tree); 111 112 mutex_destroy(&vq->vq_lock); 113 } 114 115 static void 116 vdev_queue_io_add(vdev_queue_t *vq, zio_t *zio) 117 { 118 avl_add(&vq->vq_deadline_tree, zio); 119 avl_add(zio->io_vdev_tree, zio); 120 121 if ((zio->io_flags & ZIO_FLAG_SCRUB_THREAD) && 122 ++vq->vq_scrub_count >= vq->vq_scrub_limit) 123 spa_scrub_throttle(zio->io_spa, 1); 124 } 125 126 static void 127 vdev_queue_io_remove(vdev_queue_t *vq, zio_t *zio) 128 { 129 if ((zio->io_flags & ZIO_FLAG_SCRUB_THREAD) && 130 vq->vq_scrub_count-- >= vq->vq_scrub_limit) 131 spa_scrub_throttle(zio->io_spa, -1); 132 133 avl_remove(&vq->vq_deadline_tree, zio); 134 avl_remove(zio->io_vdev_tree, zio); 135 } 136 137 static void 138 vdev_queue_agg_io_done(zio_t *aio) 139 { 140 zio_t *dio; 141 uint64_t offset = 0; 142 143 while ((dio = aio->io_delegate_list) != NULL) { 144 if (aio->io_type == ZIO_TYPE_READ) 145 bcopy((char *)aio->io_data + offset, dio->io_data, 146 dio->io_size); 147 offset += dio->io_size; 148 aio->io_delegate_list = dio->io_delegate_next; 149 dio->io_delegate_next = NULL; 150 dio->io_error = aio->io_error; 151 zio_next_stage(dio); 152 } 153 ASSERT3U(offset, ==, aio->io_size); 154 155 zio_buf_free(aio->io_data, aio->io_size); 156 } 157 158 #define IS_ADJACENT(io, nio) \ 159 ((io)->io_offset + (io)->io_size == (nio)->io_offset) 160 161 typedef void zio_issue_func_t(zio_t *); 162 163 static zio_t * 164 vdev_queue_io_to_issue(vdev_queue_t *vq, uint64_t pending_limit, 165 zio_issue_func_t **funcp) 166 { 167 zio_t *fio, *lio, *aio, *dio; 168 avl_tree_t *tree; 169 uint64_t size; 170 171 ASSERT(MUTEX_HELD(&vq->vq_lock)); 172 173 *funcp = NULL; 174 175 if (avl_numnodes(&vq->vq_pending_tree) >= pending_limit || 176 avl_numnodes(&vq->vq_deadline_tree) == 0) 177 return (NULL); 178 179 fio = lio = avl_first(&vq->vq_deadline_tree); 180 181 tree = fio->io_vdev_tree; 182 size = fio->io_size; 183 184 while ((dio = AVL_PREV(tree, fio)) != NULL && IS_ADJACENT(dio, fio) && 185 size + dio->io_size <= vq->vq_agg_limit) { 186 dio->io_delegate_next = fio; 187 fio = dio; 188 size += dio->io_size; 189 } 190 191 while ((dio = AVL_NEXT(tree, lio)) != NULL && IS_ADJACENT(lio, dio) && 192 size + dio->io_size <= vq->vq_agg_limit) { 193 lio->io_delegate_next = dio; 194 lio = dio; 195 size += dio->io_size; 196 } 197 198 if (fio != lio) { 199 char *buf = zio_buf_alloc(size); 200 uint64_t offset = 0; 201 int nagg = 0; 202 203 ASSERT(size <= vq->vq_agg_limit); 204 205 aio = zio_vdev_child_io(fio, NULL, fio->io_vd, 206 fio->io_offset, buf, size, fio->io_type, 207 ZIO_PRIORITY_NOW, ZIO_FLAG_DONT_QUEUE | 208 ZIO_FLAG_DONT_CACHE | ZIO_FLAG_DONT_PROPAGATE | 209 ZIO_FLAG_NOBOOKMARK, 210 vdev_queue_agg_io_done, NULL); 211 212 aio->io_delegate_list = fio; 213 214 for (dio = fio; dio != NULL; dio = dio->io_delegate_next) { 215 ASSERT(dio->io_type == aio->io_type); 216 ASSERT(dio->io_vdev_tree == tree); 217 if (dio->io_type == ZIO_TYPE_WRITE) 218 bcopy(dio->io_data, buf + offset, dio->io_size); 219 offset += dio->io_size; 220 vdev_queue_io_remove(vq, dio); 221 zio_vdev_io_bypass(dio); 222 nagg++; 223 } 224 225 ASSERT(offset == size); 226 227 dprintf("%5s T=%llu off=%8llx agg=%3d " 228 "old=%5llx new=%5llx\n", 229 zio_type_name[fio->io_type], 230 fio->io_deadline, fio->io_offset, nagg, fio->io_size, size); 231 232 avl_add(&vq->vq_pending_tree, aio); 233 234 *funcp = zio_nowait; 235 return (aio); 236 } 237 238 ASSERT(fio->io_vdev_tree == tree); 239 vdev_queue_io_remove(vq, fio); 240 241 avl_add(&vq->vq_pending_tree, fio); 242 243 *funcp = zio_next_stage; 244 245 return (fio); 246 } 247 248 zio_t * 249 vdev_queue_io(zio_t *zio) 250 { 251 vdev_queue_t *vq = &zio->io_vd->vdev_queue; 252 zio_t *nio; 253 zio_issue_func_t *func; 254 255 ASSERT(zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE); 256 257 if (zio->io_flags & ZIO_FLAG_DONT_QUEUE) 258 return (zio); 259 260 zio->io_flags |= ZIO_FLAG_DONT_CACHE | ZIO_FLAG_DONT_QUEUE; 261 262 if (zio->io_type == ZIO_TYPE_READ) 263 zio->io_vdev_tree = &vq->vq_read_tree; 264 else 265 zio->io_vdev_tree = &vq->vq_write_tree; 266 267 mutex_enter(&vq->vq_lock); 268 269 zio->io_deadline = (zio->io_timestamp >> vq->vq_time_shift) + 270 zio->io_priority; 271 272 vdev_queue_io_add(vq, zio); 273 274 nio = vdev_queue_io_to_issue(vq, vq->vq_min_pending, &func); 275 276 mutex_exit(&vq->vq_lock); 277 278 if (nio == NULL || func != zio_nowait) 279 return (nio); 280 281 func(nio); 282 return (NULL); 283 } 284 285 void 286 vdev_queue_io_done(zio_t *zio) 287 { 288 vdev_queue_t *vq = &zio->io_vd->vdev_queue; 289 zio_t *nio; 290 zio_issue_func_t *func; 291 int i; 292 293 mutex_enter(&vq->vq_lock); 294 295 avl_remove(&vq->vq_pending_tree, zio); 296 297 for (i = 0; i < vq->vq_ramp_rate; i++) { 298 nio = vdev_queue_io_to_issue(vq, vq->vq_max_pending, &func); 299 if (nio == NULL) 300 break; 301 mutex_exit(&vq->vq_lock); 302 if (func == zio_next_stage) 303 zio_vdev_io_reissue(nio); 304 func(nio); 305 mutex_enter(&vq->vq_lock); 306 } 307 308 mutex_exit(&vq->vq_lock); 309 } 310