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