2 * Copyright 2002-2016, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
5 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
6 * Distributed under the terms of the NewOS License.
19 #include <KernelExport.h>
20 #include <NodeMonitor.h>
23 #include <AutoDeleter.h>
24 #include <boot/kernel_args.h>
25 #include <boot_device.h>
28 #include <FindDirectory.h>
31 #include <fs/node_monitor.h>
32 #include <kdevice_manager.h>
34 #include <Notifications.h>
35 #include <util/AutoLock.h>
39 #include "BaseDevice.h"
40 #include "FileDevice.h"
41 #include "IORequest.h"
42 #include "legacy_drivers.h"
47 # define TRACE(x) dprintf x
55 struct devfs_partition
{
56 struct devfs_vnode
* raw_device
;
72 struct devfs_vnode
* dir_head
;
79 struct devfs_partition
* partition
;
81 struct stream_symlink
{
89 struct devfs_vnode
* all_next
;
92 timespec modification_time
;
93 timespec creation_time
;
96 struct devfs_vnode
* parent
;
97 struct devfs_vnode
* dir_next
;
98 struct devfs_stream stream
;
101 #define DEVFS_HASH_SIZE 16
105 typedef ino_t KeyType
;
106 typedef devfs_vnode ValueType
;
108 size_t HashKey(KeyType key
) const
110 return key
^ (key
>> 32);
113 size_t Hash(ValueType
* value
) const
115 return HashKey(value
->id
);
118 bool Compare(KeyType key
, ValueType
* value
) const
120 return value
->id
== key
;
123 ValueType
*& GetLink(ValueType
* value
) const
125 return value
->all_next
;
129 typedef BOpenHashTable
<NodeHash
> NodeTable
;
136 NodeTable
* vnode_hash
;
137 struct devfs_vnode
* root_vnode
;
140 struct devfs_dir_cookie
{
141 struct list_link link
;
142 struct devfs_vnode
* current
;
143 int32 state
; // iteration state
146 struct devfs_cookie
{
150 struct synchronous_io_cookie
{
155 // directory iteration states
157 ITERATION_STATE_DOT
= 0,
158 ITERATION_STATE_DOT_DOT
= 1,
159 ITERATION_STATE_OTHERS
= 2,
160 ITERATION_STATE_BEGIN
= ITERATION_STATE_DOT
,
163 // extern only to make forward declaration possible
164 extern fs_volume_ops kVolumeOps
;
165 extern fs_vnode_ops kVnodeOps
;
170 static status_t
get_node_for_path(struct devfs
* fs
, const char* path
,
171 struct devfs_vnode
** _node
);
172 static void get_device_name(struct devfs_vnode
* vnode
, char* buffer
,
174 static status_t
unpublish_node(struct devfs
* fs
, devfs_vnode
* node
,
176 static status_t
publish_device(struct devfs
* fs
, const char* path
,
180 // The one and only allowed devfs instance
181 static struct devfs
* sDeviceFileSystem
= NULL
;
184 // #pragma mark - devfs private
190 bigtime_t time
= real_time_clock_usecs();
193 tv
.tv_sec
= time
/ 1000000;
194 tv
.tv_nsec
= (time
% 1000000) * 1000;
200 get_parent_id(struct devfs_vnode
* vnode
)
202 if (vnode
->parent
!= NULL
)
203 return vnode
->parent
->id
;
211 // We may scan every device twice:
212 // - once before there is a boot device,
213 // - and once when there is one
215 return gBootDevice
>= 0 ? kNormalScan
: kBootScan
;
220 scan_for_drivers_if_needed(devfs_vnode
* dir
)
222 ASSERT(S_ISDIR(dir
->stream
.type
));
224 MutexLocker
_(dir
->stream
.u
.dir
.scan_lock
);
226 if (dir
->stream
.u
.dir
.scanned
>= scan_mode())
230 if (path
.InitCheck() != B_OK
)
233 get_device_name(dir
, path
.LockBuffer(), path
.BufferSize());
236 TRACE(("scan_for_drivers_if_needed: mode %ld: %s\n", scan_mode(),
239 // scan for drivers at this path
240 static int32 updateCycle
= 1;
241 device_manager_probe(path
.Path(), updateCycle
++);
242 legacy_driver_probe(path
.Path());
244 dir
->stream
.u
.dir
.scanned
= scan_mode();
250 init_directory_vnode(struct devfs_vnode
* vnode
, int permissions
)
252 vnode
->stream
.type
= S_IFDIR
| permissions
;
253 mutex_init(&vnode
->stream
.u
.dir
.scan_lock
, "devfs scan");
254 vnode
->stream
.u
.dir
.dir_head
= NULL
;
255 list_init(&vnode
->stream
.u
.dir
.cookies
);
259 static struct devfs_vnode
*
260 devfs_create_vnode(struct devfs
* fs
, devfs_vnode
* parent
, const char* name
)
262 struct devfs_vnode
* vnode
;
264 vnode
= (struct devfs_vnode
*)malloc(sizeof(struct devfs_vnode
));
268 memset(vnode
, 0, sizeof(struct devfs_vnode
));
269 vnode
->id
= fs
->next_vnode_id
++;
271 vnode
->name
= strdup(name
);
272 if (vnode
->name
== NULL
) {
277 vnode
->creation_time
= vnode
->modification_time
= current_timespec();
278 vnode
->uid
= geteuid();
279 vnode
->gid
= parent
? parent
->gid
: getegid();
280 // inherit group from parent if possible
287 devfs_delete_vnode(struct devfs
* fs
, struct devfs_vnode
* vnode
,
290 // Can't delete it if it's in a directory or is a directory
292 if (!forceDelete
&& ((S_ISDIR(vnode
->stream
.type
)
293 && vnode
->stream
.u
.dir
.dir_head
!= NULL
)
294 || vnode
->dir_next
!= NULL
))
295 return B_NOT_ALLOWED
;
297 // remove it from the global hash table
298 fs
->vnode_hash
->Remove(vnode
);
300 if (S_ISCHR(vnode
->stream
.type
)) {
301 if (vnode
->stream
.u
.dev
.partition
== NULL
) {
302 // pass the call through to the underlying device
303 vnode
->stream
.u
.dev
.device
->Removed();
305 // for partitions, we have to release the raw device but must
306 // not free the device info as it was inherited from the raw
307 // device and is still in use there
308 put_vnode(fs
->volume
, vnode
->stream
.u
.dev
.partition
->raw_device
->id
);
310 } else if (S_ISDIR(vnode
->stream
.type
)) {
311 mutex_destroy(&vnode
->stream
.u
.dir
.scan_lock
);
321 /*! Makes sure none of the dircookies point to the vnode passed in */
323 update_dir_cookies(struct devfs_vnode
* dir
, struct devfs_vnode
* vnode
)
325 struct devfs_dir_cookie
* cookie
= NULL
;
327 while ((cookie
= (devfs_dir_cookie
*)list_get_next_item(
328 &dir
->stream
.u
.dir
.cookies
, cookie
)) != NULL
) {
329 if (cookie
->current
== vnode
)
330 cookie
->current
= vnode
->dir_next
;
335 static struct devfs_vnode
*
336 devfs_find_in_dir(struct devfs_vnode
* dir
, const char* path
)
338 struct devfs_vnode
* vnode
;
340 if (!S_ISDIR(dir
->stream
.type
))
343 if (!strcmp(path
, "."))
345 if (!strcmp(path
, ".."))
348 for (vnode
= dir
->stream
.u
.dir
.dir_head
; vnode
; vnode
= vnode
->dir_next
) {
349 //TRACE(("devfs_find_in_dir: looking at entry '%s'\n", vnode->name));
350 if (strcmp(vnode
->name
, path
) == 0) {
351 //TRACE(("devfs_find_in_dir: found it at %p\n", vnode));
360 devfs_insert_in_dir(struct devfs_vnode
* dir
, struct devfs_vnode
* vnode
,
363 if (!S_ISDIR(dir
->stream
.type
))
366 // make sure the directory stays sorted alphabetically
368 devfs_vnode
* node
= dir
->stream
.u
.dir
.dir_head
;
369 devfs_vnode
* last
= NULL
;
370 while (node
&& strcmp(node
->name
, vnode
->name
) < 0) {
372 node
= node
->dir_next
;
375 // the new vnode is the first entry in the list
376 vnode
->dir_next
= dir
->stream
.u
.dir
.dir_head
;
377 dir
->stream
.u
.dir
.dir_head
= vnode
;
379 // insert after that node
380 vnode
->dir_next
= last
->dir_next
;
381 last
->dir_next
= vnode
;
385 dir
->modification_time
= current_timespec();
388 notify_entry_created(sDeviceFileSystem
->id
, dir
->id
, vnode
->name
,
390 notify_stat_changed(sDeviceFileSystem
->id
, get_parent_id(dir
), dir
->id
,
391 B_STAT_MODIFICATION_TIME
);
398 devfs_remove_from_dir(struct devfs_vnode
* dir
, struct devfs_vnode
* removeNode
,
401 struct devfs_vnode
* vnode
= dir
->stream
.u
.dir
.dir_head
;
402 struct devfs_vnode
* lastNode
= NULL
;
404 for (; vnode
!= NULL
; lastNode
= vnode
, vnode
= vnode
->dir_next
) {
405 if (vnode
== removeNode
) {
406 // make sure no dircookies point to this vnode
407 update_dir_cookies(dir
, vnode
);
410 lastNode
->dir_next
= vnode
->dir_next
;
412 dir
->stream
.u
.dir
.dir_head
= vnode
->dir_next
;
413 vnode
->dir_next
= NULL
;
414 dir
->modification_time
= current_timespec();
417 notify_entry_removed(sDeviceFileSystem
->id
, dir
->id
, vnode
->name
,
419 notify_stat_changed(sDeviceFileSystem
->id
, get_parent_id(dir
),
420 dir
->id
, B_STAT_MODIFICATION_TIME
);
425 return B_ENTRY_NOT_FOUND
;
430 add_partition(struct devfs
* fs
, struct devfs_vnode
* device
, const char* name
,
431 const partition_info
& info
)
433 struct devfs_vnode
* partitionNode
;
436 if (!S_ISCHR(device
->stream
.type
))
439 // we don't support nested partitions
440 if (device
->stream
.u
.dev
.partition
!= NULL
)
443 // reduce checks to a minimum - things like negative offsets could be useful
448 struct devfs_partition
* partition
= (struct devfs_partition
*)malloc(
449 sizeof(struct devfs_partition
));
450 if (partition
== NULL
)
453 memcpy(&partition
->info
, &info
, sizeof(partition_info
));
455 RecursiveLocker
locker(fs
->lock
);
457 // you cannot change a partition once set
458 if (devfs_find_in_dir(device
->parent
, name
)) {
459 status
= B_BAD_VALUE
;
463 // increase reference count of raw device -
464 // the partition device really needs it
465 status
= get_vnode(fs
->volume
, device
->id
, (void**)&partition
->raw_device
);
469 // now create the partition vnode
470 partitionNode
= devfs_create_vnode(fs
, device
->parent
, name
);
471 if (partitionNode
== NULL
) {
472 status
= B_NO_MEMORY
;
476 partitionNode
->stream
.type
= device
->stream
.type
;
477 partitionNode
->stream
.u
.dev
.device
= device
->stream
.u
.dev
.device
;
478 partitionNode
->stream
.u
.dev
.partition
= partition
;
480 fs
->vnode_hash
->Insert(partitionNode
);
481 devfs_insert_in_dir(device
->parent
, partitionNode
);
483 TRACE(("add_partition(name = %s, offset = %Ld, size = %Ld)\n",
484 name
, info
.offset
, info
.size
));
488 put_vnode(fs
->volume
, device
->id
);
496 translate_partition_access(devfs_partition
* partition
, off_t
& offset
,
500 ASSERT(offset
< partition
->info
.size
);
502 size
= (size_t)min_c((off_t
)size
, partition
->info
.size
- offset
);
503 offset
+= partition
->info
.offset
;
508 translate_partition_access(devfs_partition
* partition
, io_request
* request
)
510 off_t offset
= request
->Offset();
513 ASSERT(offset
+ (off_t
)request
->Length() <= partition
->info
.size
);
515 request
->SetOffset(offset
+ partition
->info
.offset
);
520 get_node_for_path(struct devfs
* fs
, const char* path
,
521 struct devfs_vnode
** _node
)
523 return vfs_get_fs_node_from_path(fs
->volume
, path
, false, true,
529 unpublish_node(struct devfs
* fs
, devfs_vnode
* node
, mode_t type
)
531 if ((node
->stream
.type
& S_IFMT
) != type
)
534 recursive_lock_lock(&fs
->lock
);
536 status_t status
= devfs_remove_from_dir(node
->parent
, node
);
540 status
= remove_vnode(fs
->volume
, node
->id
);
543 recursive_lock_unlock(&fs
->lock
);
549 publish_node(devfs
* fs
, devfs_vnode
* dirNode
, struct devfs_vnode
* node
)
551 fs
->vnode_hash
->Insert(node
);
552 devfs_insert_in_dir(dirNode
, node
);
557 publish_directory(struct devfs
* fs
, const char* path
)
559 ASSERT_LOCKED_RECURSIVE(&fs
->lock
);
561 // copy the path over to a temp buffer so we can munge it
562 KPath
tempPath(path
);
563 if (tempPath
.InitCheck() != B_OK
)
566 TRACE(("devfs: publish directory \"%s\"\n", path
));
567 char* temp
= tempPath
.LockBuffer();
569 // create the path leading to the device
570 // parse the path passed in, stripping out '/'
572 struct devfs_vnode
* dir
= fs
->root_vnode
;
573 struct devfs_vnode
* vnode
= NULL
;
574 status_t status
= B_OK
;
575 int32 i
= 0, last
= 0;
578 if (temp
[i
] == '/') {
581 } else if (temp
[i
] != '\0') {
586 //TRACE(("\tpath component '%s'\n", &temp[last]));
588 // we have a path component
589 vnode
= devfs_find_in_dir(dir
, &temp
[last
]);
591 if (S_ISDIR(vnode
->stream
.type
)) {
597 // we hit something on our path that's not a directory
598 status
= B_FILE_EXISTS
;
601 vnode
= devfs_create_vnode(fs
, dir
, &temp
[last
]);
603 status
= B_NO_MEMORY
;
608 // set up the new directory
609 init_directory_vnode(vnode
, 0755);
610 publish_node(sDeviceFileSystem
, dir
, vnode
);
622 new_node(struct devfs
* fs
, const char* path
, struct devfs_vnode
** _node
,
623 struct devfs_vnode
** _dir
)
625 ASSERT_LOCKED_RECURSIVE(&fs
->lock
);
627 // copy the path over to a temp buffer so we can munge it
628 KPath
tempPath(path
);
629 if (tempPath
.InitCheck() != B_OK
)
632 char* temp
= tempPath
.LockBuffer();
634 // create the path leading to the device
635 // parse the path passed in, stripping out '/'
637 struct devfs_vnode
* dir
= fs
->root_vnode
;
638 struct devfs_vnode
* vnode
= NULL
;
639 status_t status
= B_OK
;
640 int32 i
= 0, last
= 0;
644 if (temp
[i
] == '\0') {
645 atLeaf
= true; // we'll be done after this one
646 } else if (temp
[i
] == '/') {
654 //TRACE(("\tpath component '%s'\n", &temp[last]));
656 // we have a path component
657 vnode
= devfs_find_in_dir(dir
, &temp
[last
]);
660 // we are not at the leaf of the path, so as long as
661 // this is a dir we're okay
662 if (S_ISDIR(vnode
->stream
.type
)) {
668 // we are at the leaf and hit another node
669 // or we aren't but hit a non-dir node.
671 status
= B_FILE_EXISTS
;
674 vnode
= devfs_create_vnode(fs
, dir
, &temp
[last
]);
676 status
= B_NO_MEMORY
;
681 // set up the new vnode
684 init_directory_vnode(vnode
, 0755);
685 publish_node(fs
, dir
, vnode
);
687 // this is the last component
688 // Note: We do not yet insert the node into the directory, as it
689 // is not yet fully initialized. Instead we return the directory
690 // vnode so that the calling function can insert it after all
691 // initialization is done. This ensures that no create notification
692 // is sent out for a vnode that is not yet fully valid.
708 publish_device(struct devfs
* fs
, const char* path
, BaseDevice
* device
)
710 TRACE(("publish_device(path = \"%s\", device = %p)\n", path
, device
));
712 if (sDeviceFileSystem
== NULL
) {
713 panic("publish_device() called before devfs mounted\n");
717 if (device
== NULL
|| path
== NULL
|| path
[0] == '\0' || path
[0] == '/')
720 // TODO: this has to be done in the BaseDevice sub classes!
722 // are the provided device hooks okay?
723 if (info
->device_open
== NULL
|| info
->device_close
== NULL
724 || info
->device_free
== NULL
725 || ((info
->device_read
== NULL
|| info
->device_write
== NULL
)
726 && info
->device_io
== NULL
))
730 struct devfs_vnode
* node
;
731 struct devfs_vnode
* dirNode
;
734 RecursiveLocker
locker(&fs
->lock
);
736 status
= new_node(fs
, path
, &node
, &dirNode
);
740 // all went fine, let's initialize the node
741 node
->stream
.type
= S_IFCHR
| 0644;
742 node
->stream
.u
.dev
.device
= device
;
743 device
->SetID(node
->id
);
745 // the node is now fully valid and we may insert it into the dir
746 publish_node(fs
, dirNode
, node
);
751 /*! Construct complete device name (as used for device_open()).
752 This is safe to use only when the device is in use (and therefore
753 cannot be unpublished during the iteration).
756 get_device_name(struct devfs_vnode
* vnode
, char* buffer
, size_t size
)
758 RecursiveLocker
_(sDeviceFileSystem
->lock
);
760 struct devfs_vnode
* leaf
= vnode
;
765 for (; vnode
->parent
&& vnode
->parent
!= vnode
; vnode
= vnode
->parent
) {
766 offset
+= strlen(vnode
->name
) + 1;
769 // construct full path name
771 for (vnode
= leaf
; vnode
->parent
&& vnode
->parent
!= vnode
;
772 vnode
= vnode
->parent
) {
773 size_t length
= strlen(vnode
->name
);
774 size_t start
= offset
- length
- 1;
776 if (size
>= offset
) {
777 strcpy(buffer
+ start
, vnode
->name
);
779 buffer
[offset
- 1] = '/';
788 device_read(void* _cookie
, off_t offset
, void* buffer
, size_t* length
)
790 synchronous_io_cookie
* cookie
= (synchronous_io_cookie
*)_cookie
;
791 return cookie
->device
->Read(cookie
->cookie
, offset
, buffer
, length
);
796 device_write(void* _cookie
, off_t offset
, void* buffer
, size_t* length
)
798 synchronous_io_cookie
* cookie
= (synchronous_io_cookie
*)_cookie
;
799 return cookie
->device
->Write(cookie
->cookie
, offset
, buffer
, length
);
804 dump_node(int argc
, char** argv
)
807 print_debugger_command_usage(argv
[0]);
811 struct devfs_vnode
* vnode
= (struct devfs_vnode
*)parse_expression(argv
[1]);
813 kprintf("invalid node address\n");
817 kprintf("DEVFS NODE: %p\n", vnode
);
818 kprintf(" id: %" B_PRIdINO
"\n", vnode
->id
);
819 kprintf(" name: \"%s\"\n", vnode
->name
);
820 kprintf(" type: %x\n", vnode
->stream
.type
);
821 kprintf(" parent: %p\n", vnode
->parent
);
822 kprintf(" dir next: %p\n", vnode
->dir_next
);
824 if (S_ISDIR(vnode
->stream
.type
)) {
825 kprintf(" dir scanned: %" B_PRId32
"\n", vnode
->stream
.u
.dir
.scanned
);
826 kprintf(" contents:\n");
828 devfs_vnode
* children
= vnode
->stream
.u
.dir
.dir_head
;
829 while (children
!= NULL
) {
830 kprintf(" %p, id %" B_PRIdINO
"\n", children
, children
->id
);
831 children
= children
->dir_next
;
833 } else if (S_ISLNK(vnode
->stream
.type
)) {
834 kprintf(" symlink to: %s\n", vnode
->stream
.u
.symlink
.path
);
836 kprintf(" device: %p\n", vnode
->stream
.u
.dev
.device
);
837 kprintf(" partition: %p\n", vnode
->stream
.u
.dev
.partition
);
838 if (vnode
->stream
.u
.dev
.partition
!= NULL
) {
839 partition_info
& info
= vnode
->stream
.u
.dev
.partition
->info
;
840 kprintf(" raw device node: %p\n",
841 vnode
->stream
.u
.dev
.partition
->raw_device
);
842 kprintf(" offset: %" B_PRIdOFF
"\n", info
.offset
);
843 kprintf(" size: %" B_PRIdOFF
"\n", info
.size
);
844 kprintf(" block size: %" B_PRId32
"\n", info
.logical_block_size
);
845 kprintf(" session: %" B_PRId32
"\n", info
.session
);
846 kprintf(" partition: %" B_PRId32
"\n", info
.partition
);
847 kprintf(" device: %s\n", info
.device
);
848 set_debug_variable("_raw",
849 (addr_t
)vnode
->stream
.u
.dev
.partition
->raw_device
);
858 dump_cookie(int argc
, char** argv
)
861 print_debugger_command_usage(argv
[0]);
866 if (!evaluate_debug_expression(argv
[1], &address
, false))
869 struct devfs_cookie
* cookie
= (devfs_cookie
*)(addr_t
)address
;
871 kprintf("DEVFS COOKIE: %p\n", cookie
);
872 kprintf(" device_cookie: %p\n", cookie
->device_cookie
);
878 // #pragma mark - file system interface
882 devfs_mount(fs_volume
* volume
, const char* devfs
, uint32 flags
,
883 const char* args
, ino_t
* _rootNodeID
)
885 struct devfs_vnode
* vnode
;
889 TRACE(("devfs_mount: entry\n"));
891 if (sDeviceFileSystem
) {
892 TRACE(("double mount of devfs attempted\n"));
897 fs
= (struct devfs
*)malloc(sizeof(struct devfs
));
903 volume
->private_volume
= fs
;
904 volume
->ops
= &kVolumeOps
;
907 fs
->next_vnode_id
= 0;
909 recursive_lock_init(&fs
->lock
, "devfs lock");
911 fs
->vnode_hash
= new(std::nothrow
) NodeTable();
912 if (fs
->vnode_hash
== NULL
|| fs
->vnode_hash
->Init(DEVFS_HASH_SIZE
) != B_OK
) {
918 vnode
= devfs_create_vnode(fs
, NULL
, "");
925 vnode
->parent
= vnode
;
927 // create a dir stream for it to hold
928 init_directory_vnode(vnode
, 0755);
929 fs
->root_vnode
= vnode
;
931 fs
->vnode_hash
->Insert(vnode
);
932 publish_vnode(volume
, vnode
->id
, vnode
, &kVnodeOps
, vnode
->stream
.type
, 0);
934 *_rootNodeID
= vnode
->id
;
935 sDeviceFileSystem
= fs
;
939 delete fs
->vnode_hash
;
941 recursive_lock_destroy(&fs
->lock
);
949 devfs_unmount(fs_volume
* _volume
)
951 struct devfs
* fs
= (struct devfs
*)_volume
->private_volume
;
952 struct devfs_vnode
* vnode
;
954 TRACE(("devfs_unmount: entry fs = %p\n", fs
));
956 recursive_lock_lock(&fs
->lock
);
958 // release the reference to the root
959 put_vnode(fs
->volume
, fs
->root_vnode
->id
);
961 // delete all of the vnodes
962 NodeTable::Iterator
i(fs
->vnode_hash
);
963 while (i
.HasNext()) {
965 devfs_delete_vnode(fs
, vnode
, true);
967 delete fs
->vnode_hash
;
969 recursive_lock_destroy(&fs
->lock
);
977 devfs_sync(fs_volume
* _volume
)
979 TRACE(("devfs_sync: entry\n"));
986 devfs_lookup(fs_volume
* _volume
, fs_vnode
* _dir
, const char* name
, ino_t
* _id
)
988 struct devfs
* fs
= (struct devfs
*)_volume
->private_volume
;
989 struct devfs_vnode
* dir
= (struct devfs_vnode
*)_dir
->private_node
;
990 struct devfs_vnode
* vnode
;
993 TRACE(("devfs_lookup: entry dir %p, name '%s'\n", dir
, name
));
995 if (!S_ISDIR(dir
->stream
.type
))
996 return B_NOT_A_DIRECTORY
;
998 // Make sure the directory contents are up to date
999 scan_for_drivers_if_needed(dir
);
1001 RecursiveLocker
locker(&fs
->lock
);
1004 vnode
= devfs_find_in_dir(dir
, name
);
1005 if (vnode
== NULL
) {
1006 // We don't have to rescan here, because thanks to node monitoring
1007 // we already know it does not exist
1008 return B_ENTRY_NOT_FOUND
;
1011 status
= get_vnode(fs
->volume
, vnode
->id
, NULL
);
1022 devfs_get_vnode_name(fs_volume
* _volume
, fs_vnode
* _vnode
, char* buffer
,
1025 struct devfs_vnode
* vnode
= (struct devfs_vnode
*)_vnode
->private_node
;
1027 TRACE(("devfs_get_vnode_name: vnode = %p\n", vnode
));
1029 strlcpy(buffer
, vnode
->name
, bufferSize
);
1035 devfs_get_vnode(fs_volume
* _volume
, ino_t id
, fs_vnode
* _vnode
, int* _type
,
1036 uint32
* _flags
, bool reenter
)
1038 struct devfs
* fs
= (struct devfs
*)_volume
->private_volume
;
1040 TRACE(("devfs_get_vnode: asking for vnode id = %Ld, vnode = %p, r %d\n", id
, _vnode
, reenter
));
1042 RecursiveLocker
_(fs
->lock
);
1044 struct devfs_vnode
* vnode
= fs
->vnode_hash
->Lookup(id
);
1046 return B_ENTRY_NOT_FOUND
;
1048 TRACE(("devfs_get_vnode: looked it up at %p\n", vnode
));
1050 _vnode
->private_node
= vnode
;
1051 _vnode
->ops
= &kVnodeOps
;
1052 *_type
= vnode
->stream
.type
;
1059 devfs_put_vnode(fs_volume
* _volume
, fs_vnode
* _vnode
, bool reenter
)
1062 struct devfs_vnode
* vnode
= (struct devfs_vnode
*)_vnode
->private_node
;
1064 TRACE(("devfs_put_vnode: entry on vnode %p, id = %Ld, reenter %d\n",
1065 vnode
, vnode
->id
, reenter
));
1073 devfs_remove_vnode(fs_volume
* _volume
, fs_vnode
* _v
, bool reenter
)
1075 struct devfs
* fs
= (struct devfs
*)_volume
->private_volume
;
1076 struct devfs_vnode
* vnode
= (struct devfs_vnode
*)_v
->private_node
;
1078 TRACE(("devfs_removevnode: remove %p (%Ld), reenter %d\n", vnode
, vnode
->id
, reenter
));
1080 RecursiveLocker
locker(&fs
->lock
);
1082 if (vnode
->dir_next
) {
1083 // can't remove node if it's linked to the dir
1084 panic("devfs_removevnode: vnode %p asked to be removed is present in dir\n", vnode
);
1087 devfs_delete_vnode(fs
, vnode
, false);
1094 devfs_open(fs_volume
* _volume
, fs_vnode
* _vnode
, int openMode
,
1097 struct devfs_vnode
* vnode
= (struct devfs_vnode
*)_vnode
->private_node
;
1098 struct devfs_cookie
* cookie
;
1099 status_t status
= B_OK
;
1101 cookie
= (struct devfs_cookie
*)malloc(sizeof(struct devfs_cookie
));
1105 TRACE(("devfs_open: vnode %p, openMode 0x%x, cookie %p\n", vnode
, openMode
,
1108 cookie
->device_cookie
= NULL
;
1110 if (S_ISCHR(vnode
->stream
.type
)) {
1111 BaseDevice
* device
= vnode
->stream
.u
.dev
.device
;
1112 status
= device
->InitDevice();
1113 if (status
!= B_OK
) {
1118 char path
[B_FILE_NAME_LENGTH
];
1119 get_device_name(vnode
, path
, sizeof(path
));
1121 status
= device
->Open(path
, openMode
, &cookie
->device_cookie
);
1123 device
->UninitDevice();
1136 devfs_close(fs_volume
* _volume
, fs_vnode
* _vnode
, void* _cookie
)
1138 struct devfs_vnode
* vnode
= (struct devfs_vnode
*)_vnode
->private_node
;
1139 struct devfs_cookie
* cookie
= (struct devfs_cookie
*)_cookie
;
1141 TRACE(("devfs_close: entry vnode %p, cookie %p\n", vnode
, cookie
));
1143 if (S_ISCHR(vnode
->stream
.type
)) {
1144 // pass the call through to the underlying device
1145 return vnode
->stream
.u
.dev
.device
->Close(cookie
->device_cookie
);
1153 devfs_free_cookie(fs_volume
* _volume
, fs_vnode
* _vnode
, void* _cookie
)
1155 struct devfs_vnode
* vnode
= (struct devfs_vnode
*)_vnode
->private_node
;
1156 struct devfs_cookie
* cookie
= (struct devfs_cookie
*)_cookie
;
1158 TRACE(("devfs_freecookie: entry vnode %p, cookie %p\n", vnode
, cookie
));
1160 if (S_ISCHR(vnode
->stream
.type
)) {
1161 // pass the call through to the underlying device
1162 vnode
->stream
.u
.dev
.device
->Free(cookie
->device_cookie
);
1163 vnode
->stream
.u
.dev
.device
->UninitDevice();
1172 devfs_fsync(fs_volume
* _volume
, fs_vnode
* _v
)
1179 devfs_read_link(fs_volume
* _volume
, fs_vnode
* _link
, char* buffer
,
1180 size_t* _bufferSize
)
1182 struct devfs_vnode
* link
= (struct devfs_vnode
*)_link
->private_node
;
1184 if (!S_ISLNK(link
->stream
.type
))
1187 if (link
->stream
.u
.symlink
.length
< *_bufferSize
)
1188 *_bufferSize
= link
->stream
.u
.symlink
.length
;
1190 memcpy(buffer
, link
->stream
.u
.symlink
.path
, *_bufferSize
);
1196 devfs_read(fs_volume
* _volume
, fs_vnode
* _vnode
, void* _cookie
, off_t pos
,
1197 void* buffer
, size_t* _length
)
1199 struct devfs_vnode
* vnode
= (struct devfs_vnode
*)_vnode
->private_node
;
1200 struct devfs_cookie
* cookie
= (struct devfs_cookie
*)_cookie
;
1202 //TRACE(("devfs_read: vnode %p, cookie %p, pos %Ld, len %p\n",
1203 // vnode, cookie, pos, _length));
1205 if (!S_ISCHR(vnode
->stream
.type
))
1211 if (vnode
->stream
.u
.dev
.partition
!= NULL
) {
1212 if (pos
>= vnode
->stream
.u
.dev
.partition
->info
.size
)
1215 translate_partition_access(vnode
->stream
.u
.dev
.partition
, pos
, *_length
);
1221 // pass the call through to the device
1222 return vnode
->stream
.u
.dev
.device
->Read(cookie
->device_cookie
, pos
, buffer
,
1228 devfs_write(fs_volume
* _volume
, fs_vnode
* _vnode
, void* _cookie
, off_t pos
,
1229 const void* buffer
, size_t* _length
)
1231 struct devfs_vnode
* vnode
= (struct devfs_vnode
*)_vnode
->private_node
;
1232 struct devfs_cookie
* cookie
= (struct devfs_cookie
*)_cookie
;
1234 //TRACE(("devfs_write: vnode %p, cookie %p, pos %Ld, len %p\n",
1235 // vnode, cookie, pos, _length));
1237 if (!S_ISCHR(vnode
->stream
.type
))
1243 if (vnode
->stream
.u
.dev
.partition
!= NULL
) {
1244 if (pos
>= vnode
->stream
.u
.dev
.partition
->info
.size
)
1247 translate_partition_access(vnode
->stream
.u
.dev
.partition
, pos
, *_length
);
1253 return vnode
->stream
.u
.dev
.device
->Write(cookie
->device_cookie
, pos
, buffer
,
1259 devfs_create_dir(fs_volume
* _volume
, fs_vnode
* _dir
, const char* name
,
1262 struct devfs
* fs
= (struct devfs
*)_volume
->private_volume
;
1263 struct devfs_vnode
* dir
= (struct devfs_vnode
*)_dir
->private_node
;
1265 struct devfs_vnode
* vnode
= devfs_find_in_dir(dir
, name
);
1266 if (vnode
!= NULL
) {
1270 vnode
= devfs_create_vnode(fs
, dir
, name
);
1271 if (vnode
== NULL
) {
1275 // set up the new directory
1276 init_directory_vnode(vnode
, perms
);
1277 publish_node(sDeviceFileSystem
, dir
, vnode
);
1284 devfs_open_dir(fs_volume
* _volume
, fs_vnode
* _vnode
, void** _cookie
)
1286 struct devfs
* fs
= (struct devfs
*)_volume
->private_volume
;
1287 struct devfs_vnode
* vnode
= (struct devfs_vnode
*)_vnode
->private_node
;
1288 struct devfs_dir_cookie
* cookie
;
1290 TRACE(("devfs_open_dir: vnode %p\n", vnode
));
1292 if (!S_ISDIR(vnode
->stream
.type
))
1295 cookie
= (devfs_dir_cookie
*)malloc(sizeof(devfs_dir_cookie
));
1299 // make sure the directory has up-to-date contents
1300 scan_for_drivers_if_needed(vnode
);
1302 RecursiveLocker
locker(&fs
->lock
);
1304 cookie
->current
= vnode
->stream
.u
.dir
.dir_head
;
1305 cookie
->state
= ITERATION_STATE_BEGIN
;
1307 list_add_item(&vnode
->stream
.u
.dir
.cookies
, cookie
);
1315 devfs_free_dir_cookie(fs_volume
* _volume
, fs_vnode
* _vnode
, void* _cookie
)
1317 struct devfs_vnode
* vnode
= (struct devfs_vnode
*)_vnode
->private_node
;
1318 struct devfs_dir_cookie
* cookie
= (devfs_dir_cookie
*)_cookie
;
1319 struct devfs
* fs
= (struct devfs
*)_volume
->private_volume
;
1321 TRACE(("devfs_free_dir_cookie: entry vnode %p, cookie %p\n", vnode
, cookie
));
1323 RecursiveLocker
locker(&fs
->lock
);
1325 list_remove_item(&vnode
->stream
.u
.dir
.cookies
, cookie
);
1332 devfs_read_dir(fs_volume
* _volume
, fs_vnode
* _vnode
, void* _cookie
,
1333 struct dirent
* dirent
, size_t bufferSize
, uint32
* _num
)
1335 struct devfs_vnode
* vnode
= (devfs_vnode
*)_vnode
->private_node
;
1336 struct devfs_dir_cookie
* cookie
= (devfs_dir_cookie
*)_cookie
;
1337 struct devfs
* fs
= (struct devfs
*)_volume
->private_volume
;
1338 status_t status
= B_OK
;
1339 struct devfs_vnode
* childNode
= NULL
;
1340 const char* name
= NULL
;
1341 struct devfs_vnode
* nextChildNode
= NULL
;
1342 int32 nextState
= cookie
->state
;
1344 TRACE(("devfs_read_dir: vnode %p, cookie %p, buffer %p, size %ld\n",
1345 _vnode
, cookie
, dirent
, bufferSize
));
1347 if (!S_ISDIR(vnode
->stream
.type
))
1350 RecursiveLocker
locker(&fs
->lock
);
1352 switch (cookie
->state
) {
1353 case ITERATION_STATE_DOT
:
1356 nextChildNode
= vnode
->stream
.u
.dir
.dir_head
;
1357 nextState
= cookie
->state
+ 1;
1359 case ITERATION_STATE_DOT_DOT
:
1360 childNode
= vnode
->parent
;
1362 nextChildNode
= vnode
->stream
.u
.dir
.dir_head
;
1363 nextState
= cookie
->state
+ 1;
1366 childNode
= cookie
->current
;
1368 name
= childNode
->name
;
1369 nextChildNode
= childNode
->dir_next
;
1379 dirent
->d_dev
= fs
->id
;
1380 dirent
->d_ino
= childNode
->id
;
1381 dirent
->d_reclen
= strlen(name
) + sizeof(struct dirent
);
1383 if (dirent
->d_reclen
> bufferSize
)
1386 status
= user_strlcpy(dirent
->d_name
, name
,
1387 bufferSize
- sizeof(struct dirent
));
1391 cookie
->current
= nextChildNode
;
1392 cookie
->state
= nextState
;
1400 devfs_rewind_dir(fs_volume
* _volume
, fs_vnode
* _vnode
, void* _cookie
)
1402 struct devfs_vnode
* vnode
= (struct devfs_vnode
*)_vnode
->private_node
;
1403 struct devfs_dir_cookie
* cookie
= (devfs_dir_cookie
*)_cookie
;
1404 struct devfs
* fs
= (struct devfs
*)_volume
->private_volume
;
1406 TRACE(("devfs_rewind_dir: vnode %p, cookie %p\n", vnode
, cookie
));
1408 if (!S_ISDIR(vnode
->stream
.type
))
1411 RecursiveLocker
locker(&fs
->lock
);
1413 cookie
->current
= vnode
->stream
.u
.dir
.dir_head
;
1414 cookie
->state
= ITERATION_STATE_BEGIN
;
1420 /*! Forwards the opcode to the device driver, but also handles some devfs
1421 specific functionality, like partitions.
1424 devfs_ioctl(fs_volume
* _volume
, fs_vnode
* _vnode
, void* _cookie
, uint32 op
,
1425 void* buffer
, size_t length
)
1427 struct devfs_vnode
* vnode
= (struct devfs_vnode
*)_vnode
->private_node
;
1428 struct devfs_cookie
* cookie
= (struct devfs_cookie
*)_cookie
;
1430 TRACE(("devfs_ioctl: vnode %p, cookie %p, op %ld, buf %p, len %ld\n",
1431 vnode
, cookie
, op
, buffer
, length
));
1433 // we are actually checking for a *device* here, we don't make the
1434 // distinction between char and block devices
1435 if (S_ISCHR(vnode
->stream
.type
)) {
1437 case B_GET_GEOMETRY
:
1439 struct devfs_partition
* partition
1440 = vnode
->stream
.u
.dev
.partition
;
1441 if (partition
== NULL
)
1444 device_geometry geometry
;
1445 status_t status
= vnode
->stream
.u
.dev
.device
->Control(
1446 cookie
->device_cookie
, op
, &geometry
, length
);
1450 // patch values to match partition size
1451 if (geometry
.bytes_per_sector
== 0)
1452 geometry
.bytes_per_sector
= 512;
1454 devfs_compute_geometry_size(&geometry
,
1455 partition
->info
.size
/ geometry
.bytes_per_sector
,
1456 geometry
.bytes_per_sector
);
1458 return user_memcpy(buffer
, &geometry
, sizeof(device_geometry
));
1461 case B_GET_DRIVER_FOR_DEVICE
:
1465 if (!vnode
->stream
.u
.dev
.driver
)
1466 return B_ENTRY_NOT_FOUND
;
1467 path
= vnode
->stream
.u
.dev
.driver
->path
;
1469 return B_ENTRY_NOT_FOUND
;
1471 return user_strlcpy((char*)buffer
, path
, B_FILE_NAME_LENGTH
);
1476 case B_GET_PARTITION_INFO
:
1478 struct devfs_partition
* partition
1479 = vnode
->stream
.u
.dev
.partition
;
1480 if (!S_ISCHR(vnode
->stream
.type
)
1481 || partition
== NULL
1482 || length
!= sizeof(partition_info
))
1485 return user_memcpy(buffer
, &partition
->info
,
1486 sizeof(partition_info
));
1489 case B_SET_PARTITION
:
1490 return B_NOT_ALLOWED
;
1492 case B_GET_PATH_FOR_DEVICE
:
1495 // TODO: we might want to actually find the mountpoint
1496 // of that instance of devfs...
1497 // but for now we assume it's mounted on /dev
1498 strcpy(path
, "/dev/");
1499 get_device_name(vnode
, path
+ 5, sizeof(path
) - 5);
1500 if (length
&& (length
<= strlen(path
)))
1502 return user_strlcpy((char*)buffer
, path
, sizeof(path
));
1505 // old unsupported R5 private stuff
1507 case B_GET_NEXT_OPEN_DEVICE
:
1508 dprintf("devfs: unsupported legacy ioctl B_GET_NEXT_OPEN_DEVICE\n");
1509 return B_UNSUPPORTED
;
1510 case B_ADD_FIXED_DRIVER
:
1511 dprintf("devfs: unsupported legacy ioctl B_ADD_FIXED_DRIVER\n");
1512 return B_UNSUPPORTED
;
1513 case B_REMOVE_FIXED_DRIVER
:
1514 dprintf("devfs: unsupported legacy ioctl B_REMOVE_FIXED_DRIVER\n");
1515 return B_UNSUPPORTED
;
1519 return vnode
->stream
.u
.dev
.device
->Control(cookie
->device_cookie
,
1520 op
, buffer
, length
);
1528 devfs_set_flags(fs_volume
* _volume
, fs_vnode
* _vnode
, void* _cookie
,
1531 struct devfs_vnode
* vnode
= (struct devfs_vnode
*)_vnode
->private_node
;
1532 struct devfs_cookie
* cookie
= (struct devfs_cookie
*)_cookie
;
1534 // we need to pass the O_NONBLOCK flag to the underlying device
1536 if (!S_ISCHR(vnode
->stream
.type
))
1537 return B_NOT_ALLOWED
;
1539 return vnode
->stream
.u
.dev
.device
->Control(cookie
->device_cookie
,
1540 flags
& O_NONBLOCK
? B_SET_NONBLOCKING_IO
: B_SET_BLOCKING_IO
, NULL
, 0);
1545 devfs_select(fs_volume
* _volume
, fs_vnode
* _vnode
, void* _cookie
,
1546 uint8 event
, selectsync
* sync
)
1548 struct devfs_vnode
* vnode
= (struct devfs_vnode
*)_vnode
->private_node
;
1549 struct devfs_cookie
* cookie
= (struct devfs_cookie
*)_cookie
;
1551 if (!S_ISCHR(vnode
->stream
.type
))
1552 return B_NOT_ALLOWED
;
1554 // If the device has no select() hook, notify select() now.
1555 if (!vnode
->stream
.u
.dev
.device
->HasSelect())
1556 return notify_select_event((selectsync
*)sync
, event
);
1558 return vnode
->stream
.u
.dev
.device
->Select(cookie
->device_cookie
, event
,
1564 devfs_deselect(fs_volume
* _volume
, fs_vnode
* _vnode
, void* _cookie
,
1565 uint8 event
, selectsync
* sync
)
1567 struct devfs_vnode
* vnode
= (struct devfs_vnode
*)_vnode
->private_node
;
1568 struct devfs_cookie
* cookie
= (struct devfs_cookie
*)_cookie
;
1570 if (!S_ISCHR(vnode
->stream
.type
))
1571 return B_NOT_ALLOWED
;
1573 // If the device has no select() hook, notify select() now.
1574 if (!vnode
->stream
.u
.dev
.device
->HasDeselect())
1577 return vnode
->stream
.u
.dev
.device
->Deselect(cookie
->device_cookie
, event
,
1583 devfs_can_page(fs_volume
* _volume
, fs_vnode
* _vnode
, void* cookie
)
1586 struct devfs_vnode
* vnode
= (devfs_vnode
*)_vnode
->private_node
;
1588 //TRACE(("devfs_canpage: vnode %p\n", vnode));
1590 if (!S_ISCHR(vnode
->stream
.type
)
1591 || vnode
->stream
.u
.dev
.device
->Node() == NULL
1595 return vnode
->stream
.u
.dev
.device
->HasRead()
1596 || vnode
->stream
.u
.dev
.device
->HasIO();
1598 // TODO: Obsolete hook!
1604 devfs_read_pages(fs_volume
* _volume
, fs_vnode
* _vnode
, void* _cookie
,
1605 off_t pos
, const iovec
* vecs
, size_t count
, size_t* _numBytes
)
1607 struct devfs_vnode
* vnode
= (devfs_vnode
*)_vnode
->private_node
;
1608 struct devfs_cookie
* cookie
= (struct devfs_cookie
*)_cookie
;
1610 //TRACE(("devfs_read_pages: vnode %p, vecs %p, count = %lu, pos = %Ld, size = %lu\n", vnode, vecs, count, pos, *_numBytes));
1612 if (!S_ISCHR(vnode
->stream
.type
)
1613 || (!vnode
->stream
.u
.dev
.device
->HasRead()
1614 && !vnode
->stream
.u
.dev
.device
->HasIO())
1616 return B_NOT_ALLOWED
;
1621 if (vnode
->stream
.u
.dev
.partition
!= NULL
) {
1622 if (pos
>= vnode
->stream
.u
.dev
.partition
->info
.size
)
1625 translate_partition_access(vnode
->stream
.u
.dev
.partition
, pos
,
1629 if (vnode
->stream
.u
.dev
.device
->HasIO()) {
1630 // TODO: use io_requests for this!
1633 // emulate read_pages() using read()
1635 status_t error
= B_OK
;
1636 size_t bytesTransferred
= 0;
1638 size_t remainingBytes
= *_numBytes
;
1639 for (size_t i
= 0; i
< count
&& remainingBytes
> 0; i
++) {
1640 size_t toRead
= min_c(vecs
[i
].iov_len
, remainingBytes
);
1641 size_t length
= toRead
;
1643 error
= vnode
->stream
.u
.dev
.device
->Read(cookie
->device_cookie
, pos
,
1644 vecs
[i
].iov_base
, &length
);
1649 bytesTransferred
+= length
;
1650 remainingBytes
-= length
;
1652 if (length
< toRead
)
1656 *_numBytes
= bytesTransferred
;
1658 return bytesTransferred
> 0 ? B_OK
: error
;
1663 devfs_write_pages(fs_volume
* _volume
, fs_vnode
* _vnode
, void* _cookie
,
1664 off_t pos
, const iovec
* vecs
, size_t count
, size_t* _numBytes
)
1666 struct devfs_vnode
* vnode
= (devfs_vnode
*)_vnode
->private_node
;
1667 struct devfs_cookie
* cookie
= (struct devfs_cookie
*)_cookie
;
1669 //TRACE(("devfs_write_pages: vnode %p, vecs %p, count = %lu, pos = %Ld, size = %lu\n", vnode, vecs, count, pos, *_numBytes));
1671 if (!S_ISCHR(vnode
->stream
.type
)
1672 || (!vnode
->stream
.u
.dev
.device
->HasWrite()
1673 && !vnode
->stream
.u
.dev
.device
->HasIO())
1675 return B_NOT_ALLOWED
;
1680 if (vnode
->stream
.u
.dev
.partition
!= NULL
) {
1681 if (pos
>= vnode
->stream
.u
.dev
.partition
->info
.size
)
1684 translate_partition_access(vnode
->stream
.u
.dev
.partition
, pos
,
1688 if (vnode
->stream
.u
.dev
.device
->HasIO()) {
1689 // TODO: use io_requests for this!
1692 // emulate write_pages() using write()
1694 status_t error
= B_OK
;
1695 size_t bytesTransferred
= 0;
1697 size_t remainingBytes
= *_numBytes
;
1698 for (size_t i
= 0; i
< count
&& remainingBytes
> 0; i
++) {
1699 size_t toWrite
= min_c(vecs
[i
].iov_len
, remainingBytes
);
1700 size_t length
= toWrite
;
1702 error
= vnode
->stream
.u
.dev
.device
->Write(cookie
->device_cookie
, pos
,
1703 vecs
[i
].iov_base
, &length
);
1708 bytesTransferred
+= length
;
1709 remainingBytes
-= length
;
1711 if (length
< toWrite
)
1715 *_numBytes
= bytesTransferred
;
1717 return bytesTransferred
> 0 ? B_OK
: error
;
1722 devfs_io(fs_volume
* volume
, fs_vnode
* _vnode
, void* _cookie
,
1723 io_request
* request
)
1725 TRACE(("[%ld] devfs_io(request: %p)\n", find_thread(NULL
), request
));
1727 devfs_vnode
* vnode
= (devfs_vnode
*)_vnode
->private_node
;
1728 devfs_cookie
* cookie
= (devfs_cookie
*)_cookie
;
1730 bool isWrite
= request
->IsWrite();
1732 if (!S_ISCHR(vnode
->stream
.type
)
1733 || (((isWrite
&& !vnode
->stream
.u
.dev
.device
->HasWrite())
1734 || (!isWrite
&& !vnode
->stream
.u
.dev
.device
->HasRead()))
1735 && !vnode
->stream
.u
.dev
.device
->HasIO())
1736 || cookie
== NULL
) {
1737 request
->SetStatusAndNotify(B_NOT_ALLOWED
);
1738 return B_NOT_ALLOWED
;
1741 if (vnode
->stream
.u
.dev
.partition
!= NULL
) {
1742 if (request
->Offset() + (off_t
)request
->Length()
1743 > vnode
->stream
.u
.dev
.partition
->info
.size
) {
1744 request
->SetStatusAndNotify(B_BAD_VALUE
);
1747 translate_partition_access(vnode
->stream
.u
.dev
.partition
, request
);
1750 if (vnode
->stream
.u
.dev
.device
->HasIO())
1751 return vnode
->stream
.u
.dev
.device
->IO(cookie
->device_cookie
, request
);
1753 synchronous_io_cookie synchronousCookie
= {
1754 vnode
->stream
.u
.dev
.device
,
1755 cookie
->device_cookie
1758 return vfs_synchronous_io(request
,
1759 request
->IsWrite() ? &device_write
: &device_read
, &synchronousCookie
);
1764 devfs_read_stat(fs_volume
* _volume
, fs_vnode
* _vnode
, struct stat
* stat
)
1766 struct devfs_vnode
* vnode
= (struct devfs_vnode
*)_vnode
->private_node
;
1768 TRACE(("devfs_read_stat: vnode %p (%Ld), stat %p\n", vnode
, vnode
->id
,
1771 stat
->st_ino
= vnode
->id
;
1772 stat
->st_rdev
= vnode
->id
;
1774 stat
->st_mode
= vnode
->stream
.type
;
1777 stat
->st_blksize
= 65536;
1778 stat
->st_blocks
= 0;
1780 stat
->st_uid
= vnode
->uid
;
1781 stat
->st_gid
= vnode
->gid
;
1783 stat
->st_atim
= current_timespec();
1784 stat
->st_mtim
= stat
->st_ctim
= vnode
->modification_time
;
1785 stat
->st_crtim
= vnode
->creation_time
;
1787 // TODO: this only works for partitions right now - if we should decide
1788 // to keep this feature, we should have a better solution
1789 if (S_ISCHR(vnode
->stream
.type
)) {
1790 //device_geometry geometry;
1792 // if it's a real block device, then let's report a useful size
1793 if (vnode
->stream
.u
.dev
.partition
!= NULL
) {
1794 stat
->st_size
= vnode
->stream
.u
.dev
.partition
->info
.size
;
1796 } else if (vnode
->stream
.u
.dev
.info
->control(cookie
->device_cookie
,
1797 B_GET_GEOMETRY
, &geometry
, sizeof(struct device_geometry
)) >= B_OK
) {
1798 stat
->st_size
= 1LL * geometry
.head_count
* geometry
.cylinder_count
1799 * geometry
.sectors_per_track
* geometry
.bytes_per_sector
;
1803 // is this a real block device? then let's have it reported like that
1804 if (stat
->st_size
!= 0)
1805 stat
->st_mode
= S_IFBLK
| (vnode
->stream
.type
& S_IUMSK
);
1806 } else if (S_ISLNK(vnode
->stream
.type
)) {
1807 stat
->st_size
= vnode
->stream
.u
.symlink
.length
;
1815 devfs_write_stat(fs_volume
* _volume
, fs_vnode
* _vnode
, const struct stat
* stat
,
1818 struct devfs
* fs
= (struct devfs
*)_volume
->private_volume
;
1819 struct devfs_vnode
* vnode
= (struct devfs_vnode
*)_vnode
->private_node
;
1821 TRACE(("devfs_write_stat: vnode %p (0x%Lx), stat %p\n", vnode
, vnode
->id
,
1824 // we cannot change the size of anything
1825 if (statMask
& B_STAT_SIZE
)
1828 RecursiveLocker
locker(&fs
->lock
);
1830 if (statMask
& B_STAT_MODE
) {
1831 vnode
->stream
.type
= (vnode
->stream
.type
& ~S_IUMSK
)
1832 | (stat
->st_mode
& S_IUMSK
);
1835 if (statMask
& B_STAT_UID
)
1836 vnode
->uid
= stat
->st_uid
;
1837 if (statMask
& B_STAT_GID
)
1838 vnode
->gid
= stat
->st_gid
;
1840 if (statMask
& B_STAT_MODIFICATION_TIME
)
1841 vnode
->modification_time
= stat
->st_mtim
;
1842 if (statMask
& B_STAT_CREATION_TIME
)
1843 vnode
->creation_time
= stat
->st_crtim
;
1845 notify_stat_changed(fs
->id
, get_parent_id(vnode
), vnode
->id
, statMask
);
1851 devfs_std_ops(int32 op
, ...)
1855 add_debugger_command_etc("devfs_node", &dump_node
,
1856 "Print info on a private devfs node",
1858 "Prints information on a devfs node given by <address>.\n",
1860 add_debugger_command_etc("devfs_cookie", &dump_cookie
,
1861 "Print info on a private devfs cookie",
1863 "Prints information on a devfs cookie given by <address>.\n",
1866 legacy_driver_init();
1869 case B_MODULE_UNINIT
:
1870 remove_debugger_command("devfs_node", &dump_node
);
1871 remove_debugger_command("devfs_cookie", &dump_cookie
);
1881 fs_volume_ops kVolumeOps
= {
1888 // the other operations are not supported (attributes, indices, queries)
1892 fs_vnode_ops kVnodeOps
= {
1894 &devfs_get_vnode_name
,
1897 &devfs_remove_vnode
,
1904 NULL
, // cancel_io()
1906 NULL
, // get_file_map
1939 // same as for files - it does nothing for directories, anyway
1940 &devfs_free_dir_cookie
,
1944 // attributes operations are not supported
1950 file_system_module_info gDeviceFileSystem
= {
1952 "file_systems/devfs" B_CURRENT_FS_API_VERSION
,
1957 "devfs", // short_name
1958 "Device File System", // pretty_name
1961 NULL
, // identify_partition()
1962 NULL
, // scan_partition()
1963 NULL
, // free_identify_partition_cookie()
1964 NULL
, // free_partition_content_cookie()
1970 // #pragma mark - kernel private API
1974 devfs_unpublish_file_device(const char* path
)
1976 // get the device node
1978 status_t status
= get_node_for_path(sDeviceFileSystem
, path
, &node
);
1982 if (!S_ISCHR(node
->stream
.type
)) {
1983 put_vnode(sDeviceFileSystem
->volume
, node
->id
);
1987 // if it is indeed a file device, unpublish it
1988 FileDevice
* device
= dynamic_cast<FileDevice
*>(node
->stream
.u
.dev
.device
);
1989 if (device
== NULL
) {
1990 put_vnode(sDeviceFileSystem
->volume
, node
->id
);
1994 status
= unpublish_node(sDeviceFileSystem
, node
, S_IFCHR
);
1996 put_vnode(sDeviceFileSystem
->volume
, node
->id
);
2002 devfs_publish_file_device(const char* path
, const char* filePath
)
2004 // create a FileDevice for the file
2005 FileDevice
* device
= new(std::nothrow
) FileDevice
;
2008 ObjectDeleter
<FileDevice
> deviceDeleter(device
);
2010 status_t error
= device
->Init(filePath
);
2014 // publish the device
2015 error
= publish_device(sDeviceFileSystem
, path
, device
);
2019 deviceDeleter
.Detach();
2025 devfs_unpublish_partition(const char* path
)
2028 status_t status
= get_node_for_path(sDeviceFileSystem
, path
, &node
);
2032 status
= unpublish_node(sDeviceFileSystem
, node
, S_IFCHR
);
2033 put_vnode(sDeviceFileSystem
->volume
, node
->id
);
2039 devfs_publish_partition(const char* name
, const partition_info
* info
)
2041 if (name
== NULL
|| info
== NULL
)
2043 TRACE(("publish partition: %s (device \"%s\", offset %Ld, size %Ld)\n",
2044 name
, info
->device
, info
->offset
, info
->size
));
2046 devfs_vnode
* device
;
2047 status_t status
= get_node_for_path(sDeviceFileSystem
, info
->device
,
2052 status
= add_partition(sDeviceFileSystem
, device
, name
, *info
);
2054 put_vnode(sDeviceFileSystem
->volume
, device
->id
);
2060 devfs_rename_partition(const char* devicePath
, const char* oldName
,
2061 const char* newName
)
2063 if (oldName
== NULL
|| newName
== NULL
)
2066 devfs_vnode
* device
;
2067 status_t status
= get_node_for_path(sDeviceFileSystem
, devicePath
, &device
);
2071 RecursiveLocker
locker(sDeviceFileSystem
->lock
);
2072 devfs_vnode
* node
= devfs_find_in_dir(device
->parent
, oldName
);
2074 return B_ENTRY_NOT_FOUND
;
2076 // check if the new path already exists
2077 if (devfs_find_in_dir(device
->parent
, newName
))
2080 char* name
= strdup(newName
);
2084 devfs_remove_from_dir(device
->parent
, node
, false);
2089 devfs_insert_in_dir(device
->parent
, node
, false);
2091 notify_entry_moved(sDeviceFileSystem
->id
, device
->parent
->id
, oldName
,
2092 device
->parent
->id
, newName
, node
->id
);
2093 notify_stat_changed(sDeviceFileSystem
->id
, get_parent_id(device
->parent
),
2094 device
->parent
->id
, B_STAT_MODIFICATION_TIME
);
2101 devfs_publish_directory(const char* path
)
2103 RecursiveLocker
locker(&sDeviceFileSystem
->lock
);
2105 return publish_directory(sDeviceFileSystem
, path
);
2110 devfs_unpublish_device(const char* path
, bool disconnect
)
2113 status_t status
= get_node_for_path(sDeviceFileSystem
, path
, &node
);
2117 status
= unpublish_node(sDeviceFileSystem
, node
, S_IFCHR
);
2119 if (status
== B_OK
&& disconnect
)
2120 vfs_disconnect_vnode(sDeviceFileSystem
->id
, node
->id
);
2122 put_vnode(sDeviceFileSystem
->volume
, node
->id
);
2127 // #pragma mark - device_manager private API
2131 devfs_publish_device(const char* path
, BaseDevice
* device
)
2133 return publish_device(sDeviceFileSystem
, path
, device
);
2138 devfs_unpublish_device(BaseDevice
* device
, bool disconnect
)
2141 status_t status
= get_vnode(sDeviceFileSystem
->volume
, device
->ID(),
2146 status
= unpublish_node(sDeviceFileSystem
, node
, S_IFCHR
);
2148 if (status
== B_OK
&& disconnect
)
2149 vfs_disconnect_vnode(sDeviceFileSystem
->id
, node
->id
);
2151 put_vnode(sDeviceFileSystem
->volume
, node
->id
);
2156 /*! Gets the device for a given devfs relative path.
2157 If successful the call must be balanced with a call to devfs_put_device().
2160 devfs_get_device(const char* path
, BaseDevice
*& _device
)
2163 status_t status
= get_node_for_path(sDeviceFileSystem
, path
, &node
);
2167 if (!S_ISCHR(node
->stream
.type
) || node
->stream
.u
.dev
.partition
!= NULL
) {
2168 put_vnode(sDeviceFileSystem
->volume
, node
->id
);
2172 _device
= node
->stream
.u
.dev
.device
;
2178 devfs_put_device(BaseDevice
* device
)
2180 put_vnode(sDeviceFileSystem
->volume
, device
->ID());
2185 devfs_compute_geometry_size(device_geometry
* geometry
, uint64 blockCount
,
2188 if (blockCount
> UINT32_MAX
)
2189 geometry
->head_count
= (blockCount
+ UINT32_MAX
- 1) / UINT32_MAX
;
2191 geometry
->head_count
= 1;
2193 geometry
->cylinder_count
= 1;
2194 geometry
->sectors_per_track
= blockCount
/ geometry
->head_count
;
2195 geometry
->bytes_per_sector
= blockSize
;
2199 // #pragma mark - support API for legacy drivers
2203 devfs_rescan_driver(const char* driverName
)
2205 TRACE(("devfs_rescan_driver: %s\n", driverName
));
2207 return legacy_driver_rescan(driverName
);
2212 devfs_publish_device(const char* path
, device_hooks
* hooks
)
2214 return legacy_driver_publish(path
, hooks
);