xref: /haiku/src/system/kernel/device_manager/devfs.cpp (revision 3b07762c548ec4016dea480d1061577cd15ec614)
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 <util/khash.h>
37 #include <vfs.h>
38 #include <vm/vm.h>
39 
40 #include "BaseDevice.h"
41 #include "FileDevice.h"
42 #include "IORequest.h"
43 #include "legacy_drivers.h"
44 
45 
46 //#define TRACE_DEVFS
47 #ifdef TRACE_DEVFS
48 #	define TRACE(x) dprintf x
49 #else
50 #	define TRACE(x)
51 #endif
52 
53 
54 struct devfs_partition {
55 	struct devfs_vnode*	raw_device;
56 	partition_info		info;
57 };
58 
59 struct driver_entry;
60 
61 enum {
62 	kNotScanned = 0,
63 	kBootScan,
64 	kNormalScan,
65 };
66 
67 struct devfs_stream {
68 	mode_t				type;
69 	union {
70 		struct stream_dir {
71 			struct devfs_vnode*		dir_head;
72 			struct list				cookies;
73 			mutex					scan_lock;
74 			int32					scanned;
75 		} dir;
76 		struct stream_dev {
77 			BaseDevice*				device;
78 			struct devfs_partition*	partition;
79 		} dev;
80 		struct stream_symlink {
81 			const char*				path;
82 			size_t					length;
83 		} symlink;
84 	} u;
85 };
86 
87 struct devfs_vnode {
88 	struct devfs_vnode*	all_next;
89 	ino_t				id;
90 	char*				name;
91 	timespec			modification_time;
92 	timespec			creation_time;
93 	uid_t				uid;
94 	gid_t				gid;
95 	struct devfs_vnode*	parent;
96 	struct devfs_vnode*	dir_next;
97 	struct devfs_stream	stream;
98 };
99 
100 #define DEVFS_HASH_SIZE 16
101 
102 struct devfs {
103 	dev_t				id;
104 	fs_volume*			volume;
105 	recursive_lock		lock;
106  	int32				next_vnode_id;
107 	hash_table*			vnode_hash;
108 	struct devfs_vnode*	root_vnode;
109 };
110 
111 struct devfs_dir_cookie {
112 	struct list_link	link;
113 	struct devfs_vnode*	current;
114 	int32				state;	// iteration state
115 };
116 
117 struct devfs_cookie {
118 	void*				device_cookie;
119 };
120 
121 struct synchronous_io_cookie {
122 	BaseDevice*		device;
123 	void*			cookie;
124 };
125 
126 // directory iteration states
127 enum {
128 	ITERATION_STATE_DOT		= 0,
129 	ITERATION_STATE_DOT_DOT	= 1,
130 	ITERATION_STATE_OTHERS	= 2,
131 	ITERATION_STATE_BEGIN	= ITERATION_STATE_DOT,
132 };
133 
134 // extern and in a private namespace only to make forward declaration possible
135 namespace {
136 	extern fs_volume_ops kVolumeOps;
137 	extern fs_vnode_ops kVnodeOps;
138 }
139 
140 
141 static status_t get_node_for_path(struct devfs* fs, const char* path,
142 	struct devfs_vnode** _node);
143 static void get_device_name(struct devfs_vnode* vnode, char* buffer,
144 	size_t size);
145 static status_t unpublish_node(struct devfs* fs, devfs_vnode* node,
146 	mode_t type);
147 static status_t publish_device(struct devfs* fs, const char* path,
148 	BaseDevice* device);
149 
150 
151 // The one and only allowed devfs instance
152 static struct devfs* sDeviceFileSystem = NULL;
153 
154 
155 //	#pragma mark - devfs private
156 
157 
158 static timespec
159 current_timespec()
160 {
161 	bigtime_t time = real_time_clock_usecs();
162 
163 	timespec tv;
164 	tv.tv_sec = time / 1000000;
165 	tv.tv_nsec = (time % 1000000) * 1000;
166 	return tv;
167 }
168 
169 
170 static int32
171 scan_mode(void)
172 {
173 	// We may scan every device twice:
174 	//  - once before there is a boot device,
175 	//  - and once when there is one
176 
177 	return gBootDevice >= 0 ? kNormalScan : kBootScan;
178 }
179 
180 
181 static status_t
182 scan_for_drivers_if_needed(devfs_vnode* dir)
183 {
184 	ASSERT(S_ISDIR(dir->stream.type));
185 
186 	MutexLocker _(dir->stream.u.dir.scan_lock);
187 
188 	if (dir->stream.u.dir.scanned >= scan_mode())
189 		return B_OK;
190 
191 	KPath path;
192 	if (path.InitCheck() != B_OK)
193 		return B_NO_MEMORY;
194 
195 	get_device_name(dir, path.LockBuffer(), path.BufferSize());
196 	path.UnlockBuffer();
197 
198 	TRACE(("scan_for_drivers_if_needed: mode %ld: %s\n", scan_mode(),
199 		path.Path()));
200 
201 	// scan for drivers at this path
202 	static int32 updateCycle = 1;
203 	device_manager_probe(path.Path(), updateCycle++);
204 	legacy_driver_probe(path.Path());
205 
206 	dir->stream.u.dir.scanned = scan_mode();
207 	return B_OK;
208 }
209 
210 
211 static uint32
212 devfs_vnode_hash(void* _vnode, const void* _key, uint32 range)
213 {
214 	struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode;
215 	const ino_t* key = (const ino_t*)_key;
216 
217 	if (vnode != NULL)
218 		return vnode->id % range;
219 
220 	return (uint64)*key % range;
221 }
222 
223 
224 static int
225 devfs_vnode_compare(void* _vnode, const void* _key)
226 {
227 	struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode;
228 	const ino_t* key = (const ino_t*)_key;
229 
230 	if (vnode->id == *key)
231 		return 0;
232 
233 	return -1;
234 }
235 
236 
237 static void
238 init_directory_vnode(struct devfs_vnode* vnode, int permissions)
239 {
240 	vnode->stream.type = S_IFDIR | permissions;
241 		mutex_init(&vnode->stream.u.dir.scan_lock, "devfs scan");
242 	vnode->stream.u.dir.dir_head = NULL;
243 	list_init(&vnode->stream.u.dir.cookies);
244 }
245 
246 
247 static struct devfs_vnode*
248 devfs_create_vnode(struct devfs* fs, devfs_vnode* parent, const char* name)
249 {
250 	struct devfs_vnode* vnode;
251 
252 	vnode = (struct devfs_vnode*)malloc(sizeof(struct devfs_vnode));
253 	if (vnode == NULL)
254 		return NULL;
255 
256 	memset(vnode, 0, sizeof(struct devfs_vnode));
257 	vnode->id = fs->next_vnode_id++;
258 
259 	vnode->name = strdup(name);
260 	if (vnode->name == NULL) {
261 		free(vnode);
262 		return NULL;
263 	}
264 
265 	vnode->creation_time = vnode->modification_time = current_timespec();
266 	vnode->uid = geteuid();
267 	vnode->gid = parent ? parent->gid : getegid();
268 		// inherit group from parent if possible
269 
270 	return vnode;
271 }
272 
273 
274 static status_t
275 devfs_delete_vnode(struct devfs* fs, struct devfs_vnode* vnode,
276 	bool forceDelete)
277 {
278 	// Can't delete it if it's in a directory or is a directory
279 	// and has children
280 	if (!forceDelete && ((S_ISDIR(vnode->stream.type)
281 				&& vnode->stream.u.dir.dir_head != NULL)
282 			|| vnode->dir_next != NULL))
283 		return B_NOT_ALLOWED;
284 
285 	// remove it from the global hash table
286 	hash_remove(fs->vnode_hash, vnode);
287 
288 	if (S_ISCHR(vnode->stream.type)) {
289 		if (vnode->stream.u.dev.partition == NULL) {
290 			// pass the call through to the underlying device
291 			vnode->stream.u.dev.device->Removed();
292 		} else {
293 			// for partitions, we have to release the raw device but must
294 			// not free the device info as it was inherited from the raw
295 			// device and is still in use there
296 			put_vnode(fs->volume, vnode->stream.u.dev.partition->raw_device->id);
297 		}
298 	} else if (S_ISDIR(vnode->stream.type)) {
299 		mutex_destroy(&vnode->stream.u.dir.scan_lock);
300 	}
301 
302 	free(vnode->name);
303 	free(vnode);
304 
305 	return B_OK;
306 }
307 
308 
309 /*! Makes sure none of the dircookies point to the vnode passed in */
310 static void
311 update_dir_cookies(struct devfs_vnode* dir, struct devfs_vnode* vnode)
312 {
313 	struct devfs_dir_cookie* cookie = NULL;
314 
315 	while ((cookie = (devfs_dir_cookie*)list_get_next_item(
316 			&dir->stream.u.dir.cookies, cookie)) != NULL) {
317 		if (cookie->current == vnode)
318 			cookie->current = vnode->dir_next;
319 	}
320 }
321 
322 
323 static struct devfs_vnode*
324 devfs_find_in_dir(struct devfs_vnode* dir, const char* path)
325 {
326 	struct devfs_vnode* vnode;
327 
328 	if (!S_ISDIR(dir->stream.type))
329 		return NULL;
330 
331 	if (!strcmp(path, "."))
332 		return dir;
333 	if (!strcmp(path, ".."))
334 		return dir->parent;
335 
336 	for (vnode = dir->stream.u.dir.dir_head; vnode; vnode = vnode->dir_next) {
337 		//TRACE(("devfs_find_in_dir: looking at entry '%s'\n", vnode->name));
338 		if (strcmp(vnode->name, path) == 0) {
339 			//TRACE(("devfs_find_in_dir: found it at %p\n", vnode));
340 			return vnode;
341 		}
342 	}
343 	return NULL;
344 }
345 
346 
347 static status_t
348 devfs_insert_in_dir(struct devfs_vnode* dir, struct devfs_vnode* vnode,
349 	bool notify = true)
350 {
351 	if (!S_ISDIR(dir->stream.type))
352 		return B_BAD_VALUE;
353 
354 	// make sure the directory stays sorted alphabetically
355 
356 	devfs_vnode* node = dir->stream.u.dir.dir_head;
357 	devfs_vnode* last = NULL;
358 	while (node && strcmp(node->name, vnode->name) < 0) {
359 		last = node;
360 		node = node->dir_next;
361 	}
362 	if (last == NULL) {
363 		// the new vnode is the first entry in the list
364 		vnode->dir_next = dir->stream.u.dir.dir_head;
365 		dir->stream.u.dir.dir_head = vnode;
366 	} else {
367 		// insert after that node
368 		vnode->dir_next = last->dir_next;
369 		last->dir_next = vnode;
370 	}
371 
372 	vnode->parent = dir;
373 	dir->modification_time = current_timespec();
374 
375 	if (notify) {
376 		notify_entry_created(sDeviceFileSystem->id, dir->id, vnode->name,
377 			vnode->id);
378 		notify_stat_changed(sDeviceFileSystem->id, dir->id,
379 			B_STAT_MODIFICATION_TIME);
380 	}
381 	return B_OK;
382 }
383 
384 
385 static status_t
386 devfs_remove_from_dir(struct devfs_vnode* dir, struct devfs_vnode* removeNode,
387 	bool notify = true)
388 {
389 	struct devfs_vnode* vnode = dir->stream.u.dir.dir_head;
390 	struct devfs_vnode* lastNode = NULL;
391 
392 	for (; vnode != NULL; lastNode = vnode, vnode = vnode->dir_next) {
393 		if (vnode == removeNode) {
394 			// make sure no dircookies point to this vnode
395 			update_dir_cookies(dir, vnode);
396 
397 			if (lastNode)
398 				lastNode->dir_next = vnode->dir_next;
399 			else
400 				dir->stream.u.dir.dir_head = vnode->dir_next;
401 			vnode->dir_next = NULL;
402 			dir->modification_time = current_timespec();
403 
404 			if (notify) {
405 				notify_entry_removed(sDeviceFileSystem->id, dir->id, vnode->name,
406 					vnode->id);
407 				notify_stat_changed(sDeviceFileSystem->id, dir->id,
408 					B_STAT_MODIFICATION_TIME);
409 			}
410 			return B_OK;
411 		}
412 	}
413 	return B_ENTRY_NOT_FOUND;
414 }
415 
416 
417 static status_t
418 add_partition(struct devfs* fs, struct devfs_vnode* device, const char* name,
419 	const partition_info& info)
420 {
421 	struct devfs_vnode* partitionNode;
422 	status_t status;
423 
424 	if (!S_ISCHR(device->stream.type))
425 		return B_BAD_VALUE;
426 
427 	// we don't support nested partitions
428 	if (device->stream.u.dev.partition != NULL)
429 		return B_BAD_VALUE;
430 
431 	// reduce checks to a minimum - things like negative offsets could be useful
432 	if (info.size < 0)
433 		return B_BAD_VALUE;
434 
435 	// create partition
436 	struct devfs_partition* partition = (struct devfs_partition*)malloc(
437 		sizeof(struct devfs_partition));
438 	if (partition == NULL)
439 		return B_NO_MEMORY;
440 
441 	memcpy(&partition->info, &info, sizeof(partition_info));
442 
443 	RecursiveLocker locker(fs->lock);
444 
445 	// you cannot change a partition once set
446 	if (devfs_find_in_dir(device->parent, name)) {
447 		status = B_BAD_VALUE;
448 		goto err1;
449 	}
450 
451 	// increase reference count of raw device -
452 	// the partition device really needs it
453 	status = get_vnode(fs->volume, device->id, (void**)&partition->raw_device);
454 	if (status < B_OK)
455 		goto err1;
456 
457 	// now create the partition vnode
458 	partitionNode = devfs_create_vnode(fs, device->parent, name);
459 	if (partitionNode == NULL) {
460 		status = B_NO_MEMORY;
461 		goto err2;
462 	}
463 
464 	partitionNode->stream.type = device->stream.type;
465 	partitionNode->stream.u.dev.device = device->stream.u.dev.device;
466 	partitionNode->stream.u.dev.partition = partition;
467 
468 	hash_insert(fs->vnode_hash, partitionNode);
469 	devfs_insert_in_dir(device->parent, partitionNode);
470 
471 	TRACE(("add_partition(name = %s, offset = %Ld, size = %Ld)\n",
472 		name, info.offset, info.size));
473 	return B_OK;
474 
475 err2:
476 	put_vnode(fs->volume, device->id);
477 err1:
478 	free(partition);
479 	return status;
480 }
481 
482 
483 static inline void
484 translate_partition_access(devfs_partition* partition, off_t& offset,
485 	size_t& size)
486 {
487 	ASSERT(offset >= 0);
488 	ASSERT(offset < partition->info.size);
489 
490 	size = (size_t)min_c((off_t)size, partition->info.size - offset);
491 	offset += partition->info.offset;
492 }
493 
494 
495 static inline void
496 translate_partition_access(devfs_partition* partition, io_request* request)
497 {
498 	off_t offset = request->Offset();
499 
500 	ASSERT(offset >= 0);
501 	ASSERT(offset + (off_t)request->Length() <= partition->info.size);
502 
503 	request->SetOffset(offset + partition->info.offset);
504 }
505 
506 
507 static status_t
508 get_node_for_path(struct devfs* fs, const char* path,
509 	struct devfs_vnode** _node)
510 {
511 	return vfs_get_fs_node_from_path(fs->volume, path, false, true,
512 		(void**)_node);
513 }
514 
515 
516 static status_t
517 unpublish_node(struct devfs* fs, devfs_vnode* node, mode_t type)
518 {
519 	if ((node->stream.type & S_IFMT) != type)
520 		return B_BAD_TYPE;
521 
522 	recursive_lock_lock(&fs->lock);
523 
524 	status_t status = devfs_remove_from_dir(node->parent, node);
525 	if (status < B_OK)
526 		goto out;
527 
528 	status = remove_vnode(fs->volume, node->id);
529 
530 out:
531 	recursive_lock_unlock(&fs->lock);
532 	return status;
533 }
534 
535 
536 static void
537 publish_node(devfs* fs, devfs_vnode* dirNode, struct devfs_vnode* node)
538 {
539 	hash_insert(fs->vnode_hash, node);
540 	devfs_insert_in_dir(dirNode, node);
541 }
542 
543 
544 static status_t
545 publish_directory(struct devfs* fs, const char* path)
546 {
547 	ASSERT_LOCKED_RECURSIVE(&fs->lock);
548 
549 	// copy the path over to a temp buffer so we can munge it
550 	KPath tempPath(path);
551 	if (tempPath.InitCheck() != B_OK)
552 		return B_NO_MEMORY;
553 
554 	TRACE(("devfs: publish directory \"%s\"\n", path));
555 	char* temp = tempPath.LockBuffer();
556 
557 	// create the path leading to the device
558 	// parse the path passed in, stripping out '/'
559 
560 	struct devfs_vnode* dir = fs->root_vnode;
561 	struct devfs_vnode* vnode = NULL;
562 	status_t status = B_OK;
563 	int32 i = 0, last = 0;
564 
565 	while (temp[last]) {
566 		if (temp[i] == '/') {
567 			temp[i] = '\0';
568 			i++;
569 		} else if (temp[i] != '\0') {
570 			i++;
571 			continue;
572 		}
573 
574 		//TRACE(("\tpath component '%s'\n", &temp[last]));
575 
576 		// we have a path component
577 		vnode = devfs_find_in_dir(dir, &temp[last]);
578 		if (vnode) {
579 			if (S_ISDIR(vnode->stream.type)) {
580 				last = i;
581 				dir = vnode;
582 				continue;
583 			}
584 
585 			// we hit something on our path that's not a directory
586 			status = B_FILE_EXISTS;
587 			goto out;
588 		} else {
589 			vnode = devfs_create_vnode(fs, dir, &temp[last]);
590 			if (!vnode) {
591 				status = B_NO_MEMORY;
592 				goto out;
593 			}
594 		}
595 
596 		// set up the new directory
597 		init_directory_vnode(vnode, 0755);
598 		publish_node(sDeviceFileSystem, dir, vnode);
599 
600 		last = i;
601 		dir = vnode;
602 	}
603 
604 out:
605 	return status;
606 }
607 
608 
609 static status_t
610 new_node(struct devfs* fs, const char* path, struct devfs_vnode** _node,
611 	struct devfs_vnode** _dir)
612 {
613 	ASSERT_LOCKED_RECURSIVE(&fs->lock);
614 
615 	// copy the path over to a temp buffer so we can munge it
616 	KPath tempPath(path);
617 	if (tempPath.InitCheck() != B_OK)
618 		return B_NO_MEMORY;
619 
620 	char* temp = tempPath.LockBuffer();
621 
622 	// create the path leading to the device
623 	// parse the path passed in, stripping out '/'
624 
625 	struct devfs_vnode* dir = fs->root_vnode;
626 	struct devfs_vnode* vnode = NULL;
627 	status_t status = B_OK;
628 	int32 i = 0, last = 0;
629 	bool atLeaf = false;
630 
631 	for (;;) {
632 		if (temp[i] == '\0') {
633 			atLeaf = true; // we'll be done after this one
634 		} else if (temp[i] == '/') {
635 			temp[i] = '\0';
636 			i++;
637 		} else {
638 			i++;
639 			continue;
640 		}
641 
642 		//TRACE(("\tpath component '%s'\n", &temp[last]));
643 
644 		// we have a path component
645 		vnode = devfs_find_in_dir(dir, &temp[last]);
646 		if (vnode) {
647 			if (!atLeaf) {
648 				// we are not at the leaf of the path, so as long as
649 				// this is a dir we're okay
650 				if (S_ISDIR(vnode->stream.type)) {
651 					last = i;
652 					dir = vnode;
653 					continue;
654 				}
655 			}
656 			// we are at the leaf and hit another node
657 			// or we aren't but hit a non-dir node.
658 			// we're screwed
659 			status = B_FILE_EXISTS;
660 			goto out;
661 		} else {
662 			vnode = devfs_create_vnode(fs, dir, &temp[last]);
663 			if (!vnode) {
664 				status = B_NO_MEMORY;
665 				goto out;
666 			}
667 		}
668 
669 		// set up the new vnode
670 		if (!atLeaf) {
671 			// this is a dir
672 			init_directory_vnode(vnode, 0755);
673 			publish_node(fs, dir, vnode);
674 		} else {
675 			// this is the last component
676 			// Note: We do not yet insert the node into the directory, as it
677 			// is not yet fully initialized. Instead we return the directory
678 			// vnode so that the calling function can insert it after all
679 			// initialization is done. This ensures that no create notification
680 			// is sent out for a vnode that is not yet fully valid.
681 			*_node = vnode;
682 			*_dir = dir;
683 			break;
684 		}
685 
686 		last = i;
687 		dir = vnode;
688 	}
689 
690 out:
691 	return status;
692 }
693 
694 
695 static status_t
696 publish_device(struct devfs* fs, const char* path, BaseDevice* device)
697 {
698 	TRACE(("publish_device(path = \"%s\", device = %p)\n", path, device));
699 
700 	if (sDeviceFileSystem == NULL) {
701 		panic("publish_device() called before devfs mounted\n");
702 		return B_ERROR;
703 	}
704 
705 	if (device == NULL || path == NULL || path[0] == '\0' || path[0] == '/')
706 		return B_BAD_VALUE;
707 
708 // TODO: this has to be done in the BaseDevice sub classes!
709 #if 0
710 	// are the provided device hooks okay?
711 	if (info->device_open == NULL || info->device_close == NULL
712 		|| info->device_free == NULL
713 		|| ((info->device_read == NULL || info->device_write == NULL)
714 			&& info->device_io == NULL))
715 		return B_BAD_VALUE;
716 #endif
717 
718 	struct devfs_vnode* node;
719 	struct devfs_vnode* dirNode;
720 	status_t status;
721 
722 	RecursiveLocker locker(&fs->lock);
723 
724 	status = new_node(fs, path, &node, &dirNode);
725 	if (status != B_OK)
726 		return status;
727 
728 	// all went fine, let's initialize the node
729 	node->stream.type = S_IFCHR | 0644;
730 	node->stream.u.dev.device = device;
731 	device->SetID(node->id);
732 
733 	// the node is now fully valid and we may insert it into the dir
734 	publish_node(fs, dirNode, node);
735 	return B_OK;
736 }
737 
738 
739 /*!	Construct complete device name (as used for device_open()).
740 	This is safe to use only when the device is in use (and therefore
741 	cannot be unpublished during the iteration).
742 */
743 static void
744 get_device_name(struct devfs_vnode* vnode, char* buffer, size_t size)
745 {
746 	RecursiveLocker _(sDeviceFileSystem->lock);
747 
748 	struct devfs_vnode* leaf = vnode;
749 	size_t offset = 0;
750 
751 	// count levels
752 
753 	for (; vnode->parent && vnode->parent != vnode; vnode = vnode->parent) {
754 		offset += strlen(vnode->name) + 1;
755 	}
756 
757 	// construct full path name
758 
759 	for (vnode = leaf; vnode->parent && vnode->parent != vnode;
760 			vnode = vnode->parent) {
761 		size_t length = strlen(vnode->name);
762 		size_t start = offset - length - 1;
763 
764 		if (size >= offset) {
765 			strcpy(buffer + start, vnode->name);
766 			if (vnode != leaf)
767 				buffer[offset - 1] = '/';
768 		}
769 
770 		offset = start;
771 	}
772 }
773 
774 
775 static status_t
776 device_read(void* _cookie, off_t offset, void* buffer, size_t* length)
777 {
778 	synchronous_io_cookie* cookie = (synchronous_io_cookie*)_cookie;
779 	return cookie->device->Read(cookie->cookie, offset, buffer, length);
780 }
781 
782 
783 static status_t
784 device_write(void* _cookie, off_t offset, void* buffer, size_t* length)
785 {
786 	synchronous_io_cookie* cookie = (synchronous_io_cookie*)_cookie;
787 	return cookie->device->Write(cookie->cookie, offset, buffer, length);
788 }
789 
790 
791 static int
792 dump_node(int argc, char** argv)
793 {
794 	if (argc != 2) {
795 		print_debugger_command_usage(argv[0]);
796 		return 0;
797 	}
798 
799 	struct devfs_vnode* vnode = (struct devfs_vnode*)parse_expression(argv[1]);
800 	if (vnode == NULL) {
801 		kprintf("invalid node address\n");
802 		return 0;
803 	}
804 
805 	kprintf("DEVFS NODE: %p\n", vnode);
806 	kprintf(" id:          %" B_PRIdINO "\n", vnode->id);
807 	kprintf(" name:        \"%s\"\n", vnode->name);
808 	kprintf(" type:        %x\n", vnode->stream.type);
809 	kprintf(" parent:      %p\n", vnode->parent);
810 	kprintf(" dir next:    %p\n", vnode->dir_next);
811 
812 	if (S_ISDIR(vnode->stream.type)) {
813 		kprintf(" dir scanned: %" B_PRId32 "\n", vnode->stream.u.dir.scanned);
814 		kprintf(" contents:\n");
815 
816 		devfs_vnode* children = vnode->stream.u.dir.dir_head;
817 		while (children != NULL) {
818 			kprintf("   %p, id %" B_PRIdINO "\n", children, children->id);
819 			children = children->dir_next;
820 		}
821 	} else if (S_ISLNK(vnode->stream.type)) {
822 		kprintf(" symlink to:  %s\n", vnode->stream.u.symlink.path);
823 	} else {
824 		kprintf(" device:      %p\n", vnode->stream.u.dev.device);
825 		kprintf(" partition:   %p\n", vnode->stream.u.dev.partition);
826 		if (vnode->stream.u.dev.partition != NULL) {
827 			partition_info& info = vnode->stream.u.dev.partition->info;
828 			kprintf("  raw device node: %p\n",
829 				vnode->stream.u.dev.partition->raw_device);
830 			kprintf("  offset:          %" B_PRIdOFF "\n", info.offset);
831 			kprintf("  size:            %" B_PRIdOFF "\n", info.size);
832 			kprintf("  block size:      %" B_PRId32 "\n", info.logical_block_size);
833 			kprintf("  session:         %" B_PRId32 "\n", info.session);
834 			kprintf("  partition:       %" B_PRId32 "\n", info.partition);
835 			kprintf("  device:          %s\n", info.device);
836 			set_debug_variable("_raw",
837 				(addr_t)vnode->stream.u.dev.partition->raw_device);
838 		}
839 	}
840 
841 	return 0;
842 }
843 
844 
845 static int
846 dump_cookie(int argc, char** argv)
847 {
848 	if (argc != 2) {
849 		print_debugger_command_usage(argv[0]);
850 		return 0;
851 	}
852 
853 	uint64 address;
854 	if (!evaluate_debug_expression(argv[1], &address, false))
855 		return 0;
856 
857 	struct devfs_cookie* cookie = (devfs_cookie*)(addr_t)address;
858 
859 	kprintf("DEVFS COOKIE: %p\n", cookie);
860 	kprintf(" device_cookie: %p\n", cookie->device_cookie);
861 
862 	return 0;
863 }
864 
865 
866 //	#pragma mark - file system interface
867 
868 
869 static status_t
870 devfs_mount(fs_volume* volume, const char* devfs, uint32 flags,
871 	const char* args, ino_t* _rootNodeID)
872 {
873 	struct devfs_vnode* vnode;
874 	struct devfs* fs;
875 	status_t err;
876 
877 	TRACE(("devfs_mount: entry\n"));
878 
879 	if (sDeviceFileSystem) {
880 		TRACE(("double mount of devfs attempted\n"));
881 		err = B_ERROR;
882 		goto err;
883 	}
884 
885 	fs = (struct devfs*)malloc(sizeof(struct devfs));
886 	if (fs == NULL) {
887 		err = B_NO_MEMORY;
888 		goto err;
889  	}
890 
891 	volume->private_volume = fs;
892 	volume->ops = &kVolumeOps;
893 	fs->volume = volume;
894 	fs->id = volume->id;
895 	fs->next_vnode_id = 0;
896 
897 	recursive_lock_init(&fs->lock, "devfs lock");
898 
899 	fs->vnode_hash = hash_init(DEVFS_HASH_SIZE, offsetof(devfs_vnode, all_next),
900 		//(addr_t)&vnode->all_next - (addr_t)vnode,
901 		&devfs_vnode_compare, &devfs_vnode_hash);
902 	if (fs->vnode_hash == NULL) {
903 		err = B_NO_MEMORY;
904 		goto err2;
905 	}
906 
907 	// create a vnode
908 	vnode = devfs_create_vnode(fs, NULL, "");
909 	if (vnode == NULL) {
910 		err = B_NO_MEMORY;
911 		goto err3;
912 	}
913 
914 	// set it up
915 	vnode->parent = vnode;
916 
917 	// create a dir stream for it to hold
918 	init_directory_vnode(vnode, 0755);
919 	fs->root_vnode = vnode;
920 
921 	hash_insert(fs->vnode_hash, vnode);
922 	publish_vnode(volume, vnode->id, vnode, &kVnodeOps, vnode->stream.type, 0);
923 
924 	*_rootNodeID = vnode->id;
925 	sDeviceFileSystem = fs;
926 	return B_OK;
927 
928 err3:
929 	hash_uninit(fs->vnode_hash);
930 err2:
931 	recursive_lock_destroy(&fs->lock);
932 	free(fs);
933 err:
934 	return err;
935 }
936 
937 
938 static status_t
939 devfs_unmount(fs_volume* _volume)
940 {
941 	struct devfs* fs = (struct devfs*)_volume->private_volume;
942 	struct devfs_vnode* vnode;
943 	struct hash_iterator i;
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 	hash_open(fs->vnode_hash, &i);
954 	while ((vnode = (devfs_vnode*)hash_next(fs->vnode_hash, &i)) != NULL) {
955 		devfs_delete_vnode(fs, vnode, true);
956 	}
957 	hash_close(fs->vnode_hash, &i, false);
958 	hash_uninit(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 = (devfs_vnode*)hash_lookup(fs->vnode_hash, &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_size = 0;
1764 	stat->st_mode = vnode->stream.type;
1765 
1766 	stat->st_nlink = 1;
1767 	stat->st_blksize = 65536;
1768 	stat->st_blocks = 0;
1769 
1770 	stat->st_uid = vnode->uid;
1771 	stat->st_gid = vnode->gid;
1772 
1773 	stat->st_atim = current_timespec();
1774 	stat->st_mtim = stat->st_ctim = vnode->modification_time;
1775 	stat->st_crtim = vnode->creation_time;
1776 
1777 	// TODO: this only works for partitions right now - if we should decide
1778 	//	to keep this feature, we should have a better solution
1779 	if (S_ISCHR(vnode->stream.type)) {
1780 		//device_geometry geometry;
1781 
1782 		// if it's a real block device, then let's report a useful size
1783 		if (vnode->stream.u.dev.partition != NULL) {
1784 			stat->st_size = vnode->stream.u.dev.partition->info.size;
1785 #if 0
1786 		} else if (vnode->stream.u.dev.info->control(cookie->device_cookie,
1787 					B_GET_GEOMETRY, &geometry, sizeof(struct device_geometry)) >= B_OK) {
1788 			stat->st_size = 1LL * geometry.head_count * geometry.cylinder_count
1789 				* geometry.sectors_per_track * geometry.bytes_per_sector;
1790 #endif
1791 		}
1792 
1793 		// is this a real block device? then let's have it reported like that
1794 		if (stat->st_size != 0)
1795 			stat->st_mode = S_IFBLK | (vnode->stream.type & S_IUMSK);
1796 	} else if (S_ISLNK(vnode->stream.type)) {
1797 		stat->st_size = vnode->stream.u.symlink.length;
1798 	}
1799 
1800 	return B_OK;
1801 }
1802 
1803 
1804 static status_t
1805 devfs_write_stat(fs_volume* _volume, fs_vnode* _vnode, const struct stat* stat,
1806 	uint32 statMask)
1807 {
1808 	struct devfs* fs = (struct devfs*)_volume->private_volume;
1809 	struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node;
1810 
1811 	TRACE(("devfs_write_stat: vnode %p (0x%Lx), stat %p\n", vnode, vnode->id,
1812 		stat));
1813 
1814 	// we cannot change the size of anything
1815 	if (statMask & B_STAT_SIZE)
1816 		return B_BAD_VALUE;
1817 
1818 	RecursiveLocker locker(&fs->lock);
1819 
1820 	if (statMask & B_STAT_MODE) {
1821 		vnode->stream.type = (vnode->stream.type & ~S_IUMSK)
1822 			| (stat->st_mode & S_IUMSK);
1823 	}
1824 
1825 	if (statMask & B_STAT_UID)
1826 		vnode->uid = stat->st_uid;
1827 	if (statMask & B_STAT_GID)
1828 		vnode->gid = stat->st_gid;
1829 
1830 	if (statMask & B_STAT_MODIFICATION_TIME)
1831 		vnode->modification_time = stat->st_mtim;
1832 	if (statMask & B_STAT_CREATION_TIME)
1833 		vnode->creation_time = stat->st_crtim;
1834 
1835 	notify_stat_changed(fs->id, vnode->id, statMask);
1836 	return B_OK;
1837 }
1838 
1839 
1840 static status_t
1841 devfs_std_ops(int32 op, ...)
1842 {
1843 	switch (op) {
1844 		case B_MODULE_INIT:
1845 			add_debugger_command_etc("devfs_node", &dump_node,
1846 				"Print info on a private devfs node",
1847 				"<address>\n"
1848 				"Prints information on a devfs node given by <address>.\n",
1849 				0);
1850 			add_debugger_command_etc("devfs_cookie", &dump_cookie,
1851 				"Print info on a private devfs cookie",
1852 				"<address>\n"
1853 				"Prints information on a devfs cookie given by <address>.\n",
1854 				0);
1855 
1856 			legacy_driver_init();
1857 			return B_OK;
1858 
1859 		case B_MODULE_UNINIT:
1860 			remove_debugger_command("devfs_node", &dump_node);
1861 			remove_debugger_command("devfs_cookie", &dump_cookie);
1862 			return B_OK;
1863 
1864 		default:
1865 			return B_ERROR;
1866 	}
1867 }
1868 
1869 namespace {
1870 
1871 fs_volume_ops kVolumeOps = {
1872 	&devfs_unmount,
1873 	NULL,
1874 	NULL,
1875 	&devfs_sync,
1876 	&devfs_get_vnode,
1877 
1878 	// the other operations are not supported (attributes, indices, queries)
1879 	NULL,
1880 };
1881 
1882 fs_vnode_ops kVnodeOps = {
1883 	&devfs_lookup,
1884 	&devfs_get_vnode_name,
1885 
1886 	&devfs_put_vnode,
1887 	&devfs_remove_vnode,
1888 
1889 	&devfs_can_page,
1890 	&devfs_read_pages,
1891 	&devfs_write_pages,
1892 
1893 	&devfs_io,
1894 	NULL,	// cancel_io()
1895 
1896 	NULL,	// get_file_map
1897 
1898 	/* common */
1899 	&devfs_ioctl,
1900 	&devfs_set_flags,
1901 	&devfs_select,
1902 	&devfs_deselect,
1903 	&devfs_fsync,
1904 
1905 	&devfs_read_link,
1906 	NULL,	// symlink
1907 	NULL,	// link
1908 	NULL,	// unlink
1909 	NULL,	// rename
1910 
1911 	NULL,	// access
1912 	&devfs_read_stat,
1913 	&devfs_write_stat,
1914 	NULL,
1915 
1916 	/* file */
1917 	NULL,	// create
1918 	&devfs_open,
1919 	&devfs_close,
1920 	&devfs_free_cookie,
1921 	&devfs_read,
1922 	&devfs_write,
1923 
1924 	/* directory */
1925 	&devfs_create_dir,
1926 	NULL,	// remove_dir
1927 	&devfs_open_dir,
1928 	&devfs_close,
1929 		// same as for files - it does nothing for directories, anyway
1930 	&devfs_free_dir_cookie,
1931 	&devfs_read_dir,
1932 	&devfs_rewind_dir,
1933 
1934 	// attributes operations are not supported
1935 	NULL,
1936 };
1937 
1938 }	// namespace
1939 
1940 file_system_module_info gDeviceFileSystem = {
1941 	{
1942 		"file_systems/devfs" B_CURRENT_FS_API_VERSION,
1943 		0,
1944 		devfs_std_ops,
1945 	},
1946 
1947 	"devfs",					// short_name
1948 	"Device File System",		// pretty_name
1949 	0,							// DDM flags
1950 
1951 	NULL,	// identify_partition()
1952 	NULL,	// scan_partition()
1953 	NULL,	// free_identify_partition_cookie()
1954 	NULL,	// free_partition_content_cookie()
1955 
1956 	&devfs_mount,
1957 };
1958 
1959 
1960 //	#pragma mark - kernel private API
1961 
1962 
1963 extern "C" status_t
1964 devfs_unpublish_file_device(const char* path)
1965 {
1966 	// get the device node
1967 	devfs_vnode* node;
1968 	status_t status = get_node_for_path(sDeviceFileSystem, path, &node);
1969 	if (status != B_OK)
1970 		return status;
1971 
1972 	if (!S_ISCHR(node->stream.type)) {
1973 		put_vnode(sDeviceFileSystem->volume, node->id);
1974 		return B_BAD_VALUE;
1975 	}
1976 
1977 	// if it is indeed a file device, unpublish it
1978 	FileDevice* device = dynamic_cast<FileDevice*>(node->stream.u.dev.device);
1979 	if (device == NULL) {
1980 		put_vnode(sDeviceFileSystem->volume, node->id);
1981 		return B_BAD_VALUE;
1982 	}
1983 
1984 	status = unpublish_node(sDeviceFileSystem, node, S_IFCHR);
1985 
1986 	put_vnode(sDeviceFileSystem->volume, node->id);
1987 	return status;
1988 }
1989 
1990 
1991 extern "C" status_t
1992 devfs_publish_file_device(const char* path, const char* filePath)
1993 {
1994 	// create a FileDevice for the file
1995 	FileDevice* device = new(std::nothrow) FileDevice;
1996 	if (device == NULL)
1997 		return B_NO_MEMORY;
1998 	ObjectDeleter<FileDevice> deviceDeleter(device);
1999 
2000 	status_t error = device->Init(filePath);
2001 	if (error != B_OK)
2002 		return error;
2003 
2004 	// publish the device
2005 	error = publish_device(sDeviceFileSystem, path, device);
2006 	if (error != B_OK)
2007 		return error;
2008 
2009 	deviceDeleter.Detach();
2010 	return B_OK;
2011 }
2012 
2013 
2014 extern "C" status_t
2015 devfs_unpublish_partition(const char* path)
2016 {
2017 	devfs_vnode* node;
2018 	status_t status = get_node_for_path(sDeviceFileSystem, path, &node);
2019 	if (status != B_OK)
2020 		return status;
2021 
2022 	status = unpublish_node(sDeviceFileSystem, node, S_IFCHR);
2023 	put_vnode(sDeviceFileSystem->volume, node->id);
2024 	return status;
2025 }
2026 
2027 
2028 extern "C" status_t
2029 devfs_publish_partition(const char* name, const partition_info* info)
2030 {
2031 	if (name == NULL || info == NULL)
2032 		return B_BAD_VALUE;
2033 	TRACE(("publish partition: %s (device \"%s\", offset %Ld, size %Ld)\n",
2034 		name, info->device, info->offset, info->size));
2035 
2036 	devfs_vnode* device;
2037 	status_t status = get_node_for_path(sDeviceFileSystem, info->device,
2038 		&device);
2039 	if (status != B_OK)
2040 		return status;
2041 
2042 	status = add_partition(sDeviceFileSystem, device, name, *info);
2043 
2044 	put_vnode(sDeviceFileSystem->volume, device->id);
2045 	return status;
2046 }
2047 
2048 
2049 extern "C" status_t
2050 devfs_rename_partition(const char* devicePath, const char* oldName,
2051 	const char* newName)
2052 {
2053 	if (oldName == NULL || newName == NULL)
2054 		return B_BAD_VALUE;
2055 
2056 	devfs_vnode* device;
2057 	status_t status = get_node_for_path(sDeviceFileSystem, devicePath, &device);
2058 	if (status != B_OK)
2059 		return status;
2060 
2061 	RecursiveLocker locker(sDeviceFileSystem->lock);
2062 	devfs_vnode* node = devfs_find_in_dir(device->parent, oldName);
2063 	if (node == NULL)
2064 		return B_ENTRY_NOT_FOUND;
2065 
2066 	// check if the new path already exists
2067 	if (devfs_find_in_dir(device->parent, newName))
2068 		return B_BAD_VALUE;
2069 
2070 	char* name = strdup(newName);
2071 	if (name == NULL)
2072 		return B_NO_MEMORY;
2073 
2074 	devfs_remove_from_dir(device->parent, node, false);
2075 
2076 	free(node->name);
2077 	node->name = name;
2078 
2079 	devfs_insert_in_dir(device->parent, node, false);
2080 
2081 	notify_entry_moved(sDeviceFileSystem->id, device->parent->id, oldName,
2082 		device->parent->id, newName, node->id);
2083 	notify_stat_changed(sDeviceFileSystem->id, device->parent->id,
2084 		B_STAT_MODIFICATION_TIME);
2085 
2086 	return B_OK;
2087 }
2088 
2089 
2090 extern "C" status_t
2091 devfs_publish_directory(const char* path)
2092 {
2093 	RecursiveLocker locker(&sDeviceFileSystem->lock);
2094 
2095 	return publish_directory(sDeviceFileSystem, path);
2096 }
2097 
2098 
2099 extern "C" status_t
2100 devfs_unpublish_device(const char* path, bool disconnect)
2101 {
2102 	devfs_vnode* node;
2103 	status_t status = get_node_for_path(sDeviceFileSystem, path, &node);
2104 	if (status != B_OK)
2105 		return status;
2106 
2107 	status = unpublish_node(sDeviceFileSystem, node, S_IFCHR);
2108 
2109 	if (status == B_OK && disconnect)
2110 		vfs_disconnect_vnode(sDeviceFileSystem->id, node->id);
2111 
2112 	put_vnode(sDeviceFileSystem->volume, node->id);
2113 	return status;
2114 }
2115 
2116 
2117 //	#pragma mark - device_manager private API
2118 
2119 
2120 status_t
2121 devfs_publish_device(const char* path, BaseDevice* device)
2122 {
2123 	return publish_device(sDeviceFileSystem, path, device);
2124 }
2125 
2126 
2127 status_t
2128 devfs_unpublish_device(BaseDevice* device, bool disconnect)
2129 {
2130 	devfs_vnode* node;
2131 	status_t status = get_vnode(sDeviceFileSystem->volume, device->ID(),
2132 		(void**)&node);
2133 	if (status != B_OK)
2134 		return status;
2135 
2136 	status = unpublish_node(sDeviceFileSystem, node, S_IFCHR);
2137 
2138 	if (status == B_OK && disconnect)
2139 		vfs_disconnect_vnode(sDeviceFileSystem->id, node->id);
2140 
2141 	put_vnode(sDeviceFileSystem->volume, node->id);
2142 	return status;
2143 }
2144 
2145 
2146 /*!	Gets the device for a given devfs relative path.
2147 	If successful the call must be balanced with a call to devfs_put_device().
2148 */
2149 status_t
2150 devfs_get_device(const char* path, BaseDevice*& _device)
2151 {
2152 	devfs_vnode* node;
2153 	status_t status = get_node_for_path(sDeviceFileSystem, path, &node);
2154 	if (status != B_OK)
2155 		return status;
2156 
2157 	if (!S_ISCHR(node->stream.type) || node->stream.u.dev.partition != NULL) {
2158 		put_vnode(sDeviceFileSystem->volume, node->id);
2159 		return B_BAD_VALUE;
2160 	}
2161 
2162 	_device = node->stream.u.dev.device;
2163 	return B_OK;
2164 }
2165 
2166 
2167 void
2168 devfs_put_device(BaseDevice* device)
2169 {
2170 	put_vnode(sDeviceFileSystem->volume, device->ID());
2171 }
2172 
2173 
2174 void
2175 devfs_compute_geometry_size(device_geometry* geometry, uint64 blockCount,
2176 	uint32 blockSize)
2177 {
2178 	if (blockCount > UINT32_MAX)
2179 		geometry->head_count = (blockCount + UINT32_MAX - 1) / UINT32_MAX;
2180 	else
2181 		geometry->head_count = 1;
2182 
2183 	geometry->cylinder_count = 1;
2184 	geometry->sectors_per_track = blockCount / geometry->head_count;
2185 	geometry->bytes_per_sector = blockSize;
2186 }
2187 
2188 
2189 //	#pragma mark - support API for legacy drivers
2190 
2191 
2192 extern "C" status_t
2193 devfs_rescan_driver(const char* driverName)
2194 {
2195 	TRACE(("devfs_rescan_driver: %s\n", driverName));
2196 
2197 	return legacy_driver_rescan(driverName);
2198 }
2199 
2200 
2201 extern "C" status_t
2202 devfs_publish_device(const char* path, device_hooks* hooks)
2203 {
2204 	return legacy_driver_publish(path, hooks);
2205 }
2206