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