]> git.proxmox.com Git - ceph.git/blob - ceph/src/blk/BlockDevice.cc
fd07e443c1365f470861edef5be391ebafb0936b
[ceph.git] / ceph / src / blk / BlockDevice.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2015 XSky <haomai@xsky.com>
7 *
8 * Author: Haomai Wang <haomaiwang@gmail.com>
9 *
10 * This is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License version 2.1, as published by the Free Software
13 * Foundation. See file COPYING.
14 *
15 */
16
17 #include <libgen.h>
18 #include <unistd.h>
19
20 #include "BlockDevice.h"
21
22 #if defined(HAVE_LIBAIO) || defined(HAVE_POSIXAIO)
23 #include "kernel/KernelDevice.h"
24 #endif
25
26 #if defined(HAVE_SPDK)
27 #include "spdk/NVMEDevice.h"
28 #endif
29
30 #if defined(HAVE_BLUESTORE_PMEM)
31 #include "pmem/PMEMDevice.h"
32 #endif
33
34 #if defined(HAVE_LIBZBD)
35 #include "zoned/HMSMRDevice.h"
36 #endif
37
38 #include "common/debug.h"
39 #include "common/EventTrace.h"
40 #include "common/errno.h"
41 #include "include/compat.h"
42
43 #define dout_context cct
44 #define dout_subsys ceph_subsys_bdev
45 #undef dout_prefix
46 #define dout_prefix *_dout << "bdev "
47
48 using std::string;
49
50
51 blk_access_mode_t buffermode(bool buffered)
52 {
53 return buffered ? blk_access_mode_t::BUFFERED : blk_access_mode_t::DIRECT;
54 }
55
56 std::ostream& operator<<(std::ostream& os, const blk_access_mode_t buffered)
57 {
58 os << (buffered == blk_access_mode_t::BUFFERED ? "(buffered)" : "(direct)");
59 return os;
60 }
61
62
63
64 void IOContext::aio_wait()
65 {
66 std::unique_lock l(lock);
67 // see _aio_thread for waker logic
68 while (num_running.load() > 0) {
69 dout(10) << __func__ << " " << this
70 << " waiting for " << num_running.load() << " aios to complete"
71 << dendl;
72 cond.wait(l);
73 }
74 dout(20) << __func__ << " " << this << " done" << dendl;
75 }
76
77 uint64_t IOContext::get_num_ios() const
78 {
79 // this is about the simplest model for transaction cost you can
80 // imagine. there is some fixed overhead cost by saying there is a
81 // minimum of one "io". and then we have some cost per "io" that is
82 // a configurable (with different hdd and ssd defaults), and add
83 // that to the bytes value.
84 uint64_t ios = 0;
85 #if defined(HAVE_LIBAIO) || defined(HAVE_POSIXAIO)
86 ios += pending_aios.size();
87 #endif
88 #ifdef HAVE_SPDK
89 ios += total_nseg;
90 #endif
91 return ios;
92 }
93
94 void IOContext::release_running_aios()
95 {
96 ceph_assert(!num_running);
97 #if defined(HAVE_LIBAIO) || defined(HAVE_POSIXAIO)
98 // release aio contexts (including pinned buffers).
99 running_aios.clear();
100 #endif
101 }
102
103 BlockDevice::block_device_t
104 BlockDevice::detect_device_type(const std::string& path)
105 {
106 #if defined(HAVE_SPDK)
107 if (NVMEDevice::support(path)) {
108 return block_device_t::spdk;
109 }
110 #endif
111 #if defined(HAVE_BLUESTORE_PMEM)
112 if (PMEMDevice::support(path)) {
113 return block_device_t::pmem;
114 }
115 #endif
116 #if (defined(HAVE_LIBAIO) || defined(HAVE_POSIXAIO)) && defined(HAVE_LIBZBD)
117 if (HMSMRDevice::support(path)) {
118 return block_device_t::hm_smr;
119 }
120 #endif
121 #if defined(HAVE_LIBAIO) || defined(HAVE_POSIXAIO)
122 return block_device_t::aio;
123 #else
124 return block_device_t::unknown;
125 #endif
126 }
127
128 BlockDevice::block_device_t
129 BlockDevice::device_type_from_name(const std::string& blk_dev_name)
130 {
131 #if defined(HAVE_LIBAIO) || defined(HAVE_POSIXAIO)
132 if (blk_dev_name == "aio") {
133 return block_device_t::aio;
134 }
135 #endif
136 #if defined(HAVE_SPDK)
137 if (blk_dev_name == "spdk") {
138 return block_device_t::spdk;
139 }
140 #endif
141 #if defined(HAVE_BLUESTORE_PMEM)
142 if (blk_dev_name == "pmem") {
143 return block_device_t::pmem;
144 }
145 #endif
146 #if (defined(HAVE_LIBAIO) || defined(HAVE_POSIXAIO)) && defined(HAVE_LIBZBD)
147 if (blk_dev_name == "hm_smr") {
148 return block_device_t::hm_smr;
149 }
150 #endif
151 return block_device_t::unknown;
152 }
153
154 BlockDevice* BlockDevice::create_with_type(block_device_t device_type,
155 CephContext* cct, const std::string& path, aio_callback_t cb,
156 void *cbpriv, aio_callback_t d_cb, void *d_cbpriv)
157 {
158
159 switch (device_type) {
160 #if defined(HAVE_LIBAIO) || defined(HAVE_POSIXAIO)
161 case block_device_t::aio:
162 return new KernelDevice(cct, cb, cbpriv, d_cb, d_cbpriv);
163 #endif
164 #if defined(HAVE_SPDK)
165 case block_device_t::spdk:
166 return new NVMEDevice(cct, cb, cbpriv);
167 #endif
168 #if defined(HAVE_BLUESTORE_PMEM)
169 case block_device_t::pmem:
170 return new PMEMDevice(cct, cb, cbpriv);
171 #endif
172 #if (defined(HAVE_LIBAIO) || defined(HAVE_POSIXAIO)) && defined(HAVE_LIBZBD)
173 case block_device_t::hm_smr:
174 return new HMSMRDevice(cct, cb, cbpriv, d_cb, d_cbpriv);
175 #endif
176 default:
177 ceph_abort_msg("unsupported device");
178 return nullptr;
179 }
180 }
181
182 BlockDevice *BlockDevice::create(
183 CephContext* cct, const string& path, aio_callback_t cb,
184 void *cbpriv, aio_callback_t d_cb, void *d_cbpriv)
185 {
186 const string blk_dev_name = cct->_conf.get_val<string>("bdev_type");
187 block_device_t device_type = block_device_t::unknown;
188 if (blk_dev_name.empty()) {
189 device_type = detect_device_type(path);
190 } else {
191 device_type = device_type_from_name(blk_dev_name);
192 }
193 return create_with_type(device_type, cct, path, cb, cbpriv, d_cb, d_cbpriv);
194 }
195
196 bool BlockDevice::is_valid_io(uint64_t off, uint64_t len) const {
197 bool ret = (off % block_size == 0 &&
198 len % block_size == 0 &&
199 len > 0 &&
200 off < size &&
201 off + len <= size);
202
203 if (!ret) {
204 derr << __func__ << " " << std::hex
205 << off << "~" << len
206 << " block_size " << block_size
207 << " size " << size
208 << std::dec << dendl;
209 }
210 return ret;
211 }