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