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