1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <stdint.h> 35 #include <stdlib.h> 36 #include <string.h> 37 38 #include "blobstore.h" 39 #include "request.h" 40 41 #include "spdk/io_channel.h" 42 #include "spdk/queue.h" 43 44 #include "spdk_internal/log.h" 45 46 void 47 spdk_bs_call_cpl(struct spdk_bs_cpl *cpl, int bserrno) 48 { 49 switch (cpl->type) { 50 case SPDK_BS_CPL_TYPE_BS_BASIC: 51 cpl->u.bs_basic.cb_fn(cpl->u.bs_basic.cb_arg, 52 bserrno); 53 break; 54 case SPDK_BS_CPL_TYPE_BS_HANDLE: 55 cpl->u.bs_handle.cb_fn(cpl->u.bs_handle.cb_arg, 56 cpl->u.bs_handle.bs, 57 bserrno); 58 break; 59 case SPDK_BS_CPL_TYPE_BLOB_BASIC: 60 cpl->u.blob_basic.cb_fn(cpl->u.blob_basic.cb_arg, 61 bserrno); 62 break; 63 case SPDK_BS_CPL_TYPE_BLOBID: 64 cpl->u.blobid.cb_fn(cpl->u.blobid.cb_arg, 65 cpl->u.blobid.blobid, 66 bserrno); 67 break; 68 case SPDK_BS_CPL_TYPE_BLOB_HANDLE: 69 cpl->u.blob_handle.cb_fn(cpl->u.blob_handle.cb_arg, 70 cpl->u.blob_handle.blob, 71 bserrno); 72 break; 73 case SPDK_BS_CPL_TYPE_NESTED_SEQUENCE: 74 cpl->u.nested_seq.cb_fn(cpl->u.nested_seq.cb_arg, 75 cpl->u.nested_seq.parent, 76 bserrno); 77 break; 78 } 79 } 80 81 static void 82 spdk_bs_request_set_complete(struct spdk_bs_request_set *set) 83 { 84 struct spdk_bs_cpl cpl = set->cpl; 85 int bserrno = set->bserrno; 86 87 TAILQ_INSERT_TAIL(&set->channel->reqs, set, link); 88 89 spdk_bs_call_cpl(&cpl, bserrno); 90 } 91 92 static void 93 spdk_bs_sequence_completion(struct spdk_io_channel *channel, void *cb_arg, int bserrno) 94 { 95 struct spdk_bs_request_set *set = cb_arg; 96 97 set->bserrno = bserrno; 98 set->u.sequence.cb_fn((spdk_bs_sequence_t *)set, set->u.sequence.cb_arg, bserrno); 99 } 100 101 spdk_bs_sequence_t * 102 spdk_bs_sequence_start(struct spdk_io_channel *_channel, 103 struct spdk_bs_cpl *cpl) 104 { 105 struct spdk_bs_channel *channel; 106 struct spdk_bs_request_set *set; 107 108 channel = spdk_io_channel_get_ctx(_channel); 109 110 set = TAILQ_FIRST(&channel->reqs); 111 if (!set) { 112 return NULL; 113 } 114 TAILQ_REMOVE(&channel->reqs, set, link); 115 116 set->cpl = *cpl; 117 set->bserrno = 0; 118 set->channel = channel; 119 120 set->cb_args.cb_fn = spdk_bs_sequence_completion; 121 set->cb_args.cb_arg = set; 122 set->cb_args.channel = channel->dev_channel; 123 124 return (spdk_bs_sequence_t *)set; 125 } 126 127 void 128 spdk_bs_sequence_read(spdk_bs_sequence_t *seq, void *payload, 129 uint64_t lba, uint32_t lba_count, 130 spdk_bs_sequence_cpl cb_fn, void *cb_arg) 131 { 132 struct spdk_bs_request_set *set = (struct spdk_bs_request_set *)seq; 133 struct spdk_bs_channel *channel = set->channel; 134 135 SPDK_TRACELOG(SPDK_TRACE_BLOB_RW, "Reading %u blocks from LBA %lu\n", lba_count, lba); 136 137 set->u.sequence.cb_fn = cb_fn; 138 set->u.sequence.cb_arg = cb_arg; 139 140 channel->dev->read(channel->dev, channel->dev_channel, payload, lba, lba_count, 141 &set->cb_args); 142 } 143 144 void 145 spdk_bs_sequence_write(spdk_bs_sequence_t *seq, void *payload, 146 uint64_t lba, uint32_t lba_count, 147 spdk_bs_sequence_cpl cb_fn, void *cb_arg) 148 { 149 struct spdk_bs_request_set *set = (struct spdk_bs_request_set *)seq; 150 struct spdk_bs_channel *channel = set->channel; 151 152 SPDK_TRACELOG(SPDK_TRACE_BLOB_RW, "Writing %u blocks to LBA %lu\n", lba_count, lba); 153 154 set->u.sequence.cb_fn = cb_fn; 155 set->u.sequence.cb_arg = cb_arg; 156 157 channel->dev->write(channel->dev, channel->dev_channel, payload, lba, lba_count, 158 &set->cb_args); 159 } 160 161 void 162 spdk_bs_sequence_flush(spdk_bs_sequence_t *seq, 163 spdk_bs_sequence_cpl cb_fn, void *cb_arg) 164 { 165 struct spdk_bs_request_set *set = (struct spdk_bs_request_set *)seq; 166 struct spdk_bs_channel *channel = set->channel; 167 168 SPDK_TRACELOG(SPDK_TRACE_BLOB_RW, "Flushing\n"); 169 170 set->u.sequence.cb_fn = cb_fn; 171 set->u.sequence.cb_arg = cb_arg; 172 173 channel->dev->flush(channel->dev, channel->dev_channel, 174 &set->cb_args); 175 } 176 177 void 178 spdk_bs_sequence_unmap(spdk_bs_sequence_t *seq, 179 uint64_t lba, uint32_t lba_count, 180 spdk_bs_sequence_cpl cb_fn, void *cb_arg) 181 { 182 struct spdk_bs_request_set *set = (struct spdk_bs_request_set *)seq; 183 struct spdk_bs_channel *channel = set->channel; 184 185 SPDK_TRACELOG(SPDK_TRACE_BLOB_RW, "Unmapping %u blocks at LBA %lu\n", lba_count, lba); 186 187 set->u.sequence.cb_fn = cb_fn; 188 set->u.sequence.cb_arg = cb_arg; 189 190 channel->dev->unmap(channel->dev, channel->dev_channel, lba, lba_count, 191 &set->cb_args); 192 } 193 194 void 195 spdk_bs_sequence_finish(spdk_bs_sequence_t *seq, int bserrno) 196 { 197 if (bserrno != 0) { 198 seq->bserrno = bserrno; 199 } 200 spdk_bs_request_set_complete((struct spdk_bs_request_set *)seq); 201 } 202 203 static void 204 spdk_bs_batch_completion(struct spdk_io_channel *_channel, 205 void *cb_arg, int bserrno) 206 { 207 struct spdk_bs_request_set *set = cb_arg; 208 209 set->u.batch.outstanding_ops--; 210 if (bserrno != 0) { 211 set->bserrno = bserrno; 212 } 213 214 if (set->u.batch.outstanding_ops == 0 && set->u.batch.batch_closed) { 215 if (set->u.batch.cb_fn) { 216 set->cb_args.cb_fn = spdk_bs_sequence_completion; 217 set->u.batch.cb_fn((spdk_bs_sequence_t *)set, set->u.batch.cb_arg, bserrno); 218 } else { 219 spdk_bs_request_set_complete(set); 220 } 221 } 222 } 223 224 spdk_bs_batch_t * 225 spdk_bs_batch_open(struct spdk_io_channel *_channel, 226 struct spdk_bs_cpl *cpl) 227 { 228 struct spdk_bs_channel *channel; 229 struct spdk_bs_request_set *set; 230 231 channel = spdk_io_channel_get_ctx(_channel); 232 233 set = TAILQ_FIRST(&channel->reqs); 234 if (!set) { 235 return NULL; 236 } 237 TAILQ_REMOVE(&channel->reqs, set, link); 238 239 set->cpl = *cpl; 240 set->bserrno = 0; 241 set->channel = channel; 242 243 set->u.batch.cb_fn = NULL; 244 set->u.batch.cb_arg = NULL; 245 set->u.batch.outstanding_ops = 0; 246 set->u.batch.batch_closed = 0; 247 248 set->cb_args.cb_fn = spdk_bs_batch_completion; 249 set->cb_args.cb_arg = set; 250 set->cb_args.channel = channel->dev_channel; 251 252 return (spdk_bs_batch_t *)set; 253 } 254 255 void 256 spdk_bs_batch_read(spdk_bs_batch_t *batch, void *payload, 257 uint64_t lba, uint32_t lba_count) 258 { 259 struct spdk_bs_request_set *set = (struct spdk_bs_request_set *)batch; 260 struct spdk_bs_channel *channel = set->channel; 261 262 SPDK_TRACELOG(SPDK_TRACE_BLOB_RW, "Reading %u blocks from LBA %lu\n", lba_count, lba); 263 264 set->u.batch.outstanding_ops++; 265 channel->dev->read(channel->dev, channel->dev_channel, payload, lba, lba_count, 266 &set->cb_args); 267 } 268 269 void 270 spdk_bs_batch_write(spdk_bs_batch_t *batch, void *payload, 271 uint64_t lba, uint32_t lba_count) 272 { 273 struct spdk_bs_request_set *set = (struct spdk_bs_request_set *)batch; 274 struct spdk_bs_channel *channel = set->channel; 275 276 SPDK_TRACELOG(SPDK_TRACE_BLOB_RW, "Writing %u blocks to LBA %lu\n", lba_count, lba); 277 278 set->u.batch.outstanding_ops++; 279 channel->dev->write(channel->dev, channel->dev_channel, payload, lba, lba_count, 280 &set->cb_args); 281 } 282 283 void 284 spdk_bs_batch_flush(spdk_bs_batch_t *batch) 285 { 286 struct spdk_bs_request_set *set = (struct spdk_bs_request_set *)batch; 287 struct spdk_bs_channel *channel = set->channel; 288 289 SPDK_TRACELOG(SPDK_TRACE_BLOB_RW, "Flushing\n"); 290 291 set->u.batch.outstanding_ops++; 292 channel->dev->flush(channel->dev, channel->dev_channel, 293 &set->cb_args); 294 } 295 296 void 297 spdk_bs_batch_unmap(spdk_bs_batch_t *batch, 298 uint64_t lba, uint32_t lba_count) 299 { 300 struct spdk_bs_request_set *set = (struct spdk_bs_request_set *)batch; 301 struct spdk_bs_channel *channel = set->channel; 302 303 SPDK_TRACELOG(SPDK_TRACE_BLOB_RW, "Unmapping %u blocks at LBA %lu\n", lba_count, lba); 304 305 set->u.batch.outstanding_ops++; 306 channel->dev->unmap(channel->dev, channel->dev_channel, lba, lba_count, 307 &set->cb_args); 308 } 309 310 void 311 spdk_bs_batch_close(spdk_bs_batch_t *batch) 312 { 313 struct spdk_bs_request_set *set = (struct spdk_bs_request_set *)batch; 314 315 set->u.batch.batch_closed = 1; 316 317 if (set->u.batch.outstanding_ops == 0) { 318 if (set->u.batch.cb_fn) { 319 set->cb_args.cb_fn = spdk_bs_sequence_completion; 320 set->u.batch.cb_fn((spdk_bs_sequence_t *)set, set->u.batch.cb_arg, set->bserrno); 321 } else { 322 spdk_bs_request_set_complete(set); 323 } 324 } 325 } 326 327 spdk_bs_batch_t * 328 spdk_bs_sequence_to_batch(spdk_bs_sequence_t *seq, spdk_bs_sequence_cpl cb_fn, void *cb_arg) 329 { 330 struct spdk_bs_request_set *set = (struct spdk_bs_request_set *)seq; 331 332 set->u.batch.cb_fn = cb_fn; 333 set->u.batch.cb_arg = cb_arg; 334 set->u.batch.outstanding_ops = 0; 335 set->u.batch.batch_closed = 0; 336 337 set->cb_args.cb_fn = spdk_bs_batch_completion; 338 339 return set; 340 } 341 342 SPDK_LOG_REGISTER_TRACE_FLAG("blob_rw", SPDK_TRACE_BLOB_RW); 343