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