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