vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / drivers / disk / virtual / ram_disk / ram_disk.cpp
blobb32c888800d2d3ebada7adb64ca0d1ab1c386d7c
1 /*
2 * Copyright 2010-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <file_systems/ram_disk/ram_disk.h>
9 #include <ctype.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <unistd.h>
16 #include <algorithm>
18 #include <device_manager.h>
19 #include <Drivers.h>
21 #include <AutoDeleter.h>
22 #include <util/AutoLock.h>
23 #include <util/DoublyLinkedList.h>
25 #include <fs/KPath.h>
26 #include <lock.h>
27 #include <util/fs_trim_support.h>
28 #include <vm/vm.h>
29 #include <vm/VMCache.h>
30 #include <vm/vm_page.h>
32 #include "dma_resources.h"
33 #include "io_requests.h"
34 #include "IOSchedulerSimple.h"
37 //#define TRACE_RAM_DISK
38 #ifdef TRACE_RAM_DISK
39 # define TRACE(x...) dprintf(x)
40 #else
41 # define TRACE(x...) do {} while (false)
42 #endif
45 static const unsigned char kRamdiskIcon[] = {
46 0x6e, 0x63, 0x69, 0x66, 0x0e, 0x03, 0x01, 0x00, 0x00, 0x02, 0x00, 0x16,
47 0x02, 0x3c, 0xc7, 0xee, 0x38, 0x9b, 0xc0, 0xba, 0x16, 0x57, 0x3e, 0x39,
48 0xb0, 0x49, 0x77, 0xc8, 0x42, 0xad, 0xc7, 0x00, 0xff, 0xff, 0xd3, 0x02,
49 0x00, 0x06, 0x02, 0x3c, 0x96, 0x32, 0x3a, 0x4d, 0x3f, 0xba, 0xfc, 0x01,
50 0x3d, 0x5a, 0x97, 0x4b, 0x57, 0xa5, 0x49, 0x84, 0x4d, 0x00, 0x47, 0x47,
51 0x47, 0xff, 0xa5, 0xa0, 0xa0, 0x02, 0x00, 0x16, 0x02, 0xbc, 0x59, 0x2f,
52 0xbb, 0x29, 0xa7, 0x3c, 0x0c, 0xe4, 0xbd, 0x0b, 0x7c, 0x48, 0x92, 0xc0,
53 0x4b, 0x79, 0x66, 0x00, 0x7d, 0xff, 0xd4, 0x02, 0x00, 0x06, 0x02, 0x38,
54 0xdb, 0xb4, 0x39, 0x97, 0x33, 0xbc, 0x4a, 0x33, 0x3b, 0xa5, 0x42, 0x48,
55 0x6e, 0x66, 0x49, 0xee, 0x7b, 0x00, 0x59, 0x67, 0x56, 0xff, 0xeb, 0xb2,
56 0xb2, 0x03, 0xa7, 0xff, 0x00, 0x03, 0xff, 0x00, 0x00, 0x04, 0x01, 0x80,
57 0x03, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x6a, 0x05, 0x33, 0x02,
58 0x00, 0x06, 0x02, 0x3a, 0x5d, 0x2c, 0x39, 0xf8, 0xb1, 0xb9, 0xdb, 0xf1,
59 0x3a, 0x4c, 0x0f, 0x48, 0xae, 0xea, 0x4a, 0xc0, 0x91, 0x00, 0x74, 0x74,
60 0x74, 0xff, 0x3e, 0x3d, 0x3d, 0x02, 0x00, 0x16, 0x02, 0x38, 0x22, 0x1b,
61 0x3b, 0x11, 0x73, 0xbc, 0x5e, 0xb5, 0x39, 0x4b, 0xaa, 0x4a, 0x47, 0xf1,
62 0x49, 0xc2, 0x1d, 0x00, 0xb0, 0xff, 0x83, 0x02, 0x00, 0x16, 0x03, 0x36,
63 0xed, 0xe9, 0x36, 0xb9, 0x49, 0xba, 0x0a, 0xf6, 0x3a, 0x32, 0x6f, 0x4a,
64 0x79, 0xef, 0x4b, 0x03, 0xe7, 0x00, 0x5a, 0x38, 0xdc, 0xff, 0x7e, 0x0d,
65 0x0a, 0x06, 0x22, 0x3c, 0x22, 0x49, 0x44, 0x5b, 0x5a, 0x3e, 0x5a, 0x31,
66 0x39, 0x25, 0x0a, 0x04, 0x22, 0x3c, 0x44, 0x4b, 0x5a, 0x31, 0x39, 0x25,
67 0x0a, 0x04, 0x44, 0x4b, 0x44, 0x5b, 0x5a, 0x3e, 0x5a, 0x31, 0x0a, 0x04,
68 0x22, 0x3c, 0x22, 0x49, 0x44, 0x5b, 0x44, 0x4b, 0x08, 0x02, 0x27, 0x43,
69 0xb8, 0x14, 0xc1, 0xf1, 0x08, 0x02, 0x26, 0x43, 0x29, 0x44, 0x0a, 0x05,
70 0x44, 0x5d, 0x49, 0x5d, 0x60, 0x3e, 0x5a, 0x3b, 0x5b, 0x3f, 0x0a, 0x04,
71 0x3c, 0x5a, 0x5a, 0x3c, 0x5a, 0x36, 0x3c, 0x52, 0x0a, 0x04, 0x24, 0x4e,
72 0x3c, 0x5a, 0x3c, 0x52, 0x24, 0x48, 0x06, 0x07, 0xaa, 0x3f, 0x42, 0x2e,
73 0x24, 0x48, 0x3c, 0x52, 0x5a, 0x36, 0x51, 0x33, 0x51, 0x33, 0x50, 0x34,
74 0x4b, 0x33, 0x4d, 0x34, 0x49, 0x32, 0x49, 0x30, 0x48, 0x31, 0x49, 0x30,
75 0x06, 0x08, 0xfa, 0xfa, 0x42, 0x50, 0x3e, 0x54, 0x40, 0x55, 0x3f, 0xc7,
76 0xeb, 0x41, 0xc8, 0x51, 0x42, 0xc9, 0x4f, 0x42, 0xc8, 0xda, 0x42, 0xca,
77 0x41, 0xc0, 0xf1, 0x5d, 0x45, 0xca, 0x81, 0x46, 0xc7, 0xb7, 0x46, 0xc8,
78 0xa9, 0x46, 0xc7, 0x42, 0x44, 0x51, 0x45, 0xc6, 0xb9, 0x43, 0xc6, 0x53,
79 0x0a, 0x07, 0x3c, 0x5c, 0x40, 0x5c, 0x42, 0x5e, 0x48, 0x5e, 0x4a, 0x5c,
80 0x46, 0x5a, 0x45, 0x4b, 0x06, 0x09, 0x9a, 0xf6, 0x03, 0x42, 0x2e, 0x24,
81 0x48, 0x4e, 0x3c, 0x5a, 0x5a, 0x3c, 0x36, 0x51, 0x33, 0x51, 0x33, 0x50,
82 0x34, 0x4b, 0x33, 0x4d, 0x34, 0x49, 0x32, 0x49, 0x30, 0x48, 0x31, 0x49,
83 0x30, 0x18, 0x0a, 0x07, 0x01, 0x06, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x10,
84 0x01, 0x17, 0x84, 0x00, 0x04, 0x0a, 0x01, 0x01, 0x01, 0x00, 0x0a, 0x02,
85 0x01, 0x02, 0x00, 0x0a, 0x03, 0x01, 0x03, 0x00, 0x0a, 0x04, 0x01, 0x04,
86 0x10, 0x01, 0x17, 0x85, 0x20, 0x04, 0x0a, 0x06, 0x01, 0x05, 0x30, 0x24,
87 0xb3, 0x99, 0x01, 0x17, 0x82, 0x00, 0x04, 0x0a, 0x05, 0x01, 0x05, 0x30,
88 0x20, 0xb2, 0xe6, 0x01, 0x17, 0x82, 0x00, 0x04, 0x0a, 0x09, 0x01, 0x0b,
89 0x02, 0x3e, 0x9b, 0x12, 0xb5, 0xf9, 0x99, 0x36, 0x19, 0x10, 0x3e, 0xc0,
90 0x21, 0x48, 0xed, 0x4d, 0xc8, 0x5a, 0x02, 0x0a, 0x09, 0x01, 0x0b, 0x02,
91 0x3e, 0x9b, 0x12, 0xb5, 0xf9, 0x99, 0x36, 0x19, 0x10, 0x3e, 0xc0, 0x21,
92 0x48, 0x4c, 0xd4, 0xc7, 0x9c, 0x11, 0x0a, 0x09, 0x01, 0x0b, 0x02, 0x3e,
93 0x9b, 0x12, 0xb5, 0xf9, 0x99, 0x36, 0x19, 0x10, 0x3e, 0xc0, 0x21, 0x47,
94 0x5c, 0xe7, 0xc6, 0x2c, 0x1a, 0x0a, 0x09, 0x01, 0x0b, 0x02, 0x3e, 0x9b,
95 0x12, 0xb5, 0xf9, 0x99, 0x36, 0x19, 0x10, 0x3e, 0xc0, 0x21, 0x46, 0x1b,
96 0xf5, 0xc4, 0x28, 0x4e, 0x0a, 0x08, 0x01, 0x0c, 0x12, 0x3e, 0xc0, 0x21,
97 0xb6, 0x19, 0x10, 0x36, 0x19, 0x10, 0x3e, 0xc0, 0x21, 0x45, 0xb6, 0x34,
98 0xc4, 0x22, 0x1f, 0x01, 0x17, 0x84, 0x00, 0x04, 0x0a, 0x0a, 0x01, 0x07,
99 0x02, 0x3e, 0xc0, 0x21, 0xb6, 0x19, 0x10, 0x36, 0x19, 0x10, 0x3e, 0xc0,
100 0x21, 0x45, 0xb6, 0x34, 0xc4, 0x22, 0x1f, 0x0a, 0x0b, 0x01, 0x08, 0x02,
101 0x3e, 0xc0, 0x21, 0xb6, 0x19, 0x10, 0x36, 0x19, 0x10, 0x3e, 0xc0, 0x21,
102 0x45, 0xb6, 0x34, 0xc4, 0x22, 0x1f, 0x0a, 0x0c, 0x01, 0x09, 0x02, 0x3e,
103 0xc0, 0x21, 0xb6, 0x19, 0x10, 0x36, 0x19, 0x10, 0x3e, 0xc0, 0x21, 0x45,
104 0xb6, 0x34, 0xc4, 0x22, 0x1f, 0x0a, 0x08, 0x01, 0x0a, 0x12, 0x3e, 0x98,
105 0xfd, 0xb5, 0xf6, 0x6c, 0x35, 0xc9, 0x3d, 0x3e, 0x7b, 0x5e, 0x48, 0xf2,
106 0x4e, 0xc7, 0xee, 0x3f, 0x01, 0x17, 0x84, 0x22, 0x04, 0x0a, 0x0d, 0x01,
107 0x0a, 0x02, 0x3e, 0x98, 0xfd, 0xb5, 0xf6, 0x6c, 0x35, 0xc9, 0x3d, 0x3e,
108 0x7b, 0x5e, 0x48, 0xf2, 0x4e, 0xc7, 0xee, 0x3f, 0x0a, 0x08, 0x01, 0x0a,
109 0x12, 0x3e, 0x98, 0xfd, 0xb5, 0xf6, 0x6c, 0x35, 0xc9, 0x3d, 0x3e, 0x7b,
110 0x5e, 0x48, 0x53, 0xa1, 0xc6, 0xa0, 0xb6, 0x01, 0x17, 0x84, 0x22, 0x04,
111 0x0a, 0x0d, 0x01, 0x0a, 0x02, 0x3e, 0x98, 0xfd, 0xb5, 0xf6, 0x6c, 0x35,
112 0xc9, 0x3d, 0x3e, 0x7b, 0x5e, 0x48, 0x53, 0xa1, 0xc6, 0xa0, 0xb6, 0x0a,
113 0x08, 0x01, 0x0a, 0x12, 0x3e, 0x98, 0xfd, 0xb5, 0xf6, 0x6c, 0x35, 0xc9,
114 0x3d, 0x3e, 0x7b, 0x5e, 0x47, 0x69, 0xe9, 0xc4, 0xa6, 0x5a, 0x01, 0x17,
115 0x84, 0x22, 0x04, 0x0a, 0x0d, 0x01, 0x0a, 0x02, 0x3e, 0x98, 0xfd, 0xb5,
116 0xf6, 0x6c, 0x35, 0xc9, 0x3d, 0x3e, 0x7b, 0x5e, 0x47, 0x69, 0xe9, 0xc4,
117 0xa6, 0x5a, 0x0a, 0x08, 0x01, 0x0a, 0x12, 0x3e, 0x98, 0xfd, 0xb5, 0xf6,
118 0x6c, 0x35, 0xc9, 0x3d, 0x3e, 0x7b, 0x5e, 0x46, 0x2c, 0x90, 0xb8, 0xd1,
119 0xff, 0x01, 0x17, 0x84, 0x22, 0x04, 0x0a, 0x0d, 0x01, 0x0a, 0x02, 0x3e,
120 0x98, 0xfd, 0xb5, 0xf6, 0x6c, 0x35, 0xc9, 0x3d, 0x3e, 0x7b, 0x5e, 0x46,
121 0x2c, 0x90, 0xb8, 0xd1, 0xff
125 // parameters for the DMA resource
126 static const uint32 kDMAResourceBufferCount = 16;
127 static const uint32 kDMAResourceBounceBufferCount = 16;
129 static const char* const kDriverModuleName
130 = "drivers/disk/virtual/ram_disk/driver_v1";
131 static const char* const kControlDeviceModuleName
132 = "drivers/disk/virtual/ram_disk/control/device_v1";
133 static const char* const kRawDeviceModuleName
134 = "drivers/disk/virtual/ram_disk/raw/device_v1";
136 static const char* const kControlDeviceName = RAM_DISK_CONTROL_DEVICE_NAME;
137 static const char* const kRawDeviceBaseName = RAM_DISK_RAW_DEVICE_BASE_NAME;
139 static const char* const kFilePathItem = "ram_disk/file_path";
140 static const char* const kDeviceSizeItem = "ram_disk/device_size";
141 static const char* const kDeviceIDItem = "ram_disk/id";
144 struct RawDevice;
145 typedef DoublyLinkedList<RawDevice> RawDeviceList;
147 struct device_manager_info* sDeviceManager;
149 static RawDeviceList sDeviceList;
150 static mutex sDeviceListLock = MUTEX_INITIALIZER("ram disk device list");
151 static uint64 sUsedRawDeviceIDs = 0;
154 static int32 allocate_raw_device_id();
155 static void free_raw_device_id(int32 id);
158 struct Device {
159 Device(device_node* node)
161 fNode(node)
163 mutex_init(&fLock, "ram disk device");
166 virtual ~Device()
168 mutex_destroy(&fLock);
171 bool Lock() { mutex_lock(&fLock); return true; }
172 void Unlock() { mutex_unlock(&fLock); }
174 device_node* Node() const { return fNode; }
176 virtual status_t PublishDevice() = 0;
178 protected:
179 mutex fLock;
180 device_node* fNode;
184 struct ControlDevice : Device {
185 ControlDevice(device_node* node)
187 Device(node)
191 status_t Register(const char* filePath, uint64 deviceSize, int32& _id)
193 int32 id = allocate_raw_device_id();
194 if (id < 0)
195 return B_BUSY;
197 device_attr attrs[] = {
198 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
199 {string: "RAM Disk Raw Device"}},
200 {kDeviceSizeItem, B_UINT64_TYPE, {ui64: deviceSize}},
201 {kDeviceIDItem, B_UINT32_TYPE, {ui32: (uint32)id}},
202 {kFilePathItem, B_STRING_TYPE, {string: filePath}},
203 {NULL}
206 // If filePath is NULL, remove the attribute.
207 if (filePath == NULL) {
208 size_t count = sizeof(attrs) / sizeof(attrs[0]);
209 memset(attrs + count - 2, 0, sizeof(attrs[0]));
212 status_t error = sDeviceManager->register_node(
213 sDeviceManager->get_parent_node(Node()), kDriverModuleName, attrs,
214 NULL, NULL);
215 if (error != B_OK) {
216 free_raw_device_id(id);
217 return error;
220 _id = id;
221 return B_OK;
224 virtual status_t PublishDevice()
226 return sDeviceManager->publish_device(Node(), kControlDeviceName,
227 kControlDeviceModuleName);
232 struct RawDevice : Device, DoublyLinkedListLinkImpl<RawDevice> {
233 RawDevice(device_node* node)
235 Device(node),
236 fID(-1),
237 fUnregistered(false),
238 fDeviceSize(0),
239 fDeviceName(NULL),
240 fFilePath(NULL),
241 fCache(NULL),
242 fDMAResource(NULL),
243 fIOScheduler(NULL)
247 virtual ~RawDevice()
249 if (fID >= 0) {
250 MutexLocker locker(sDeviceListLock);
251 sDeviceList.Remove(this);
254 free(fDeviceName);
255 free(fFilePath);
258 int32 ID() const { return fID; }
259 off_t DeviceSize() const { return fDeviceSize; }
260 const char* DeviceName() const { return fDeviceName; }
262 bool IsUnregistered() const { return fUnregistered; }
264 void SetUnregistered(bool unregistered)
266 fUnregistered = unregistered;
269 status_t Init(int32 id, const char* filePath, uint64 deviceSize)
271 fID = id;
272 fFilePath = filePath != NULL ? strdup(filePath) : NULL;
273 if (filePath != NULL && fFilePath == NULL)
274 return B_NO_MEMORY;
276 fDeviceSize = (deviceSize + B_PAGE_SIZE - 1) / B_PAGE_SIZE
277 * B_PAGE_SIZE;
279 if (fDeviceSize < B_PAGE_SIZE
280 || (uint64)fDeviceSize / B_PAGE_SIZE
281 > vm_page_num_pages() * 2 / 3) {
282 return B_BAD_VALUE;
285 // construct our device path
286 KPath path(kRawDeviceBaseName);
287 char buffer[32];
288 snprintf(buffer, sizeof(buffer), "%" B_PRId32 "/raw", fID);
290 status_t error = path.Append(buffer);
291 if (error != B_OK)
292 return error;
294 fDeviceName = path.DetachBuffer();
296 // insert into device list
297 RawDevice* nextDevice = NULL;
298 MutexLocker locker(sDeviceListLock);
299 for (RawDeviceList::Iterator it = sDeviceList.GetIterator();
300 (nextDevice = it.Next()) != NULL;) {
301 if (nextDevice->ID() > fID)
302 break;
305 sDeviceList.InsertBefore(nextDevice, this);
307 return B_OK;
310 status_t Prepare()
312 status_t error = VMCacheFactory::CreateAnonymousCache(fCache, false, 0,
313 0, false, VM_PRIORITY_SYSTEM);
314 if (error != B_OK) {
315 Unprepare();
316 return error;
319 fCache->temporary = 1;
320 fCache->virtual_end = fDeviceSize;
322 error = fCache->Commit(fDeviceSize, VM_PRIORITY_SYSTEM);
323 if (error != B_OK) {
324 Unprepare();
325 return error;
328 if (fFilePath != NULL) {
329 error = _LoadFile();
330 if (error != B_OK) {
331 Unprepare();
332 return error;
336 // no DMA restrictions
337 const dma_restrictions restrictions = {};
339 fDMAResource = new(std::nothrow) DMAResource;
340 if (fDMAResource == NULL) {
341 Unprepare();
342 return B_NO_MEMORY;
345 error = fDMAResource->Init(restrictions, B_PAGE_SIZE,
346 kDMAResourceBufferCount, kDMAResourceBounceBufferCount);
347 if (error != B_OK) {
348 Unprepare();
349 return error;
352 fIOScheduler = new(std::nothrow) IOSchedulerSimple(fDMAResource);
353 if (fIOScheduler == NULL) {
354 Unprepare();
355 return B_NO_MEMORY;
358 error = fIOScheduler->Init("ram disk device scheduler");
359 if (error != B_OK) {
360 Unprepare();
361 return error;
364 fIOScheduler->SetCallback(&_DoIOEntry, this);
366 return B_OK;
369 void Unprepare()
371 delete fIOScheduler;
372 fIOScheduler = NULL;
374 delete fDMAResource;
375 fDMAResource = NULL;
377 if (fCache != NULL) {
378 fCache->Lock();
379 fCache->ReleaseRefAndUnlock();
380 fCache = NULL;
384 void GetInfo(ram_disk_ioctl_info& _info) const
386 _info.id = fID;
387 _info.size = fDeviceSize;
388 memset(&_info.path, 0, sizeof(_info.path));
389 if (fFilePath != NULL)
390 strlcpy(_info.path, fFilePath, sizeof(_info.path));
393 status_t Flush()
395 static const size_t kPageCountPerIteration = 1024;
396 static const size_t kMaxGapSize = 15;
398 int fd = open(fFilePath, O_WRONLY);
399 if (fd < 0)
400 return errno;
401 FileDescriptorCloser fdCloser(fd);
403 vm_page** pages = new(std::nothrow) vm_page*[kPageCountPerIteration];
404 ArrayDeleter<vm_page*> pagesDeleter(pages);
406 uint8* buffer = (uint8*)malloc(kPageCountPerIteration * B_PAGE_SIZE);
407 MemoryDeleter bufferDeleter(buffer);
409 if (pages == NULL || buffer == NULL)
410 return B_NO_MEMORY;
412 // Iterate through all pages of the cache and write those back that have
413 // been modified.
414 AutoLocker<VMCache> locker(fCache);
416 status_t error = B_OK;
418 for (off_t offset = 0; offset < fDeviceSize;) {
419 // find the first modified page at or after the current offset
420 VMCachePagesTree::Iterator it
421 = fCache->pages.GetIterator(offset / B_PAGE_SIZE, true, true);
422 vm_page* firstModified;
423 while ((firstModified = it.Next()) != NULL
424 && !firstModified->modified) {
427 if (firstModified == NULL)
428 break;
430 if (firstModified->busy) {
431 fCache->WaitForPageEvents(firstModified, PAGE_EVENT_NOT_BUSY,
432 true);
433 continue;
436 pages[0] = firstModified;
437 page_num_t firstPageIndex = firstModified->cache_offset;
438 offset = firstPageIndex * B_PAGE_SIZE;
440 // Collect more pages until the gap between two modified pages gets
441 // too large or we hit the end of our array.
442 size_t previousModifiedIndex = 0;
443 size_t previousIndex = 0;
444 while (vm_page* page = it.Next()) {
445 page_num_t index = page->cache_offset - firstPageIndex;
446 if (page->busy
447 || index >= kPageCountPerIteration
448 || index - previousModifiedIndex > kMaxGapSize) {
449 break;
452 pages[index] = page;
454 // clear page array gap since the previous page
455 if (previousIndex + 1 < index) {
456 memset(pages + previousIndex + 1, 0,
457 (index - previousIndex - 1) * sizeof(vm_page*));
460 previousIndex = index;
461 if (page->modified)
462 previousModifiedIndex = index;
465 // mark all pages we want to write busy
466 size_t pagesToWrite = previousModifiedIndex + 1;
467 for (size_t i = 0; i < pagesToWrite; i++) {
468 if (vm_page* page = pages[i]) {
469 DEBUG_PAGE_ACCESS_START(page);
470 page->busy = true;
474 locker.Unlock();
476 // copy the pages to our buffer
477 for (size_t i = 0; i < pagesToWrite; i++) {
478 if (vm_page* page = pages[i]) {
479 error = vm_memcpy_from_physical(buffer + i * B_PAGE_SIZE,
480 page->physical_page_number * B_PAGE_SIZE, B_PAGE_SIZE,
481 false);
482 if (error != B_OK) {
483 dprintf("ramdisk: error copying page %" B_PRIu64
484 " data: %s\n", (uint64)page->physical_page_number,
485 strerror(error));
486 break;
488 } else
489 memset(buffer + i * B_PAGE_SIZE, 0, B_PAGE_SIZE);
492 // write the buffer
493 if (error == B_OK) {
494 ssize_t bytesWritten = pwrite(fd, buffer,
495 pagesToWrite * B_PAGE_SIZE, offset);
496 if (bytesWritten < 0) {
497 dprintf("ramdisk: error writing pages to file: %s\n",
498 strerror(bytesWritten));
499 error = bytesWritten;
501 else if ((size_t)bytesWritten != pagesToWrite * B_PAGE_SIZE) {
502 dprintf("ramdisk: error writing pages to file: short "
503 "write (%zd/%zu)\n", bytesWritten,
504 pagesToWrite * B_PAGE_SIZE);
505 error = B_ERROR;
509 // mark the pages unbusy, on success also unmodified
510 locker.Lock();
512 for (size_t i = 0; i < pagesToWrite; i++) {
513 if (vm_page* page = pages[i]) {
514 if (error == B_OK)
515 page->modified = false;
516 fCache->MarkPageUnbusy(page);
517 DEBUG_PAGE_ACCESS_END(page);
521 if (error != B_OK)
522 break;
524 offset += pagesToWrite * B_PAGE_SIZE;
527 return error;
530 status_t Trim(fs_trim_data* trimData)
532 TRACE("trim_device()\n");
534 uint64 trimmedSize = 0;
535 for (uint32 i = 0; i < trimData->range_count; i++) {
536 trimmedSize += trimData->ranges[i].size;
538 off_t offset = trimData->ranges[i].offset;
539 off_t length = trimData->ranges[i].size;
541 // Round up offset and length to multiple of the page size
542 // The offset is rounded up, so some space may be left
543 // (not trimmed) at the start of the range.
544 offset = (offset + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
545 // Adjust the length for the possibly skipped range
546 length -= trimData->ranges[i].offset - offset;
547 // The length is rounded down, so some space at the end may also
548 // be left (not trimmed).
549 length &= ~(B_PAGE_SIZE - 1);
551 TRACE("ramdisk: trim %" B_PRIdOFF " bytes from %" B_PRIdOFF "\n",
552 length, offset);
554 ASSERT(offset % B_PAGE_SIZE == 0);
555 ASSERT(length % B_PAGE_SIZE == 0);
557 vm_page** pages = new(std::nothrow) vm_page*[length / B_PAGE_SIZE];
558 if (pages == NULL)
559 return B_NO_MEMORY;
560 ArrayDeleter<vm_page*> pagesDeleter(pages);
562 _GetPages(offset, length, false, pages);
564 AutoLocker<VMCache> locker(fCache);
565 uint32 j;
566 for (j = 0; j < length / B_PAGE_SIZE; j++) {
567 // If we run out of pages (some may already be trimmed), stop.
568 if (pages[j] == NULL)
569 break;
571 TRACE("free range %" B_PRIu32 ", page %" B_PRIu32 ", offset %"
572 B_PRIdOFF "\n", i, j, offset);
573 if (pages[j]->Cache())
574 fCache->RemovePage(pages[j]);
575 vm_page_free(NULL, pages[j]);
579 trimData->trimmed_size = trimmedSize;
581 return B_OK;
586 status_t DoIO(IORequest* request)
588 return fIOScheduler->ScheduleRequest(request);
591 virtual status_t PublishDevice()
593 return sDeviceManager->publish_device(Node(), fDeviceName,
594 kRawDeviceModuleName);
597 private:
598 static status_t _DoIOEntry(void* data, IOOperation* operation)
600 return ((RawDevice*)data)->_DoIO(operation);
603 status_t _DoIO(IOOperation* operation)
605 off_t offset = operation->Offset();
606 generic_size_t length = operation->Length();
608 ASSERT(offset % B_PAGE_SIZE == 0);
609 ASSERT(length % B_PAGE_SIZE == 0);
611 const generic_io_vec* vecs = operation->Vecs();
612 generic_size_t vecOffset = 0;
613 bool isWrite = operation->IsWrite();
615 vm_page** pages = new(std::nothrow) vm_page*[length / B_PAGE_SIZE];
616 if (pages == NULL)
617 return B_NO_MEMORY;
618 ArrayDeleter<vm_page*> pagesDeleter(pages);
620 _GetPages(offset, length, isWrite, pages);
622 status_t error = B_OK;
623 size_t index = 0;
625 while (length > 0) {
626 vm_page* page = pages[index];
628 if (isWrite)
629 page->modified = true;
631 error = _CopyData(page, vecs, vecOffset, isWrite);
632 if (error != B_OK)
633 break;
635 offset += B_PAGE_SIZE;
636 length -= B_PAGE_SIZE;
637 index++;
640 _PutPages(operation->Offset(), operation->Length(), pages,
641 error == B_OK);
643 if (error != B_OK) {
644 fIOScheduler->OperationCompleted(operation, error, 0);
645 return error;
648 fIOScheduler->OperationCompleted(operation, B_OK, operation->Length());
649 return B_OK;
652 void _GetPages(off_t offset, off_t length, bool isWrite, vm_page** pages)
654 // get the pages, we already have
655 AutoLocker<VMCache> locker(fCache);
657 size_t pageCount = length / B_PAGE_SIZE;
658 size_t index = 0;
659 size_t missingPages = 0;
661 while (length > 0) {
662 vm_page* page = fCache->LookupPage(offset);
663 if (page != NULL) {
664 if (page->busy) {
665 fCache->WaitForPageEvents(page, PAGE_EVENT_NOT_BUSY, true);
666 continue;
669 DEBUG_PAGE_ACCESS_START(page);
670 page->busy = true;
671 } else
672 missingPages++;
674 pages[index++] = page;
675 offset += B_PAGE_SIZE;
676 length -= B_PAGE_SIZE;
679 locker.Unlock();
681 // For a write we need to reserve the missing pages.
682 if (isWrite && missingPages > 0) {
683 vm_page_reservation reservation;
684 vm_page_reserve_pages(&reservation, missingPages,
685 VM_PRIORITY_SYSTEM);
687 for (size_t i = 0; i < pageCount; i++) {
688 if (pages[i] != NULL)
689 continue;
691 pages[i] = vm_page_allocate_page(&reservation,
692 PAGE_STATE_WIRED | VM_PAGE_ALLOC_BUSY);
694 if (--missingPages == 0)
695 break;
698 vm_page_unreserve_pages(&reservation);
702 void _PutPages(off_t offset, off_t length, vm_page** pages, bool success)
704 AutoLocker<VMCache> locker(fCache);
706 // Mark all pages unbusy. On error free the newly allocated pages.
707 size_t index = 0;
709 while (length > 0) {
710 vm_page* page = pages[index++];
711 if (page != NULL) {
712 if (page->CacheRef() == NULL) {
713 if (success) {
714 fCache->InsertPage(page, offset);
715 fCache->MarkPageUnbusy(page);
716 DEBUG_PAGE_ACCESS_END(page);
717 } else
718 vm_page_free(NULL, page);
719 } else {
720 fCache->MarkPageUnbusy(page);
721 DEBUG_PAGE_ACCESS_END(page);
725 offset += B_PAGE_SIZE;
726 length -= B_PAGE_SIZE;
730 status_t _CopyData(vm_page* page, const generic_io_vec*& vecs,
731 generic_size_t& vecOffset, bool toPage)
733 // map page to virtual memory
734 Thread* thread = thread_get_current_thread();
735 uint8* pageData = NULL;
736 void* handle;
737 if (page != NULL) {
738 thread_pin_to_current_cpu(thread);
739 addr_t virtualAddress;
740 status_t error = vm_get_physical_page_current_cpu(
741 page->physical_page_number * B_PAGE_SIZE, &virtualAddress,
742 &handle);
743 if (error != B_OK) {
744 thread_unpin_from_current_cpu(thread);
745 return error;
748 pageData = (uint8*)virtualAddress;
751 status_t error = B_OK;
752 size_t length = B_PAGE_SIZE;
753 while (length > 0) {
754 size_t toCopy = std::min((generic_size_t)length,
755 vecs->length - vecOffset);
757 if (toCopy == 0) {
758 vecs++;
759 vecOffset = 0;
760 continue;
763 phys_addr_t vecAddress = vecs->base + vecOffset;
765 error = toPage
766 ? vm_memcpy_from_physical(pageData, vecAddress, toCopy, false)
767 : (page != NULL
768 ? vm_memcpy_to_physical(vecAddress, pageData, toCopy, false)
769 : vm_memset_physical(vecAddress, 0, toCopy));
770 if (error != B_OK)
771 break;
773 pageData += toCopy;
774 length -= toCopy;
775 vecOffset += toCopy;
778 if (page != NULL) {
779 vm_put_physical_page_current_cpu((addr_t)pageData, handle);
780 thread_unpin_from_current_cpu(thread);
783 return error;
786 status_t _LoadFile()
788 static const size_t kPageCountPerIteration = 1024;
790 int fd = open(fFilePath, O_RDONLY);
791 if (fd < 0)
792 return errno;
793 FileDescriptorCloser fdCloser(fd);
795 vm_page** pages = new(std::nothrow) vm_page*[kPageCountPerIteration];
796 ArrayDeleter<vm_page*> pagesDeleter(pages);
798 uint8* buffer = (uint8*)malloc(kPageCountPerIteration * B_PAGE_SIZE);
799 MemoryDeleter bufferDeleter(buffer);
800 // TODO: Ideally we wouldn't use a buffer to read the file content,
801 // but read into the pages we allocated directly. Unfortunately
802 // there's no API to do that yet.
804 if (pages == NULL || buffer == NULL)
805 return B_NO_MEMORY;
807 status_t error = B_OK;
809 page_num_t allocatedPages = 0;
810 off_t offset = 0;
811 off_t sizeRemaining = fDeviceSize;
812 while (sizeRemaining > 0) {
813 // Note: fDeviceSize is B_PAGE_SIZE aligned.
814 size_t pagesToRead = std::min(kPageCountPerIteration,
815 size_t(sizeRemaining / B_PAGE_SIZE));
817 // allocate the missing pages
818 if (allocatedPages < pagesToRead) {
819 vm_page_reservation reservation;
820 vm_page_reserve_pages(&reservation,
821 pagesToRead - allocatedPages, VM_PRIORITY_SYSTEM);
823 while (allocatedPages < pagesToRead) {
824 pages[allocatedPages++]
825 = vm_page_allocate_page(&reservation, PAGE_STATE_WIRED);
828 vm_page_unreserve_pages(&reservation);
831 // read from the file
832 size_t bytesToRead = pagesToRead * B_PAGE_SIZE;
833 ssize_t bytesRead = pread(fd, buffer, bytesToRead, offset);
834 if (bytesRead < 0) {
835 error = bytesRead;
836 break;
838 size_t pagesRead = (bytesRead + B_PAGE_SIZE - 1) / B_PAGE_SIZE;
839 if (pagesRead < pagesToRead) {
840 error = B_ERROR;
841 break;
844 // clear the last read page, if partial
845 if ((size_t)bytesRead < pagesRead * B_PAGE_SIZE) {
846 memset(buffer + bytesRead, 0,
847 pagesRead * B_PAGE_SIZE - bytesRead);
850 // copy data to allocated pages
851 for (size_t i = 0; i < pagesRead; i++) {
852 vm_page* page = pages[i];
853 error = vm_memcpy_to_physical(
854 page->physical_page_number * B_PAGE_SIZE,
855 buffer + i * B_PAGE_SIZE, B_PAGE_SIZE, false);
856 if (error != B_OK)
857 break;
860 if (error != B_OK)
861 break;
863 // Add pages to cache. Ignore clear pages, though. Move those to the
864 // beginning of the array, so we can reuse them in the next
865 // iteration.
866 AutoLocker<VMCache> locker(fCache);
868 size_t clearPages = 0;
869 for (size_t i = 0; i < pagesRead; i++) {
870 uint64* pageData = (uint64*)(buffer + i * B_PAGE_SIZE);
871 bool isClear = true;
872 for (size_t k = 0; isClear && k < B_PAGE_SIZE / 8; k++)
873 isClear = pageData[k] == 0;
875 if (isClear) {
876 pages[clearPages++] = pages[i];
877 } else {
878 fCache->InsertPage(pages[i], offset + i * B_PAGE_SIZE);
879 DEBUG_PAGE_ACCESS_END(pages[i]);
883 locker.Unlock();
885 // Move any left-over allocated pages to the end of the empty pages
886 // and compute the new allocated pages count.
887 if (pagesRead < allocatedPages) {
888 size_t count = allocatedPages - pagesRead;
889 memcpy(pages + clearPages, pages + pagesRead,
890 count * sizeof(vm_page*));
891 clearPages += count;
893 allocatedPages = clearPages;
895 offset += pagesRead * B_PAGE_SIZE;
896 sizeRemaining -= pagesRead * B_PAGE_SIZE;
899 // free left-over allocated pages
900 for (size_t i = 0; i < allocatedPages; i++)
901 vm_page_free(NULL, pages[i]);
903 return error;
906 private:
907 int32 fID;
908 bool fUnregistered;
909 off_t fDeviceSize;
910 char* fDeviceName;
911 char* fFilePath;
912 VMCache* fCache;
913 DMAResource* fDMAResource;
914 IOScheduler* fIOScheduler;
918 struct RawDeviceCookie {
919 RawDeviceCookie(RawDevice* device, int openMode)
921 fDevice(device),
922 fOpenMode(openMode)
926 RawDevice* Device() const { return fDevice; }
927 int OpenMode() const { return fOpenMode; }
929 private:
930 RawDevice* fDevice;
931 int fOpenMode;
935 // #pragma mark -
938 static int32
939 allocate_raw_device_id()
941 MutexLocker deviceListLocker(sDeviceListLock);
942 for (size_t i = 0; i < sizeof(sUsedRawDeviceIDs) * 8; i++) {
943 if ((sUsedRawDeviceIDs & ((uint64)1 << i)) == 0) {
944 sUsedRawDeviceIDs |= (uint64)1 << i;
945 return (int32)i;
949 return -1;
953 static void
954 free_raw_device_id(int32 id)
956 MutexLocker deviceListLocker(sDeviceListLock);
957 sUsedRawDeviceIDs &= ~((uint64)1 << id);
961 static RawDevice*
962 find_raw_device(int32 id)
964 for (RawDeviceList::Iterator it = sDeviceList.GetIterator();
965 RawDevice* device = it.Next();) {
966 if (device->ID() == id)
967 return device;
970 return NULL;
974 static status_t
975 ioctl_register(ControlDevice* controlDevice, ram_disk_ioctl_register* request)
977 KPath path;
978 uint64 deviceSize = 0;
980 if (request->path[0] != '\0') {
981 // check if the path is null-terminated
982 if (strnlen(request->path, sizeof(request->path))
983 == sizeof(request->path)) {
984 return B_BAD_VALUE;
987 // get a normalized file path
988 status_t error = path.SetTo(request->path, true);
989 if (error != B_OK) {
990 dprintf("ramdisk: register: Invalid path \"%s\": %s\n",
991 request->path, strerror(error));
992 return B_BAD_VALUE;
995 struct stat st;
996 if (lstat(path.Path(), &st) != 0) {
997 dprintf("ramdisk: register: Failed to stat \"%s\": %s\n",
998 path.Path(), strerror(errno));
999 return errno;
1002 if (!S_ISREG(st.st_mode)) {
1003 dprintf("ramdisk: register: \"%s\" is not a file!\n", path.Path());
1004 return B_BAD_VALUE;
1007 deviceSize = st.st_size;
1008 } else {
1009 deviceSize = request->size;
1012 return controlDevice->Register(path.Length() > 0 ? path.Path() : NULL,
1013 deviceSize, request->id);
1017 static status_t
1018 ioctl_unregister(ControlDevice* controlDevice,
1019 ram_disk_ioctl_unregister* request)
1021 // find the device in the list and unregister it
1022 MutexLocker locker(sDeviceListLock);
1023 RawDevice* device = find_raw_device(request->id);
1024 if (device == NULL)
1025 return B_ENTRY_NOT_FOUND;
1027 // mark unregistered before we unlock
1028 if (device->IsUnregistered())
1029 return B_BUSY;
1030 device->SetUnregistered(true);
1031 locker.Unlock();
1033 device_node* node = device->Node();
1034 status_t error = sDeviceManager->unpublish_device(node,
1035 device->DeviceName());
1036 if (error != B_OK) {
1037 dprintf("ramdisk: unregister: Failed to unpublish device \"%s\": %s\n",
1038 device->DeviceName(), strerror(error));
1039 return error;
1042 error = sDeviceManager->unregister_node(node);
1043 // Note: B_BUSY is OK. The node will removed as soon as possible.
1044 if (error != B_OK && error != B_BUSY) {
1045 dprintf("ramdisk: unregister: Failed to unregister node for device %"
1046 B_PRId32 ": %s\n", request->id, strerror(error));
1047 return error;
1050 return B_OK;
1054 static status_t
1055 ioctl_info(RawDevice* device, ram_disk_ioctl_info* request)
1057 device->GetInfo(*request);
1058 return B_OK;
1062 template<typename DeviceType, typename Request>
1063 static status_t
1064 handle_ioctl(DeviceType* device,
1065 status_t (*handler)(DeviceType*, Request*), void* buffer)
1067 // copy request to the kernel heap
1068 if (buffer == NULL || !IS_USER_ADDRESS(buffer))
1069 return B_BAD_ADDRESS;
1071 Request* request = new(std::nothrow) Request;
1072 if (request == NULL)
1073 return B_NO_MEMORY;
1074 ObjectDeleter<Request> requestDeleter(request);
1076 if (user_memcpy(request, buffer, sizeof(Request)) != B_OK)
1077 return B_BAD_ADDRESS;
1079 // handle the ioctl
1080 status_t error = handler(device, request);
1081 if (error != B_OK)
1082 return error;
1084 // copy the request back to userland
1085 if (user_memcpy(buffer, request, sizeof(Request)) != B_OK)
1086 return B_BAD_ADDRESS;
1088 return B_OK;
1092 // #pragma mark - driver
1095 static float
1096 ram_disk_driver_supports_device(device_node* parent)
1098 const char* bus = NULL;
1099 if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)
1100 == B_OK
1101 && strcmp(bus, "generic") == 0) {
1102 return 0.8;
1105 return -1;
1109 static status_t
1110 ram_disk_driver_register_device(device_node* parent)
1112 device_attr attrs[] = {
1113 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
1114 {string: "RAM Disk Control Device"}},
1115 {NULL}
1118 return sDeviceManager->register_node(parent, kDriverModuleName, attrs, NULL,
1119 NULL);
1123 static status_t
1124 ram_disk_driver_init_driver(device_node* node, void** _driverCookie)
1126 uint64 deviceSize;
1127 if (sDeviceManager->get_attr_uint64(node, kDeviceSizeItem, &deviceSize,
1128 false) == B_OK) {
1129 int32 id = -1;
1130 sDeviceManager->get_attr_uint32(node, kDeviceIDItem, (uint32*)&id,
1131 false);
1132 if (id < 0)
1133 return B_ERROR;
1135 const char* filePath = NULL;
1136 sDeviceManager->get_attr_string(node, kFilePathItem, &filePath, false);
1138 RawDevice* device = new(std::nothrow) RawDevice(node);
1139 if (device == NULL)
1140 return B_NO_MEMORY;
1142 status_t error = device->Init(id, filePath, deviceSize);
1143 if (error != B_OK) {
1144 delete device;
1145 return error;
1148 *_driverCookie = (Device*)device;
1149 } else {
1150 ControlDevice* device = new(std::nothrow) ControlDevice(node);
1151 if (device == NULL)
1152 return B_NO_MEMORY;
1154 *_driverCookie = (Device*)device;
1157 return B_OK;
1161 static void
1162 ram_disk_driver_uninit_driver(void* driverCookie)
1164 Device* device = (Device*)driverCookie;
1165 if (RawDevice* rawDevice = dynamic_cast<RawDevice*>(device))
1166 free_raw_device_id(rawDevice->ID());
1167 delete device;
1171 static status_t
1172 ram_disk_driver_register_child_devices(void* driverCookie)
1174 Device* device = (Device*)driverCookie;
1175 return device->PublishDevice();
1179 // #pragma mark - control device
1182 static status_t
1183 ram_disk_control_device_init_device(void* driverCookie, void** _deviceCookie)
1185 *_deviceCookie = driverCookie;
1186 return B_OK;
1190 static void
1191 ram_disk_control_device_uninit_device(void* deviceCookie)
1196 static status_t
1197 ram_disk_control_device_open(void* deviceCookie, const char* path, int openMode,
1198 void** _cookie)
1200 *_cookie = deviceCookie;
1201 return B_OK;
1205 static status_t
1206 ram_disk_control_device_close(void* cookie)
1208 return B_OK;
1212 static status_t
1213 ram_disk_control_device_free(void* cookie)
1215 return B_OK;
1219 static status_t
1220 ram_disk_control_device_read(void* cookie, off_t position, void* buffer,
1221 size_t* _length)
1223 return B_BAD_VALUE;
1227 static status_t
1228 ram_disk_control_device_write(void* cookie, off_t position, const void* data,
1229 size_t* _length)
1231 return B_BAD_VALUE;
1235 static status_t
1236 ram_disk_control_device_control(void* cookie, uint32 op, void* buffer,
1237 size_t length)
1239 ControlDevice* device = (ControlDevice*)cookie;
1241 switch (op) {
1242 case RAM_DISK_IOCTL_REGISTER:
1243 return handle_ioctl(device, &ioctl_register, buffer);
1245 case RAM_DISK_IOCTL_UNREGISTER:
1246 return handle_ioctl(device, &ioctl_unregister, buffer);
1249 return B_BAD_VALUE;
1253 // #pragma mark - raw device
1256 static status_t
1257 ram_disk_raw_device_init_device(void* driverCookie, void** _deviceCookie)
1259 RawDevice* device = static_cast<RawDevice*>((Device*)driverCookie);
1261 status_t error = device->Prepare();
1262 if (error != B_OK)
1263 return error;
1265 *_deviceCookie = device;
1266 return B_OK;
1270 static void
1271 ram_disk_raw_device_uninit_device(void* deviceCookie)
1273 RawDevice* device = (RawDevice*)deviceCookie;
1274 device->Unprepare();
1278 static status_t
1279 ram_disk_raw_device_open(void* deviceCookie, const char* path, int openMode,
1280 void** _cookie)
1282 RawDevice* device = (RawDevice*)deviceCookie;
1284 RawDeviceCookie* cookie = new(std::nothrow) RawDeviceCookie(device,
1285 openMode);
1286 if (cookie == NULL)
1287 return B_NO_MEMORY;
1289 *_cookie = cookie;
1290 return B_OK;
1294 static status_t
1295 ram_disk_raw_device_close(void* cookie)
1297 return B_OK;
1301 static status_t
1302 ram_disk_raw_device_free(void* _cookie)
1304 RawDeviceCookie* cookie = (RawDeviceCookie*)_cookie;
1305 delete cookie;
1306 return B_OK;
1310 static status_t
1311 ram_disk_raw_device_read(void* _cookie, off_t pos, void* buffer,
1312 size_t* _length)
1314 RawDeviceCookie* cookie = (RawDeviceCookie*)_cookie;
1315 RawDevice* device = cookie->Device();
1317 size_t length = *_length;
1319 if (pos >= device->DeviceSize())
1320 return B_BAD_VALUE;
1321 if (pos + (off_t)length > device->DeviceSize())
1322 length = device->DeviceSize() - pos;
1324 IORequest request;
1325 status_t status = request.Init(pos, (addr_t)buffer, length, false, 0);
1326 if (status != B_OK)
1327 return status;
1329 status = device->DoIO(&request);
1330 if (status != B_OK)
1331 return status;
1333 status = request.Wait(0, 0);
1334 if (status == B_OK)
1335 *_length = length;
1336 return status;
1340 static status_t
1341 ram_disk_raw_device_write(void* _cookie, off_t pos, const void* buffer,
1342 size_t* _length)
1344 RawDeviceCookie* cookie = (RawDeviceCookie*)_cookie;
1345 RawDevice* device = cookie->Device();
1347 size_t length = *_length;
1349 if (pos >= device->DeviceSize())
1350 return B_BAD_VALUE;
1351 if (pos + (off_t)length > device->DeviceSize())
1352 length = device->DeviceSize() - pos;
1354 IORequest request;
1355 status_t status = request.Init(pos, (addr_t)buffer, length, true, 0);
1356 if (status != B_OK)
1357 return status;
1359 status = device->DoIO(&request);
1360 if (status != B_OK)
1361 return status;
1363 status = request.Wait(0, 0);
1364 if (status == B_OK)
1365 *_length = length;
1367 return status;
1371 static status_t
1372 ram_disk_raw_device_io(void* _cookie, io_request* request)
1374 RawDeviceCookie* cookie = (RawDeviceCookie*)_cookie;
1375 RawDevice* device = cookie->Device();
1377 return device->DoIO(request);
1381 static status_t
1382 ram_disk_raw_device_control(void* _cookie, uint32 op, void* buffer,
1383 size_t length)
1385 RawDeviceCookie* cookie = (RawDeviceCookie*)_cookie;
1386 RawDevice* device = cookie->Device();
1388 switch (op) {
1389 case B_GET_DEVICE_SIZE:
1391 size_t size = device->DeviceSize();
1392 return user_memcpy(buffer, &size, sizeof(size_t));
1395 case B_SET_NONBLOCKING_IO:
1396 case B_SET_BLOCKING_IO:
1397 return B_OK;
1399 case B_GET_READ_STATUS:
1400 case B_GET_WRITE_STATUS:
1402 bool value = true;
1403 return user_memcpy(buffer, &value, sizeof(bool));
1406 case B_GET_GEOMETRY:
1407 case B_GET_BIOS_GEOMETRY:
1409 device_geometry geometry;
1410 geometry.bytes_per_sector = B_PAGE_SIZE;
1411 geometry.sectors_per_track = 1;
1412 geometry.cylinder_count = device->DeviceSize() / B_PAGE_SIZE;
1413 // TODO: We're limited to 2^32 * B_PAGE_SIZE, if we don't use
1414 // sectors_per_track and head_count.
1415 geometry.head_count = 1;
1416 geometry.device_type = B_DISK;
1417 geometry.removable = true;
1418 geometry.read_only = false;
1419 geometry.write_once = false;
1421 return user_memcpy(buffer, &geometry, sizeof(device_geometry));
1424 case B_GET_MEDIA_STATUS:
1426 status_t status = B_OK;
1427 return user_memcpy(buffer, &status, sizeof(status_t));
1430 case B_GET_ICON_NAME:
1431 return user_strlcpy((char*)buffer, "devices/drive-ramdisk",
1432 B_FILE_NAME_LENGTH);
1434 case B_GET_VECTOR_ICON:
1436 device_icon iconData;
1437 if (length != sizeof(device_icon))
1438 return B_BAD_VALUE;
1439 if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK)
1440 return B_BAD_ADDRESS;
1442 if (iconData.icon_size >= (int32)sizeof(kRamdiskIcon)) {
1443 if (user_memcpy(iconData.icon_data, kRamdiskIcon,
1444 sizeof(kRamdiskIcon)) != B_OK)
1445 return B_BAD_ADDRESS;
1448 iconData.icon_size = sizeof(kRamdiskIcon);
1449 return user_memcpy(buffer, &iconData, sizeof(device_icon));
1452 case B_SET_UNINTERRUPTABLE_IO:
1453 case B_SET_INTERRUPTABLE_IO:
1454 case B_FLUSH_DRIVE_CACHE:
1455 return B_OK;
1457 case RAM_DISK_IOCTL_FLUSH:
1459 status_t error = device->Flush();
1460 if (error != B_OK) {
1461 dprintf("ramdisk: flush: Failed to flush device: %s\n",
1462 strerror(error));
1463 return error;
1466 return B_OK;
1469 case B_TRIM_DEVICE:
1471 fs_trim_data* trimData;
1472 MemoryDeleter deleter;
1473 status_t status = get_trim_data_from_user(buffer, length, deleter,
1474 trimData);
1475 if (status != B_OK)
1476 return status;
1478 status = device->Trim(trimData);
1479 if (status != B_OK)
1480 return status;
1482 return copy_trim_data_to_user(buffer, trimData);
1485 case RAM_DISK_IOCTL_INFO:
1486 return handle_ioctl(device, &ioctl_info, buffer);
1489 return B_BAD_VALUE;
1493 // #pragma mark -
1496 module_dependency module_dependencies[] = {
1497 {B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&sDeviceManager},
1502 static const struct driver_module_info sChecksumDeviceDriverModule = {
1504 kDriverModuleName,
1506 NULL
1509 ram_disk_driver_supports_device,
1510 ram_disk_driver_register_device,
1511 ram_disk_driver_init_driver,
1512 ram_disk_driver_uninit_driver,
1513 ram_disk_driver_register_child_devices
1516 static const struct device_module_info sChecksumControlDeviceModule = {
1518 kControlDeviceModuleName,
1520 NULL
1523 ram_disk_control_device_init_device,
1524 ram_disk_control_device_uninit_device,
1525 NULL,
1527 ram_disk_control_device_open,
1528 ram_disk_control_device_close,
1529 ram_disk_control_device_free,
1531 ram_disk_control_device_read,
1532 ram_disk_control_device_write,
1533 NULL, // io
1535 ram_disk_control_device_control,
1537 NULL, // select
1538 NULL // deselect
1541 static const struct device_module_info sChecksumRawDeviceModule = {
1543 kRawDeviceModuleName,
1545 NULL
1548 ram_disk_raw_device_init_device,
1549 ram_disk_raw_device_uninit_device,
1550 NULL,
1552 ram_disk_raw_device_open,
1553 ram_disk_raw_device_close,
1554 ram_disk_raw_device_free,
1556 ram_disk_raw_device_read,
1557 ram_disk_raw_device_write,
1558 ram_disk_raw_device_io,
1560 ram_disk_raw_device_control,
1562 NULL, // select
1563 NULL // deselect
1566 const module_info* modules[] = {
1567 (module_info*)&sChecksumDeviceDriverModule,
1568 (module_info*)&sChecksumControlDeviceModule,
1569 (module_info*)&sChecksumRawDeviceModule,
1570 NULL