1 /* 2 * Copyright 2010-2013, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <file_systems/ram_disk/ram_disk.h> 8 9 #include <ctype.h> 10 #include <errno.h> 11 #include <fcntl.h> 12 #include <stdio.h> 13 #include <string.h> 14 #include <unistd.h> 15 16 #include <algorithm> 17 18 #include <device_manager.h> 19 #include <Drivers.h> 20 21 #include <AutoDeleter.h> 22 #include <util/AutoLock.h> 23 #include <util/DoublyLinkedList.h> 24 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> 31 32 #include "dma_resources.h" 33 #include "io_requests.h" 34 #include "IOSchedulerSimple.h" 35 36 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 43 44 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 122 }; 123 124 125 // parameters for the DMA resource 126 static const uint32 kDMAResourceBufferCount = 16; 127 static const uint32 kDMAResourceBounceBufferCount = 16; 128 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"; 135 136 static const char* const kControlDeviceName = RAM_DISK_CONTROL_DEVICE_NAME; 137 static const char* const kRawDeviceBaseName = RAM_DISK_RAW_DEVICE_BASE_NAME; 138 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"; 142 143 144 struct RawDevice; 145 typedef DoublyLinkedList<RawDevice> RawDeviceList; 146 147 struct device_manager_info* sDeviceManager; 148 149 static RawDeviceList sDeviceList; 150 static mutex sDeviceListLock = MUTEX_INITIALIZER("ram disk device list"); 151 static uint64 sUsedRawDeviceIDs = 0; 152 153 154 static int32 allocate_raw_device_id(); 155 static void free_raw_device_id(int32 id); 156 157 158 struct Device { 159 Device(device_node* node) 160 : 161 fNode(node) 162 { 163 mutex_init(&fLock, "ram disk device"); 164 } 165 166 virtual ~Device() 167 { 168 mutex_destroy(&fLock); 169 } 170 171 bool Lock() { mutex_lock(&fLock); return true; } 172 void Unlock() { mutex_unlock(&fLock); } 173 174 device_node* Node() const { return fNode; } 175 176 virtual status_t PublishDevice() = 0; 177 178 protected: 179 mutex fLock; 180 device_node* fNode; 181 }; 182 183 184 struct ControlDevice : Device { 185 ControlDevice(device_node* node) 186 : 187 Device(node) 188 { 189 } 190 191 status_t Register(const char* filePath, uint64 deviceSize, int32& _id) 192 { 193 int32 id = allocate_raw_device_id(); 194 if (id < 0) 195 return B_BUSY; 196 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} 204 }; 205 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])); 210 } 211 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; 218 } 219 220 _id = id; 221 return B_OK; 222 } 223 224 virtual status_t PublishDevice() 225 { 226 return sDeviceManager->publish_device(Node(), kControlDeviceName, 227 kControlDeviceModuleName); 228 } 229 }; 230 231 232 struct RawDevice : Device, DoublyLinkedListLinkImpl<RawDevice> { 233 RawDevice(device_node* node) 234 : 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) 244 { 245 } 246 247 virtual ~RawDevice() 248 { 249 if (fID >= 0) { 250 MutexLocker locker(sDeviceListLock); 251 sDeviceList.Remove(this); 252 } 253 254 free(fDeviceName); 255 free(fFilePath); 256 } 257 258 int32 ID() const { return fID; } 259 off_t DeviceSize() const { return fDeviceSize; } 260 const char* DeviceName() const { return fDeviceName; } 261 262 bool IsUnregistered() const { return fUnregistered; } 263 264 void SetUnregistered(bool unregistered) 265 { 266 fUnregistered = unregistered; 267 } 268 269 status_t Init(int32 id, const char* filePath, uint64 deviceSize) 270 { 271 fID = id; 272 fFilePath = filePath != NULL ? strdup(filePath) : NULL; 273 if (filePath != NULL && fFilePath == NULL) 274 return B_NO_MEMORY; 275 276 fDeviceSize = (deviceSize + B_PAGE_SIZE - 1) / B_PAGE_SIZE 277 * B_PAGE_SIZE; 278 279 if (fDeviceSize < B_PAGE_SIZE 280 || (uint64)fDeviceSize / B_PAGE_SIZE 281 > vm_page_num_pages() * 2 / 3) { 282 return B_BAD_VALUE; 283 } 284 285 // construct our device path 286 KPath path(kRawDeviceBaseName); 287 char buffer[32]; 288 snprintf(buffer, sizeof(buffer), "%" B_PRId32 "/raw", fID); 289 290 status_t error = path.Append(buffer); 291 if (error != B_OK) 292 return error; 293 294 fDeviceName = path.DetachBuffer(); 295 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; 303 } 304 305 sDeviceList.InsertBefore(nextDevice, this); 306 307 return B_OK; 308 } 309 310 status_t Prepare() 311 { 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; 317 } 318 319 fCache->temporary = 1; 320 fCache->virtual_end = fDeviceSize; 321 322 error = fCache->Commit(fDeviceSize, VM_PRIORITY_SYSTEM); 323 if (error != B_OK) { 324 Unprepare(); 325 return error; 326 } 327 328 if (fFilePath != NULL) { 329 error = _LoadFile(); 330 if (error != B_OK) { 331 Unprepare(); 332 return error; 333 } 334 } 335 336 // no DMA restrictions 337 const dma_restrictions restrictions = {}; 338 339 fDMAResource = new(std::nothrow) DMAResource; 340 if (fDMAResource == NULL) { 341 Unprepare(); 342 return B_NO_MEMORY; 343 } 344 345 error = fDMAResource->Init(restrictions, B_PAGE_SIZE, 346 kDMAResourceBufferCount, kDMAResourceBounceBufferCount); 347 if (error != B_OK) { 348 Unprepare(); 349 return error; 350 } 351 352 fIOScheduler = new(std::nothrow) IOSchedulerSimple(fDMAResource); 353 if (fIOScheduler == NULL) { 354 Unprepare(); 355 return B_NO_MEMORY; 356 } 357 358 error = fIOScheduler->Init("ram disk device scheduler"); 359 if (error != B_OK) { 360 Unprepare(); 361 return error; 362 } 363 364 fIOScheduler->SetCallback(&_DoIOEntry, this); 365 366 return B_OK; 367 } 368 369 void Unprepare() 370 { 371 delete fIOScheduler; 372 fIOScheduler = NULL; 373 374 delete fDMAResource; 375 fDMAResource = NULL; 376 377 if (fCache != NULL) { 378 fCache->Lock(); 379 fCache->ReleaseRefAndUnlock(); 380 fCache = NULL; 381 } 382 } 383 384 void GetInfo(ram_disk_ioctl_info& _info) const 385 { 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)); 391 } 392 393 status_t Flush() 394 { 395 static const size_t kPageCountPerIteration = 1024; 396 static const size_t kMaxGapSize = 15; 397 398 int fd = open(fFilePath, O_WRONLY); 399 if (fd < 0) 400 return errno; 401 FileDescriptorCloser fdCloser(fd); 402 403 vm_page** pages = new(std::nothrow) vm_page*[kPageCountPerIteration]; 404 ArrayDeleter<vm_page*> pagesDeleter(pages); 405 406 uint8* buffer = (uint8*)malloc(kPageCountPerIteration * B_PAGE_SIZE); 407 MemoryDeleter bufferDeleter(buffer); 408 409 if (pages == NULL || buffer == NULL) 410 return B_NO_MEMORY; 411 412 // Iterate through all pages of the cache and write those back that have 413 // been modified. 414 AutoLocker<VMCache> locker(fCache); 415 416 status_t error = B_OK; 417 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) { 425 } 426 427 if (firstModified == NULL) 428 break; 429 430 if (firstModified->busy) { 431 fCache->WaitForPageEvents(firstModified, PAGE_EVENT_NOT_BUSY, 432 true); 433 continue; 434 } 435 436 pages[0] = firstModified; 437 page_num_t firstPageIndex = firstModified->cache_offset; 438 offset = firstPageIndex * B_PAGE_SIZE; 439 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; 450 } 451 452 pages[index] = page; 453 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*)); 458 } 459 460 previousIndex = index; 461 if (page->modified) 462 previousModifiedIndex = index; 463 } 464 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; 471 } 472 } 473 474 locker.Unlock(); 475 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; 487 } 488 } else 489 memset(buffer + i * B_PAGE_SIZE, 0, B_PAGE_SIZE); 490 } 491 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; 500 } 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; 506 } 507 } 508 509 // mark the pages unbusy, on success also unmodified 510 locker.Lock(); 511 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); 518 } 519 } 520 521 if (error != B_OK) 522 break; 523 524 offset += pagesToWrite * B_PAGE_SIZE; 525 } 526 527 return error; 528 } 529 530 status_t Trim(fs_trim_data* trimData) 531 { 532 TRACE("trim_device()\n"); 533 534 uint64 trimmedSize = 0; 535 for (uint32 i = 0; i < trimData->range_count; i++) { 536 trimmedSize += trimData->ranges[i].size; 537 538 off_t offset = trimData->ranges[i].offset; 539 off_t length = trimData->ranges[i].size; 540 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); 550 551 TRACE("ramdisk: trim %" B_PRIdOFF " bytes from %" B_PRIdOFF "\n", 552 length, offset); 553 554 ASSERT(offset % B_PAGE_SIZE == 0); 555 ASSERT(length % B_PAGE_SIZE == 0); 556 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); 561 562 _GetPages(offset, length, false, pages); 563 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; 570 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]); 576 } 577 } 578 579 trimData->trimmed_size = trimmedSize; 580 581 return B_OK; 582 } 583 584 585 586 status_t DoIO(IORequest* request) 587 { 588 return fIOScheduler->ScheduleRequest(request); 589 } 590 591 virtual status_t PublishDevice() 592 { 593 return sDeviceManager->publish_device(Node(), fDeviceName, 594 kRawDeviceModuleName); 595 } 596 597 private: 598 static status_t _DoIOEntry(void* data, IOOperation* operation) 599 { 600 return ((RawDevice*)data)->_DoIO(operation); 601 } 602 603 status_t _DoIO(IOOperation* operation) 604 { 605 off_t offset = operation->Offset(); 606 generic_size_t length = operation->Length(); 607 608 ASSERT(offset % B_PAGE_SIZE == 0); 609 ASSERT(length % B_PAGE_SIZE == 0); 610 611 const generic_io_vec* vecs = operation->Vecs(); 612 generic_size_t vecOffset = 0; 613 bool isWrite = operation->IsWrite(); 614 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); 619 620 _GetPages(offset, length, isWrite, pages); 621 622 status_t error = B_OK; 623 size_t index = 0; 624 625 while (length > 0) { 626 vm_page* page = pages[index]; 627 628 if (isWrite) 629 page->modified = true; 630 631 error = _CopyData(page, vecs, vecOffset, isWrite); 632 if (error != B_OK) 633 break; 634 635 offset += B_PAGE_SIZE; 636 length -= B_PAGE_SIZE; 637 index++; 638 } 639 640 _PutPages(operation->Offset(), operation->Length(), pages, 641 error == B_OK); 642 643 if (error != B_OK) { 644 fIOScheduler->OperationCompleted(operation, error, 0); 645 return error; 646 } 647 648 fIOScheduler->OperationCompleted(operation, B_OK, operation->Length()); 649 return B_OK; 650 } 651 652 void _GetPages(off_t offset, off_t length, bool isWrite, vm_page** pages) 653 { 654 // TODO: This method is duplicated in ramfs' DataContainer. Perhaps it 655 // should be put into a common location? 656 657 // get the pages, we already have 658 AutoLocker<VMCache> locker(fCache); 659 660 size_t pageCount = length / B_PAGE_SIZE; 661 size_t index = 0; 662 size_t missingPages = 0; 663 664 while (length > 0) { 665 vm_page* page = fCache->LookupPage(offset); 666 if (page != NULL) { 667 if (page->busy) { 668 fCache->WaitForPageEvents(page, PAGE_EVENT_NOT_BUSY, true); 669 continue; 670 } 671 672 DEBUG_PAGE_ACCESS_START(page); 673 page->busy = true; 674 } else 675 missingPages++; 676 677 pages[index++] = page; 678 offset += B_PAGE_SIZE; 679 length -= B_PAGE_SIZE; 680 } 681 682 locker.Unlock(); 683 684 // For a write we need to reserve the missing pages. 685 if (isWrite && missingPages > 0) { 686 vm_page_reservation reservation; 687 vm_page_reserve_pages(&reservation, missingPages, 688 VM_PRIORITY_SYSTEM); 689 690 for (size_t i = 0; i < pageCount; i++) { 691 if (pages[i] != NULL) 692 continue; 693 694 pages[i] = vm_page_allocate_page(&reservation, 695 PAGE_STATE_WIRED | VM_PAGE_ALLOC_BUSY); 696 697 if (--missingPages == 0) 698 break; 699 } 700 701 vm_page_unreserve_pages(&reservation); 702 } 703 } 704 705 void _PutPages(off_t offset, off_t length, vm_page** pages, bool success) 706 { 707 // TODO: This method is duplicated in ramfs' DataContainer. Perhaps it 708 // should be put into a common location? 709 710 AutoLocker<VMCache> locker(fCache); 711 712 // Mark all pages unbusy. On error free the newly allocated pages. 713 size_t index = 0; 714 715 while (length > 0) { 716 vm_page* page = pages[index++]; 717 if (page != NULL) { 718 if (page->CacheRef() == NULL) { 719 if (success) { 720 fCache->InsertPage(page, offset); 721 fCache->MarkPageUnbusy(page); 722 DEBUG_PAGE_ACCESS_END(page); 723 } else 724 vm_page_free(NULL, page); 725 } else { 726 fCache->MarkPageUnbusy(page); 727 DEBUG_PAGE_ACCESS_END(page); 728 } 729 } 730 731 offset += B_PAGE_SIZE; 732 length -= B_PAGE_SIZE; 733 } 734 } 735 736 status_t _CopyData(vm_page* page, const generic_io_vec*& vecs, 737 generic_size_t& vecOffset, bool toPage) 738 { 739 // map page to virtual memory 740 Thread* thread = thread_get_current_thread(); 741 uint8* pageData = NULL; 742 void* handle; 743 if (page != NULL) { 744 thread_pin_to_current_cpu(thread); 745 addr_t virtualAddress; 746 status_t error = vm_get_physical_page_current_cpu( 747 page->physical_page_number * B_PAGE_SIZE, &virtualAddress, 748 &handle); 749 if (error != B_OK) { 750 thread_unpin_from_current_cpu(thread); 751 return error; 752 } 753 754 pageData = (uint8*)virtualAddress; 755 } 756 757 status_t error = B_OK; 758 size_t length = B_PAGE_SIZE; 759 while (length > 0) { 760 size_t toCopy = std::min((generic_size_t)length, 761 vecs->length - vecOffset); 762 763 if (toCopy == 0) { 764 vecs++; 765 vecOffset = 0; 766 continue; 767 } 768 769 phys_addr_t vecAddress = vecs->base + vecOffset; 770 771 error = toPage 772 ? vm_memcpy_from_physical(pageData, vecAddress, toCopy, false) 773 : (page != NULL 774 ? vm_memcpy_to_physical(vecAddress, pageData, toCopy, false) 775 : vm_memset_physical(vecAddress, 0, toCopy)); 776 if (error != B_OK) 777 break; 778 779 pageData += toCopy; 780 length -= toCopy; 781 vecOffset += toCopy; 782 } 783 784 if (page != NULL) { 785 vm_put_physical_page_current_cpu((addr_t)pageData, handle); 786 thread_unpin_from_current_cpu(thread); 787 } 788 789 return error; 790 } 791 792 status_t _LoadFile() 793 { 794 static const size_t kPageCountPerIteration = 1024; 795 796 int fd = open(fFilePath, O_RDONLY); 797 if (fd < 0) 798 return errno; 799 FileDescriptorCloser fdCloser(fd); 800 801 vm_page** pages = new(std::nothrow) vm_page*[kPageCountPerIteration]; 802 ArrayDeleter<vm_page*> pagesDeleter(pages); 803 804 uint8* buffer = (uint8*)malloc(kPageCountPerIteration * B_PAGE_SIZE); 805 MemoryDeleter bufferDeleter(buffer); 806 // TODO: Ideally we wouldn't use a buffer to read the file content, 807 // but read into the pages we allocated directly. Unfortunately 808 // there's no API to do that yet. 809 810 if (pages == NULL || buffer == NULL) 811 return B_NO_MEMORY; 812 813 status_t error = B_OK; 814 815 page_num_t allocatedPages = 0; 816 off_t offset = 0; 817 off_t sizeRemaining = fDeviceSize; 818 while (sizeRemaining > 0) { 819 // Note: fDeviceSize is B_PAGE_SIZE aligned. 820 size_t pagesToRead = std::min(kPageCountPerIteration, 821 size_t(sizeRemaining / B_PAGE_SIZE)); 822 823 // allocate the missing pages 824 if (allocatedPages < pagesToRead) { 825 vm_page_reservation reservation; 826 vm_page_reserve_pages(&reservation, 827 pagesToRead - allocatedPages, VM_PRIORITY_SYSTEM); 828 829 while (allocatedPages < pagesToRead) { 830 pages[allocatedPages++] 831 = vm_page_allocate_page(&reservation, PAGE_STATE_WIRED); 832 } 833 834 vm_page_unreserve_pages(&reservation); 835 } 836 837 // read from the file 838 size_t bytesToRead = pagesToRead * B_PAGE_SIZE; 839 ssize_t bytesRead = pread(fd, buffer, bytesToRead, offset); 840 if (bytesRead < 0) { 841 error = bytesRead; 842 break; 843 } 844 size_t pagesRead = (bytesRead + B_PAGE_SIZE - 1) / B_PAGE_SIZE; 845 if (pagesRead < pagesToRead) { 846 error = B_ERROR; 847 break; 848 } 849 850 // clear the last read page, if partial 851 if ((size_t)bytesRead < pagesRead * B_PAGE_SIZE) { 852 memset(buffer + bytesRead, 0, 853 pagesRead * B_PAGE_SIZE - bytesRead); 854 } 855 856 // copy data to allocated pages 857 for (size_t i = 0; i < pagesRead; i++) { 858 vm_page* page = pages[i]; 859 error = vm_memcpy_to_physical( 860 page->physical_page_number * B_PAGE_SIZE, 861 buffer + i * B_PAGE_SIZE, B_PAGE_SIZE, false); 862 if (error != B_OK) 863 break; 864 } 865 866 if (error != B_OK) 867 break; 868 869 // Add pages to cache. Ignore clear pages, though. Move those to the 870 // beginning of the array, so we can reuse them in the next 871 // iteration. 872 AutoLocker<VMCache> locker(fCache); 873 874 size_t clearPages = 0; 875 for (size_t i = 0; i < pagesRead; i++) { 876 uint64* pageData = (uint64*)(buffer + i * B_PAGE_SIZE); 877 bool isClear = true; 878 for (size_t k = 0; isClear && k < B_PAGE_SIZE / 8; k++) 879 isClear = pageData[k] == 0; 880 881 if (isClear) { 882 pages[clearPages++] = pages[i]; 883 } else { 884 fCache->InsertPage(pages[i], offset + i * B_PAGE_SIZE); 885 DEBUG_PAGE_ACCESS_END(pages[i]); 886 } 887 } 888 889 locker.Unlock(); 890 891 // Move any left-over allocated pages to the end of the empty pages 892 // and compute the new allocated pages count. 893 if (pagesRead < allocatedPages) { 894 size_t count = allocatedPages - pagesRead; 895 memcpy(pages + clearPages, pages + pagesRead, 896 count * sizeof(vm_page*)); 897 clearPages += count; 898 } 899 allocatedPages = clearPages; 900 901 offset += pagesRead * B_PAGE_SIZE; 902 sizeRemaining -= pagesRead * B_PAGE_SIZE; 903 } 904 905 // free left-over allocated pages 906 for (size_t i = 0; i < allocatedPages; i++) 907 vm_page_free(NULL, pages[i]); 908 909 return error; 910 } 911 912 private: 913 int32 fID; 914 bool fUnregistered; 915 off_t fDeviceSize; 916 char* fDeviceName; 917 char* fFilePath; 918 VMCache* fCache; 919 DMAResource* fDMAResource; 920 IOScheduler* fIOScheduler; 921 }; 922 923 924 struct RawDeviceCookie { 925 RawDeviceCookie(RawDevice* device, int openMode) 926 : 927 fDevice(device), 928 fOpenMode(openMode) 929 { 930 } 931 932 RawDevice* Device() const { return fDevice; } 933 int OpenMode() const { return fOpenMode; } 934 935 private: 936 RawDevice* fDevice; 937 int fOpenMode; 938 }; 939 940 941 // #pragma mark - 942 943 944 static int32 945 allocate_raw_device_id() 946 { 947 MutexLocker deviceListLocker(sDeviceListLock); 948 for (size_t i = 0; i < sizeof(sUsedRawDeviceIDs) * 8; i++) { 949 if ((sUsedRawDeviceIDs & ((uint64)1 << i)) == 0) { 950 sUsedRawDeviceIDs |= (uint64)1 << i; 951 return (int32)i; 952 } 953 } 954 955 return -1; 956 } 957 958 959 static void 960 free_raw_device_id(int32 id) 961 { 962 MutexLocker deviceListLocker(sDeviceListLock); 963 sUsedRawDeviceIDs &= ~((uint64)1 << id); 964 } 965 966 967 static RawDevice* 968 find_raw_device(int32 id) 969 { 970 for (RawDeviceList::Iterator it = sDeviceList.GetIterator(); 971 RawDevice* device = it.Next();) { 972 if (device->ID() == id) 973 return device; 974 } 975 976 return NULL; 977 } 978 979 980 static status_t 981 ioctl_register(ControlDevice* controlDevice, ram_disk_ioctl_register* request) 982 { 983 KPath path; 984 uint64 deviceSize = 0; 985 986 if (request->path[0] != '\0') { 987 // check if the path is null-terminated 988 if (strnlen(request->path, sizeof(request->path)) 989 == sizeof(request->path)) { 990 return B_BAD_VALUE; 991 } 992 993 // get a normalized file path 994 status_t error = path.SetTo(request->path, true); 995 if (error != B_OK) { 996 dprintf("ramdisk: register: Invalid path \"%s\": %s\n", 997 request->path, strerror(error)); 998 return B_BAD_VALUE; 999 } 1000 1001 struct stat st; 1002 if (lstat(path.Path(), &st) != 0) { 1003 dprintf("ramdisk: register: Failed to stat \"%s\": %s\n", 1004 path.Path(), strerror(errno)); 1005 return errno; 1006 } 1007 1008 if (!S_ISREG(st.st_mode)) { 1009 dprintf("ramdisk: register: \"%s\" is not a file!\n", path.Path()); 1010 return B_BAD_VALUE; 1011 } 1012 1013 deviceSize = st.st_size; 1014 } else { 1015 deviceSize = request->size; 1016 } 1017 1018 return controlDevice->Register(path.Length() > 0 ? path.Path() : NULL, 1019 deviceSize, request->id); 1020 } 1021 1022 1023 static status_t 1024 ioctl_unregister(ControlDevice* controlDevice, 1025 ram_disk_ioctl_unregister* request) 1026 { 1027 // find the device in the list and unregister it 1028 MutexLocker locker(sDeviceListLock); 1029 RawDevice* device = find_raw_device(request->id); 1030 if (device == NULL) 1031 return B_ENTRY_NOT_FOUND; 1032 1033 // mark unregistered before we unlock 1034 if (device->IsUnregistered()) 1035 return B_BUSY; 1036 device->SetUnregistered(true); 1037 locker.Unlock(); 1038 1039 device_node* node = device->Node(); 1040 status_t error = sDeviceManager->unpublish_device(node, 1041 device->DeviceName()); 1042 if (error != B_OK) { 1043 dprintf("ramdisk: unregister: Failed to unpublish device \"%s\": %s\n", 1044 device->DeviceName(), strerror(error)); 1045 return error; 1046 } 1047 1048 error = sDeviceManager->unregister_node(node); 1049 // Note: B_BUSY is OK. The node will removed as soon as possible. 1050 if (error != B_OK && error != B_BUSY) { 1051 dprintf("ramdisk: unregister: Failed to unregister node for device %" 1052 B_PRId32 ": %s\n", request->id, strerror(error)); 1053 return error; 1054 } 1055 1056 return B_OK; 1057 } 1058 1059 1060 static status_t 1061 ioctl_info(RawDevice* device, ram_disk_ioctl_info* request) 1062 { 1063 device->GetInfo(*request); 1064 return B_OK; 1065 } 1066 1067 1068 template<typename DeviceType, typename Request> 1069 static status_t 1070 handle_ioctl(DeviceType* device, 1071 status_t (*handler)(DeviceType*, Request*), void* buffer) 1072 { 1073 // copy request to the kernel heap 1074 if (buffer == NULL || !IS_USER_ADDRESS(buffer)) 1075 return B_BAD_ADDRESS; 1076 1077 Request* request = new(std::nothrow) Request; 1078 if (request == NULL) 1079 return B_NO_MEMORY; 1080 ObjectDeleter<Request> requestDeleter(request); 1081 1082 if (user_memcpy(request, buffer, sizeof(Request)) != B_OK) 1083 return B_BAD_ADDRESS; 1084 1085 // handle the ioctl 1086 status_t error = handler(device, request); 1087 if (error != B_OK) 1088 return error; 1089 1090 // copy the request back to userland 1091 if (user_memcpy(buffer, request, sizeof(Request)) != B_OK) 1092 return B_BAD_ADDRESS; 1093 1094 return B_OK; 1095 } 1096 1097 1098 // #pragma mark - driver 1099 1100 1101 static float 1102 ram_disk_driver_supports_device(device_node* parent) 1103 { 1104 const char* bus = NULL; 1105 if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) 1106 == B_OK 1107 && strcmp(bus, "generic") == 0) { 1108 return 0.8; 1109 } 1110 1111 return -1; 1112 } 1113 1114 1115 static status_t 1116 ram_disk_driver_register_device(device_node* parent) 1117 { 1118 device_attr attrs[] = { 1119 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, 1120 {string: "RAM Disk Control Device"}}, 1121 {NULL} 1122 }; 1123 1124 return sDeviceManager->register_node(parent, kDriverModuleName, attrs, NULL, 1125 NULL); 1126 } 1127 1128 1129 static status_t 1130 ram_disk_driver_init_driver(device_node* node, void** _driverCookie) 1131 { 1132 uint64 deviceSize; 1133 if (sDeviceManager->get_attr_uint64(node, kDeviceSizeItem, &deviceSize, 1134 false) == B_OK) { 1135 int32 id = -1; 1136 sDeviceManager->get_attr_uint32(node, kDeviceIDItem, (uint32*)&id, 1137 false); 1138 if (id < 0) 1139 return B_ERROR; 1140 1141 const char* filePath = NULL; 1142 sDeviceManager->get_attr_string(node, kFilePathItem, &filePath, false); 1143 1144 RawDevice* device = new(std::nothrow) RawDevice(node); 1145 if (device == NULL) 1146 return B_NO_MEMORY; 1147 1148 status_t error = device->Init(id, filePath, deviceSize); 1149 if (error != B_OK) { 1150 delete device; 1151 return error; 1152 } 1153 1154 *_driverCookie = (Device*)device; 1155 } else { 1156 ControlDevice* device = new(std::nothrow) ControlDevice(node); 1157 if (device == NULL) 1158 return B_NO_MEMORY; 1159 1160 *_driverCookie = (Device*)device; 1161 } 1162 1163 return B_OK; 1164 } 1165 1166 1167 static void 1168 ram_disk_driver_uninit_driver(void* driverCookie) 1169 { 1170 Device* device = (Device*)driverCookie; 1171 if (RawDevice* rawDevice = dynamic_cast<RawDevice*>(device)) 1172 free_raw_device_id(rawDevice->ID()); 1173 delete device; 1174 } 1175 1176 1177 static status_t 1178 ram_disk_driver_register_child_devices(void* driverCookie) 1179 { 1180 Device* device = (Device*)driverCookie; 1181 return device->PublishDevice(); 1182 } 1183 1184 1185 // #pragma mark - control device 1186 1187 1188 static status_t 1189 ram_disk_control_device_init_device(void* driverCookie, void** _deviceCookie) 1190 { 1191 *_deviceCookie = driverCookie; 1192 return B_OK; 1193 } 1194 1195 1196 static void 1197 ram_disk_control_device_uninit_device(void* deviceCookie) 1198 { 1199 } 1200 1201 1202 static status_t 1203 ram_disk_control_device_open(void* deviceCookie, const char* path, int openMode, 1204 void** _cookie) 1205 { 1206 *_cookie = deviceCookie; 1207 return B_OK; 1208 } 1209 1210 1211 static status_t 1212 ram_disk_control_device_close(void* cookie) 1213 { 1214 return B_OK; 1215 } 1216 1217 1218 static status_t 1219 ram_disk_control_device_free(void* cookie) 1220 { 1221 return B_OK; 1222 } 1223 1224 1225 static status_t 1226 ram_disk_control_device_read(void* cookie, off_t position, void* buffer, 1227 size_t* _length) 1228 { 1229 return B_BAD_VALUE; 1230 } 1231 1232 1233 static status_t 1234 ram_disk_control_device_write(void* cookie, off_t position, const void* data, 1235 size_t* _length) 1236 { 1237 return B_BAD_VALUE; 1238 } 1239 1240 1241 static status_t 1242 ram_disk_control_device_control(void* cookie, uint32 op, void* buffer, 1243 size_t length) 1244 { 1245 ControlDevice* device = (ControlDevice*)cookie; 1246 1247 switch (op) { 1248 case RAM_DISK_IOCTL_REGISTER: 1249 return handle_ioctl(device, &ioctl_register, buffer); 1250 1251 case RAM_DISK_IOCTL_UNREGISTER: 1252 return handle_ioctl(device, &ioctl_unregister, buffer); 1253 } 1254 1255 return B_BAD_VALUE; 1256 } 1257 1258 1259 // #pragma mark - raw device 1260 1261 1262 static status_t 1263 ram_disk_raw_device_init_device(void* driverCookie, void** _deviceCookie) 1264 { 1265 RawDevice* device = static_cast<RawDevice*>((Device*)driverCookie); 1266 1267 status_t error = device->Prepare(); 1268 if (error != B_OK) 1269 return error; 1270 1271 *_deviceCookie = device; 1272 return B_OK; 1273 } 1274 1275 1276 static void 1277 ram_disk_raw_device_uninit_device(void* deviceCookie) 1278 { 1279 RawDevice* device = (RawDevice*)deviceCookie; 1280 device->Unprepare(); 1281 } 1282 1283 1284 static status_t 1285 ram_disk_raw_device_open(void* deviceCookie, const char* path, int openMode, 1286 void** _cookie) 1287 { 1288 RawDevice* device = (RawDevice*)deviceCookie; 1289 1290 RawDeviceCookie* cookie = new(std::nothrow) RawDeviceCookie(device, 1291 openMode); 1292 if (cookie == NULL) 1293 return B_NO_MEMORY; 1294 1295 *_cookie = cookie; 1296 return B_OK; 1297 } 1298 1299 1300 static status_t 1301 ram_disk_raw_device_close(void* cookie) 1302 { 1303 return B_OK; 1304 } 1305 1306 1307 static status_t 1308 ram_disk_raw_device_free(void* _cookie) 1309 { 1310 RawDeviceCookie* cookie = (RawDeviceCookie*)_cookie; 1311 delete cookie; 1312 return B_OK; 1313 } 1314 1315 1316 static status_t 1317 ram_disk_raw_device_read(void* _cookie, off_t pos, void* buffer, 1318 size_t* _length) 1319 { 1320 RawDeviceCookie* cookie = (RawDeviceCookie*)_cookie; 1321 RawDevice* device = cookie->Device(); 1322 1323 size_t length = *_length; 1324 1325 if (pos >= device->DeviceSize()) 1326 return B_BAD_VALUE; 1327 if (pos + (off_t)length > device->DeviceSize()) 1328 length = device->DeviceSize() - pos; 1329 1330 IORequest request; 1331 status_t status = request.Init(pos, (addr_t)buffer, length, false, 0); 1332 if (status != B_OK) 1333 return status; 1334 1335 status = device->DoIO(&request); 1336 if (status != B_OK) 1337 return status; 1338 1339 status = request.Wait(0, 0); 1340 if (status == B_OK) 1341 *_length = length; 1342 return status; 1343 } 1344 1345 1346 static status_t 1347 ram_disk_raw_device_write(void* _cookie, off_t pos, const void* buffer, 1348 size_t* _length) 1349 { 1350 RawDeviceCookie* cookie = (RawDeviceCookie*)_cookie; 1351 RawDevice* device = cookie->Device(); 1352 1353 size_t length = *_length; 1354 1355 if (pos >= device->DeviceSize()) 1356 return B_BAD_VALUE; 1357 if (pos + (off_t)length > device->DeviceSize()) 1358 length = device->DeviceSize() - pos; 1359 1360 IORequest request; 1361 status_t status = request.Init(pos, (addr_t)buffer, length, true, 0); 1362 if (status != B_OK) 1363 return status; 1364 1365 status = device->DoIO(&request); 1366 if (status != B_OK) 1367 return status; 1368 1369 status = request.Wait(0, 0); 1370 if (status == B_OK) 1371 *_length = length; 1372 1373 return status; 1374 } 1375 1376 1377 static status_t 1378 ram_disk_raw_device_io(void* _cookie, io_request* request) 1379 { 1380 RawDeviceCookie* cookie = (RawDeviceCookie*)_cookie; 1381 RawDevice* device = cookie->Device(); 1382 1383 return device->DoIO(request); 1384 } 1385 1386 1387 static status_t 1388 ram_disk_raw_device_control(void* _cookie, uint32 op, void* buffer, 1389 size_t length) 1390 { 1391 RawDeviceCookie* cookie = (RawDeviceCookie*)_cookie; 1392 RawDevice* device = cookie->Device(); 1393 1394 switch (op) { 1395 case B_GET_DEVICE_SIZE: 1396 { 1397 size_t size = device->DeviceSize(); 1398 return user_memcpy(buffer, &size, sizeof(size_t)); 1399 } 1400 1401 case B_SET_NONBLOCKING_IO: 1402 case B_SET_BLOCKING_IO: 1403 return B_OK; 1404 1405 case B_GET_READ_STATUS: 1406 case B_GET_WRITE_STATUS: 1407 { 1408 bool value = true; 1409 return user_memcpy(buffer, &value, sizeof(bool)); 1410 } 1411 1412 case B_GET_GEOMETRY: 1413 case B_GET_BIOS_GEOMETRY: 1414 { 1415 device_geometry geometry; 1416 geometry.bytes_per_sector = B_PAGE_SIZE; 1417 geometry.sectors_per_track = 1; 1418 geometry.cylinder_count = device->DeviceSize() / B_PAGE_SIZE; 1419 // TODO: We're limited to 2^32 * B_PAGE_SIZE, if we don't use 1420 // sectors_per_track and head_count. 1421 geometry.head_count = 1; 1422 geometry.device_type = B_DISK; 1423 geometry.removable = true; 1424 geometry.read_only = false; 1425 geometry.write_once = false; 1426 1427 return user_memcpy(buffer, &geometry, sizeof(device_geometry)); 1428 } 1429 1430 case B_GET_MEDIA_STATUS: 1431 { 1432 status_t status = B_OK; 1433 return user_memcpy(buffer, &status, sizeof(status_t)); 1434 } 1435 1436 case B_GET_ICON_NAME: 1437 return user_strlcpy((char*)buffer, "devices/drive-ramdisk", 1438 B_FILE_NAME_LENGTH); 1439 1440 case B_GET_VECTOR_ICON: 1441 { 1442 device_icon iconData; 1443 if (length != sizeof(device_icon)) 1444 return B_BAD_VALUE; 1445 if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK) 1446 return B_BAD_ADDRESS; 1447 1448 if (iconData.icon_size >= (int32)sizeof(kRamdiskIcon)) { 1449 if (user_memcpy(iconData.icon_data, kRamdiskIcon, 1450 sizeof(kRamdiskIcon)) != B_OK) 1451 return B_BAD_ADDRESS; 1452 } 1453 1454 iconData.icon_size = sizeof(kRamdiskIcon); 1455 return user_memcpy(buffer, &iconData, sizeof(device_icon)); 1456 } 1457 1458 case B_SET_UNINTERRUPTABLE_IO: 1459 case B_SET_INTERRUPTABLE_IO: 1460 case B_FLUSH_DRIVE_CACHE: 1461 return B_OK; 1462 1463 case RAM_DISK_IOCTL_FLUSH: 1464 { 1465 status_t error = device->Flush(); 1466 if (error != B_OK) { 1467 dprintf("ramdisk: flush: Failed to flush device: %s\n", 1468 strerror(error)); 1469 return error; 1470 } 1471 1472 return B_OK; 1473 } 1474 1475 case B_TRIM_DEVICE: 1476 { 1477 fs_trim_data* trimData; 1478 MemoryDeleter deleter; 1479 status_t status = get_trim_data_from_user(buffer, length, deleter, 1480 trimData); 1481 if (status != B_OK) 1482 return status; 1483 1484 status = device->Trim(trimData); 1485 if (status != B_OK) 1486 return status; 1487 1488 return copy_trim_data_to_user(buffer, trimData); 1489 } 1490 1491 case RAM_DISK_IOCTL_INFO: 1492 return handle_ioctl(device, &ioctl_info, buffer); 1493 } 1494 1495 return B_BAD_VALUE; 1496 } 1497 1498 1499 // #pragma mark - 1500 1501 1502 module_dependency module_dependencies[] = { 1503 {B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&sDeviceManager}, 1504 {} 1505 }; 1506 1507 1508 static const struct driver_module_info sChecksumDeviceDriverModule = { 1509 { 1510 kDriverModuleName, 1511 0, 1512 NULL 1513 }, 1514 1515 ram_disk_driver_supports_device, 1516 ram_disk_driver_register_device, 1517 ram_disk_driver_init_driver, 1518 ram_disk_driver_uninit_driver, 1519 ram_disk_driver_register_child_devices 1520 }; 1521 1522 static const struct device_module_info sChecksumControlDeviceModule = { 1523 { 1524 kControlDeviceModuleName, 1525 0, 1526 NULL 1527 }, 1528 1529 ram_disk_control_device_init_device, 1530 ram_disk_control_device_uninit_device, 1531 NULL, 1532 1533 ram_disk_control_device_open, 1534 ram_disk_control_device_close, 1535 ram_disk_control_device_free, 1536 1537 ram_disk_control_device_read, 1538 ram_disk_control_device_write, 1539 NULL, // io 1540 1541 ram_disk_control_device_control, 1542 1543 NULL, // select 1544 NULL // deselect 1545 }; 1546 1547 static const struct device_module_info sChecksumRawDeviceModule = { 1548 { 1549 kRawDeviceModuleName, 1550 0, 1551 NULL 1552 }, 1553 1554 ram_disk_raw_device_init_device, 1555 ram_disk_raw_device_uninit_device, 1556 NULL, 1557 1558 ram_disk_raw_device_open, 1559 ram_disk_raw_device_close, 1560 ram_disk_raw_device_free, 1561 1562 ram_disk_raw_device_read, 1563 ram_disk_raw_device_write, 1564 ram_disk_raw_device_io, 1565 1566 ram_disk_raw_device_control, 1567 1568 NULL, // select 1569 NULL // deselect 1570 }; 1571 1572 const module_info* modules[] = { 1573 (module_info*)&sChecksumDeviceDriverModule, 1574 (module_info*)&sChecksumControlDeviceModule, 1575 (module_info*)&sChecksumRawDeviceModule, 1576 NULL 1577 }; 1578