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