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 %Ld, 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 %Ld, 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 return notify_select_event((selectsync*)sync, event); 1619 else 1620 return B_OK; 1621 } 1622 1623 return vnode->stream.u.dev.device->Select(cookie->device_cookie, event, 1624 (selectsync*)sync); 1625 } 1626 1627 1628 static status_t 1629 devfs_deselect(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, 1630 uint8 event, selectsync* sync) 1631 { 1632 struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; 1633 struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie; 1634 1635 if (!S_ISCHR(vnode->stream.type)) 1636 return B_NOT_ALLOWED; 1637 1638 // If the device has no select() hook, notify select() now. 1639 if (!vnode->stream.u.dev.device->HasDeselect()) 1640 return B_OK; 1641 1642 return vnode->stream.u.dev.device->Deselect(cookie->device_cookie, event, 1643 (selectsync*)sync); 1644 } 1645 1646 1647 static bool 1648 devfs_can_page(fs_volume* _volume, fs_vnode* _vnode, void* cookie) 1649 { 1650 #if 0 1651 struct devfs_vnode* vnode = (devfs_vnode*)_vnode->private_node; 1652 1653 //TRACE(("devfs_canpage: vnode %p\n", vnode)); 1654 1655 if (!S_ISCHR(vnode->stream.type) 1656 || vnode->stream.u.dev.device->Node() == NULL 1657 || cookie == NULL) 1658 return false; 1659 1660 return vnode->stream.u.dev.device->HasRead() 1661 || vnode->stream.u.dev.device->HasIO(); 1662 #endif 1663 // TODO: Obsolete hook! 1664 return false; 1665 } 1666 1667 1668 static status_t 1669 devfs_read_pages(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, 1670 off_t pos, const iovec* vecs, size_t count, size_t* _numBytes) 1671 { 1672 struct devfs_vnode* vnode = (devfs_vnode*)_vnode->private_node; 1673 struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie; 1674 1675 //TRACE(("devfs_read_pages: vnode %p, vecs %p, count = %lu, pos = %Ld, size = %lu\n", vnode, vecs, count, pos, *_numBytes)); 1676 1677 if (!S_ISCHR(vnode->stream.type) 1678 || (!vnode->stream.u.dev.device->HasRead() 1679 && !vnode->stream.u.dev.device->HasIO()) 1680 || cookie == NULL) 1681 return B_NOT_ALLOWED; 1682 1683 if (pos < 0) 1684 return B_BAD_VALUE; 1685 1686 if (vnode->stream.u.dev.partition != NULL) { 1687 if (pos >= vnode->stream.u.dev.partition->info.size) 1688 return B_BAD_VALUE; 1689 1690 translate_partition_access(vnode->stream.u.dev.partition, pos, 1691 *_numBytes); 1692 } 1693 1694 if (vnode->stream.u.dev.device->HasIO()) { 1695 // TODO: use io_requests for this! 1696 } 1697 1698 // emulate read_pages() using read() 1699 1700 status_t error = B_OK; 1701 size_t bytesTransferred = 0; 1702 1703 size_t remainingBytes = *_numBytes; 1704 for (size_t i = 0; i < count && remainingBytes > 0; i++) { 1705 size_t toRead = min_c(vecs[i].iov_len, remainingBytes); 1706 size_t length = toRead; 1707 1708 error = vnode->stream.u.dev.device->Read(cookie->device_cookie, pos, 1709 vecs[i].iov_base, &length); 1710 if (error != B_OK) 1711 break; 1712 1713 pos += length; 1714 bytesTransferred += length; 1715 remainingBytes -= length; 1716 1717 if (length < toRead) 1718 break; 1719 } 1720 1721 *_numBytes = bytesTransferred; 1722 1723 return bytesTransferred > 0 ? B_OK : error; 1724 } 1725 1726 1727 static status_t 1728 devfs_write_pages(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, 1729 off_t pos, const iovec* vecs, size_t count, size_t* _numBytes) 1730 { 1731 struct devfs_vnode* vnode = (devfs_vnode*)_vnode->private_node; 1732 struct devfs_cookie* cookie = (struct devfs_cookie*)_cookie; 1733 1734 //TRACE(("devfs_write_pages: vnode %p, vecs %p, count = %lu, pos = %Ld, size = %lu\n", vnode, vecs, count, pos, *_numBytes)); 1735 1736 if (!S_ISCHR(vnode->stream.type) 1737 || (!vnode->stream.u.dev.device->HasWrite() 1738 && !vnode->stream.u.dev.device->HasIO()) 1739 || cookie == NULL) 1740 return B_NOT_ALLOWED; 1741 1742 if (pos < 0) 1743 return B_BAD_VALUE; 1744 1745 if (vnode->stream.u.dev.partition != NULL) { 1746 if (pos >= vnode->stream.u.dev.partition->info.size) 1747 return B_BAD_VALUE; 1748 1749 translate_partition_access(vnode->stream.u.dev.partition, pos, 1750 *_numBytes); 1751 } 1752 1753 if (vnode->stream.u.dev.device->HasIO()) { 1754 // TODO: use io_requests for this! 1755 } 1756 1757 // emulate write_pages() using write() 1758 1759 status_t error = B_OK; 1760 size_t bytesTransferred = 0; 1761 1762 size_t remainingBytes = *_numBytes; 1763 for (size_t i = 0; i < count && remainingBytes > 0; i++) { 1764 size_t toWrite = min_c(vecs[i].iov_len, remainingBytes); 1765 size_t length = toWrite; 1766 1767 error = vnode->stream.u.dev.device->Write(cookie->device_cookie, pos, 1768 vecs[i].iov_base, &length); 1769 if (error != B_OK) 1770 break; 1771 1772 pos += length; 1773 bytesTransferred += length; 1774 remainingBytes -= length; 1775 1776 if (length < toWrite) 1777 break; 1778 } 1779 1780 *_numBytes = bytesTransferred; 1781 1782 return bytesTransferred > 0 ? B_OK : error; 1783 } 1784 1785 1786 static status_t 1787 devfs_io(fs_volume* volume, fs_vnode* _vnode, void* _cookie, 1788 io_request* request) 1789 { 1790 TRACE(("[%d] devfs_io(request: %p)\n", find_thread(NULL), request)); 1791 1792 devfs_vnode* vnode = (devfs_vnode*)_vnode->private_node; 1793 devfs_cookie* cookie = (devfs_cookie*)_cookie; 1794 1795 if (!S_ISCHR(vnode->stream.type) || cookie == NULL) { 1796 request->SetStatusAndNotify(B_NOT_ALLOWED); 1797 return B_NOT_ALLOWED; 1798 } 1799 1800 if (!vnode->stream.u.dev.device->HasIO()) 1801 return B_UNSUPPORTED; 1802 1803 if (vnode->stream.u.dev.partition != NULL) { 1804 if (request->Offset() + (off_t)request->Length() 1805 > vnode->stream.u.dev.partition->info.size) { 1806 request->SetStatusAndNotify(B_BAD_VALUE); 1807 return B_BAD_VALUE; 1808 } 1809 translate_partition_access(vnode->stream.u.dev.partition, request); 1810 } 1811 1812 return vnode->stream.u.dev.device->IO(cookie->device_cookie, request); 1813 } 1814 1815 1816 static status_t 1817 devfs_read_stat(fs_volume* _volume, fs_vnode* _vnode, struct stat* stat) 1818 { 1819 struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; 1820 1821 TRACE(("devfs_read_stat: vnode %p (%" B_PRIdINO "), stat %p\n", 1822 vnode, vnode->id, stat)); 1823 1824 stat->st_ino = vnode->id; 1825 stat->st_rdev = vnode->id; 1826 stat->st_size = 0; 1827 stat->st_mode = vnode->stream.type; 1828 1829 stat->st_nlink = 1; 1830 stat->st_blksize = 65536; 1831 stat->st_blocks = 0; 1832 1833 stat->st_uid = vnode->uid; 1834 stat->st_gid = vnode->gid; 1835 1836 stat->st_atim = current_timespec(); 1837 stat->st_mtim = stat->st_ctim = vnode->modification_time; 1838 stat->st_crtim = vnode->creation_time; 1839 1840 // TODO: this only works for partitions right now - if we should decide 1841 // to keep this feature, we should have a better solution 1842 if (S_ISCHR(vnode->stream.type)) { 1843 //device_geometry geometry; 1844 1845 // if it's a real block device, then let's report a useful size 1846 if (vnode->stream.u.dev.partition != NULL) { 1847 stat->st_size = vnode->stream.u.dev.partition->info.size; 1848 #if 0 1849 } else if (vnode->stream.u.dev.info->control(cookie->device_cookie, 1850 B_GET_GEOMETRY, &geometry, sizeof(struct device_geometry)) >= B_OK) { 1851 stat->st_size = 1LL * geometry.head_count * geometry.cylinder_count 1852 * geometry.sectors_per_track * geometry.bytes_per_sector; 1853 #endif 1854 } 1855 1856 // is this a real block device? then let's have it reported like that 1857 if (stat->st_size != 0) 1858 stat->st_mode = S_IFBLK | (vnode->stream.type & S_IUMSK); 1859 } else if (S_ISLNK(vnode->stream.type)) { 1860 stat->st_size = vnode->stream.u.symlink.length; 1861 } 1862 1863 return B_OK; 1864 } 1865 1866 1867 static status_t 1868 devfs_write_stat(fs_volume* _volume, fs_vnode* _vnode, const struct stat* stat, 1869 uint32 statMask) 1870 { 1871 struct devfs* fs = (struct devfs*)_volume->private_volume; 1872 struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node; 1873 1874 TRACE(("devfs_write_stat: vnode %p (0x%" B_PRIdINO "), stat %p\n", 1875 vnode, vnode->id, stat)); 1876 1877 // we cannot change the size of anything 1878 if (statMask & B_STAT_SIZE) 1879 return B_BAD_VALUE; 1880 1881 RecursiveLocker locker(&fs->lock); 1882 1883 if (statMask & B_STAT_MODE) { 1884 vnode->stream.type = (vnode->stream.type & ~S_IUMSK) 1885 | (stat->st_mode & S_IUMSK); 1886 } 1887 1888 if (statMask & B_STAT_UID) 1889 vnode->uid = stat->st_uid; 1890 if (statMask & B_STAT_GID) 1891 vnode->gid = stat->st_gid; 1892 1893 if (statMask & B_STAT_MODIFICATION_TIME) 1894 vnode->modification_time = stat->st_mtim; 1895 if (statMask & B_STAT_CREATION_TIME) 1896 vnode->creation_time = stat->st_crtim; 1897 1898 notify_stat_changed(fs->id, get_parent_id(vnode), vnode->id, statMask); 1899 return B_OK; 1900 } 1901 1902 1903 static status_t 1904 devfs_std_ops(int32 op, ...) 1905 { 1906 switch (op) { 1907 case B_MODULE_INIT: 1908 add_debugger_command_etc("devfs_node", &dump_node, 1909 "Print info on a private devfs node", 1910 "<address>\n" 1911 "Prints information on a devfs node given by <address>.\n", 1912 0); 1913 add_debugger_command_etc("devfs_cookie", &dump_cookie, 1914 "Print info on a private devfs cookie", 1915 "<address>\n" 1916 "Prints information on a devfs cookie given by <address>.\n", 1917 0); 1918 1919 legacy_driver_init(); 1920 return B_OK; 1921 1922 case B_MODULE_UNINIT: 1923 remove_debugger_command("devfs_node", &dump_node); 1924 remove_debugger_command("devfs_cookie", &dump_cookie); 1925 return B_OK; 1926 1927 default: 1928 return B_ERROR; 1929 } 1930 } 1931 1932 namespace { 1933 1934 fs_volume_ops kVolumeOps = { 1935 &devfs_unmount, 1936 NULL, 1937 NULL, 1938 &devfs_sync, 1939 &devfs_get_vnode, 1940 1941 // the other operations are not supported (attributes, indices, queries) 1942 NULL, 1943 }; 1944 1945 fs_vnode_ops kVnodeOps = { 1946 &devfs_lookup, 1947 &devfs_get_vnode_name, 1948 1949 &devfs_put_vnode, 1950 &devfs_remove_vnode, 1951 1952 &devfs_can_page, 1953 &devfs_read_pages, 1954 &devfs_write_pages, 1955 1956 &devfs_io, 1957 NULL, // cancel_io() 1958 1959 NULL, // get_file_map 1960 1961 /* common */ 1962 &devfs_ioctl, 1963 &devfs_set_flags, 1964 &devfs_select, 1965 &devfs_deselect, 1966 &devfs_fsync, 1967 1968 &devfs_read_link, 1969 NULL, // symlink 1970 NULL, // link 1971 NULL, // unlink 1972 NULL, // rename 1973 1974 NULL, // access 1975 &devfs_read_stat, 1976 &devfs_write_stat, 1977 NULL, 1978 1979 /* file */ 1980 NULL, // create 1981 &devfs_open, 1982 &devfs_close, 1983 &devfs_free_cookie, 1984 &devfs_read, 1985 &devfs_write, 1986 1987 /* directory */ 1988 &devfs_create_dir, 1989 NULL, // remove_dir 1990 &devfs_open_dir, 1991 &devfs_close, 1992 // same as for files - it does nothing for directories, anyway 1993 &devfs_free_dir_cookie, 1994 &devfs_read_dir, 1995 &devfs_rewind_dir, 1996 1997 // attributes operations are not supported 1998 NULL, 1999 }; 2000 2001 } // namespace 2002 2003 file_system_module_info gDeviceFileSystem = { 2004 { 2005 "file_systems/devfs" B_CURRENT_FS_API_VERSION, 2006 0, 2007 devfs_std_ops, 2008 }, 2009 2010 "devfs", // short_name 2011 "Device File System", // pretty_name 2012 0, // DDM flags 2013 2014 NULL, // identify_partition() 2015 NULL, // scan_partition() 2016 NULL, // free_identify_partition_cookie() 2017 NULL, // free_partition_content_cookie() 2018 2019 &devfs_mount, 2020 }; 2021 2022 2023 // #pragma mark - kernel private API 2024 2025 2026 extern "C" status_t 2027 devfs_unpublish_file_device(const char* path) 2028 { 2029 // get the device node 2030 devfs_vnode* node; 2031 status_t status = get_node_for_path(sDeviceFileSystem, path, &node); 2032 if (status != B_OK) 2033 return status; 2034 2035 if (!S_ISCHR(node->stream.type)) { 2036 put_vnode(sDeviceFileSystem->volume, node->id); 2037 return B_BAD_VALUE; 2038 } 2039 2040 // if it is indeed a file device, unpublish it 2041 FileDevice* device = dynamic_cast<FileDevice*>(node->stream.u.dev.device); 2042 if (device == NULL) { 2043 put_vnode(sDeviceFileSystem->volume, node->id); 2044 return B_BAD_VALUE; 2045 } 2046 2047 status = unpublish_node(sDeviceFileSystem, node, S_IFCHR); 2048 2049 put_vnode(sDeviceFileSystem->volume, node->id); 2050 return status; 2051 } 2052 2053 2054 extern "C" status_t 2055 devfs_publish_file_device(const char* path, const char* filePath) 2056 { 2057 // create a FileDevice for the file 2058 FileDevice* device = new(std::nothrow) FileDevice; 2059 if (device == NULL) 2060 return B_NO_MEMORY; 2061 ObjectDeleter<FileDevice> deviceDeleter(device); 2062 2063 status_t error = device->Init(filePath); 2064 if (error != B_OK) 2065 return error; 2066 2067 // publish the device 2068 error = publish_device(sDeviceFileSystem, path, device); 2069 if (error != B_OK) 2070 return error; 2071 2072 deviceDeleter.Detach(); 2073 return B_OK; 2074 } 2075 2076 2077 extern "C" status_t 2078 devfs_unpublish_partition(const char* path) 2079 { 2080 devfs_vnode* node; 2081 status_t status = get_node_for_path(sDeviceFileSystem, path, &node); 2082 if (status != B_OK) 2083 return status; 2084 2085 status = unpublish_node(sDeviceFileSystem, node, S_IFCHR); 2086 put_vnode(sDeviceFileSystem->volume, node->id); 2087 return status; 2088 } 2089 2090 2091 extern "C" status_t 2092 devfs_publish_partition(const char* name, const partition_info* info) 2093 { 2094 if (name == NULL || info == NULL) 2095 return B_BAD_VALUE; 2096 TRACE(("publish partition: %s (device \"%s\", offset %" B_PRIdOFF 2097 ", size %" B_PRIdOFF ")\n", 2098 name, info->device, info->offset, info->size)); 2099 2100 devfs_vnode* device; 2101 status_t status = get_node_for_path(sDeviceFileSystem, info->device, 2102 &device); 2103 if (status != B_OK) 2104 return status; 2105 2106 status = add_partition(sDeviceFileSystem, device, name, *info); 2107 2108 put_vnode(sDeviceFileSystem->volume, device->id); 2109 return status; 2110 } 2111 2112 2113 extern "C" status_t 2114 devfs_rename_partition(const char* devicePath, const char* oldName, 2115 const char* newName) 2116 { 2117 if (oldName == NULL || newName == NULL) 2118 return B_BAD_VALUE; 2119 2120 devfs_vnode* device; 2121 status_t status = get_node_for_path(sDeviceFileSystem, devicePath, &device); 2122 if (status != B_OK) 2123 return status; 2124 2125 RecursiveLocker locker(sDeviceFileSystem->lock); 2126 devfs_vnode* node = devfs_find_in_dir(device->parent, oldName); 2127 if (node == NULL) 2128 return B_ENTRY_NOT_FOUND; 2129 2130 // check if the new path already exists 2131 if (devfs_find_in_dir(device->parent, newName)) 2132 return B_BAD_VALUE; 2133 2134 char* name = strdup(newName); 2135 if (name == NULL) 2136 return B_NO_MEMORY; 2137 2138 devfs_remove_from_dir(device->parent, node, false); 2139 2140 free(node->name); 2141 node->name = name; 2142 2143 devfs_insert_in_dir(device->parent, node, false); 2144 2145 notify_entry_moved(sDeviceFileSystem->id, device->parent->id, oldName, 2146 device->parent->id, newName, node->id); 2147 notify_stat_changed(sDeviceFileSystem->id, get_parent_id(device->parent), 2148 device->parent->id, B_STAT_MODIFICATION_TIME); 2149 2150 return B_OK; 2151 } 2152 2153 2154 extern "C" status_t 2155 devfs_publish_directory(const char* path) 2156 { 2157 RecursiveLocker locker(&sDeviceFileSystem->lock); 2158 2159 return publish_directory(sDeviceFileSystem, path); 2160 } 2161 2162 2163 extern "C" status_t 2164 devfs_unpublish_device(const char* path, bool disconnect) 2165 { 2166 devfs_vnode* node; 2167 status_t status = get_node_for_path(sDeviceFileSystem, path, &node); 2168 if (status != B_OK) 2169 return status; 2170 2171 status = unpublish_node(sDeviceFileSystem, node, S_IFCHR); 2172 2173 if (status == B_OK && disconnect) 2174 vfs_disconnect_vnode(sDeviceFileSystem->id, node->id); 2175 2176 put_vnode(sDeviceFileSystem->volume, node->id); 2177 return status; 2178 } 2179 2180 2181 // #pragma mark - device_manager private API 2182 2183 2184 status_t 2185 devfs_publish_device(const char* path, BaseDevice* device) 2186 { 2187 return publish_device(sDeviceFileSystem, path, device); 2188 } 2189 2190 2191 status_t 2192 devfs_unpublish_device(BaseDevice* device, bool disconnect) 2193 { 2194 devfs_vnode* node; 2195 status_t status = get_vnode(sDeviceFileSystem->volume, device->ID(), 2196 (void**)&node); 2197 if (status != B_OK) 2198 return status; 2199 2200 status = unpublish_node(sDeviceFileSystem, node, S_IFCHR); 2201 2202 if (status == B_OK && disconnect) 2203 vfs_disconnect_vnode(sDeviceFileSystem->id, node->id); 2204 2205 put_vnode(sDeviceFileSystem->volume, node->id); 2206 return status; 2207 } 2208 2209 2210 /*! Gets the device for a given devfs relative path. 2211 If successful the call must be balanced with a call to devfs_put_device(). 2212 */ 2213 status_t 2214 devfs_get_device(const char* path, BaseDevice*& _device) 2215 { 2216 devfs_vnode* node; 2217 status_t status = get_node_for_path(sDeviceFileSystem, path, &node); 2218 if (status != B_OK) 2219 return status; 2220 2221 if (!S_ISCHR(node->stream.type) || node->stream.u.dev.partition != NULL) { 2222 put_vnode(sDeviceFileSystem->volume, node->id); 2223 return B_BAD_VALUE; 2224 } 2225 2226 _device = node->stream.u.dev.device; 2227 return B_OK; 2228 } 2229 2230 2231 void 2232 devfs_put_device(BaseDevice* device) 2233 { 2234 put_vnode(sDeviceFileSystem->volume, device->ID()); 2235 } 2236 2237 2238 void 2239 devfs_compute_geometry_size(device_geometry* geometry, uint64 blockCount, 2240 uint32 blockSize) 2241 { 2242 geometry->head_count = 1; 2243 while (blockCount > UINT32_MAX) { 2244 geometry->head_count <<= 1; 2245 blockCount >>= 1; 2246 } 2247 2248 geometry->cylinder_count = 1; 2249 geometry->sectors_per_track = blockCount; 2250 geometry->bytes_per_sector = blockSize; 2251 } 2252 2253 2254 // #pragma mark - support API for legacy drivers 2255 2256 2257 extern "C" status_t 2258 devfs_rescan_driver(const char* driverName) 2259 { 2260 TRACE(("devfs_rescan_driver: %s\n", driverName)); 2261 2262 return legacy_driver_rescan(driverName); 2263 } 2264 2265 2266 extern "C" status_t 2267 devfs_publish_device(const char* path, device_hooks* hooks) 2268 { 2269 return legacy_driver_publish(path, hooks); 2270 } 2271