]> git.proxmox.com Git - ceph.git/blame - ceph/src/spdk/ocf/tests/functional/pyocf/types/volume.py
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / spdk / ocf / tests / functional / pyocf / types / volume.py
CommitLineData
9f95a23c
TL
1#
2# Copyright(c) 2019 Intel Corporation
3# SPDX-License-Identifier: BSD-3-Clause-Clear
4#
5
6from ctypes import (
7 POINTER,
8 c_void_p,
9 c_uint32,
10 c_char_p,
11 create_string_buffer,
12 memmove,
13 memset,
14 Structure,
15 CFUNCTYPE,
16 c_int,
17 c_uint,
18 c_uint64,
19 sizeof,
20 cast,
21 string_at,
22)
23from hashlib import md5
24import weakref
25
26from .io import Io, IoOps, IoDir
27from .shared import OcfErrorCode, Uuid
28from ..ocf import OcfLib
29from ..utils import print_buffer, Size as S
30from .data import Data
31
32
33class VolumeCaps(Structure):
34 _fields_ = [("_atomic_writes", c_uint32, 1)]
35
36
37class VolumeOps(Structure):
38 SUBMIT_IO = CFUNCTYPE(None, POINTER(Io))
39 SUBMIT_FLUSH = CFUNCTYPE(None, c_void_p)
40 SUBMIT_METADATA = CFUNCTYPE(None, c_void_p)
41 SUBMIT_DISCARD = CFUNCTYPE(None, c_void_p)
42 SUBMIT_WRITE_ZEROES = CFUNCTYPE(None, c_void_p)
43 OPEN = CFUNCTYPE(c_int, c_void_p)
44 CLOSE = CFUNCTYPE(None, c_void_p)
45 GET_MAX_IO_SIZE = CFUNCTYPE(c_uint, c_void_p)
46 GET_LENGTH = CFUNCTYPE(c_uint64, c_void_p)
47
48 _fields_ = [
49 ("_submit_io", SUBMIT_IO),
50 ("_submit_flush", SUBMIT_FLUSH),
51 ("_submit_metadata", SUBMIT_METADATA),
52 ("_submit_discard", SUBMIT_DISCARD),
53 ("_submit_write_zeroes", SUBMIT_WRITE_ZEROES),
54 ("_open", OPEN),
55 ("_close", CLOSE),
56 ("_get_max_io_size", GET_MAX_IO_SIZE),
57 ("_get_length", GET_LENGTH),
58 ]
59
60
61class VolumeProperties(Structure):
62 _fields_ = [
63 ("_name", c_char_p),
64 ("_io_priv_size", c_uint32),
65 ("_volume_priv_size", c_uint32),
66 ("_caps", VolumeCaps),
67 ("_ops", VolumeOps),
68 ("_io_ops", IoOps),
f67539c2 69 ("_deinit", c_char_p),
9f95a23c
TL
70 ]
71
72
73class VolumeIoPriv(Structure):
f67539c2 74 _fields_ = [("_data", c_void_p), ("_offset", c_uint64)]
9f95a23c
TL
75
76
77class Volume(Structure):
f67539c2
TL
78 VOLUME_POISON = 0x13
79
9f95a23c
TL
80 _fields_ = [("_storage", c_void_p)]
81 _instances_ = {}
82 _uuid_ = {}
83
84 props = None
85
86 def __init__(self, size: S, uuid=None):
87 super().__init__()
88 self.size = size
89 if uuid:
90 if uuid in type(self)._uuid_:
91 raise Exception(
92 "Volume with uuid {} already created".format(uuid)
93 )
94 self.uuid = uuid
95 else:
96 self.uuid = str(id(self))
97
98 type(self)._uuid_[self.uuid] = weakref.ref(self)
99
100 self.data = create_string_buffer(int(self.size))
f67539c2 101 memset(self.data, self.VOLUME_POISON, self.size)
9f95a23c
TL
102 self._storage = cast(self.data, c_void_p)
103
104 self.reset_stats()
105 self.opened = False
106
f67539c2
TL
107 def get_copy(self):
108 new_volume = Volume(self.size)
109 memmove(new_volume.data, self.data, self.size)
110 return new_volume
111
9f95a23c
TL
112 @classmethod
113 def get_props(cls):
114 if not cls.props:
115 cls.props = VolumeProperties(
116 _name=str(cls.__name__).encode("ascii"),
117 _io_priv_size=sizeof(VolumeIoPriv),
118 _volume_priv_size=0,
119 _caps=VolumeCaps(_atomic_writes=0),
120 _ops=VolumeOps(
121 _submit_io=cls._submit_io,
122 _submit_flush=cls._submit_flush,
123 _submit_metadata=cls._submit_metadata,
124 _submit_discard=cls._submit_discard,
125 _submit_write_zeroes=cls._submit_write_zeroes,
126 _open=cls._open,
127 _close=cls._close,
128 _get_max_io_size=cls._get_max_io_size,
129 _get_length=cls._get_length,
130 ),
131 _io_ops=IoOps(
132 _set_data=cls._io_set_data, _get_data=cls._io_get_data
133 ),
f67539c2 134 _deinit=0,
9f95a23c
TL
135 )
136
137 return cls.props
138
139 @classmethod
140 def get_instance(cls, ref):
141 instance = cls._instances_[ref]()
142 if instance is None:
143 print("tried to access {} but it's gone".format(ref))
144
145 return instance
146
147 @classmethod
148 def get_by_uuid(cls, uuid):
149 return cls._uuid_[uuid]()
150
151 @staticmethod
152 @VolumeOps.SUBMIT_IO
153 def _submit_io(io):
154 io_structure = cast(io, POINTER(Io))
f67539c2
TL
155 volume = Volume.get_instance(
156 OcfLib.getInstance().ocf_io_get_volume(io_structure)
157 )
9f95a23c
TL
158
159 volume.submit_io(io_structure)
160
161 @staticmethod
162 @VolumeOps.SUBMIT_FLUSH
163 def _submit_flush(flush):
164 io_structure = cast(flush, POINTER(Io))
f67539c2
TL
165 volume = Volume.get_instance(
166 OcfLib.getInstance().ocf_io_get_volume(io_structure)
167 )
9f95a23c
TL
168
169 volume.submit_flush(io_structure)
170
171 @staticmethod
172 @VolumeOps.SUBMIT_METADATA
173 def _submit_metadata(meta):
174 pass
175
176 @staticmethod
177 @VolumeOps.SUBMIT_DISCARD
178 def _submit_discard(discard):
179 io_structure = cast(discard, POINTER(Io))
f67539c2
TL
180 volume = Volume.get_instance(
181 OcfLib.getInstance().ocf_io_get_volume(io_structure)
182 )
9f95a23c
TL
183
184 volume.submit_discard(io_structure)
185
186 @staticmethod
187 @VolumeOps.SUBMIT_WRITE_ZEROES
188 def _submit_write_zeroes(write_zeroes):
189 pass
190
191 @staticmethod
192 @CFUNCTYPE(c_int, c_void_p)
193 def _open(ref):
194 uuid_ptr = cast(
195 OcfLib.getInstance().ocf_volume_get_uuid(ref), POINTER(Uuid)
196 )
197 uuid = str(uuid_ptr.contents._data, encoding="ascii")
198 try:
199 volume = Volume.get_by_uuid(uuid)
f67539c2 200 except: # noqa E722 TODO:Investigate whether this really should be so broad
9f95a23c
TL
201 print("Tried to access unallocated volume {}".format(uuid))
202 print("{}".format(Volume._uuid_))
203 return -1
204
205 if volume.opened:
206 return OcfErrorCode.OCF_ERR_NOT_OPEN_EXC
207
208 Volume._instances_[ref] = weakref.ref(volume)
209
210 return volume.open()
211
212 @staticmethod
213 @VolumeOps.CLOSE
214 def _close(ref):
215 volume = Volume.get_instance(ref)
216 volume.close()
217 volume.opened = False
218
219 @staticmethod
220 @VolumeOps.GET_MAX_IO_SIZE
221 def _get_max_io_size(ref):
222 return Volume.get_instance(ref).get_max_io_size()
223
224 @staticmethod
225 @VolumeOps.GET_LENGTH
226 def _get_length(ref):
227 return Volume.get_instance(ref).get_length()
228
229 @staticmethod
230 @IoOps.SET_DATA
231 def _io_set_data(io, data, offset):
232 io_priv = cast(
233 OcfLib.getInstance().ocf_io_get_priv(io), POINTER(VolumeIoPriv)
234 )
235 data = Data.get_instance(data)
f67539c2 236 io_priv.contents._offset = offset
9f95a23c
TL
237 io_priv.contents._data = data.handle
238
239 return 0
240
241 @staticmethod
242 @IoOps.GET_DATA
243 def _io_get_data(io):
244 io_priv = cast(
245 OcfLib.getInstance().ocf_io_get_priv(io), POINTER(VolumeIoPriv)
246 )
247 return io_priv.contents._data
248
249 def open(self):
250 self.opened = True
251 return 0
252
253 def close(self):
254 pass
255
256 def get_length(self):
257 return self.size
258
259 def get_max_io_size(self):
260 return S.from_KiB(128)
261
262 def submit_flush(self, flush):
263 flush.contents._end(flush, 0)
264
265 def submit_discard(self, discard):
266 try:
267 dst = self._storage + discard.contents._addr
f67539c2 268 memset(dst, 0, discard.contents._bytes)
9f95a23c
TL
269
270 discard.contents._end(discard, 0)
f67539c2 271 except: # noqa E722
9f95a23c
TL
272 discard.contents._end(discard, -5)
273
274 def get_stats(self):
275 return self.stats
276
277 def reset_stats(self):
278 self.stats = {IoDir.WRITE: 0, IoDir.READ: 0}
279
280 def submit_io(self, io):
281 try:
282 self.stats[IoDir(io.contents._dir)] += 1
283
f67539c2
TL
284 io_priv = cast(
285 OcfLib.getInstance().ocf_io_get_priv(io), POINTER(VolumeIoPriv))
286 offset = io_priv.contents._offset
287
9f95a23c 288 if io.contents._dir == IoDir.WRITE:
f67539c2
TL
289 src_ptr = cast(OcfLib.getInstance().ocf_io_get_data(io), c_void_p)
290 src = Data.get_instance(src_ptr.value).handle.value + offset
9f95a23c
TL
291 dst = self._storage + io.contents._addr
292 elif io.contents._dir == IoDir.READ:
f67539c2
TL
293 dst_ptr = cast(OcfLib.getInstance().ocf_io_get_data(io), c_void_p)
294 dst = Data.get_instance(dst_ptr.value).handle.value + offset
9f95a23c
TL
295 src = self._storage + io.contents._addr
296
297 memmove(dst, src, io.contents._bytes)
f67539c2 298 io_priv.contents._offset += io.contents._bytes
9f95a23c
TL
299
300 io.contents._end(io, 0)
f67539c2 301 except: # noqa E722
9f95a23c
TL
302 io.contents._end(io, -5)
303
f67539c2 304 def dump(self, offset=0, size=0, ignore=VOLUME_POISON, **kwargs):
9f95a23c
TL
305 if size == 0:
306 size = int(self.size) - int(offset)
f67539c2 307
9f95a23c
TL
308 print_buffer(
309 self._storage,
f67539c2
TL
310 size,
311 ignore=ignore,
312 **kwargs
9f95a23c
TL
313 )
314
315 def md5(self):
316 m = md5()
317 m.update(string_at(self._storage, self.size))
318 return m.hexdigest()
319
320
321class ErrorDevice(Volume):
322 def __init__(self, size, error_sectors: set = None, uuid=None):
323 super().__init__(size, uuid)
324 self.error_sectors = error_sectors or set()
325
326 def set_mapping(self, error_sectors: set):
327 self.error_sectors = error_sectors
328
329 def submit_io(self, io):
330 if io.contents._addr in self.error_sectors:
331 io.contents._end(io, -5)
332 self.stats["errors"][io.contents._dir] += 1
333 else:
334 super().submit_io(io)
335
336 def reset_stats(self):
337 super().reset_stats()
338 self.stats["errors"] = {IoDir.WRITE: 0, IoDir.READ: 0}
339
340
f67539c2
TL
341class TraceDevice(Volume):
342 def __init__(self, size, trace_fcn=None, uuid=None):
343 super().__init__(size, uuid)
344 self.trace_fcn = trace_fcn
345
346 def submit_io(self, io):
347 submit = True
348
349 if self.trace_fcn:
350 submit = self.trace_fcn(self, io)
351
352 if submit:
353 super().submit_io(io)
354
355
9f95a23c
TL
356lib = OcfLib.getInstance()
357lib.ocf_io_get_priv.restype = POINTER(VolumeIoPriv)
f67539c2
TL
358lib.ocf_io_get_volume.argtypes = [c_void_p]
359lib.ocf_io_get_volume.restype = c_void_p
360lib.ocf_io_get_data.argtypes = [c_void_p]
361lib.ocf_io_get_data.restype = c_void_p