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