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