1 // SPDX-License-Identifier: GPL-2.0
2 #include <cassert>
3
4 #include "qcow2.h"
5 #include "ublksrv_tgt.h"
6
IOWaiters()7 IOWaiters::IOWaiters(): io_waiters({})
8 {
9 }
10
add_waiter(unsigned tag)11 void IOWaiters::add_waiter(unsigned tag) {
12 __mapping_meta_add_waiter(tag, 0x3fffff);
13 }
14
15 /* The caller is waiting on the specified entry update */
add_waiter_idx(unsigned tag,unsigned entry_idx)16 void IOWaiters::add_waiter_idx(unsigned tag, unsigned entry_idx) {
17 __mapping_meta_add_waiter(tag, entry_idx);
18 }
19
20 /*
21 * For wakeup other IOs waiting for this meta.
22 *
23 * qcow2_tgt_io_done() will wakeup for current IO, that isn't covered
24 * by here.
25 */
__mapping_meta_wakeup_all(const struct ublksrv_queue * q,unsigned my_tag,unsigned entry_idx,bool all)26 void IOWaiters::__mapping_meta_wakeup_all(const struct ublksrv_queue *q,
27 unsigned my_tag, unsigned entry_idx, bool all) {
28 std::unordered_set<unsigned> tags(move(io_waiters));
29 std::unordered_set<unsigned>::const_iterator it = tags.cbegin();
30
31 ublk_dbg(UBLK_DBG_QCOW2_IO_WAITER, "%s: %d %p my tag %d enter\n",
32 __func__, __LINE__, this, my_tag);
33 while (it != tags.cend()) {
34 unsigned t = *it;
35 unsigned tag = t & (QCOW2_MAX_QUEUE_DEPTH - 1);
36 unsigned idx = t >> QCOW2_TAG_BITS;
37
38 /* can't wakeup me */
39 if (tag == my_tag) {
40 it = tags.erase(it);
41 continue;
42 }
43
44 ublk_dbg(UBLK_DBG_QCOW2_IO_WAITER, "%s: %d my tag %d tag %d idx %x\n",
45 __func__, __LINE__, my_tag, tag, idx);
46 if (all || idx == entry_idx) {
47 struct ublk_io_tgt *__io =
48 ublk_get_io_tgt_data(q, tag);
49
50 it = tags.erase(it);
51 __io->tgt_io_cqe = NULL;
52
53 try {
54 ((struct ublk_io_tgt *)__io)->co.resume();
55 } catch (MetaIoException &meta_error) {
56 io_waiters.merge(tags);
57 throw MetaIoException();
58 } catch (MetaUpdateException &meta_update_error) {
59 io_waiters.merge(tags);
60 throw MetaUpdateException();
61 }
62 } else {
63 it++;
64 }
65 ublk_dbg(UBLK_DBG_QCOW2_IO_WAITER, "%s: %d %p my tag %d tag %d idx %x\n",
66 __func__, __LINE__, this, my_tag, tag, idx);
67 }
68 io_waiters.merge(tags);
69 ublk_dbg(UBLK_DBG_QCOW2_IO_WAITER, "%s: %d %p my tag %d exit\n",
70 __func__, __LINE__, this, my_tag);
71 }
72
wakeup_all(const struct ublksrv_queue * q,unsigned my_tag)73 void IOWaiters::wakeup_all(const struct ublksrv_queue *q, unsigned my_tag) {
74 __mapping_meta_wakeup_all(q, my_tag, 0x3fffff, true);
75 }
76
wakeup_all_idx(const struct ublksrv_queue * q,unsigned my_tag,unsigned entry_idx)77 void IOWaiters::wakeup_all_idx(const struct ublksrv_queue *q, unsigned my_tag,
78 unsigned entry_idx) {
79 __mapping_meta_wakeup_all(q, my_tag, entry_idx, false);
80 }
81