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