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