2 * Copyright 2010-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
7 #include <file_systems/ram_disk/ram_disk.h>
18 #include <device_manager.h>
21 #include <AutoDeleter.h>
22 #include <util/AutoLock.h>
23 #include <util/DoublyLinkedList.h>
27 #include <util/fs_trim_support.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
39 # define TRACE(x...) dprintf(x)
41 # define TRACE(x...) do {} while (false)
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";
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
);
159 Device(device_node
* node
)
163 mutex_init(&fLock
, "ram disk 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;
184 struct ControlDevice
: Device
{
185 ControlDevice(device_node
* node
)
191 status_t
Register(const char* filePath
, uint64 deviceSize
, int32
& _id
)
193 int32 id
= allocate_raw_device_id();
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
}},
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
,
216 free_raw_device_id(id
);
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
)
237 fUnregistered(false),
250 MutexLocker
locker(sDeviceListLock
);
251 sDeviceList
.Remove(this);
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
)
272 fFilePath
= filePath
!= NULL
? strdup(filePath
) : NULL
;
273 if (filePath
!= NULL
&& fFilePath
== NULL
)
276 fDeviceSize
= (deviceSize
+ B_PAGE_SIZE
- 1) / B_PAGE_SIZE
279 if (fDeviceSize
< B_PAGE_SIZE
280 || (uint64
)fDeviceSize
/ B_PAGE_SIZE
281 > vm_page_num_pages() * 2 / 3) {
285 // construct our device path
286 KPath
path(kRawDeviceBaseName
);
288 snprintf(buffer
, sizeof(buffer
), "%" B_PRId32
"/raw", fID
);
290 status_t error
= path
.Append(buffer
);
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
)
305 sDeviceList
.InsertBefore(nextDevice
, this);
312 status_t error
= VMCacheFactory::CreateAnonymousCache(fCache
, false, 0,
313 0, false, VM_PRIORITY_SYSTEM
);
319 fCache
->temporary
= 1;
320 fCache
->virtual_end
= fDeviceSize
;
322 error
= fCache
->Commit(fDeviceSize
, VM_PRIORITY_SYSTEM
);
328 if (fFilePath
!= NULL
) {
336 // no DMA restrictions
337 const dma_restrictions restrictions
= {};
339 fDMAResource
= new(std::nothrow
) DMAResource
;
340 if (fDMAResource
== NULL
) {
345 error
= fDMAResource
->Init(restrictions
, B_PAGE_SIZE
,
346 kDMAResourceBufferCount
, kDMAResourceBounceBufferCount
);
352 fIOScheduler
= new(std::nothrow
) IOSchedulerSimple(fDMAResource
);
353 if (fIOScheduler
== NULL
) {
358 error
= fIOScheduler
->Init("ram disk device scheduler");
364 fIOScheduler
->SetCallback(&_DoIOEntry
, this);
377 if (fCache
!= NULL
) {
379 fCache
->ReleaseRefAndUnlock();
384 void GetInfo(ram_disk_ioctl_info
& _info
) const
387 _info
.size
= fDeviceSize
;
388 memset(&_info
.path
, 0, sizeof(_info
.path
));
389 if (fFilePath
!= NULL
)
390 strlcpy(_info
.path
, fFilePath
, sizeof(_info
.path
));
395 static const size_t kPageCountPerIteration
= 1024;
396 static const size_t kMaxGapSize
= 15;
398 int fd
= open(fFilePath
, O_WRONLY
);
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
)
412 // Iterate through all pages of the cache and write those back that have
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
)
430 if (firstModified
->busy
) {
431 fCache
->WaitForPageEvents(firstModified
, PAGE_EVENT_NOT_BUSY
,
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
;
447 || index
>= kPageCountPerIteration
448 || index
- previousModifiedIndex
> kMaxGapSize
) {
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
;
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
);
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
,
483 dprintf("ramdisk: error copying page %" B_PRIu64
484 " data: %s\n", (uint64
)page
->physical_page_number
,
489 memset(buffer
+ i
* B_PAGE_SIZE
, 0, B_PAGE_SIZE
);
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
);
509 // mark the pages unbusy, on success also unmodified
512 for (size_t i
= 0; i
< pagesToWrite
; i
++) {
513 if (vm_page
* page
= pages
[i
]) {
515 page
->modified
= false;
516 fCache
->MarkPageUnbusy(page
);
517 DEBUG_PAGE_ACCESS_END(page
);
524 offset
+= pagesToWrite
* B_PAGE_SIZE
;
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",
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
];
560 ArrayDeleter
<vm_page
*> pagesDeleter(pages
);
562 _GetPages(offset
, length
, false, pages
);
564 AutoLocker
<VMCache
> locker(fCache
);
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
)
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
;
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
);
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
];
618 ArrayDeleter
<vm_page
*> pagesDeleter(pages
);
620 _GetPages(offset
, length
, isWrite
, pages
);
622 status_t error
= B_OK
;
626 vm_page
* page
= pages
[index
];
629 page
->modified
= true;
631 error
= _CopyData(page
, vecs
, vecOffset
, isWrite
);
635 offset
+= B_PAGE_SIZE
;
636 length
-= B_PAGE_SIZE
;
640 _PutPages(operation
->Offset(), operation
->Length(), pages
,
644 fIOScheduler
->OperationCompleted(operation
, error
, 0);
648 fIOScheduler
->OperationCompleted(operation
, B_OK
, operation
->Length());
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
;
659 size_t missingPages
= 0;
662 vm_page
* page
= fCache
->LookupPage(offset
);
665 fCache
->WaitForPageEvents(page
, PAGE_EVENT_NOT_BUSY
, true);
669 DEBUG_PAGE_ACCESS_START(page
);
674 pages
[index
++] = page
;
675 offset
+= B_PAGE_SIZE
;
676 length
-= B_PAGE_SIZE
;
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
,
687 for (size_t i
= 0; i
< pageCount
; i
++) {
688 if (pages
[i
] != NULL
)
691 pages
[i
] = vm_page_allocate_page(&reservation
,
692 PAGE_STATE_WIRED
| VM_PAGE_ALLOC_BUSY
);
694 if (--missingPages
== 0)
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.
710 vm_page
* page
= pages
[index
++];
712 if (page
->CacheRef() == NULL
) {
714 fCache
->InsertPage(page
, offset
);
715 fCache
->MarkPageUnbusy(page
);
716 DEBUG_PAGE_ACCESS_END(page
);
718 vm_page_free(NULL
, page
);
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
;
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
,
744 thread_unpin_from_current_cpu(thread
);
748 pageData
= (uint8
*)virtualAddress
;
751 status_t error
= B_OK
;
752 size_t length
= B_PAGE_SIZE
;
754 size_t toCopy
= std::min((generic_size_t
)length
,
755 vecs
->length
- vecOffset
);
763 phys_addr_t vecAddress
= vecs
->base
+ vecOffset
;
766 ? vm_memcpy_from_physical(pageData
, vecAddress
, toCopy
, false)
768 ? vm_memcpy_to_physical(vecAddress
, pageData
, toCopy
, false)
769 : vm_memset_physical(vecAddress
, 0, toCopy
));
779 vm_put_physical_page_current_cpu((addr_t
)pageData
, handle
);
780 thread_unpin_from_current_cpu(thread
);
788 static const size_t kPageCountPerIteration
= 1024;
790 int fd
= open(fFilePath
, O_RDONLY
);
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
)
807 status_t error
= B_OK
;
809 page_num_t allocatedPages
= 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
);
838 size_t pagesRead
= (bytesRead
+ B_PAGE_SIZE
- 1) / B_PAGE_SIZE
;
839 if (pagesRead
< pagesToRead
) {
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);
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
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
);
872 for (size_t k
= 0; isClear
&& k
< B_PAGE_SIZE
/ 8; k
++)
873 isClear
= pageData
[k
] == 0;
876 pages
[clearPages
++] = pages
[i
];
878 fCache
->InsertPage(pages
[i
], offset
+ i
* B_PAGE_SIZE
);
879 DEBUG_PAGE_ACCESS_END(pages
[i
]);
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
*));
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
]);
913 DMAResource
* fDMAResource
;
914 IOScheduler
* fIOScheduler
;
918 struct RawDeviceCookie
{
919 RawDeviceCookie(RawDevice
* device
, int openMode
)
926 RawDevice
* Device() const { return fDevice
; }
927 int OpenMode() const { return fOpenMode
; }
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
;
954 free_raw_device_id(int32 id
)
956 MutexLocker
deviceListLocker(sDeviceListLock
);
957 sUsedRawDeviceIDs
&= ~((uint64
)1 << id
);
962 find_raw_device(int32 id
)
964 for (RawDeviceList::Iterator it
= sDeviceList
.GetIterator();
965 RawDevice
* device
= it
.Next();) {
966 if (device
->ID() == id
)
975 ioctl_register(ControlDevice
* controlDevice
, ram_disk_ioctl_register
* request
)
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
)) {
987 // get a normalized file path
988 status_t error
= path
.SetTo(request
->path
, true);
990 dprintf("ramdisk: register: Invalid path \"%s\": %s\n",
991 request
->path
, strerror(error
));
996 if (lstat(path
.Path(), &st
) != 0) {
997 dprintf("ramdisk: register: Failed to stat \"%s\": %s\n",
998 path
.Path(), strerror(errno
));
1002 if (!S_ISREG(st
.st_mode
)) {
1003 dprintf("ramdisk: register: \"%s\" is not a file!\n", path
.Path());
1007 deviceSize
= st
.st_size
;
1009 deviceSize
= request
->size
;
1012 return controlDevice
->Register(path
.Length() > 0 ? path
.Path() : NULL
,
1013 deviceSize
, request
->id
);
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
);
1025 return B_ENTRY_NOT_FOUND
;
1027 // mark unregistered before we unlock
1028 if (device
->IsUnregistered())
1030 device
->SetUnregistered(true);
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
));
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
));
1055 ioctl_info(RawDevice
* device
, ram_disk_ioctl_info
* request
)
1057 device
->GetInfo(*request
);
1062 template<typename DeviceType
, typename Request
>
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
)
1074 ObjectDeleter
<Request
> requestDeleter(request
);
1076 if (user_memcpy(request
, buffer
, sizeof(Request
)) != B_OK
)
1077 return B_BAD_ADDRESS
;
1080 status_t error
= handler(device
, request
);
1084 // copy the request back to userland
1085 if (user_memcpy(buffer
, request
, sizeof(Request
)) != B_OK
)
1086 return B_BAD_ADDRESS
;
1092 // #pragma mark - driver
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)
1101 && strcmp(bus
, "generic") == 0) {
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"}},
1118 return sDeviceManager
->register_node(parent
, kDriverModuleName
, attrs
, NULL
,
1124 ram_disk_driver_init_driver(device_node
* node
, void** _driverCookie
)
1127 if (sDeviceManager
->get_attr_uint64(node
, kDeviceSizeItem
, &deviceSize
,
1130 sDeviceManager
->get_attr_uint32(node
, kDeviceIDItem
, (uint32
*)&id
,
1135 const char* filePath
= NULL
;
1136 sDeviceManager
->get_attr_string(node
, kFilePathItem
, &filePath
, false);
1138 RawDevice
* device
= new(std::nothrow
) RawDevice(node
);
1142 status_t error
= device
->Init(id
, filePath
, deviceSize
);
1143 if (error
!= B_OK
) {
1148 *_driverCookie
= (Device
*)device
;
1150 ControlDevice
* device
= new(std::nothrow
) ControlDevice(node
);
1154 *_driverCookie
= (Device
*)device
;
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());
1172 ram_disk_driver_register_child_devices(void* driverCookie
)
1174 Device
* device
= (Device
*)driverCookie
;
1175 return device
->PublishDevice();
1179 // #pragma mark - control device
1183 ram_disk_control_device_init_device(void* driverCookie
, void** _deviceCookie
)
1185 *_deviceCookie
= driverCookie
;
1191 ram_disk_control_device_uninit_device(void* deviceCookie
)
1197 ram_disk_control_device_open(void* deviceCookie
, const char* path
, int openMode
,
1200 *_cookie
= deviceCookie
;
1206 ram_disk_control_device_close(void* cookie
)
1213 ram_disk_control_device_free(void* cookie
)
1220 ram_disk_control_device_read(void* cookie
, off_t position
, void* buffer
,
1228 ram_disk_control_device_write(void* cookie
, off_t position
, const void* data
,
1236 ram_disk_control_device_control(void* cookie
, uint32 op
, void* buffer
,
1239 ControlDevice
* device
= (ControlDevice
*)cookie
;
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
);
1253 // #pragma mark - raw device
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();
1265 *_deviceCookie
= device
;
1271 ram_disk_raw_device_uninit_device(void* deviceCookie
)
1273 RawDevice
* device
= (RawDevice
*)deviceCookie
;
1274 device
->Unprepare();
1279 ram_disk_raw_device_open(void* deviceCookie
, const char* path
, int openMode
,
1282 RawDevice
* device
= (RawDevice
*)deviceCookie
;
1284 RawDeviceCookie
* cookie
= new(std::nothrow
) RawDeviceCookie(device
,
1295 ram_disk_raw_device_close(void* cookie
)
1302 ram_disk_raw_device_free(void* _cookie
)
1304 RawDeviceCookie
* cookie
= (RawDeviceCookie
*)_cookie
;
1311 ram_disk_raw_device_read(void* _cookie
, off_t pos
, void* buffer
,
1314 RawDeviceCookie
* cookie
= (RawDeviceCookie
*)_cookie
;
1315 RawDevice
* device
= cookie
->Device();
1317 size_t length
= *_length
;
1319 if (pos
>= device
->DeviceSize())
1321 if (pos
+ (off_t
)length
> device
->DeviceSize())
1322 length
= device
->DeviceSize() - pos
;
1325 status_t status
= request
.Init(pos
, (addr_t
)buffer
, length
, false, 0);
1329 status
= device
->DoIO(&request
);
1333 status
= request
.Wait(0, 0);
1341 ram_disk_raw_device_write(void* _cookie
, off_t pos
, const void* buffer
,
1344 RawDeviceCookie
* cookie
= (RawDeviceCookie
*)_cookie
;
1345 RawDevice
* device
= cookie
->Device();
1347 size_t length
= *_length
;
1349 if (pos
>= device
->DeviceSize())
1351 if (pos
+ (off_t
)length
> device
->DeviceSize())
1352 length
= device
->DeviceSize() - pos
;
1355 status_t status
= request
.Init(pos
, (addr_t
)buffer
, length
, true, 0);
1359 status
= device
->DoIO(&request
);
1363 status
= request
.Wait(0, 0);
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
);
1382 ram_disk_raw_device_control(void* _cookie
, uint32 op
, void* buffer
,
1385 RawDeviceCookie
* cookie
= (RawDeviceCookie
*)_cookie
;
1386 RawDevice
* device
= cookie
->Device();
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
:
1399 case B_GET_READ_STATUS
:
1400 case B_GET_WRITE_STATUS
:
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
))
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
:
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",
1471 fs_trim_data
* trimData
;
1472 MemoryDeleter deleter
;
1473 status_t status
= get_trim_data_from_user(buffer
, length
, deleter
,
1478 status
= device
->Trim(trimData
);
1482 return copy_trim_data_to_user(buffer
, trimData
);
1485 case RAM_DISK_IOCTL_INFO
:
1486 return handle_ioctl(device
, &ioctl_info
, buffer
);
1496 module_dependency module_dependencies
[] = {
1497 {B_DEVICE_MANAGER_MODULE_NAME
, (module_info
**)&sDeviceManager
},
1502 static const struct driver_module_info sChecksumDeviceDriverModule
= {
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
,
1523 ram_disk_control_device_init_device
,
1524 ram_disk_control_device_uninit_device
,
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
,
1535 ram_disk_control_device_control
,
1541 static const struct device_module_info sChecksumRawDeviceModule
= {
1543 kRawDeviceModuleName
,
1548 ram_disk_raw_device_init_device
,
1549 ram_disk_raw_device_uninit_device
,
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
,
1566 const module_info
* modules
[] = {
1567 (module_info
*)&sChecksumDeviceDriverModule
,
1568 (module_info
*)&sChecksumControlDeviceModule
,
1569 (module_info
*)&sChecksumRawDeviceModule
,