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