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