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