xref: /openbmc/qemu/block/null.c (revision 3665dd6bb9043bef181c91e2dce9e1efff47ed51)
1  /*
2   * Null block driver
3   *
4   * Authors:
5   *  Fam Zheng <famz@redhat.com>
6   *
7   * Copyright (C) 2014 Red Hat, Inc.
8   *
9   * This work is licensed under the terms of the GNU GPL, version 2 or later.
10   * See the COPYING file in the top-level directory.
11   */
12  
13  #include "qemu/osdep.h"
14  #include "qapi/error.h"
15  #include "qapi/qmp/qdict.h"
16  #include "qapi/qmp/qstring.h"
17  #include "qemu/module.h"
18  #include "qemu/option.h"
19  #include "block/block-io.h"
20  #include "block/block_int.h"
21  #include "sysemu/replay.h"
22  
23  #define NULL_OPT_LATENCY "latency-ns"
24  #define NULL_OPT_ZEROES  "read-zeroes"
25  
26  typedef struct {
27      int64_t length;
28      int64_t latency_ns;
29      bool read_zeroes;
30  } BDRVNullState;
31  
32  static QemuOptsList runtime_opts = {
33      .name = "null",
34      .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
35      .desc = {
36          {
37              .name = BLOCK_OPT_SIZE,
38              .type = QEMU_OPT_SIZE,
39              .help = "size of the null block",
40          },
41          {
42              .name = NULL_OPT_LATENCY,
43              .type = QEMU_OPT_NUMBER,
44              .help = "nanoseconds (approximated) to wait "
45                      "before completing request",
46          },
47          {
48              .name = NULL_OPT_ZEROES,
49              .type = QEMU_OPT_BOOL,
50              .help = "return zeroes when read",
51          },
52          { /* end of list */ }
53      },
54  };
55  
null_co_parse_filename(const char * filename,QDict * options,Error ** errp)56  static void null_co_parse_filename(const char *filename, QDict *options,
57                                     Error **errp)
58  {
59      /* This functions only exists so that a null-co:// filename is accepted
60       * with the null-co driver. */
61      if (strcmp(filename, "null-co://")) {
62          error_setg(errp, "The only allowed filename for this driver is "
63                           "'null-co://'");
64          return;
65      }
66  }
67  
null_aio_parse_filename(const char * filename,QDict * options,Error ** errp)68  static void null_aio_parse_filename(const char *filename, QDict *options,
69                                      Error **errp)
70  {
71      /* This functions only exists so that a null-aio:// filename is accepted
72       * with the null-aio driver. */
73      if (strcmp(filename, "null-aio://")) {
74          error_setg(errp, "The only allowed filename for this driver is "
75                           "'null-aio://'");
76          return;
77      }
78  }
79  
null_open(BlockDriverState * bs,QDict * options,int flags,Error ** errp)80  static int null_open(BlockDriverState *bs, QDict *options, int flags,
81                       Error **errp)
82  {
83      QemuOpts *opts;
84      BDRVNullState *s = bs->opaque;
85      int ret = 0;
86  
87      opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
88      qemu_opts_absorb_qdict(opts, options, &error_abort);
89      s->length =
90          qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 1 << 30);
91      s->latency_ns =
92          qemu_opt_get_number(opts, NULL_OPT_LATENCY, 0);
93      if (s->latency_ns < 0) {
94          error_setg(errp, "latency-ns is invalid");
95          ret = -EINVAL;
96      }
97      s->read_zeroes = qemu_opt_get_bool(opts, NULL_OPT_ZEROES, false);
98      qemu_opts_del(opts);
99      bs->supported_write_flags = BDRV_REQ_FUA;
100      return ret;
101  }
102  
null_co_getlength(BlockDriverState * bs)103  static int64_t coroutine_fn null_co_getlength(BlockDriverState *bs)
104  {
105      BDRVNullState *s = bs->opaque;
106      return s->length;
107  }
108  
null_co_common(BlockDriverState * bs)109  static coroutine_fn int null_co_common(BlockDriverState *bs)
110  {
111      BDRVNullState *s = bs->opaque;
112  
113      if (s->latency_ns) {
114          qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, s->latency_ns);
115      }
116      return 0;
117  }
118  
null_co_preadv(BlockDriverState * bs,int64_t offset,int64_t bytes,QEMUIOVector * qiov,BdrvRequestFlags flags)119  static coroutine_fn int null_co_preadv(BlockDriverState *bs,
120                                         int64_t offset, int64_t bytes,
121                                         QEMUIOVector *qiov,
122                                         BdrvRequestFlags flags)
123  {
124      BDRVNullState *s = bs->opaque;
125  
126      if (s->read_zeroes) {
127          qemu_iovec_memset(qiov, 0, 0, bytes);
128      }
129  
130      return null_co_common(bs);
131  }
132  
null_co_pwritev(BlockDriverState * bs,int64_t offset,int64_t bytes,QEMUIOVector * qiov,BdrvRequestFlags flags)133  static coroutine_fn int null_co_pwritev(BlockDriverState *bs,
134                                          int64_t offset, int64_t bytes,
135                                          QEMUIOVector *qiov,
136                                          BdrvRequestFlags flags)
137  {
138      return null_co_common(bs);
139  }
140  
null_co_flush(BlockDriverState * bs)141  static coroutine_fn int null_co_flush(BlockDriverState *bs)
142  {
143      return null_co_common(bs);
144  }
145  
146  typedef struct {
147      BlockAIOCB common;
148      QEMUTimer timer;
149  } NullAIOCB;
150  
151  static const AIOCBInfo null_aiocb_info = {
152      .aiocb_size = sizeof(NullAIOCB),
153  };
154  
null_bh_cb(void * opaque)155  static void null_bh_cb(void *opaque)
156  {
157      NullAIOCB *acb = opaque;
158      acb->common.cb(acb->common.opaque, 0);
159      qemu_aio_unref(acb);
160  }
161  
null_timer_cb(void * opaque)162  static void null_timer_cb(void *opaque)
163  {
164      NullAIOCB *acb = opaque;
165      acb->common.cb(acb->common.opaque, 0);
166      timer_deinit(&acb->timer);
167      qemu_aio_unref(acb);
168  }
169  
null_aio_common(BlockDriverState * bs,BlockCompletionFunc * cb,void * opaque)170  static inline BlockAIOCB *null_aio_common(BlockDriverState *bs,
171                                            BlockCompletionFunc *cb,
172                                            void *opaque)
173  {
174      NullAIOCB *acb;
175      BDRVNullState *s = bs->opaque;
176  
177      acb = qemu_aio_get(&null_aiocb_info, bs, cb, opaque);
178      /* Only emulate latency after vcpu is running. */
179      if (s->latency_ns) {
180          aio_timer_init(bdrv_get_aio_context(bs), &acb->timer,
181                         QEMU_CLOCK_REALTIME, SCALE_NS,
182                         null_timer_cb, acb);
183          timer_mod_ns(&acb->timer,
184                       qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns);
185      } else {
186          replay_bh_schedule_oneshot_event(bdrv_get_aio_context(bs),
187                                           null_bh_cb, acb);
188      }
189      return &acb->common;
190  }
191  
null_aio_preadv(BlockDriverState * bs,int64_t offset,int64_t bytes,QEMUIOVector * qiov,BdrvRequestFlags flags,BlockCompletionFunc * cb,void * opaque)192  static BlockAIOCB *null_aio_preadv(BlockDriverState *bs,
193                                     int64_t offset, int64_t bytes,
194                                     QEMUIOVector *qiov, BdrvRequestFlags flags,
195                                     BlockCompletionFunc *cb,
196                                     void *opaque)
197  {
198      BDRVNullState *s = bs->opaque;
199  
200      if (s->read_zeroes) {
201          qemu_iovec_memset(qiov, 0, 0, bytes);
202      }
203  
204      return null_aio_common(bs, cb, opaque);
205  }
206  
null_aio_pwritev(BlockDriverState * bs,int64_t offset,int64_t bytes,QEMUIOVector * qiov,BdrvRequestFlags flags,BlockCompletionFunc * cb,void * opaque)207  static BlockAIOCB *null_aio_pwritev(BlockDriverState *bs,
208                                      int64_t offset, int64_t bytes,
209                                      QEMUIOVector *qiov, BdrvRequestFlags flags,
210                                      BlockCompletionFunc *cb,
211                                      void *opaque)
212  {
213      return null_aio_common(bs, cb, opaque);
214  }
215  
null_aio_flush(BlockDriverState * bs,BlockCompletionFunc * cb,void * opaque)216  static BlockAIOCB *null_aio_flush(BlockDriverState *bs,
217                                    BlockCompletionFunc *cb,
218                                    void *opaque)
219  {
220      return null_aio_common(bs, cb, opaque);
221  }
222  
null_reopen_prepare(BDRVReopenState * reopen_state,BlockReopenQueue * queue,Error ** errp)223  static int null_reopen_prepare(BDRVReopenState *reopen_state,
224                                 BlockReopenQueue *queue, Error **errp)
225  {
226      return 0;
227  }
228  
null_co_block_status(BlockDriverState * bs,bool want_zero,int64_t offset,int64_t bytes,int64_t * pnum,int64_t * map,BlockDriverState ** file)229  static int coroutine_fn null_co_block_status(BlockDriverState *bs,
230                                               bool want_zero, int64_t offset,
231                                               int64_t bytes, int64_t *pnum,
232                                               int64_t *map,
233                                               BlockDriverState **file)
234  {
235      BDRVNullState *s = bs->opaque;
236      int ret = BDRV_BLOCK_OFFSET_VALID;
237  
238      *pnum = bytes;
239      *map = offset;
240      *file = bs;
241  
242      if (s->read_zeroes) {
243          ret |= BDRV_BLOCK_ZERO;
244      }
245      return ret;
246  }
247  
null_refresh_filename(BlockDriverState * bs)248  static void null_refresh_filename(BlockDriverState *bs)
249  {
250      const QDictEntry *e;
251  
252      for (e = qdict_first(bs->full_open_options); e;
253           e = qdict_next(bs->full_open_options, e))
254      {
255          /* These options can be ignored */
256          if (strcmp(qdict_entry_key(e), "filename") &&
257              strcmp(qdict_entry_key(e), "driver") &&
258              strcmp(qdict_entry_key(e), NULL_OPT_LATENCY))
259          {
260              return;
261          }
262      }
263  
264      snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://",
265               bs->drv->format_name);
266  }
267  
268  static int64_t coroutine_fn
null_co_get_allocated_file_size(BlockDriverState * bs)269  null_co_get_allocated_file_size(BlockDriverState *bs)
270  {
271      return 0;
272  }
273  
274  static const char *const null_strong_runtime_opts[] = {
275      BLOCK_OPT_SIZE,
276      NULL_OPT_ZEROES,
277  
278      NULL
279  };
280  
281  static BlockDriver bdrv_null_co = {
282      .format_name            = "null-co",
283      .protocol_name          = "null-co",
284      .instance_size          = sizeof(BDRVNullState),
285  
286      .bdrv_open              = null_open,
287      .bdrv_parse_filename    = null_co_parse_filename,
288      .bdrv_co_getlength      = null_co_getlength,
289      .bdrv_co_get_allocated_file_size = null_co_get_allocated_file_size,
290  
291      .bdrv_co_preadv         = null_co_preadv,
292      .bdrv_co_pwritev        = null_co_pwritev,
293      .bdrv_co_flush_to_disk  = null_co_flush,
294      .bdrv_reopen_prepare    = null_reopen_prepare,
295  
296      .bdrv_co_block_status   = null_co_block_status,
297  
298      .bdrv_refresh_filename  = null_refresh_filename,
299      .strong_runtime_opts    = null_strong_runtime_opts,
300  };
301  
302  static BlockDriver bdrv_null_aio = {
303      .format_name            = "null-aio",
304      .protocol_name          = "null-aio",
305      .instance_size          = sizeof(BDRVNullState),
306  
307      .bdrv_open              = null_open,
308      .bdrv_parse_filename    = null_aio_parse_filename,
309      .bdrv_co_getlength      = null_co_getlength,
310      .bdrv_co_get_allocated_file_size = null_co_get_allocated_file_size,
311  
312      .bdrv_aio_preadv        = null_aio_preadv,
313      .bdrv_aio_pwritev       = null_aio_pwritev,
314      .bdrv_aio_flush         = null_aio_flush,
315      .bdrv_reopen_prepare    = null_reopen_prepare,
316  
317      .bdrv_co_block_status   = null_co_block_status,
318  
319      .bdrv_refresh_filename  = null_refresh_filename,
320      .strong_runtime_opts    = null_strong_runtime_opts,
321  };
322  
bdrv_null_init(void)323  static void bdrv_null_init(void)
324  {
325      bdrv_register(&bdrv_null_co);
326      bdrv_register(&bdrv_null_aio);
327  }
328  
329  block_init(bdrv_null_init);
330