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