1 /* 2 * Copyright 2002-2016, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 6 * Distributed under the terms of the NewOS License. 7 */ 8 9 10 #include <fs/devfs.h> 11 12 #include <errno.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <sys/stat.h> 17 18 #include <Drivers.h> 19 #include <KernelExport.h> 20 #include <NodeMonitor.h> 21 22 #include <arch/cpu.h> 23 #include <AutoDeleter.h> 24 #include <boot/kernel_args.h> 25 #include <boot_device.h> 26 #include <debug.h> 27 #include <elf.h> 28 #include <FindDirectory.h> 29 #include <fs/devfs.h> 30 #include <fs/KPath.h> 31 #include <fs/node_monitor.h> 32 #include <kdevice_manager.h> 33 #include <lock.h> 34 #include <Notifications.h> 35 #include <util/AutoLock.h> 36 #include <util/fs_trim_support.h> 37 #include <vfs.h> 38 #include <vm/vm.h> 39 #include <wait_for_objects.h> 40 41 #include "BaseDevice.h" 42 #include "FileDevice.h" 43 #include "IORequest.h" 44 #include "legacy_drivers.h" 45 46 47 //#define TRACE_DEVFS 48 #ifdef TRACE_DEVFS 49 # define TRACE(x) dprintf x 50 #else 51 # define TRACE(x) 52 #endif 53 54 55 namespace { 56 57 struct devfs_partition { 58 struct devfs_vnode* raw_device; 59 partition_info info; 60 }; 61 62 struct driver_entry; 63 64 enum { 65 kNotScanned = 0, 66 kBootScan, 67 kNormalScan, 68 }; 69 70 struct devfs_stream { 71 mode_t type; 72 union { 73 struct stream_dir { 74 struct devfs_vnode* dir_head; 75 struct list cookies; 76 mutex scan_lock; 77 int32 scanned; 78 } dir; 79 struct stream_dev { 80 BaseDevice* device; 81 struct devfs_partition* partition; 82 } dev; 83 struct stream_symlink { 84 const char* path; 85 size_t length; 86 } symlink; 87 } u; 88 }; 89 90 struct devfs_vnode { 91 struct devfs_vnode* all_next; 92 ino_t id; 93 char* name; 94 timespec modification_time; 95 timespec creation_time; 96 uid_t uid; 97 gid_t gid; 98 struct devfs_vnode* parent; 99 struct devfs_vnode* dir_next; 100 struct devfs_stream stream; 101 }; 102 103 #define DEVFS_HASH_SIZE 16 104 105 106 struct NodeHash { 107 typedef ino_t KeyType; 108 typedef devfs_vnode ValueType; 109 110 size_t HashKey(KeyType key) const 111 { 112 return key ^ (key >> 32); 113 } 114 115 size_t Hash(ValueType* value) const 116 { 117 return HashKey(value->id); 118 } 119 120 bool Compare(KeyType key, ValueType* value) const 121 { 122 return value->id == key; 123 } 124 125 ValueType*& GetLink(ValueType* value) const 126 { 127 return value->all_next; 128 } 129 }; 130 131 typedef BOpenHashTable<NodeHash> NodeTable; 132 133 struct devfs { 134 dev_t id; 135 fs_volume* volume; 136 recursive_lock lock; 137 int32 next_vnode_id; 138 NodeTable* vnode_hash; 139 struct devfs_vnode* root_vnode; 140 }; 141 142 struct devfs_dir_cookie { 143 struct list_link link; 144 struct devfs_vnode* current; 145 int32 state; // iteration state 146 }; 147 148 struct devfs_cookie { 149 void* device_cookie; 150 }; 151 152 // directory iteration states 153 enum { 154 ITERATION_STATE_DOT = 0, 155 ITERATION_STATE_DOT_DOT = 1, 156 ITERATION_STATE_OTHERS = 2, 157 ITERATION_STATE_BEGIN = ITERATION_STATE_DOT, 158 }; 159 160 // extern only to make forward declaration possible 161 extern fs_volume_ops kVolumeOps; 162 extern fs_vnode_ops kVnodeOps; 163 164 } // namespace 165 166 167 static status_t get_node_for_path(struct devfs* fs, const char* path, 168 struct devfs_vnode** _node); 169 static void get_device_name(struct devfs_vnode* vnode, char* buffer, 170 size_t size); 171 static status_t unpublish_node(struct devfs* fs, devfs_vnode* node, 172 mode_t type); 173 static status_t publish_device(struct devfs* fs, const char* path, 174 BaseDevice* device); 175 176 177 // The one and only allowed devfs instance 178 static struct devfs* sDeviceFileSystem = NULL; 179 180 181 // #pragma mark - devfs private 182 183 184 static timespec 185 current_timespec() 186 { 187 bigtime_t time = real_time_clock_usecs(); 188 189 timespec tv; 190 tv.tv_sec = time / 1000000; 191 tv.tv_nsec = (time % 1000000) * 1000; 192 return tv; 193 } 194 195 196 static ino_t 197 get_parent_id(struct devfs_vnode* vnode) 198 { 199 if (vnode->parent != NULL) 200 return vnode->parent->id; 201 return -1; 202 } 203 204 205 static int32 206 scan_mode(void) 207 { 208 // We may scan every device twice: 209 // - once before there is a boot device, 210 // - and once when there is one 211 212 return gBootDevice >= 0 ? kNormalScan : kBootScan; 213 } 214 215 216 static status_t 217 scan_for_drivers_if_needed(devfs_vnode* dir) 218 { 219 ASSERT(S_ISDIR(dir->stream.type)); 220 221 MutexLocker _(dir->stream.u.dir.scan_lock); 222 223 if (dir->stream.u.dir.scanned >= scan_mode()) 224 return B_OK; 225 226 KPath path; 227 if (path.InitCheck() != B_OK) 228 return B_NO_MEMORY; 229 230 get_device_name(dir, path.LockBuffer(), path.BufferSize()); 231 path.UnlockBuffer(); 232 233 TRACE(("scan_for_drivers_if_needed: mode %" B_PRId32 ": %s\n", 234 scan_mode(), path.Path())); 235 236 // scan for drivers at this path 237 static int32 updateCycle = 1; 238 device_manager_probe(path.Path(), updateCycle++); 239 legacy_driver_probe(path.Path()); 240 241 dir->stream.u.dir.scanned = scan_mode(); 242 return B_OK; 243 } 244 245 246 static void 247 init_directory_vnode(struct devfs_vnode* vnode, int permissions) 248 { 249 vnode->stream.type = S_IFDIR | permissions; 250 mutex_init(&vnode->stream.u.dir.scan_lock, "devfs scan"); 251 vnode->stream.u.dir.dir_head = NULL; 252 list_init(&vnode->stream.u.dir.cookies); 253 } 254 255 256 static struct devfs_vnode* 257 devfs_create_vnode(struct devfs* fs, devfs_vnode* parent, const char* name) 258 { 259 struct devfs_vnode* vnode; 260 261 vnode = (struct devfs_vnode*)malloc(sizeof(struct devfs_vnode)); 262 if (vnode == NULL) 263 return NULL; 264 265 memset(vnode, 0, sizeof(struct devfs_vnode)); 266 vnode->id = fs->next_vnode_id++; 267 268 vnode->name = strdup(name); 269 if (vnode->name == NULL) { 270 free(vnode); 271 return NULL; 272 } 273 274 vnode->creation_time = vnode->modification_time = current_timespec(); 275 vnode->uid = geteuid(); 276 vnode->gid = parent ? parent->gid : getegid(); 277 // inherit group from parent if possible 278 279 return vnode; 280 } 281 282 283 static status_t 284 devfs_delete_vnode(struct devfs* fs, struct devfs_vnode* vnode, 285 bool forceDelete) 286 { 287 // Can't delete it if it's in a directory or is a directory 288 // and has children 289 if (!forceDelete && ((S_ISDIR(vnode->stream.type) 290 && vnode->stream.u.dir.dir_head != NULL) 291 || vnode->dir_next != NULL)) 292 return B_NOT_ALLOWED; 293 294 // remove it from the global hash table 295 fs->vnode_hash->Remove(vnode); 296 297 if (S_ISCHR(vnode->stream.type)) { 298 if (vnode->stream.u.dev.partition == NULL) { 299 // pass the call through to the underlying device 300 vnode->stream.u.dev.device->Removed(); 301 } else { 302 // for partitions, we have to release the raw device but must 303 // not free the device info as it was inherited from the raw 304 // device and is still in use there 305 put_vnode(fs->volume, vnode->stream.u.dev.partition->raw_device->id); 306 } 307 } else if (S_ISDIR(vnode->stream.type)) { 308 mutex_destroy(&vnode->stream.u.dir.scan_lock); 309 } 310 311 free(vnode->name); 312 free(vnode); 313 314 return B_OK; 315 } 316 317 318 /*! Makes sure none of the dircookies point to the vnode passed in */ 319 static void 320 update_dir_cookies(struct devfs_vnode* dir, struct devfs_vnode* vnode) 321 { 322 struct devfs_dir_cookie* cookie = NULL; 323 324 while ((cookie = (devfs_dir_cookie*)list_get_next_item( 325 &dir->stream.u.dir.cookies, cookie)) != NULL) { 326 if (cookie->current == vnode) 327 cookie->current = vnode->dir_next; 328 } 329 } 330 331 332 static struct devfs_vnode* 333 devfs_find_in_dir(struct devfs_vnode* dir, const char* path) 334 { 335 struct devfs_vnode* vnode; 336 337 if (!S_ISDIR(dir->stream.type)) 338 return NULL; 339 340 if (!strcmp(path, ".")) 341 return dir; 342 if (!strcmp(path, "..")) 343 return dir->parent; 344 345 for (vnode = dir->stream.u.dir.dir_head; vnode; vnode = vnode->dir_next) { 346 //TRACE(("devfs_find_in_dir: looking at entry '%s'\n", vnode->name)); 347 if (strcmp(vnode->name, path) == 0) { 348 //TRACE(("devfs_find_in_dir: found it at %p\n", vnode)); 349 return vnode; 350 } 351 } 352 return NULL; 353 } 354 355 356 static status_t 357 devfs_insert_in_dir(struct devfs_vnode* dir, struct devfs_vnode* vnode, 358 bool notify = true) 359 { 360 if (!S_ISDIR(dir->stream.type)) 361 return B_BAD_VALUE; 362 363 // make sure the directory stays sorted alphabetically 364 365 devfs_vnode* node = dir->stream.u.dir.dir_head; 366 devfs_vnode* last = NULL; 367 while (node && strcmp(node->name, vnode->name) < 0) { 368 last = node; 369 node = node->dir_next; 370 } 371 if (last == NULL) { 372 // the new vnode is the first entry in the list 373 vnode->dir_next = dir->stream.u.dir.dir_head; 374 dir->stream.u.dir.dir_head = vnode; 375 } else { 376 // insert after that node 377 vnode->dir_next = last->dir_next; 378 last->dir_next = vnode; 379 } 380 381 vnode->parent = dir; 382 dir->modification_time = current_timespec(); 383 384 if (notify) { 385 notify_entry_created(sDeviceFileSystem->id, dir->id, vnode->name, 386 vnode->id); 387 notify_stat_changed(sDeviceFileSystem->id, get_parent_id(dir), dir->id, 388 B_STAT_MODIFICATION_TIME); 389 } 390 return B_OK; 391 } 392 393 394 static status_t 395 devfs_remove_from_dir(struct devfs_vnode* dir, struct devfs_vnode* removeNode, 396 bool notify = true) 397 { 398 struct devfs_vnode* vnode = dir->stream.u.dir.dir_head; 399 struct devfs_vnode* lastNode = NULL; 400 401 for (; vnode != NULL; lastNode = vnode, vnode = vnode->dir_next) { 402 if (vnode == removeNode) { 403 // make sure no dircookies point to this vnode 404 update_dir_cookies(dir, vnode); 405 406 if (lastNode) 407 lastNode->dir_next = vnode->dir_next; 408 else 409 dir->stream.u.dir.dir_head = vnode->dir_next; 410 vnode->dir_next = NULL; 411 dir->modification_time = current_timespec(); 412 413 if (notify) { 414 notify_entry_removed(sDeviceFileSystem->id, dir->id, vnode->name, 415 vnode->id); 416 notify_stat_changed(sDeviceFileSystem->id, get_parent_id(dir), 417 dir->id, B_STAT_MODIFICATION_TIME); 418 } 419 return B_OK; 420 } 421 } 422 return B_ENTRY_NOT_FOUND; 423 } 424 425 426 static status_t 427 add_partition(struct devfs* fs, struct devfs_vnode* device, const char* name, 428 const partition_info& info) 429 { 430 struct devfs_vnode* partitionNode; 431 status_t status; 432 433 if (!S_ISCHR(device->stream.type)) 434 return B_BAD_VALUE; 435 436 // we don't support nested partitions 437 if (device->stream.u.dev.partition != NULL) 438 return B_BAD_VALUE; 439 440 // reduce checks to a minimum - things like negative offsets could be useful 441 if (info.size < 0) 442 return B_BAD_VALUE; 443 444 // create partition 445 struct devfs_partition* partition = (struct devfs_partition*)malloc( 446 sizeof(struct devfs_partition)); 447 if (partition == NULL) 448 return B_NO_MEMORY; 449 450 memcpy(&partition->info, &info, sizeof(partition_info)); 451 452 RecursiveLocker locker(fs->lock); 453 454 // you cannot change a partition once set 455 if (devfs_find_in_dir(device->parent, name)) { 456 status = B_BAD_VALUE; 457 goto err1; 458 } 459 460 // increase reference count of raw device - 461 // the partition device really needs it 462 status = get_vnode(fs->volume, device->id, (void**)&partition->raw_device); 463 if (status < B_OK) 464 goto err1; 465 466 // now create the partition vnode 467 partitionNode = devfs_create_vnode(fs, device->parent, name); 468 if (partitionNode == NULL) { 469 status = B_NO_MEMORY; 470 goto err2; 471 } 472 473 partitionNode->stream.type = device->stream.type; 474 partitionNode->stream.u.dev.device = device->stream.u.dev.device; 475 partitionNode->stream.u.dev.partition = partition; 476 477 fs->vnode_hash->Insert(partitionNode); 478 devfs_insert_in_dir(device->parent, partitionNode); 479 480 TRACE(("add_partition(name = %s, offset = %" B_PRIdOFF 481 ", size = %" B_PRIdOFF ")\n", 482 name, info.offset, info.size)); 483 return B_OK; 484 485 err2: 486 put_vnode(fs->volume, device->id); 487 err1: 488 free(partition); 489 return status; 490 } 491 492 493 static inline void 494 translate_partition_access(devfs_partition* partition, off_t& offset, 495 size_t& size) 496 { 497 ASSERT(offset >= 0); 498 ASSERT(offset < partition->info.size); 499 500 size = (size_t)min_c((off_t)size, partition->info.size - offset); 501 offset += partition->info.offset; 502 } 503 504 505 static bool 506 translate_partition_access(devfs_partition* partition, uint64& offset, 507 uint64& size) 508 { 509 const off_t partitionSize = partition->info.size; 510 const off_t partitionOffset = partition->info.offset; 511 512 // Check that off_t values can be cast to uint64, 513 // partition offset can theoretically be negative 514 ASSERT(partitionSize >= 0); 515 STATIC_ASSERT(sizeof(partitionSize) <= sizeof(uint64)); 516 STATIC_ASSERT(sizeof(partitionOffset) <= sizeof(uint64)); 517 518 // Check that calculations give expected results 519 if (offset >= (uint64)partitionSize) 520 return false; 521 if (partitionOffset >= 0 && offset > UINT64_MAX - (uint64)partitionOffset) 522 return false; 523 if (partitionOffset < 0 && offset < (uint64)-partitionOffset) 524 return false; 525 526 size = min_c(size, (uint64)partitionSize - offset); 527 if (partitionOffset >= 0) 528 offset += (uint64)partitionOffset; 529 else 530 offset -= (uint64)-partitionOffset; 531 532 return true; 533 } 534 535 536 static inline void 537 translate_partition_access(devfs_partition* partition, io_request* request) 538 { 539 off_t offset = request->Offset(); 540 541 ASSERT(offset >= 0); 542 ASSERT(offset + (off_t)request->Length() <= partition->info.size); 543 544 request->SetOffset(offset + partition->info.offset); 545 } 546 547 548 static status_t 549 get_node_for_path(struct devfs* fs, const char* path, 550 struct devfs_vnode** _node) 551 { 552 return vfs_get_fs_node_from_path(fs->volume, path, false, true, 553 (void**)_node); 554 } 555 556 557 static status_t 558 unpublish_node(struct devfs* fs, devfs_vnode* node, mode_t type) 559 { 560 if ((node->stream.type & S_IFMT) != type) 561 return B_BAD_TYPE; 562 563 recursive_lock_lock(&fs->lock); 564 565 status_t status = devfs_remove_from_dir(node->parent, node); 566 if (status < B_OK) 567 goto out; 568 569 status = remove_vnode(fs->volume, node->id); 570 571 out: 572 recursive_lock_unlock(&fs->lock); 573 return status; 574 } 575 576 577 static void 578 publish_node(devfs* fs, devfs_vnode* dirNode, struct devfs_vnode* node) 579 { 580 fs->vnode_hash->Insert(node); 581 devfs_insert_in_dir(dirNode, node); 582 } 583 584 585 static status_t 586 publish_directory(struct devfs* fs, const char* path) 587 { 588 ASSERT_LOCKED_RECURSIVE(&fs->lock); 589 590 // copy the path over to a temp buffer so we can munge it 591 KPath tempPath(path); 592 if (tempPath.InitCheck() != B_OK) 593 return B_NO_MEMORY; 594 595 TRACE(("devfs: publish directory \"%s\"\n", path)); 596 char* temp = tempPath.LockBuffer(); 597 598 // create the path leading to the device 599 // parse the path passed in, stripping out '/' 600 601 struct devfs_vnode* dir = fs->root_vnode; 602 struct devfs_vnode* vnode = NULL; 603 status_t status = B_OK; 604 int32 i = 0, last = 0; 605 606 while (temp[last]) { 607 if (temp[i] == '/') { 608 temp[i] = '\0'; 609 i++; 610 } else if (temp[i] != '\0') { 611 i++; 612 continue; 613 } 614 615 //TRACE(("\tpath component '%s'\n", &temp[last])); 616 617 // we have a path component 618 vnode = devfs_find_in_dir(dir, &temp[last]); 619 if (vnode) { 620 if (S_ISDIR(vnode->stream.type)) { 621 last = i; 622 dir = vnode; 623 continue; 624 } 625 626 // we hit something on our path that's not a directory 627 status = B_FILE_EXISTS; 628 goto out; 629 } else { 630 vnode = devfs_create_vnode(fs, dir, &temp[last]); 631 if (!vnode) { 632 status = B_NO_MEMORY; 633 goto out; 634 } 635 } 636 637 // set up the new directory 638 init_directory_vnode(vnode, 0755); 639 publish_node(sDeviceFileSystem, dir, vnode); 640 641 last = i; 642 dir = vnode; 643 } 644 645 out: 646 return status; 647 } 648 649 650 static status_t 651 new_node(struct devfs* fs, const char* path, struct devfs_vnode** _node, 652 struct devfs_vnode** _dir) 653 { 654 ASSERT_LOCKED_RECURSIVE(&fs->lock); 655 656 // copy the path over to a temp buffer so we can munge it 657 KPath tempPath(path); 658 if (tempPath.InitCheck() != B_OK) 659 return B_NO_MEMORY; 660 661 char* temp = tempPath.LockBuffer(); 662 663 // create the path leading to the device 664 // parse the path passed in, stripping out '/' 665 666 struct devfs_vnode* dir = fs->root_vnode; 667 struct devfs_vnode* vnode = NULL; 668 status_t status = B_OK; 669 int32 i = 0, last = 0; 670 bool atLeaf = false; 671 672 for (;;) { 673 if (temp[i] == '\0') { 674 atLeaf = true; // we'll be done after this one 675 } else if (temp[i] == '/') { 676 temp[i] = '\0'; 677 i++; 678 } else { 679 i++; 680 continue; 681 } 682 683 //TRACE(("\tpath component '%s'\n", &temp[last])); 684 685 // we have a path component 686 vnode = devfs_find_in_dir(dir, &temp[last]); 687 if (vnode) { 688 if (!atLeaf) { 689 // we are not at the leaf of the path, so as long as 690 // this is a dir we're okay 691 if (S_ISDIR(vnode->stream.type)) { 692 last = i; 693 dir = vnode; 694 continue; 695 } 696 } 697 // we are at the leaf and hit another node 698 // or we aren't but hit a non-dir node. 699 // we're screwed 700 status = B_FILE_EXISTS; 701 goto out; 702 } else { 703 vnode = devfs_create_vnode(fs, dir, &temp[last]); 704 if (!vnode) { 705 status = B_NO_MEMORY; 706 goto out; 707 } 708 } 709 710 // set up the new vnode 711 if (!atLeaf) { 712 // this is a dir 713 init_directory_vnode(vnode, 0755); 714 publish_node(fs, dir, vnode); 715 } else { 716 // this is the last component 717 // Note: We do not yet insert the node into the directory, as it 718 // is not yet fully initialized. Instead we return the directory 719 // vnode so that the calling function can insert it after all 720 // initialization is done. This ensures that no create notification 721 // is sent out for a vnode that is not yet fully valid. 722 *_node = vnode; 723 *_dir = dir; 724 break; 725 } 726 727 last = i; 728 dir = vnode; 729 } 730 731 out: 732 return status; 733 } 734 735 736 static status_t 737 publish_device(struct devfs* fs, const char* path, BaseDevice* device) 738 { 739 TRACE(("publish_device(path = \"%s\", device = %p)\n", path, device)); 740 741 if (sDeviceFileSystem == NULL) { 742 panic("publish_device() called before devfs mounted\n"); 743 return B_ERROR; 744 } 745 746 if (device == NULL || path == NULL || path[0] == '\0' || path[0] == '/') 747 return B_BAD_VALUE; 748 749 // TODO: this has to be done in the BaseDevice sub classes! 750 #if 0 751 // are the provided device hooks okay? 752 if (info->device_open == NULL || info->device_close == NULL 753 || info->device_free == NULL 754 || ((info->device_read == NULL || info->device_write == NULL) 755 && info->device_io == NULL)) 756 return B_BAD_VALUE; 757 #endif 758 759 struct devfs_vnode* node; 760 struct devfs_vnode* dirNode; 761 status_t status; 762 763 RecursiveLocker locker(&fs->lock); 764 765 status = new_node(fs, path, &node, &dirNode); 766 if (status != B_OK) 767 return status; 768 769 // all went fine, let's initialize the node 770 node->stream.type = S_IFCHR | 0644; 771 node->stream.u.dev.device = device; 772 device->SetID(node->id); 773 774 // the node is now fully valid and we may insert it into the dir 775 publish_node(fs, dirNode, node); 776 return B_OK; 777 } 778 779 780 /*! Construct complete device name (as used for device_open()). 781 This is safe to use only when the device is in use (and therefore 782 cannot be unpublished during the iteration). 783 */ 784 static void 785 get_device_name(struct devfs_vnode* vnode, char* buffer, size_t size) 786 { 787 RecursiveLocker _(sDeviceFileSystem->lock); 788 789 struct devfs_vnode* leaf = vnode; 790 size_t offset = 0; 791 792 // count levels 793 794 for (; vnode->parent && vnode->parent != vnode; vnode = vnode->parent) { 795 offset += strlen(vnode->name) + 1; 796 } 797 798 // construct full path name 799 800 for (vnode = leaf; vnode->parent && vnode->parent != vnode; 801 vnode = vnode->parent) { 802 size_t length = strlen(vnode->name); 803 size_t start = offset - length - 1; 804 805 if (size >= offset) { 806 strcpy(buffer + start, vnode->name); 807 if (vnode != leaf) 808 buffer[offset - 1] = '/'; 809 } 810 811 offset = start; 812 } 813 } 814 815 816 static int 817 dump_node(int argc, char** argv) 818 { 819 if (argc != 2) { 820 print_debugger_command_usage(argv[0]); 821 return 0; 822 } 823 824 struct devfs_vnode* vnode = (struct devfs_vnode*)parse_expression(argv[1]); 825 if (vnode == NULL) { 826 kprintf("invalid node address\n"); 827 return 0; 828 } 829 830 kprintf("DEVFS NODE: %p\n", vnode); 831 kprintf(" id: %" B_PRIdINO "\n", vnode->id); 832 kprintf(" name: \"%s\"\n", vnode->name); 833 kprintf(" type: %x\n", vnode->stream.type); 834 kprintf(" parent: %p\n", vnode->parent); 835 kprintf(" dir next: %p\n", vnode->dir_next); 836 837 if (S_ISDIR(vnode->stream.type)) { 838 kprintf(" dir scanned: %" B_PRId32 "\n", vnode->stream.u.dir.scanned); 839 kprintf(" contents:\n"); 840 841 devfs_vnode* children = vnode->stream.u.dir.dir_head; 842 while (children != NULL) { 843 kprintf(" %p, id %" B_PRIdINO "\n", children, children->id); 844 children = children->dir_next; 845 } 846 } else if (S_ISLNK(vnode->stream.type)) { 847 kprintf(" symlink to: %s\n", vnode->stream.u.symlink.path); 848 } else { 849 kprintf(" device: %p\n", vnode->stream.u.dev.device); 850 kprintf(" partition: %p\n", vnode->stream.u.dev.partition); 851 if (vnode->stream.u.dev.partition != NULL) { 852 partition_info& info = vnode->stream.u.dev.partition->info; 853 kprintf(" raw device node: %p\n", 854 vnode->stream.u.dev.partition->raw_device); 855 kprintf(" offset: %" B_PRIdOFF "\n", info.offset); 856 kprintf(" size: %" B_PRIdOFF "\n", info.size); 857 kprintf(" block size: %" B_PRId32 "\n", info.logical_block_size); 858 kprintf(" session: %" B_PRId32 "\n", info.session); 859 kprintf(" partition: %" B_PRId32 "\n", info.partition); 860 kprintf(" device: %s\n", info.device); 861 set_debug_variable("_raw", 862 (addr_t)vnode->stream.u.dev.partition->raw_device); 863 } 864 } 865 866 return 0; 867 } 868 869 870 static int 871 dump_cookie(int argc, char** argv) 872 { 873 if (argc != 2) { 874 print_debugger_command_usage(argv[0]); 875 return 0; 876 } 877 878 uint64 address; 879 if (!evaluate_debug_expression(argv[1], &address, false)) 880 return 0; 881 882 struct devfs_cookie* cookie = (devfs_cookie*)(addr_t)address; 883 884 kprintf("DEVFS COOKIE: %p\n", cookie); 885 kprintf(" device_cookie: %p\n", cookie->device_cookie); 886 887 return 0; 888 } 889 890 891 // #pragma mark - file system interface 892 893 894 static status_t 895 devfs_mount(fs_volume* volume, const char* devfs, uint32 flags, 896 const char* args, ino_t* _rootNodeID) 897 { 898 struct devfs_vnode* vnode; 899 struct devfs* fs; 900 status_t err; 901 902 TRACE(("devfs_mount: entry\n")); 903 904 if (sDeviceFileSystem) { 905 TRACE(("double mount of devfs attempted\n")); 906 err = B_ERROR; 907 goto err; 908 } 909 910 fs = (struct devfs*)malloc(sizeof(struct devfs)); 911 if (fs == NULL) { 912 err = B_NO_MEMORY; 913 goto err; 914 } 915 916 volume->private_volume = fs; 917 volume->ops = &kVolumeOps; 918 fs->volume = volume; 919 fs->id = volume->id; 920 fs->next_vnode_id = 0; 921 922 recursive_lock_init(&fs->lock, "devfs lock"); 923 924 fs->vnode_hash = new(std::nothrow) NodeTable(); 925 if (fs->vnode_hash == NULL || fs->vnode_hash->Init(DEVFS_HASH_SIZE) != B_OK) { 926 err = B_NO_MEMORY; 927 goto err2; 928 } 929 930 // create a vnode 931 vnode = devfs_create_vnode(fs, NULL, ""); 932 if (vnode == NULL) { 933 err = B_NO_MEMORY; 934 goto err3; 935 } 936 937 // set it up 938 vnode->parent = vnode; 939 940 // create a dir stream for it to hold 941 init_directory_vnode(vnode, 0755); 942 fs->root_vnode = vnode; 943 944 fs->vnode_hash->Insert(vnode); 945 publish_vnode(volume, vnode->id, vnode, &kVnodeOps, vnode->stream.type, 0); 946 947 *_rootNodeID = vnode->id; 948 sDeviceFileSystem = fs; 949 return B_OK; 950 951 err3: 952 delete fs->vnode_hash; 953 err2: 954 recursive_lock_destroy(&fs->lock); 955 free(fs); 956 err: 957 return err; 958 } 959 960 961 static status_t 962 devfs_unmount(fs_volume* _volume) 963 { 964 struct devfs* fs = (struct devfs*)_volume->private_volume; 965 struct devfs_vnode* vnode; 966 967 TRACE(("devfs_unmount: entry fs = %p\n", fs)); 968 969 recursive_lock_lock(&fs->lock); 970 971 // release the reference to the root 972 put_vnode(fs->volume, fs->root_vnode->id); 973 974 // delete all of the vnodes 975 NodeTable::Iterator i(fs->vnode_hash); 976 while (i.HasNext()) { 977 vnode = i.Next(); 978 devfs_delete_vnode(fs, vnode, true); 979 } 980 delete fs->vnode_hash; 981 982 recursive_lock_destroy(&fs->lock); 983 free(fs); 984 985 return B_OK; 986 } 987 988 989 static status_t 990 devfs_sync(fs_volume* _volume) 991 { 992 TRACE(("devfs_sync: entry\n")); 993 994 return B_OK; 995 } 996 997 998 static status_t 999 devfs_lookup(fs_volume* _volume, fs_vnode* _dir, const char* name, ino_t* _id) 1000 { 1001 struct devfs* fs = (struct devfs*)_volume->private_volume; 1002 struct devfs_vnode* dir = (struct devfs_vnode*)_dir->private_node; 1003 struct devfs_vnode* vnode; 1004 status_t status; 1005 1006 TRACE(("devfs_lookup: entry dir %p, name '%s'\n", dir, name)); 1007 1008 if (!S_ISDIR(dir->stream.type)) 1009 return B_NOT_A_DIRECTORY; 1010 1011 // Make sure the directory contents are up to date 1012 scan_for_drivers_if_needed(dir); 1013 1014 RecursiveLocker locker(&fs->lock); 1015 1016 // look it up 1017 vnode = devfs_find_in_dir(dir, name); 1018 if (vnode == NULL) { 1019 // We don't have to rescan here, because thanks to node monitoring 1020 // we already know it does not exist 1021 return B_ENTRY_NOT_FOUND; 1022 } 1023 1024 status = get_vnode(fs->volume, vnode->id, NULL); 1025 if (status < B_OK) 1026 return status; 1027 1028 *_id = vnode->id; 1029 1030 return B_OK; 1031 } 1032 1033 1034 static status_t 1035 devfs_get_vnode_name(fs_volume* _volume, fs_vnode* _vnode, char* buffer, 1036 size_t bufferSize) 1037 { 1038 struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; 1039 1040 TRACE(("devfs_get_vnode_name: vnode = %p\n", vnode)); 1041 1042 strlcpy(buffer, vnode->name, bufferSize); 1043 return B_OK; 1044 } 1045 1046 1047 static status_t 1048 devfs_get_vnode(fs_volume* _volume, ino_t id, fs_vnode* _vnode, int* _type, 1049 uint32* _flags, bool reenter) 1050 { 1051 struct devfs* fs = (struct devfs*)_volume->private_volume; 1052 1053 TRACE(("devfs_get_vnode: asking for vnode id = %" B_PRIdINO 1054 ", vnode = %p, r %d\n", id, _vnode, reenter)); 1055 1056 RecursiveLocker _(fs->lock); 1057 1058 struct devfs_vnode* vnode = fs->vnode_hash->Lookup(id); 1059 if (vnode == NULL) 1060 return B_ENTRY_NOT_FOUND; 1061 1062 TRACE(("devfs_get_vnode: looked it up at %p\n", vnode)); 1063 1064 _vnode->private_node = vnode; 1065 _vnode->ops = &kVnodeOps; 1066 *_type = vnode->stream.type; 1067 *_flags = 0; 1068 return B_OK; 1069 } 1070 1071 1072 static status_t 1073 devfs_put_vnode(fs_volume* _volume, fs_vnode* _vnode, bool reenter) 1074 { 1075 #ifdef TRACE_DEVFS 1076 struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; 1077 1078 TRACE(("devfs_put_vnode: entry on vnode %p, id = %" B_PRIdINO 1079 ", reenter %d\n", vnode, vnode->id, reenter)); 1080 #endif 1081 1082 return B_OK; 1083 } 1084 1085 1086 static status_t 1087 devfs_remove_vnode(fs_volume* _volume, fs_vnode* _v, bool reenter) 1088 { 1089 struct devfs* fs = (struct devfs*)_volume->private_volume; 1090 struct devfs_vnode* vnode = (struct devfs_vnode*)_v->private_node; 1091 1092 TRACE(("devfs_removevnode: remove %p (%" B_PRIdINO "), reenter %d\n", 1093 vnode, vnode->id, reenter)); 1094 1095 RecursiveLocker locker(&fs->lock); 1096 1097 if (vnode->dir_next) { 1098 // can't remove node if it's linked to the dir 1099 panic("devfs_removevnode: vnode %p asked to be removed is present in dir\n", vnode); 1100 } 1101 1102 devfs_delete_vnode(fs, vnode, false); 1103 1104 return B_OK; 1105 } 1106 1107 1108 static status_t 1109 devfs_open(fs_volume* _volume, fs_vnode* _vnode, int openMode, 1110 void** _cookie) 1111 { 1112 struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; 1113 struct devfs_cookie* cookie; 1114 status_t status = B_OK; 1115 1116 cookie = (struct devfs_cookie*)malloc(sizeof(struct devfs_cookie)); 1117 if (cookie == NULL) 1118 return B_NO_MEMORY; 1119 1120 TRACE(("devfs_open: vnode %p, openMode 0x%x, cookie %p\n", vnode, openMode, 1121 cookie)); 1122 1123 cookie->device_cookie = NULL; 1124 1125 if (S_ISCHR(vnode->stream.type)) { 1126 BaseDevice* device = vnode->stream.u.dev.device; 1127 status = device->InitDevice(); 1128 if (status != B_OK) { 1129 free(cookie); 1130 return status; 1131 } 1132 1133 char path[B_FILE_NAME_LENGTH]; 1134 get_device_name(vnode, path, sizeof(path)); 1135 1136 status = device->Open(path, openMode, &cookie->device_cookie); 1137 if (status != B_OK) 1138 device->UninitDevice(); 1139 } 1140 1141 if (status != B_OK) 1142 free(cookie); 1143 else 1144 *_cookie = cookie; 1145 1146 return status; 1147 } 1148 1149 1150 static status_t 1151 devfs_close(fs_volume* _volume, fs_vnode* _vnode, void* _cookie) 1152 { 1153 struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; 1154 struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie; 1155 1156 TRACE(("devfs_close: entry vnode %p, cookie %p\n", vnode, cookie)); 1157 1158 if (S_ISCHR(vnode->stream.type)) { 1159 // pass the call through to the underlying device 1160 return vnode->stream.u.dev.device->Close(cookie->device_cookie); 1161 } 1162 1163 return B_OK; 1164 } 1165 1166 1167 static status_t 1168 devfs_free_cookie(fs_volume* _volume, fs_vnode* _vnode, void* _cookie) 1169 { 1170 struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; 1171 struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie; 1172 1173 TRACE(("devfs_freecookie: entry vnode %p, cookie %p\n", vnode, cookie)); 1174 1175 if (S_ISCHR(vnode->stream.type)) { 1176 // pass the call through to the underlying device 1177 vnode->stream.u.dev.device->Free(cookie->device_cookie); 1178 vnode->stream.u.dev.device->UninitDevice(); 1179 } 1180 1181 free(cookie); 1182 return B_OK; 1183 } 1184 1185 1186 static status_t 1187 devfs_fsync(fs_volume* _volume, fs_vnode* _v) 1188 { 1189 return B_OK; 1190 } 1191 1192 1193 static status_t 1194 devfs_read_link(fs_volume* _volume, fs_vnode* _link, char* buffer, 1195 size_t* _bufferSize) 1196 { 1197 struct devfs_vnode* link = (struct devfs_vnode*)_link->private_node; 1198 1199 if (!S_ISLNK(link->stream.type)) 1200 return B_BAD_VALUE; 1201 1202 memcpy(buffer, link->stream.u.symlink.path, min_c(*_bufferSize, 1203 link->stream.u.symlink.length)); 1204 1205 *_bufferSize = link->stream.u.symlink.length; 1206 1207 return B_OK; 1208 } 1209 1210 1211 static status_t 1212 devfs_read(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, off_t pos, 1213 void* buffer, size_t* _length) 1214 { 1215 struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; 1216 struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie; 1217 1218 //TRACE(("devfs_read: vnode %p, cookie %p, pos %lld, len %p\n", 1219 // vnode, cookie, pos, _length)); 1220 1221 if (!S_ISCHR(vnode->stream.type)) 1222 return B_BAD_VALUE; 1223 1224 if (pos < 0) 1225 return B_BAD_VALUE; 1226 1227 if (vnode->stream.u.dev.partition != NULL) { 1228 if (pos >= vnode->stream.u.dev.partition->info.size) 1229 return B_BAD_VALUE; 1230 1231 translate_partition_access(vnode->stream.u.dev.partition, pos, 1232 *_length); 1233 } 1234 1235 if (*_length == 0) 1236 return B_OK; 1237 1238 // pass the call through to the device 1239 return vnode->stream.u.dev.device->Read(cookie->device_cookie, pos, buffer, 1240 _length); 1241 } 1242 1243 1244 static status_t 1245 devfs_write(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, off_t pos, 1246 const void* buffer, size_t* _length) 1247 { 1248 struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; 1249 struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie; 1250 1251 //TRACE(("devfs_write: vnode %p, cookie %p, pos %lld, len %p\n", 1252 // vnode, cookie, pos, _length)); 1253 1254 if (!S_ISCHR(vnode->stream.type)) 1255 return B_BAD_VALUE; 1256 1257 if (pos < 0) 1258 return B_BAD_VALUE; 1259 1260 if (vnode->stream.u.dev.partition != NULL) { 1261 if (pos >= vnode->stream.u.dev.partition->info.size) 1262 return B_BAD_VALUE; 1263 1264 translate_partition_access(vnode->stream.u.dev.partition, pos, 1265 *_length); 1266 } 1267 1268 if (*_length == 0) 1269 return B_OK; 1270 1271 return vnode->stream.u.dev.device->Write(cookie->device_cookie, pos, buffer, 1272 _length); 1273 } 1274 1275 1276 static status_t 1277 devfs_create_dir(fs_volume* _volume, fs_vnode* _dir, const char* name, 1278 int perms) 1279 { 1280 struct devfs* fs = (struct devfs*)_volume->private_volume; 1281 struct devfs_vnode* dir = (struct devfs_vnode*)_dir->private_node; 1282 1283 struct devfs_vnode* vnode = devfs_find_in_dir(dir, name); 1284 if (vnode != NULL) { 1285 return EEXIST; 1286 } 1287 1288 vnode = devfs_create_vnode(fs, dir, name); 1289 if (vnode == NULL) { 1290 return B_NO_MEMORY; 1291 } 1292 1293 // set up the new directory 1294 init_directory_vnode(vnode, perms); 1295 publish_node(sDeviceFileSystem, dir, vnode); 1296 1297 return B_OK; 1298 } 1299 1300 1301 static status_t 1302 devfs_open_dir(fs_volume* _volume, fs_vnode* _vnode, void** _cookie) 1303 { 1304 struct devfs* fs = (struct devfs*)_volume->private_volume; 1305 struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; 1306 struct devfs_dir_cookie* cookie; 1307 1308 TRACE(("devfs_open_dir: vnode %p\n", vnode)); 1309 1310 if (!S_ISDIR(vnode->stream.type)) 1311 return B_BAD_VALUE; 1312 1313 cookie = (devfs_dir_cookie*)malloc(sizeof(devfs_dir_cookie)); 1314 if (cookie == NULL) 1315 return B_NO_MEMORY; 1316 1317 // make sure the directory has up-to-date contents 1318 scan_for_drivers_if_needed(vnode); 1319 1320 RecursiveLocker locker(&fs->lock); 1321 1322 cookie->current = vnode->stream.u.dir.dir_head; 1323 cookie->state = ITERATION_STATE_BEGIN; 1324 1325 list_add_item(&vnode->stream.u.dir.cookies, cookie); 1326 *_cookie = cookie; 1327 1328 return B_OK; 1329 } 1330 1331 1332 static status_t 1333 devfs_free_dir_cookie(fs_volume* _volume, fs_vnode* _vnode, void* _cookie) 1334 { 1335 struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; 1336 struct devfs_dir_cookie* cookie = (devfs_dir_cookie*)_cookie; 1337 struct devfs* fs = (struct devfs*)_volume->private_volume; 1338 1339 TRACE(("devfs_free_dir_cookie: entry vnode %p, cookie %p\n", vnode, cookie)); 1340 1341 RecursiveLocker locker(&fs->lock); 1342 1343 list_remove_item(&vnode->stream.u.dir.cookies, cookie); 1344 free(cookie); 1345 return B_OK; 1346 } 1347 1348 1349 static status_t 1350 devfs_read_dir(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, 1351 struct dirent* dirent, size_t bufferSize, uint32* _num) 1352 { 1353 struct devfs_vnode* vnode = (devfs_vnode*)_vnode->private_node; 1354 struct devfs_dir_cookie* cookie = (devfs_dir_cookie*)_cookie; 1355 struct devfs* fs = (struct devfs*)_volume->private_volume; 1356 status_t status = B_OK; 1357 struct devfs_vnode* childNode = NULL; 1358 const char* name = NULL; 1359 struct devfs_vnode* nextChildNode = NULL; 1360 int32 nextState = cookie->state; 1361 1362 TRACE(("devfs_read_dir: vnode %p, cookie %p, buffer %p, size %ld\n", 1363 _vnode, cookie, dirent, bufferSize)); 1364 1365 if (!S_ISDIR(vnode->stream.type)) 1366 return B_BAD_VALUE; 1367 1368 RecursiveLocker locker(&fs->lock); 1369 1370 switch (cookie->state) { 1371 case ITERATION_STATE_DOT: 1372 childNode = vnode; 1373 name = "."; 1374 nextChildNode = vnode->stream.u.dir.dir_head; 1375 nextState = cookie->state + 1; 1376 break; 1377 case ITERATION_STATE_DOT_DOT: 1378 childNode = vnode->parent; 1379 name = ".."; 1380 nextChildNode = vnode->stream.u.dir.dir_head; 1381 nextState = cookie->state + 1; 1382 break; 1383 default: 1384 childNode = cookie->current; 1385 if (childNode) { 1386 name = childNode->name; 1387 nextChildNode = childNode->dir_next; 1388 } 1389 break; 1390 } 1391 1392 if (!childNode) { 1393 *_num = 0; 1394 return B_OK; 1395 } 1396 1397 dirent->d_dev = fs->id; 1398 dirent->d_ino = childNode->id; 1399 dirent->d_reclen = offsetof(struct dirent, d_name) + strlen(name) + 1; 1400 1401 if (dirent->d_reclen > bufferSize) 1402 return ENOBUFS; 1403 1404 status = user_strlcpy(dirent->d_name, name, 1405 bufferSize - offsetof(struct dirent, d_name)); 1406 if (status < B_OK) 1407 return status; 1408 1409 cookie->current = nextChildNode; 1410 cookie->state = nextState; 1411 *_num = 1; 1412 1413 return B_OK; 1414 } 1415 1416 1417 static status_t 1418 devfs_rewind_dir(fs_volume* _volume, fs_vnode* _vnode, void* _cookie) 1419 { 1420 struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; 1421 struct devfs_dir_cookie* cookie = (devfs_dir_cookie*)_cookie; 1422 struct devfs* fs = (struct devfs*)_volume->private_volume; 1423 1424 TRACE(("devfs_rewind_dir: vnode %p, cookie %p\n", vnode, cookie)); 1425 1426 if (!S_ISDIR(vnode->stream.type)) 1427 return B_BAD_VALUE; 1428 1429 RecursiveLocker locker(&fs->lock); 1430 1431 cookie->current = vnode->stream.u.dir.dir_head; 1432 cookie->state = ITERATION_STATE_BEGIN; 1433 1434 return B_OK; 1435 } 1436 1437 1438 /*! Forwards the opcode to the device driver, but also handles some devfs 1439 specific functionality, like partitions. 1440 */ 1441 static status_t 1442 devfs_ioctl(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, uint32 op, 1443 void* buffer, size_t length) 1444 { 1445 struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; 1446 struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie; 1447 1448 TRACE(("devfs_ioctl: vnode %p, cookie %p, op %" B_PRIu32 1449 ", buf %p, len %" B_PRIuSIZE "\n", 1450 vnode, cookie, op, buffer, length)); 1451 1452 // we are actually checking for a *device* here, we don't make the 1453 // distinction between char and block devices 1454 if (S_ISCHR(vnode->stream.type)) { 1455 switch (op) { 1456 case B_GET_GEOMETRY: 1457 { 1458 struct devfs_partition* partition 1459 = vnode->stream.u.dev.partition; 1460 if (partition == NULL) 1461 break; 1462 1463 device_geometry geometry; 1464 status_t status = vnode->stream.u.dev.device->Control( 1465 cookie->device_cookie, op, &geometry, length); 1466 if (status != B_OK) 1467 return status; 1468 1469 // patch values to match partition size 1470 if (geometry.bytes_per_sector == 0) 1471 geometry.bytes_per_sector = 512; 1472 1473 devfs_compute_geometry_size(&geometry, 1474 partition->info.size / geometry.bytes_per_sector, 1475 geometry.bytes_per_sector); 1476 1477 return user_memcpy(buffer, &geometry, sizeof(device_geometry)); 1478 } 1479 1480 case B_TRIM_DEVICE: 1481 { 1482 struct devfs_partition* partition 1483 = vnode->stream.u.dev.partition; 1484 1485 fs_trim_data* trimData; 1486 MemoryDeleter deleter; 1487 status_t status = get_trim_data_from_user(buffer, length, 1488 deleter, trimData); 1489 if (status != B_OK) 1490 return status; 1491 1492 #ifdef DEBUG_TRIM 1493 dprintf("TRIM: devfs: received TRIM ranges (bytes):\n"); 1494 for (uint32 i = 0; i < trimData->range_count; i++) { 1495 dprintf("[%3" B_PRIu32 "] %" B_PRIu64 " : %" 1496 B_PRIu64 "\n", i, 1497 trimData->ranges[i].offset, 1498 trimData->ranges[i].size); 1499 } 1500 #endif 1501 1502 if (partition != NULL) { 1503 // If there is a partition, offset all ranges according 1504 // to the partition start. 1505 // Range size may be reduced to fit the partition size. 1506 for (uint32 i = 0; i < trimData->range_count; i++) { 1507 if (!translate_partition_access(partition, 1508 trimData->ranges[i].offset, 1509 trimData->ranges[i].size)) { 1510 return B_BAD_VALUE; 1511 } 1512 } 1513 1514 #ifdef DEBUG_TRIM 1515 dprintf("TRIM: devfs: TRIM ranges after partition" 1516 " translation (bytes):\n"); 1517 for (uint32 i = 0; i < trimData->range_count; i++) { 1518 dprintf("[%3" B_PRIu32 "] %" B_PRIu64 " : %" 1519 B_PRIu64 "\n", i, 1520 trimData->ranges[i].offset, 1521 trimData->ranges[i].size); 1522 } 1523 #endif 1524 } 1525 1526 status = vnode->stream.u.dev.device->Control( 1527 cookie->device_cookie, op, trimData, length); 1528 1529 // Copy the data back to userland (it contains the number of 1530 // trimmed bytes) 1531 if (status == B_OK) 1532 status = copy_trim_data_to_user(buffer, trimData); 1533 1534 return status; 1535 } 1536 1537 case B_GET_PARTITION_INFO: 1538 { 1539 struct devfs_partition* partition 1540 = vnode->stream.u.dev.partition; 1541 if (!S_ISCHR(vnode->stream.type) 1542 || partition == NULL 1543 || length != sizeof(partition_info)) 1544 return B_BAD_VALUE; 1545 1546 return user_memcpy(buffer, &partition->info, 1547 sizeof(partition_info)); 1548 } 1549 1550 case B_SET_PARTITION: 1551 return B_NOT_ALLOWED; 1552 1553 case B_GET_PATH_FOR_DEVICE: 1554 { 1555 char path[256]; 1556 // TODO: we might want to actually find the mountpoint 1557 // of that instance of devfs... 1558 // but for now we assume it's mounted on /dev 1559 strcpy(path, "/dev/"); 1560 get_device_name(vnode, path + 5, sizeof(path) - 5); 1561 if (length && (length <= strlen(path))) 1562 return ERANGE; 1563 return user_strlcpy((char*)buffer, path, sizeof(path)); 1564 } 1565 1566 // old unsupported R5 private stuff 1567 1568 case B_GET_NEXT_OPEN_DEVICE: 1569 dprintf("devfs: unsupported legacy ioctl B_GET_NEXT_OPEN_DEVICE\n"); 1570 return B_UNSUPPORTED; 1571 case B_ADD_FIXED_DRIVER: 1572 dprintf("devfs: unsupported legacy ioctl B_ADD_FIXED_DRIVER\n"); 1573 return B_UNSUPPORTED; 1574 case B_REMOVE_FIXED_DRIVER: 1575 dprintf("devfs: unsupported legacy ioctl B_REMOVE_FIXED_DRIVER\n"); 1576 return B_UNSUPPORTED; 1577 1578 } 1579 1580 return vnode->stream.u.dev.device->Control(cookie->device_cookie, 1581 op, buffer, length); 1582 } 1583 1584 return B_BAD_VALUE; 1585 } 1586 1587 1588 static status_t 1589 devfs_set_flags(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, 1590 int flags) 1591 { 1592 struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; 1593 struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie; 1594 1595 // we need to pass the O_NONBLOCK flag to the underlying device 1596 1597 if (!S_ISCHR(vnode->stream.type)) 1598 return B_NOT_ALLOWED; 1599 1600 return vnode->stream.u.dev.device->Control(cookie->device_cookie, 1601 flags & O_NONBLOCK ? B_SET_NONBLOCKING_IO : B_SET_BLOCKING_IO, NULL, 0); 1602 } 1603 1604 1605 static status_t 1606 devfs_select(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, 1607 uint8 event, selectsync* sync) 1608 { 1609 struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; 1610 struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie; 1611 1612 if (!S_ISCHR(vnode->stream.type)) 1613 return B_NOT_ALLOWED; 1614 1615 // If the device has no select() hook, notify select() now. 1616 if (!vnode->stream.u.dev.device->HasSelect()) { 1617 if (!SELECT_TYPE_IS_OUTPUT_ONLY(event)) 1618 notify_select_event((selectsync*)sync, event); 1619 return B_UNSUPPORTED; 1620 } 1621 1622 return vnode->stream.u.dev.device->Select(cookie->device_cookie, event, 1623 (selectsync*)sync); 1624 } 1625 1626 1627 static status_t 1628 devfs_deselect(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, 1629 uint8 event, selectsync* sync) 1630 { 1631 struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; 1632 struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie; 1633 1634 if (!S_ISCHR(vnode->stream.type)) 1635 return B_NOT_ALLOWED; 1636 1637 if (!vnode->stream.u.dev.device->HasDeselect()) 1638 return B_OK; 1639 1640 return vnode->stream.u.dev.device->Deselect(cookie->device_cookie, event, 1641 (selectsync*)sync); 1642 } 1643 1644 1645 static bool 1646 devfs_can_page(fs_volume* _volume, fs_vnode* _vnode, void* cookie) 1647 { 1648 #if 0 1649 struct devfs_vnode* vnode = (devfs_vnode*)_vnode->private_node; 1650 1651 //TRACE(("devfs_canpage: vnode %p\n", vnode)); 1652 1653 if (!S_ISCHR(vnode->stream.type) 1654 || vnode->stream.u.dev.device->Node() == NULL 1655 || cookie == NULL) 1656 return false; 1657 1658 return vnode->stream.u.dev.device->HasRead() 1659 || vnode->stream.u.dev.device->HasIO(); 1660 #endif 1661 // TODO: Obsolete hook! 1662 return false; 1663 } 1664 1665 1666 static status_t 1667 devfs_read_pages(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, 1668 off_t pos, const iovec* vecs, size_t count, size_t* _numBytes) 1669 { 1670 struct devfs_vnode* vnode = (devfs_vnode*)_vnode->private_node; 1671 struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie; 1672 1673 //TRACE(("devfs_read_pages: vnode %p, vecs %p, count = %lu, pos = %lld, size = %lu\n", vnode, vecs, count, pos, *_numBytes)); 1674 1675 if (!S_ISCHR(vnode->stream.type) 1676 || (!vnode->stream.u.dev.device->HasRead() 1677 && !vnode->stream.u.dev.device->HasIO()) 1678 || cookie == NULL) 1679 return B_NOT_ALLOWED; 1680 1681 if (pos < 0) 1682 return B_BAD_VALUE; 1683 1684 if (vnode->stream.u.dev.partition != NULL) { 1685 if (pos >= vnode->stream.u.dev.partition->info.size) 1686 return B_BAD_VALUE; 1687 1688 translate_partition_access(vnode->stream.u.dev.partition, pos, 1689 *_numBytes); 1690 } 1691 1692 if (vnode->stream.u.dev.device->HasIO()) { 1693 // TODO: use io_requests for this! 1694 } 1695 1696 // emulate read_pages() using read() 1697 1698 status_t error = B_OK; 1699 size_t bytesTransferred = 0; 1700 1701 size_t remainingBytes = *_numBytes; 1702 for (size_t i = 0; i < count && remainingBytes > 0; i++) { 1703 size_t toRead = min_c(vecs[i].iov_len, remainingBytes); 1704 size_t length = toRead; 1705 1706 error = vnode->stream.u.dev.device->Read(cookie->device_cookie, pos, 1707 vecs[i].iov_base, &length); 1708 if (error != B_OK) 1709 break; 1710 1711 pos += length; 1712 bytesTransferred += length; 1713 remainingBytes -= length; 1714 1715 if (length < toRead) 1716 break; 1717 } 1718 1719 *_numBytes = bytesTransferred; 1720 1721 return bytesTransferred > 0 ? B_OK : error; 1722 } 1723 1724 1725 static status_t 1726 devfs_write_pages(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, 1727 off_t pos, const iovec* vecs, size_t count, size_t* _numBytes) 1728 { 1729 struct devfs_vnode* vnode = (devfs_vnode*)_vnode->private_node; 1730 struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie; 1731 1732 //TRACE(("devfs_write_pages: vnode %p, vecs %p, count = %lu, pos = %lld, size = %lu\n", vnode, vecs, count, pos, *_numBytes)); 1733 1734 if (!S_ISCHR(vnode->stream.type) 1735 || (!vnode->stream.u.dev.device->HasWrite() 1736 && !vnode->stream.u.dev.device->HasIO()) 1737 || cookie == NULL) 1738 return B_NOT_ALLOWED; 1739 1740 if (pos < 0) 1741 return B_BAD_VALUE; 1742 1743 if (vnode->stream.u.dev.partition != NULL) { 1744 if (pos >= vnode->stream.u.dev.partition->info.size) 1745 return B_BAD_VALUE; 1746 1747 translate_partition_access(vnode->stream.u.dev.partition, pos, 1748 *_numBytes); 1749 } 1750 1751 if (vnode->stream.u.dev.device->HasIO()) { 1752 // TODO: use io_requests for this! 1753 } 1754 1755 // emulate write_pages() using write() 1756 1757 status_t error = B_OK; 1758 size_t bytesTransferred = 0; 1759 1760 size_t remainingBytes = *_numBytes; 1761 for (size_t i = 0; i < count && remainingBytes > 0; i++) { 1762 size_t toWrite = min_c(vecs[i].iov_len, remainingBytes); 1763 size_t length = toWrite; 1764 1765 error = vnode->stream.u.dev.device->Write(cookie->device_cookie, pos, 1766 vecs[i].iov_base, &length); 1767 if (error != B_OK) 1768 break; 1769 1770 pos += length; 1771 bytesTransferred += length; 1772 remainingBytes -= length; 1773 1774 if (length < toWrite) 1775 break; 1776 } 1777 1778 *_numBytes = bytesTransferred; 1779 1780 return bytesTransferred > 0 ? B_OK : error; 1781 } 1782 1783 1784 static status_t 1785 devfs_io(fs_volume* volume, fs_vnode* _vnode, void* _cookie, 1786 io_request* request) 1787 { 1788 TRACE(("[%d] devfs_io(request: %p)\n", find_thread(NULL), request)); 1789 1790 devfs_vnode* vnode = (devfs_vnode*)_vnode->private_node; 1791 devfs_cookie* cookie = (devfs_cookie*)_cookie; 1792 1793 if (!S_ISCHR(vnode->stream.type) || cookie == NULL) { 1794 request->SetStatusAndNotify(B_NOT_ALLOWED); 1795 return B_NOT_ALLOWED; 1796 } 1797 1798 if (!vnode->stream.u.dev.device->HasIO()) 1799 return B_UNSUPPORTED; 1800 1801 if (vnode->stream.u.dev.partition != NULL) { 1802 if (request->Offset() + (off_t)request->Length() 1803 > vnode->stream.u.dev.partition->info.size) { 1804 request->SetStatusAndNotify(B_BAD_VALUE); 1805 return B_BAD_VALUE; 1806 } 1807 translate_partition_access(vnode->stream.u.dev.partition, request); 1808 } 1809 1810 return vnode->stream.u.dev.device->IO(cookie->device_cookie, request); 1811 } 1812 1813 1814 static status_t 1815 devfs_read_stat(fs_volume* _volume, fs_vnode* _vnode, struct stat* stat) 1816 { 1817 struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; 1818 1819 TRACE(("devfs_read_stat: vnode %p (%" B_PRIdINO "), stat %p\n", 1820 vnode, vnode->id, stat)); 1821 1822 stat->st_ino = vnode->id; 1823 stat->st_rdev = vnode->id; 1824 stat->st_size = 0; 1825 stat->st_mode = vnode->stream.type; 1826 1827 stat->st_nlink = 1; 1828 stat->st_blksize = 65536; 1829 stat->st_blocks = 0; 1830 1831 stat->st_uid = vnode->uid; 1832 stat->st_gid = vnode->gid; 1833 1834 stat->st_atim = current_timespec(); 1835 stat->st_mtim = stat->st_ctim = vnode->modification_time; 1836 stat->st_crtim = vnode->creation_time; 1837 1838 // TODO: this only works for partitions right now - if we should decide 1839 // to keep this feature, we should have a better solution 1840 if (S_ISCHR(vnode->stream.type)) { 1841 //device_geometry geometry; 1842 1843 // if it's a real block device, then let's report a useful size 1844 if (vnode->stream.u.dev.partition != NULL) { 1845 stat->st_size = vnode->stream.u.dev.partition->info.size; 1846 #if 0 1847 } else if (vnode->stream.u.dev.info->control(cookie->device_cookie, 1848 B_GET_GEOMETRY, &geometry, sizeof(struct device_geometry)) >= B_OK) { 1849 stat->st_size = 1LL * geometry.head_count * geometry.cylinder_count 1850 * geometry.sectors_per_track * geometry.bytes_per_sector; 1851 #endif 1852 } 1853 1854 // is this a real block device? then let's have it reported like that 1855 if (stat->st_size != 0) 1856 stat->st_mode = S_IFBLK | (vnode->stream.type & S_IUMSK); 1857 } else if (S_ISLNK(vnode->stream.type)) { 1858 stat->st_size = vnode->stream.u.symlink.length; 1859 } 1860 1861 return B_OK; 1862 } 1863 1864 1865 static status_t 1866 devfs_write_stat(fs_volume* _volume, fs_vnode* _vnode, const struct stat* stat, 1867 uint32 statMask) 1868 { 1869 struct devfs* fs = (struct devfs*)_volume->private_volume; 1870 struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; 1871 1872 TRACE(("devfs_write_stat: vnode %p (0x%" B_PRIdINO "), stat %p\n", 1873 vnode, vnode->id, stat)); 1874 1875 // we cannot change the size of anything 1876 if (statMask & B_STAT_SIZE) 1877 return B_BAD_VALUE; 1878 1879 RecursiveLocker locker(&fs->lock); 1880 1881 if (statMask & B_STAT_MODE) { 1882 vnode->stream.type = (vnode->stream.type & ~S_IUMSK) 1883 | (stat->st_mode & S_IUMSK); 1884 } 1885 1886 if (statMask & B_STAT_UID) 1887 vnode->uid = stat->st_uid; 1888 if (statMask & B_STAT_GID) 1889 vnode->gid = stat->st_gid; 1890 1891 if (statMask & B_STAT_MODIFICATION_TIME) 1892 vnode->modification_time = stat->st_mtim; 1893 if (statMask & B_STAT_CREATION_TIME) 1894 vnode->creation_time = stat->st_crtim; 1895 1896 notify_stat_changed(fs->id, get_parent_id(vnode), vnode->id, statMask); 1897 return B_OK; 1898 } 1899 1900 1901 static status_t 1902 devfs_std_ops(int32 op, ...) 1903 { 1904 switch (op) { 1905 case B_MODULE_INIT: 1906 add_debugger_command_etc("devfs_node", &dump_node, 1907 "Print info on a private devfs node", 1908 "<address>\n" 1909 "Prints information on a devfs node given by <address>.\n", 1910 0); 1911 add_debugger_command_etc("devfs_cookie", &dump_cookie, 1912 "Print info on a private devfs cookie", 1913 "<address>\n" 1914 "Prints information on a devfs cookie given by <address>.\n", 1915 0); 1916 1917 legacy_driver_init(); 1918 return B_OK; 1919 1920 case B_MODULE_UNINIT: 1921 remove_debugger_command("devfs_node", &dump_node); 1922 remove_debugger_command("devfs_cookie", &dump_cookie); 1923 return B_OK; 1924 1925 default: 1926 return B_ERROR; 1927 } 1928 } 1929 1930 namespace { 1931 1932 fs_volume_ops kVolumeOps = { 1933 &devfs_unmount, 1934 NULL, 1935 NULL, 1936 &devfs_sync, 1937 &devfs_get_vnode, 1938 1939 // the other operations are not supported (attributes, indices, queries) 1940 NULL, 1941 }; 1942 1943 fs_vnode_ops kVnodeOps = { 1944 &devfs_lookup, 1945 &devfs_get_vnode_name, 1946 1947 &devfs_put_vnode, 1948 &devfs_remove_vnode, 1949 1950 &devfs_can_page, 1951 &devfs_read_pages, 1952 &devfs_write_pages, 1953 1954 &devfs_io, 1955 NULL, // cancel_io() 1956 1957 NULL, // get_file_map 1958 1959 /* common */ 1960 &devfs_ioctl, 1961 &devfs_set_flags, 1962 &devfs_select, 1963 &devfs_deselect, 1964 &devfs_fsync, 1965 1966 &devfs_read_link, 1967 NULL, // symlink 1968 NULL, // link 1969 NULL, // unlink 1970 NULL, // rename 1971 1972 NULL, // access 1973 &devfs_read_stat, 1974 &devfs_write_stat, 1975 NULL, 1976 1977 /* file */ 1978 NULL, // create 1979 &devfs_open, 1980 &devfs_close, 1981 &devfs_free_cookie, 1982 &devfs_read, 1983 &devfs_write, 1984 1985 /* directory */ 1986 &devfs_create_dir, 1987 NULL, // remove_dir 1988 &devfs_open_dir, 1989 &devfs_close, 1990 // same as for files - it does nothing for directories, anyway 1991 &devfs_free_dir_cookie, 1992 &devfs_read_dir, 1993 &devfs_rewind_dir, 1994 1995 // attributes operations are not supported 1996 NULL, 1997 }; 1998 1999 } // namespace 2000 2001 file_system_module_info gDeviceFileSystem = { 2002 { 2003 "file_systems/devfs" B_CURRENT_FS_API_VERSION, 2004 0, 2005 devfs_std_ops, 2006 }, 2007 2008 "devfs", // short_name 2009 "Device File System", // pretty_name 2010 0, // DDM flags 2011 2012 NULL, // identify_partition() 2013 NULL, // scan_partition() 2014 NULL, // free_identify_partition_cookie() 2015 NULL, // free_partition_content_cookie() 2016 2017 &devfs_mount, 2018 }; 2019 2020 2021 // #pragma mark - kernel private API 2022 2023 2024 extern "C" status_t 2025 devfs_unpublish_file_device(const char* path) 2026 { 2027 // get the device node 2028 devfs_vnode* node; 2029 status_t status = get_node_for_path(sDeviceFileSystem, path, &node); 2030 if (status != B_OK) 2031 return status; 2032 2033 if (!S_ISCHR(node->stream.type)) { 2034 put_vnode(sDeviceFileSystem->volume, node->id); 2035 return B_BAD_VALUE; 2036 } 2037 2038 // if it is indeed a file device, unpublish it 2039 FileDevice* device = dynamic_cast<FileDevice*>(node->stream.u.dev.device); 2040 if (device == NULL) { 2041 put_vnode(sDeviceFileSystem->volume, node->id); 2042 return B_BAD_VALUE; 2043 } 2044 2045 status = unpublish_node(sDeviceFileSystem, node, S_IFCHR); 2046 2047 put_vnode(sDeviceFileSystem->volume, node->id); 2048 return status; 2049 } 2050 2051 2052 extern "C" status_t 2053 devfs_publish_file_device(const char* path, const char* filePath) 2054 { 2055 // create a FileDevice for the file 2056 FileDevice* device = new(std::nothrow) FileDevice; 2057 if (device == NULL) 2058 return B_NO_MEMORY; 2059 ObjectDeleter<FileDevice> deviceDeleter(device); 2060 2061 status_t error = device->Init(filePath); 2062 if (error != B_OK) 2063 return error; 2064 2065 // publish the device 2066 error = publish_device(sDeviceFileSystem, path, device); 2067 if (error != B_OK) 2068 return error; 2069 2070 deviceDeleter.Detach(); 2071 return B_OK; 2072 } 2073 2074 2075 extern "C" status_t 2076 devfs_unpublish_partition(const char* path) 2077 { 2078 devfs_vnode* node; 2079 status_t status = get_node_for_path(sDeviceFileSystem, path, &node); 2080 if (status != B_OK) 2081 return status; 2082 2083 status = unpublish_node(sDeviceFileSystem, node, S_IFCHR); 2084 put_vnode(sDeviceFileSystem->volume, node->id); 2085 return status; 2086 } 2087 2088 2089 extern "C" status_t 2090 devfs_publish_partition(const char* name, const partition_info* info) 2091 { 2092 if (name == NULL || info == NULL) 2093 return B_BAD_VALUE; 2094 TRACE(("publish partition: %s (device \"%s\", offset %" B_PRIdOFF 2095 ", size %" B_PRIdOFF ")\n", 2096 name, info->device, info->offset, info->size)); 2097 2098 devfs_vnode* device; 2099 status_t status = get_node_for_path(sDeviceFileSystem, info->device, 2100 &device); 2101 if (status != B_OK) 2102 return status; 2103 2104 status = add_partition(sDeviceFileSystem, device, name, *info); 2105 2106 put_vnode(sDeviceFileSystem->volume, device->id); 2107 return status; 2108 } 2109 2110 2111 extern "C" status_t 2112 devfs_rename_partition(const char* devicePath, const char* oldName, 2113 const char* newName) 2114 { 2115 if (oldName == NULL || newName == NULL) 2116 return B_BAD_VALUE; 2117 2118 devfs_vnode* device; 2119 status_t status = get_node_for_path(sDeviceFileSystem, devicePath, &device); 2120 if (status != B_OK) 2121 return status; 2122 2123 RecursiveLocker locker(sDeviceFileSystem->lock); 2124 devfs_vnode* node = devfs_find_in_dir(device->parent, oldName); 2125 if (node == NULL) 2126 return B_ENTRY_NOT_FOUND; 2127 2128 // check if the new path already exists 2129 if (devfs_find_in_dir(device->parent, newName)) 2130 return B_BAD_VALUE; 2131 2132 char* name = strdup(newName); 2133 if (name == NULL) 2134 return B_NO_MEMORY; 2135 2136 devfs_remove_from_dir(device->parent, node, false); 2137 2138 free(node->name); 2139 node->name = name; 2140 2141 devfs_insert_in_dir(device->parent, node, false); 2142 2143 notify_entry_moved(sDeviceFileSystem->id, device->parent->id, oldName, 2144 device->parent->id, newName, node->id); 2145 notify_stat_changed(sDeviceFileSystem->id, get_parent_id(device->parent), 2146 device->parent->id, B_STAT_MODIFICATION_TIME); 2147 2148 return B_OK; 2149 } 2150 2151 2152 extern "C" status_t 2153 devfs_publish_directory(const char* path) 2154 { 2155 RecursiveLocker locker(&sDeviceFileSystem->lock); 2156 2157 return publish_directory(sDeviceFileSystem, path); 2158 } 2159 2160 2161 extern "C" status_t 2162 devfs_unpublish_device(const char* path, bool disconnect) 2163 { 2164 devfs_vnode* node; 2165 status_t status = get_node_for_path(sDeviceFileSystem, path, &node); 2166 if (status != B_OK) 2167 return status; 2168 2169 status = unpublish_node(sDeviceFileSystem, node, S_IFCHR); 2170 2171 if (status == B_OK && disconnect) 2172 vfs_disconnect_vnode(sDeviceFileSystem->id, node->id); 2173 2174 put_vnode(sDeviceFileSystem->volume, node->id); 2175 return status; 2176 } 2177 2178 2179 // #pragma mark - device_manager private API 2180 2181 2182 status_t 2183 devfs_publish_device(const char* path, BaseDevice* device) 2184 { 2185 return publish_device(sDeviceFileSystem, path, device); 2186 } 2187 2188 2189 status_t 2190 devfs_unpublish_device(BaseDevice* device, bool disconnect) 2191 { 2192 devfs_vnode* node; 2193 status_t status = get_vnode(sDeviceFileSystem->volume, device->ID(), 2194 (void**)&node); 2195 if (status != B_OK) 2196 return status; 2197 2198 status = unpublish_node(sDeviceFileSystem, node, S_IFCHR); 2199 2200 if (status == B_OK && disconnect) 2201 vfs_disconnect_vnode(sDeviceFileSystem->id, node->id); 2202 2203 put_vnode(sDeviceFileSystem->volume, node->id); 2204 return status; 2205 } 2206 2207 2208 /*! Gets the device for a given devfs relative path. 2209 If successful the call must be balanced with a call to devfs_put_device(). 2210 */ 2211 status_t 2212 devfs_get_device(const char* path, BaseDevice*& _device) 2213 { 2214 devfs_vnode* node; 2215 status_t status = get_node_for_path(sDeviceFileSystem, path, &node); 2216 if (status != B_OK) 2217 return status; 2218 2219 if (!S_ISCHR(node->stream.type) || node->stream.u.dev.partition != NULL) { 2220 put_vnode(sDeviceFileSystem->volume, node->id); 2221 return B_BAD_VALUE; 2222 } 2223 2224 _device = node->stream.u.dev.device; 2225 return B_OK; 2226 } 2227 2228 2229 void 2230 devfs_put_device(BaseDevice* device) 2231 { 2232 put_vnode(sDeviceFileSystem->volume, device->ID()); 2233 } 2234 2235 2236 void 2237 devfs_compute_geometry_size(device_geometry* geometry, uint64 blockCount, 2238 uint32 blockSize) 2239 { 2240 geometry->head_count = 1; 2241 while (blockCount > UINT32_MAX) { 2242 geometry->head_count <<= 1; 2243 blockCount >>= 1; 2244 } 2245 2246 geometry->cylinder_count = 1; 2247 geometry->sectors_per_track = blockCount; 2248 geometry->bytes_per_sector = blockSize; 2249 } 2250 2251 2252 // #pragma mark - support API for legacy drivers 2253 2254 2255 extern "C" status_t 2256 devfs_rescan_driver(const char* driverName) 2257 { 2258 TRACE(("devfs_rescan_driver: %s\n", driverName)); 2259 2260 return legacy_driver_rescan(driverName); 2261 } 2262 2263 2264 extern "C" status_t 2265 devfs_publish_device(const char* path, device_hooks* hooks) 2266 { 2267 return legacy_driver_publish(path, hooks); 2268 } 2269