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