152a38012Sejakowatz/*
26f7fc220SAxel Dörfler * Copyright 2002-2016, Axel D��rfler, axeld@pinc-software.de.
308ec6140SAxel Dörfler * Distributed under the terms of the MIT License.
408ec6140SAxel Dörfler *
508ec6140SAxel Dörfler * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
608ec6140SAxel Dörfler * Distributed under the terms of the NewOS License.
708ec6140SAxel Dörfler */
808ec6140SAxel Dörfler
952a38012Sejakowatz
10368167edSAxel Dörfler#include <fs/devfs.h>
11db55a020SAxel Dörfler
12db55a020SAxel Dörfler#include <errno.h>
13db55a020SAxel Dörfler#include <stdio.h>
14db55a020SAxel Dörfler#include <stdlib.h>
15db55a020SAxel Dörfler#include <string.h>
16db55a020SAxel Dörfler#include <sys/stat.h>
17a48a5ab8SAxel Dörfler
18c920230fSAxel Dörfler#include <Drivers.h>
19db55a020SAxel Dörfler#include <KernelExport.h>
2075e4b869SAxel Dörfler#include <NodeMonitor.h>
21c920230fSAxel Dörfler
22db55a020SAxel Dörfler#include <arch/cpu.h>
23a9689e84SIngo Weinhold#include <AutoDeleter.h>
24db55a020SAxel Dörfler#include <boot/kernel_args.h>
25b53cc465SAxel Dörfler#include <boot_device.h>
2652a38012Sejakowatz#include <debug.h>
2780f6ef8bSAxel Dörfler#include <elf.h>
282764548eSStephan Aßmus#include <FindDirectory.h>
299b9cb227SAxel Dörfler#include <fs/devfs.h>
30368167edSAxel Dörfler#include <fs/KPath.h>
31368167edSAxel Dörfler#include <fs/node_monitor.h>
32db55a020SAxel Dörfler#include <kdevice_manager.h>
3352a38012Sejakowatz#include <lock.h>
34db55a020SAxel Dörfler#include <Notifications.h>
35db55a020SAxel Dörfler#include <util/AutoLock.h>
36db55a020SAxel Dörfler#include <vfs.h>
37e50cf876SIngo Weinhold#include <vm/vm.h>
38f3b05a74SXiang Fan#include <wait_for_objects.h>
3952a38012Sejakowatz
40368167edSAxel Dörfler#include "BaseDevice.h"
41a9689e84SIngo Weinhold#include "FileDevice.h"
42aa4ba93eSIngo Weinhold#include "IORequest.h"
43368167edSAxel Dörfler#include "legacy_drivers.h"
4452a38012Sejakowatz
4552a38012Sejakowatz
462976912aSAxel Dörfler//#define TRACE_DEVFS
47c920230fSAxel Dörfler#ifdef TRACE_DEVFS
48243d156eSAxel Dörfler#	define TRACE(x) dprintf x
4952a38012Sejakowatz#else
50243d156eSAxel Dörfler#	define TRACE(x)
5152a38012Sejakowatz#endif
5252a38012Sejakowatz
537be577a3SAxel Dörfler
54c73d1301SMichael Lotznamespace {
55c73d1301SMichael Lotz
5680f6ef8bSAxel Dörflerstruct devfs_partition {
57368167edSAxel Dörfler	struct devfs_vnode*	raw_device;
5880f6ef8bSAxel Dörfler	partition_info		info;
5952a38012Sejakowatz};
6052a38012Sejakowatz
6180f6ef8bSAxel Dörflerstruct driver_entry;
6280f6ef8bSAxel Dörfler
6368c1f3d2SAxel Dörflerenum {
6468c1f3d2SAxel Dörfler	kNotScanned = 0,
6568c1f3d2SAxel Dörfler	kBootScan,
6668c1f3d2SAxel Dörfler	kNormalScan,
6768c1f3d2SAxel Dörfler};
6868c1f3d2SAxel Dörfler
6952a38012Sejakowatzstruct devfs_stream {
70368167edSAxel Dörfler	mode_t				type;
7152a38012Sejakowatz	union {
7252a38012Sejakowatz		struct stream_dir {
73368167edSAxel Dörfler			struct devfs_vnode*		dir_head;
7480f6ef8bSAxel Dörfler			struct list				cookies;
75ab7516c8SAxel Dörfler			mutex					scan_lock;
7668c1f3d2SAxel Dörfler			int32					scanned;
7752a38012Sejakowatz		} dir;
7852a38012Sejakowatz		struct stream_dev {
79368167edSAxel Dörfler			BaseDevice*				device;
80368167edSAxel Dörfler			struct devfs_partition*	partition;
8152a38012Sejakowatz		} dev;
827be577a3SAxel Dörfler		struct stream_symlink {
83368167edSAxel Dörfler			const char*				path;
8480f6ef8bSAxel Dörfler			size_t					length;
857be577a3SAxel Dörfler		} symlink;
8652a38012Sejakowatz	} u;
8752a38012Sejakowatz};
8852a38012Sejakowatz
8952a38012Sejakowatzstruct devfs_vnode {
90368167edSAxel Dörfler	struct devfs_vnode*	all_next;
91368167edSAxel Dörfler	ino_t				id;
92368167edSAxel Dörfler	char*				name;
93fa00207cSAxel Dörfler	timespec			modification_time;
94fa00207cSAxel Dörfler	timespec			creation_time;
95368167edSAxel Dörfler	uid_t				uid;
96368167edSAxel Dörfler	gid_t				gid;
97368167edSAxel Dörfler	struct devfs_vnode*	parent;
98368167edSAxel Dörfler	struct devfs_vnode*	dir_next;
99368167edSAxel Dörfler	struct devfs_stream	stream;
10052a38012Sejakowatz};
10152a38012Sejakowatz
10280f6ef8bSAxel Dörfler#define DEVFS_HASH_SIZE 16
10380f6ef8bSAxel Dörfler
1046a89f804SAdrien Destugues
1056a89f804SAdrien Destuguesstruct NodeHash {
1066a89f804SAdrien Destugues	typedef ino_t			KeyType;
1076a89f804SAdrien Destugues	typedef	devfs_vnode		ValueType;
1086a89f804SAdrien Destugues
1096a89f804SAdrien Destugues	size_t HashKey(KeyType key) const
1106a89f804SAdrien Destugues	{
1116a89f804SAdrien Destugues		return key ^ (key >> 32);
1126a89f804SAdrien Destugues	}
1136a89f804SAdrien Destugues
1146a89f804SAdrien Destugues	size_t Hash(ValueType* value) const
1156a89f804SAdrien Destugues	{
1166a89f804SAdrien Destugues		return HashKey(value->id);
1176a89f804SAdrien Destugues	}
1186a89f804SAdrien Destugues
1196a89f804SAdrien Destugues	bool Compare(KeyType key, ValueType* value) const
1206a89f804SAdrien Destugues	{
1216a89f804SAdrien Destugues		return value->id == key;
1226a89f804SAdrien Destugues	}
1236a89f804SAdrien Destugues
1246a89f804SAdrien Destugues	ValueType*& GetLink(ValueType* value) const
1256a89f804SAdrien Destugues	{
1266a89f804SAdrien Destugues		return value->all_next;
1276a89f804SAdrien Destugues	}
1286a89f804SAdrien Destugues};
1296a89f804SAdrien Destugues
1306a89f804SAdrien Destuguestypedef BOpenHashTable<NodeHash> NodeTable;
1316a89f804SAdrien Destugues
13252a38012Sejakowatzstruct devfs {
1337ffafac8SIngo Weinhold	dev_t				id;
134368167edSAxel Dörfler	fs_volume*			volume;
1357ffafac8SIngo Weinhold	recursive_lock		lock;
1366a89f804SAdrien Destugues	int32				next_vnode_id;
1376a89f804SAdrien Destugues	NodeTable*			vnode_hash;
138368167edSAxel Dörfler	struct devfs_vnode*	root_vnode;
13952a38012Sejakowatz};
14052a38012Sejakowatz
141140e3bb0SAxel Dörflerstruct devfs_dir_cookie {
142368167edSAxel Dörfler	struct list_link	link;
143368167edSAxel Dörfler	struct devfs_vnode*	current;
144368167edSAxel Dörfler	int32				state;	// iteration state
145140e3bb0SAxel Dörfler};
146140e3bb0SAxel Dörfler
14752a38012Sejakowatzstruct devfs_cookie {
148368167edSAxel Dörfler	void*				device_cookie;
14952a38012Sejakowatz};
15052a38012Sejakowatz
151bb94d91dSIngo Weinholdstruct synchronous_io_cookie {
152bb94d91dSIngo Weinhold	BaseDevice*		device;
153bb94d91dSIngo Weinhold	void*			cookie;
154bb94d91dSIngo Weinhold};
155bb94d91dSIngo Weinhold
156119e5eeeSIngo Weinhold// directory iteration states
157119e5eeeSIngo Weinholdenum {
158119e5eeeSIngo Weinhold	ITERATION_STATE_DOT		= 0,
159119e5eeeSIngo Weinhold	ITERATION_STATE_DOT_DOT	= 1,
160119e5eeeSIngo Weinhold	ITERATION_STATE_OTHERS	= 2,
161119e5eeeSIngo Weinhold	ITERATION_STATE_BEGIN	= ITERATION_STATE_DOT,
162119e5eeeSIngo Weinhold};
163119e5eeeSIngo Weinhold
164c73d1301SMichael Lotz// extern only to make forward declaration possible
165c73d1301SMichael Lotzextern fs_volume_ops kVolumeOps;
166c73d1301SMichael Lotzextern fs_vnode_ops kVnodeOps;
167c73d1301SMichael Lotz
168c73d1301SMichael Lotz} // namespace
1697ffafac8SIngo Weinhold
17068c1f3d2SAxel Dörfler
17131cf5e52SAxel Dörflerstatic status_t get_node_for_path(struct devfs* fs, const char* path,
17231cf5e52SAxel Dörfler	struct devfs_vnode** _node);
17331cf5e52SAxel Dörflerstatic void get_device_name(struct devfs_vnode* vnode, char* buffer,
174d5a279feSAxel Dörfler	size_t size);
17531cf5e52SAxel Dörflerstatic status_t unpublish_node(struct devfs* fs, devfs_vnode* node,
176db55a020SAxel Dörfler	mode_t type);
17731cf5e52SAxel Dörflerstatic status_t publish_device(struct devfs* fs, const char* path,
178368167edSAxel Dörfler	BaseDevice* device);
17980f6ef8bSAxel Dörfler
18068c1f3d2SAxel Dörfler
18131cf5e52SAxel Dörfler// The one and only allowed devfs instance
182368167edSAxel Dörflerstatic struct devfs* sDeviceFileSystem = NULL;
1839e8dc2a9SIngo Weinhold
18480f6ef8bSAxel Dörfler
185368167edSAxel Dörfler//	#pragma mark - devfs private
18680f6ef8bSAxel Dörfler
18780f6ef8bSAxel Dörfler
188fa00207cSAxel Dörflerstatic timespec
189fa00207cSAxel Dörflercurrent_timespec()
190fa00207cSAxel Dörfler{
191fa00207cSAxel Dörfler	bigtime_t time = real_time_clock_usecs();
192fa00207cSAxel Dörfler
193fa00207cSAxel Dörfler	timespec tv;
194fa00207cSAxel Dörfler	tv.tv_sec = time / 1000000;
195fa00207cSAxel Dörfler	tv.tv_nsec = (time % 1000000) * 1000;
196fa00207cSAxel Dörfler	return tv;
197fa00207cSAxel Dörfler}
198fa00207cSAxel Dörfler
199fa00207cSAxel Dörfler
2006f7fc220SAxel Dörflerstatic ino_t
2016f7fc220SAxel Dörflerget_parent_id(struct devfs_vnode* vnode)
2026f7fc220SAxel Dörfler{
2036f7fc220SAxel Dörfler	if (vnode->parent != NULL)
2046f7fc220SAxel Dörfler		return vnode->parent->id;
2056f7fc220SAxel Dörfler	return -1;
2066f7fc220SAxel Dörfler}
2076f7fc220SAxel Dörfler
2086f7fc220SAxel Dörfler
20968c1f3d2SAxel Dörflerstatic int32
21068c1f3d2SAxel Dörflerscan_mode(void)
21168c1f3d2SAxel Dörfler{
21268c1f3d2SAxel Dörfler	// We may scan every device twice:
21368c1f3d2SAxel Dörfler	//  - once before there is a boot device,
21468c1f3d2SAxel Dörfler	//  - and once when there is one
21568c1f3d2SAxel Dörfler
21668c1f3d2SAxel Dörfler	return gBootDevice >= 0 ? kNormalScan : kBootScan;
21768c1f3d2SAxel Dörfler}
21868c1f3d2SAxel Dörfler
21968c1f3d2SAxel Dörfler
22068c1f3d2SAxel Dörflerstatic status_t
221ab7516c8SAxel Dörflerscan_for_drivers_if_needed(devfs_vnode* dir)
22268c1f3d2SAxel Dörfler{
223ab7516c8SAxel Dörfler	ASSERT(S_ISDIR(dir->stream.type));
224ab7516c8SAxel Dörfler
225ab7516c8SAxel Dörfler	MutexLocker _(dir->stream.u.dir.scan_lock);
226ab7516c8SAxel Dörfler
227ab7516c8SAxel Dörfler	if (dir->stream.u.dir.scanned >= scan_mode())
228ab7516c8SAxel Dörfler		return B_OK;
229ab7516c8SAxel Dörfler
23068c1f3d2SAxel Dörfler	KPath path;
23168c1f3d2SAxel Dörfler	if (path.InitCheck() != B_OK)
23268c1f3d2SAxel Dörfler		return B_NO_MEMORY;
23368c1f3d2SAxel Dörfler
23468c1f3d2SAxel Dörfler	get_device_name(dir, path.LockBuffer(), path.BufferSize());
23568c1f3d2SAxel Dörfler	path.UnlockBuffer();
23668c1f3d2SAxel Dörfler
237ab7516c8SAxel Dörfler	TRACE(("scan_for_drivers_if_needed: mode %ld: %s\n", scan_mode(),
238ab7516c8SAxel Dörfler		path.Path()));
23968c1f3d2SAxel Dörfler
24068c1f3d2SAxel Dörfler	// scan for drivers at this path
241368167edSAxel Dörfler	static int32 updateCycle = 1;
242368167edSAxel Dörfler	device_manager_probe(path.Path(), updateCycle++);
243368167edSAxel Dörfler	legacy_driver_probe(path.Path());
24468c1f3d2SAxel Dörfler
24568c1f3d2SAxel Dörfler	dir->stream.u.dir.scanned = scan_mode();
24668c1f3d2SAxel Dörfler	return B_OK;
24768c1f3d2SAxel Dörfler}
24868c1f3d2SAxel Dörfler
24968c1f3d2SAxel Dörfler
250ab7516c8SAxel Dörflerstatic void
251ab7516c8SAxel Dörflerinit_directory_vnode(struct devfs_vnode* vnode, int permissions)
252ab7516c8SAxel Dörfler{
253ab7516c8SAxel Dörfler	vnode->stream.type = S_IFDIR | permissions;
254ab7516c8SAxel Dörfler		mutex_init(&vnode->stream.u.dir.scan_lock, "devfs scan");
255ab7516c8SAxel Dörfler	vnode->stream.u.dir.dir_head = NULL;
256ab7516c8SAxel Dörfler	list_init(&vnode->stream.u.dir.cookies);
257ab7516c8SAxel Dörfler}
258ab7516c8SAxel Dörfler
259ab7516c8SAxel Dörfler
260368167edSAxel Dörflerstatic struct devfs_vnode*
261368167edSAxel Dörflerdevfs_create_vnode(struct devfs* fs, devfs_vnode* parent, const char* name)
26252a38012Sejakowatz{
263368167edSAxel Dörfler	struct devfs_vnode* vnode;
26452a38012Sejakowatz
265368167edSAxel Dörfler	vnode = (struct devfs_vnode*)malloc(sizeof(struct devfs_vnode));
266ded78bc1SAxel Dörfler	if (vnode == NULL)
26752a38012Sejakowatz		return NULL;
26852a38012Sejakowatz
269ded78bc1SAxel Dörfler	memset(vnode, 0, sizeof(struct devfs_vnode));
270ded78bc1SAxel Dörfler	vnode->id = fs->next_vnode_id++;
27152a38012Sejakowatz
272ded78bc1SAxel Dörfler	vnode->name = strdup(name);
273ded78bc1SAxel Dörfler	if (vnode->name == NULL) {
274ded78bc1SAxel Dörfler		free(vnode);
27552a38012Sejakowatz		return NULL;
27652a38012Sejakowatz	}
27752a38012Sejakowatz
278fa00207cSAxel Dörfler	vnode->creation_time = vnode->modification_time = current_timespec();
27975e4b869SAxel Dörfler	vnode->uid = geteuid();
28075e4b869SAxel Dörfler	vnode->gid = parent ? parent->gid : getegid();
28175e4b869SAxel Dörfler		// inherit group from parent if possible
28275e4b869SAxel Dörfler
283ded78bc1SAxel Dörfler	return vnode;
28452a38012Sejakowatz}
28552a38012Sejakowatz
28607fefdf4SAxel Dörfler
28790abd04bSbeveloperstatic status_t
288368167edSAxel Dörflerdevfs_delete_vnode(struct devfs* fs, struct devfs_vnode* vnode,
289368167edSAxel Dörfler	bool forceDelete)
29052a38012Sejakowatz{
29131cf5e52SAxel Dörfler	// Can't delete it if it's in a directory or is a directory
29252a38012Sejakowatz	// and has children
293368167edSAxel Dörfler	if (!forceDelete && ((S_ISDIR(vnode->stream.type)
294368167edSAxel Dörfler				&& vnode->stream.u.dir.dir_head != NULL)
295ded78bc1SAxel Dörfler			|| vnode->dir_next != NULL))
296065aa7f6SAxel Dörfler		return B_NOT_ALLOWED;
29752a38012Sejakowatz
29852a38012Sejakowatz	// remove it from the global hash table
2996a89f804SAdrien Destugues	fs->vnode_hash->Remove(vnode);
30052a38012Sejakowatz
30175e4b869SAxel Dörfler	if (S_ISCHR(vnode->stream.type)) {
302cb894815SAxel Dörfler		if (vnode->stream.u.dev.partition == NULL) {
303cb894815SAxel Dörfler			// pass the call through to the underlying device
304cb894815SAxel Dörfler			vnode->stream.u.dev.device->Removed();
305cb894815SAxel Dörfler		} else {
306cb894815SAxel Dörfler			// for partitions, we have to release the raw device but must
307cb894815SAxel Dörfler			// not free the device info as it was inherited from the raw
308cb894815SAxel Dörfler			// device and is still in use there
309cb894815SAxel Dörfler			put_vnode(fs->volume, vnode->stream.u.dev.partition->raw_device->id);
3103568352dSMichael Lotz		}
311ab7516c8SAxel Dörfler	} else if (S_ISDIR(vnode->stream.type)) {
312ab7516c8SAxel Dörfler		mutex_destroy(&vnode->stream.u.dir.scan_lock);
313f363b723SAxel Dörfler	}
314243d156eSAxel Dörfler
315ded78bc1SAxel Dörfler	free(vnode->name);
316ded78bc1SAxel Dörfler	free(vnode);
31752a38012Sejakowatz
31875e4b869SAxel Dörfler	return B_OK;
31952a38012Sejakowatz}
32052a38012Sejakowatz
32107fefdf4SAxel Dörfler
322e6fdb84bSAxel Dörfler/*! Makes sure none of the dircookies point to the vnode passed in */
32307fefdf4SAxel Dörflerstatic void
324368167edSAxel Dörflerupdate_dir_cookies(struct devfs_vnode* dir, struct devfs_vnode* vnode)
32552a38012Sejakowatz{
326368167edSAxel Dörfler	struct devfs_dir_cookie* cookie = NULL;
32752a38012Sejakowatz
328368167edSAxel Dörfler	while ((cookie = (devfs_dir_cookie*)list_get_next_item(
329d5a279feSAxel Dörfler			&dir->stream.u.dir.cookies, cookie)) != NULL) {
330140e3bb0SAxel Dörfler		if (cookie->current == vnode)
331140e3bb0SAxel Dörfler			cookie->current = vnode->dir_next;
33252a38012Sejakowatz	}
33352a38012Sejakowatz}
33452a38012Sejakowatz
33552a38012Sejakowatz
336368167edSAxel Dörflerstatic struct devfs_vnode*
337368167edSAxel Dörflerdevfs_find_in_dir(struct devfs_vnode* dir, const char* path)
33852a38012Sejakowatz{
339368167edSAxel Dörfler	struct devfs_vnode* vnode;
34052a38012Sejakowatz
34175e4b869SAxel Dörfler	if (!S_ISDIR(dir->stream.type))
34252a38012Sejakowatz		return NULL;
34352a38012Sejakowatz
344243d156eSAxel Dörfler	if (!strcmp(path, "."))
34552a38012Sejakowatz		return dir;
346243d156eSAxel Dörfler	if (!strcmp(path, ".."))
34752a38012Sejakowatz		return dir->parent;
34852a38012Sejakowatz
34968c1f3d2SAxel Dörfler	for (vnode = dir->stream.u.dir.dir_head; vnode; vnode = vnode->dir_next) {
35068c1f3d2SAxel Dörfler		//TRACE(("devfs_find_in_dir: looking at entry '%s'\n", vnode->name));
35168c1f3d2SAxel Dörfler		if (strcmp(vnode->name, path) == 0) {
35268c1f3d2SAxel Dörfler			//TRACE(("devfs_find_in_dir: found it at %p\n", vnode));
35368c1f3d2SAxel Dörfler			return vnode;
35452a38012Sejakowatz		}
35552a38012Sejakowatz	}
35652a38012Sejakowatz	return NULL;
35752a38012Sejakowatz}
35852a38012Sejakowatz
35907fefdf4SAxel Dörfler
36090abd04bSbeveloperstatic status_t
361a365e1cfSIngo Weinholddevfs_insert_in_dir(struct devfs_vnode* dir, struct devfs_vnode* vnode,
362a365e1cfSIngo Weinhold	bool notify = true)
36352a38012Sejakowatz{
36475e4b869SAxel Dörfler	if (!S_ISDIR(dir->stream.type))
36575e4b869SAxel Dörfler		return B_BAD_VALUE;
36652a38012Sejakowatz
3674195ac0cSAxel Dörfler	// make sure the directory stays sorted alphabetically
3684195ac0cSAxel Dörfler
369368167edSAxel Dörfler	devfs_vnode* node = dir->stream.u.dir.dir_head;
370368167edSAxel Dörfler	devfs_vnode* last = NULL;
3714195ac0cSAxel Dörfler	while (node && strcmp(node->name, vnode->name) < 0) {
3724195ac0cSAxel Dörfler		last = node;
3734195ac0cSAxel Dörfler		node = node->dir_next;
3744195ac0cSAxel Dörfler	}
3754195ac0cSAxel Dörfler	if (last == NULL) {
3764195ac0cSAxel Dörfler		// the new vnode is the first entry in the list
3774195ac0cSAxel Dörfler		vnode->dir_next = dir->stream.u.dir.dir_head;
3784195ac0cSAxel Dörfler		dir->stream.u.dir.dir_head = vnode;
3794195ac0cSAxel Dörfler	} else {
3804195ac0cSAxel Dörfler		// insert after that node
3814195ac0cSAxel Dörfler		vnode->dir_next = last->dir_next;
3824195ac0cSAxel Dörfler		last->dir_next = vnode;
3834195ac0cSAxel Dörfler	}
38452a38012Sejakowatz
3856094d89fSAxel Dörfler	vnode->parent = dir;
386fa00207cSAxel Dörfler	dir->modification_time = current_timespec();
3876094d89fSAxel Dörfler
388a365e1cfSIngo Weinhold	if (notify) {
389a365e1cfSIngo Weinhold		notify_entry_created(sDeviceFileSystem->id, dir->id, vnode->name,
390a365e1cfSIngo Weinhold			vnode->id);
3916f7fc220SAxel Dörfler		notify_stat_changed(sDeviceFileSystem->id, get_parent_id(dir), dir->id,
392a365e1cfSIngo Weinhold			B_STAT_MODIFICATION_TIME);
393a365e1cfSIngo Weinhold	}
39475e4b869SAxel Dörfler	return B_OK;
39552a38012Sejakowatz}
39652a38012Sejakowatz
39707fefdf4SAxel Dörfler
39890abd04bSbeveloperstatic status_t
399a365e1cfSIngo Weinholddevfs_remove_from_dir(struct devfs_vnode* dir, struct devfs_vnode* removeNode,
400a365e1cfSIngo Weinhold	bool notify = true)
40152a38012Sejakowatz{
40231cf5e52SAxel Dörfler	struct devfs_vnode* vnode = dir->stream.u.dir.dir_head;
40331cf5e52SAxel Dörfler	struct devfs_vnode* lastNode = NULL;
40452a38012Sejakowatz
4056094d89fSAxel Dörfler	for (; vnode != NULL; lastNode = vnode, vnode = vnode->dir_next) {
4066094d89fSAxel Dörfler		if (vnode == removeNode) {
4076094d89fSAxel Dörfler			// make sure no dircookies point to this vnode
408140e3bb0SAxel Dörfler			update_dir_cookies(dir, vnode);
40952a38012Sejakowatz
4106094d89fSAxel Dörfler			if (lastNode)
4116094d89fSAxel Dörfler				lastNode->dir_next = vnode->dir_next;
41252a38012Sejakowatz			else
4136094d89fSAxel Dörfler				dir->stream.u.dir.dir_head = vnode->dir_next;
4146094d89fSAxel Dörfler			vnode->dir_next = NULL;
415fa00207cSAxel Dörfler			dir->modification_time = current_timespec();
4166094d89fSAxel Dörfler
417a365e1cfSIngo Weinhold			if (notify) {
418a365e1cfSIngo Weinhold				notify_entry_removed(sDeviceFileSystem->id, dir->id, vnode->name,
419a365e1cfSIngo Weinhold					vnode->id);
4206f7fc220SAxel Dörfler				notify_stat_changed(sDeviceFileSystem->id, get_parent_id(dir),
4216f7fc220SAxel Dörfler					dir->id, B_STAT_MODIFICATION_TIME);
422a365e1cfSIngo Weinhold			}
42375e4b869SAxel Dörfler			return B_OK;
42452a38012Sejakowatz		}
42552a38012Sejakowatz	}
42675e4b869SAxel Dörfler	return B_ENTRY_NOT_FOUND;
42752a38012Sejakowatz}
42852a38012Sejakowatz
42907fefdf4SAxel Dörfler
43090abd04bSbeveloperstatic status_t
431368167edSAxel Dörfleradd_partition(struct devfs* fs, struct devfs_vnode* device, const char* name,
432368167edSAxel Dörfler	const partition_info& info)
43352a38012Sejakowatz{
434368167edSAxel Dörfler	struct devfs_vnode* partitionNode;
435a48a5ab8SAxel Dörfler	status_t status;
43607f317bfSAxel Dörfler
4370ec71451SAxel Dörfler	if (!S_ISCHR(device->stream.type))
438a48a5ab8SAxel Dörfler		return B_BAD_VALUE;
43907f317bfSAxel Dörfler
44052a38012Sejakowatz	// we don't support nested partitions
441cb894815SAxel Dörfler	if (device->stream.u.dev.partition != NULL)
442a48a5ab8SAxel Dörfler		return B_BAD_VALUE;
44307f317bfSAxel Dörfler
44452a38012Sejakowatz	// reduce checks to a minimum - things like negative offsets could be useful
445243d156eSAxel Dörfler	if (info.size < 0)
446a48a5ab8SAxel Dörfler		return B_BAD_VALUE;
44707f317bfSAxel Dörfler
44868c1f3d2SAxel Dörfler	// create partition
449368167edSAxel Dörfler	struct devfs_partition* partition = (struct devfs_partition*)malloc(
450d5a279feSAxel Dörfler		sizeof(struct devfs_partition));
45168c1f3d2SAxel Dörfler	if (partition == NULL)
452a48a5ab8SAxel Dörfler		return B_NO_MEMORY;
45307f317bfSAxel Dörfler
45468c1f3d2SAxel Dörfler	memcpy(&partition->info, &info, sizeof(partition_info));
45507f317bfSAxel Dörfler
456368167edSAxel Dörfler	RecursiveLocker locker(fs->lock);
45707f317bfSAxel Dörfler
45852a38012Sejakowatz	// you cannot change a partition once set
4590ec71451SAxel Dörfler	if (devfs_find_in_dir(device->parent, name)) {
460a48a5ab8SAxel Dörfler		status = B_BAD_VALUE;
46152a38012Sejakowatz		goto err1;
46252a38012Sejakowatz	}
46307f317bfSAxel Dörfler
4647dbbb04aSAxel Dörfler	// increase reference count of raw device -
4657dbbb04aSAxel Dörfler	// the partition device really needs it
46649004dc7SMichael Lotz	status = get_vnode(fs->volume, device->id, (void**)&partition->raw_device);
467a48a5ab8SAxel Dörfler	if (status < B_OK)
46852a38012Sejakowatz		goto err1;
46952a38012Sejakowatz
470a48a5ab8SAxel Dörfler	// now create the partition vnode
47168c1f3d2SAxel Dörfler	partitionNode = devfs_create_vnode(fs, device->parent, name);
47268c1f3d2SAxel Dörfler	if (partitionNode == NULL) {
473a48a5ab8SAxel Dörfler		status = B_NO_MEMORY;
47452a38012Sejakowatz		goto err2;
47552a38012Sejakowatz	}
47652a38012Sejakowatz
47768c1f3d2SAxel Dörfler	partitionNode->stream.type = device->stream.type;
478368167edSAxel Dörfler	partitionNode->stream.u.dev.device = device->stream.u.dev.device;
47968c1f3d2SAxel Dörfler	partitionNode->stream.u.dev.partition = partition;
48052a38012Sejakowatz
4816a89f804SAdrien Destugues	fs->vnode_hash->Insert(partitionNode);
48268c1f3d2SAxel Dörfler	devfs_insert_in_dir(device->parent, partitionNode);
48352a38012Sejakowatz
48468c1f3d2SAxel Dörfler	TRACE(("add_partition(name = %s, offset = %Ld, size = %Ld)\n",
48568c1f3d2SAxel Dörfler		name, info.offset, info.size));
486a48a5ab8SAxel Dörfler	return B_OK;
48707f317bfSAxel Dörfler
48852a38012Sejakowatzerr2:
4897ffafac8SIngo Weinhold	put_vnode(fs->volume, device->id);
49068c1f3d2SAxel Dörflererr1:
49168c1f3d2SAxel Dörfler	free(partition);
492a48a5ab8SAxel Dörfler	return status;
493a48a5ab8SAxel Dörfler}
494a48a5ab8SAxel Dörfler
495a48a5ab8SAxel Dörfler
496a48a5ab8SAxel Dörflerstatic inline void
497368167edSAxel Dörflertranslate_partition_access(devfs_partition* partition, off_t& offset,
498368167edSAxel Dörfler	size_t& size)
499a48a5ab8SAxel Dörfler{
500ba8c1ff5SMarcus Overhagen	ASSERT(offset >= 0);
501ba8c1ff5SMarcus Overhagen	ASSERT(offset < partition->info.size);
502a48a5ab8SAxel Dörfler
503a0641688SMichael Lotz	size = (size_t)min_c((off_t)size, partition->info.size - offset);
50480f6ef8bSAxel Dörfler	offset += partition->info.offset;
50552a38012Sejakowatz}
50652a38012Sejakowatz
50707fefdf4SAxel Dörfler
508bb94d91dSIngo Weinholdstatic inline void
509bb94d91dSIngo Weinholdtranslate_partition_access(devfs_partition* partition, io_request* request)
510bb94d91dSIngo Weinhold{
511bb94d91dSIngo Weinhold	off_t offset = request->Offset();
512bb94d91dSIngo Weinhold
513bb94d91dSIngo Weinhold	ASSERT(offset >= 0);
5141d578e15SIngo Weinhold	ASSERT(offset + (off_t)request->Length() <= partition->info.size);
515bb94d91dSIngo Weinhold
516bb94d91dSIngo Weinhold	request->SetOffset(offset + partition->info.offset);
517bb94d91dSIngo Weinhold}
518bb94d91dSIngo Weinhold
519bb94d91dSIngo Weinhold
5200ec71451SAxel Dörflerstatic status_t
52131cf5e52SAxel Dörflerget_node_for_path(struct devfs* fs, const char* path,
52231cf5e52SAxel Dörfler	struct devfs_vnode** _node)
5230ec71451SAxel Dörfler{
524a9689e84SIngo Weinhold	return vfs_get_fs_node_from_path(fs->volume, path, false, true,
52531cf5e52SAxel Dörfler		(void**)_node);
526eeb43232SAxel Dörfler}
527eeb43232SAxel Dörfler
528eeb43232SAxel Dörfler
529eeb43232SAxel Dörflerstatic status_t
53031cf5e52SAxel Dörflerunpublish_node(struct devfs* fs, devfs_vnode* node, mode_t type)
531eeb43232SAxel Dörfler{
532606e0d36SAxel Dörfler	if ((node->stream.type & S_IFMT) != type)
533606e0d36SAxel Dörfler		return B_BAD_TYPE;
534eeb43232SAxel Dörfler
53580f6ef8bSAxel Dörfler	recursive_lock_lock(&fs->lock);
536eeb43232SAxel Dörfler
537606e0d36SAxel Dörfler	status_t status = devfs_remove_from_dir(node->parent, node);
538eeb43232SAxel Dörfler	if (status < B_OK)
539606e0d36SAxel Dörfler		goto out;
540eeb43232SAxel Dörfler
5417ffafac8SIngo Weinhold	status = remove_vnode(fs->volume, node->id);
542eeb43232SAxel Dörfler
543606e0d36SAxel Dörflerout:
54480f6ef8bSAxel Dörfler	recursive_lock_unlock(&fs->lock);
545606e0d36SAxel Dörfler	return status;
546606e0d36SAxel Dörfler}
547606e0d36SAxel Dörfler
548606e0d36SAxel Dörfler
549ab7516c8SAxel Dörflerstatic void
550ab7516c8SAxel Dörflerpublish_node(devfs* fs, devfs_vnode* dirNode, struct devfs_vnode* node)
551ab7516c8SAxel Dörfler{
5526a89f804SAdrien Destugues	fs->vnode_hash->Insert(node);
553ab7516c8SAxel Dörfler	devfs_insert_in_dir(dirNode, node);
554ab7516c8SAxel Dörfler}
555ab7516c8SAxel Dörfler
556ab7516c8SAxel Dörfler
5577ec59908SAxel Dörflerstatic status_t
55831cf5e52SAxel Dörflerpublish_directory(struct devfs* fs, const char* path)
5597ec59908SAxel Dörfler{
56080f6ef8bSAxel Dörfler	ASSERT_LOCKED_RECURSIVE(&fs->lock);
5617ec59908SAxel Dörfler
5627ec59908SAxel Dörfler	// copy the path over to a temp buffer so we can munge it
5637ec59908SAxel Dörfler	KPath tempPath(path);
5646bdc405fSAxel Dörfler	if (tempPath.InitCheck() != B_OK)
5656bdc405fSAxel Dörfler		return B_NO_MEMORY;
5666bdc405fSAxel Dörfler
567368167edSAxel Dörfler	TRACE(("devfs: publish directory \"%s\"\n", path));
56831cf5e52SAxel Dörfler	char* temp = tempPath.LockBuffer();
5697ec59908SAxel Dörfler
5707ec59908SAxel Dörfler	// create the path leading to the device
5717ec59908SAxel Dörfler	// parse the path passed in, stripping out '/'
5727ec59908SAxel Dörfler
57331cf5e52SAxel Dörfler	struct devfs_vnode* dir = fs->root_vnode;
57431cf5e52SAxel Dörfler	struct devfs_vnode* vnode = NULL;
5757ec59908SAxel Dörfler	status_t status = B_OK;
5767ec59908SAxel Dörfler	int32 i = 0, last = 0;
5777ec59908SAxel Dörfler
57880f6ef8bSAxel Dörfler	while (temp[last]) {
5797ec59908SAxel Dörfler		if (temp[i] == '/') {
5807ec59908SAxel Dörfler			temp[i] = '\0';
5817ec59908SAxel Dörfler			i++;
5827ec59908SAxel Dörfler		} else if (temp[i] != '\0') {
5837ec59908SAxel Dörfler			i++;
5847ec59908SAxel Dörfler			continue;
5857ec59908SAxel Dörfler		}
5867ec59908SAxel Dörfler
58768c1f3d2SAxel Dörfler		//TRACE(("\tpath component '%s'\n", &temp[last]));
5887ec59908SAxel Dörfler
5897ec59908SAxel Dörfler		// we have a path component
5907ec59908SAxel Dörfler		vnode = devfs_find_in_dir(dir, &temp[last]);
5917ec59908SAxel Dörfler		if (vnode) {
5927ec59908SAxel Dörfler			if (S_ISDIR(vnode->stream.type)) {
5937ec59908SAxel Dörfler				last = i;
5947ec59908SAxel Dörfler				dir = vnode;
5957ec59908SAxel Dörfler				continue;
5967ec59908SAxel Dörfler			}
5977ec59908SAxel Dörfler
5987ec59908SAxel Dörfler			// we hit something on our path that's not a directory
5997ec59908SAxel Dörfler			status = B_FILE_EXISTS;
6007ec59908SAxel Dörfler			goto out;
6017ec59908SAxel Dörfler		} else {
6027ec59908SAxel Dörfler			vnode = devfs_create_vnode(fs, dir, &temp[last]);
6037ec59908SAxel Dörfler			if (!vnode) {
6047ec59908SAxel Dörfler				status = B_NO_MEMORY;
6057ec59908SAxel Dörfler				goto out;
6067ec59908SAxel Dörfler			}
6077ec59908SAxel Dörfler		}
6087ec59908SAxel Dörfler
6097ec59908SAxel Dörfler		// set up the new directory
610ab7516c8SAxel Dörfler		init_directory_vnode(vnode, 0755);
611ab7516c8SAxel Dörfler		publish_node(sDeviceFileSystem, dir, vnode);
6127ec59908SAxel Dörfler
6137ec59908SAxel Dörfler		last = i;
6147ec59908SAxel Dörfler		dir = vnode;
6157ec59908SAxel Dörfler	}
6167ec59908SAxel Dörfler
6177ec59908SAxel Dörflerout:
6187ec59908SAxel Dörfler	return status;
6197ec59908SAxel Dörfler}
6207ec59908SAxel Dörfler
6217ec59908SAxel Dörfler
622f363b723SAxel Dörflerstatic status_t
62331cf5e52SAxel Dörflernew_node(struct devfs* fs, const char* path, struct devfs_vnode** _node,
62431cf5e52SAxel Dörfler	struct devfs_vnode** _dir)
625f363b723SAxel Dörfler{
6265c99d639SIngo Weinhold	ASSERT_LOCKED_RECURSIVE(&fs->lock);
627f363b723SAxel Dörfler
628f363b723SAxel Dörfler	// copy the path over to a temp buffer so we can munge it
629e876e8c5SAxel Dörfler	KPath tempPath(path);
6306bdc405fSAxel Dörfler	if (tempPath.InitCheck() != B_OK)
6316bdc405fSAxel Dörfler		return B_NO_MEMORY;
6326bdc405fSAxel Dörfler
63331cf5e52SAxel Dörfler	char* temp = tempPath.LockBuffer();
634f363b723SAxel Dörfler
635f363b723SAxel Dörfler	// create the path leading to the device
636f363b723SAxel Dörfler	// parse the path passed in, stripping out '/'
637e876e8c5SAxel Dörfler
63831cf5e52SAxel Dörfler	struct devfs_vnode* dir = fs->root_vnode;
63931cf5e52SAxel Dörfler	struct devfs_vnode* vnode = NULL;
640e876e8c5SAxel Dörfler	status_t status = B_OK;
641f363b723SAxel Dörfler	int32 i = 0, last = 0;
642f363b723SAxel Dörfler	bool atLeaf = false;
643f363b723SAxel Dörfler
644f363b723SAxel Dörfler	for (;;) {
6457ec59908SAxel Dörfler		if (temp[i] == '\0') {
646f363b723SAxel Dörfler			atLeaf = true; // we'll be done after this one
647f363b723SAxel Dörfler		} else if (temp[i] == '/') {
6487ec59908SAxel Dörfler			temp[i] = '\0';
649f363b723SAxel Dörfler			i++;
650f363b723SAxel Dörfler		} else {
651f363b723SAxel Dörfler			i++;
652f363b723SAxel Dörfler			continue;
653f363b723SAxel Dörfler		}
654f363b723SAxel Dörfler
65568c1f3d2SAxel Dörfler		//TRACE(("\tpath component '%s'\n", &temp[last]));
656f363b723SAxel Dörfler
657f363b723SAxel Dörfler		// we have a path component
658f363b723SAxel Dörfler		vnode = devfs_find_in_dir(dir, &temp[last]);
659f363b723SAxel Dörfler		if (vnode) {
660f363b723SAxel Dörfler			if (!atLeaf) {
661f363b723SAxel Dörfler				// we are not at the leaf of the path, so as long as
662f363b723SAxel Dörfler				// this is a dir we're okay
66375e4b869SAxel Dörfler				if (S_ISDIR(vnode->stream.type)) {
664f363b723SAxel Dörfler					last = i;
665f363b723SAxel Dörfler					dir = vnode;
666f363b723SAxel Dörfler					continue;
667f363b723SAxel Dörfler				}
668f363b723SAxel Dörfler			}
669f363b723SAxel Dörfler			// we are at the leaf and hit another node
670f363b723SAxel Dörfler			// or we aren't but hit a non-dir node.
671f363b723SAxel Dörfler			// we're screwed
672f363b723SAxel Dörfler			status = B_FILE_EXISTS;
673f363b723SAxel Dörfler			goto out;
674f363b723SAxel Dörfler		} else {
675554e58f0SAxel Dörfler			vnode = devfs_create_vnode(fs, dir, &temp[last]);
676f363b723SAxel Dörfler			if (!vnode) {
677f363b723SAxel Dörfler				status = B_NO_MEMORY;
678f363b723SAxel Dörfler				goto out;
679f363b723SAxel Dörfler			}
680f363b723SAxel Dörfler		}
681f363b723SAxel Dörfler
682f363b723SAxel Dörfler		// set up the new vnode
683554e58f0SAxel Dörfler		if (!atLeaf) {
684f363b723SAxel Dörfler			// this is a dir
685ab7516c8SAxel Dörfler			init_directory_vnode(vnode, 0755);
686ab7516c8SAxel Dörfler			publish_node(fs, dir, vnode);
687554e58f0SAxel Dörfler		} else {
688554e58f0SAxel Dörfler			// this is the last component
6892509807aSMichael Lotz			// Note: We do not yet insert the node into the directory, as it
6902509807aSMichael Lotz			// is not yet fully initialized. Instead we return the directory
6912509807aSMichael Lotz			// vnode so that the calling function can insert it after all
6922509807aSMichael Lotz			// initialization is done. This ensures that no create notification
6932509807aSMichael Lotz			// is sent out for a vnode that is not yet fully valid.
694554e58f0SAxel Dörfler			*_node = vnode;
6952509807aSMichael Lotz			*_dir = dir;
696f363b723SAxel Dörfler			break;
6972509807aSMichael Lotz		}
698554e58f0SAxel Dörfler
699f363b723SAxel Dörfler		last = i;
700f363b723SAxel Dörfler		dir = vnode;
701f363b723SAxel Dörfler	}
702f363b723SAxel Dörfler
703f363b723SAxel Dörflerout:
704554e58f0SAxel Dörfler	return status;
705554e58f0SAxel Dörfler}
706554e58f0SAxel Dörfler
707554e58f0SAxel Dörfler
708554e58f0SAxel Dörflerstatic status_t
709368167edSAxel Dörflerpublish_device(struct devfs* fs, const char* path, BaseDevice* device)
710554e58f0SAxel Dörfler{
711368167edSAxel Dörfler	TRACE(("publish_device(path = \"%s\", device = %p)\n", path, device));
712554e58f0SAxel Dörfler
713554e58f0SAxel Dörfler	if (sDeviceFileSystem == NULL) {
714554e58f0SAxel Dörfler		panic("publish_device() called before devfs mounted\n");
715554e58f0SAxel Dörfler		return B_ERROR;
716554e58f0SAxel Dörfler	}
717554e58f0SAxel Dörfler
718368167edSAxel Dörfler	if (device == NULL || path == NULL || path[0] == '\0' || path[0] == '/')
719554e58f0SAxel Dörfler		return B_BAD_VALUE;
720554e58f0SAxel Dörfler
721368167edSAxel Dörfler// TODO: this has to be done in the BaseDevice sub classes!
722368167edSAxel Dörfler#if 0
723554e58f0SAxel Dörfler	// are the provided device hooks okay?
724368167edSAxel Dörfler	if (info->device_open == NULL || info->device_close == NULL
725368167edSAxel Dörfler		|| info->device_free == NULL
726368167edSAxel Dörfler		|| ((info->device_read == NULL || info->device_write == NULL)
727368167edSAxel Dörfler			&& info->device_io == NULL))
728554e58f0SAxel Dörfler		return B_BAD_VALUE;
729368167edSAxel Dörfler#endif
730554e58f0SAxel Dörfler
731368167edSAxel Dörfler	struct devfs_vnode* node;
732368167edSAxel Dörfler	struct devfs_vnode* dirNode;
733554e58f0SAxel Dörfler	status_t status;
734554e58f0SAxel Dörfler
73580f6ef8bSAxel Dörfler	RecursiveLocker locker(&fs->lock);
736554e58f0SAxel Dörfler
737025b3675SAxel Dörfler	status = new_node(fs, path, &node, &dirNode);
738554e58f0SAxel Dörfler	if (status != B_OK)
73980f6ef8bSAxel Dörfler		return status;
740554e58f0SAxel Dörfler
741554e58f0SAxel Dörfler	// all went fine, let's initialize the node
742554e58f0SAxel Dörfler	node->stream.type = S_IFCHR | 0644;
743368167edSAxel Dörfler	node->stream.u.dev.device = device;
7448ec35e36SAxel Dörfler	device->SetID(node->id);
745554e58f0SAxel Dörfler
7462509807aSMichael Lotz	// the node is now fully valid and we may insert it into the dir
747025b3675SAxel Dörfler	publish_node(fs, dirNode, node);
748350e0b20SAxel Dörfler	return B_OK;
749f363b723SAxel Dörfler}
750f363b723SAxel Dörfler
751f363b723SAxel Dörfler
752e6fdb84bSAxel Dörfler/*!	Construct complete device name (as used for device_open()).
753e6fdb84bSAxel Dörfler	This is safe to use only when the device is in use (and therefore
754e6fdb84bSAxel Dörfler	cannot be unpublished during the iteration).
755e6fdb84bSAxel Dörfler*/
756da63fa92SAxel Dörflerstatic void
757368167edSAxel Dörflerget_device_name(struct devfs_vnode* vnode, char* buffer, size_t size)
758da63fa92SAxel Dörfler{
759ab7516c8SAxel Dörfler	RecursiveLocker _(sDeviceFileSystem->lock);
760ab7516c8SAxel Dörfler
761ab7516c8SAxel Dörfler	struct devfs_vnode* leaf = vnode;
762da63fa92SAxel Dörfler	size_t offset = 0;
763da63fa92SAxel Dörfler
764da63fa92SAxel Dörfler	// count levels
765da63fa92SAxel Dörfler
766da63fa92SAxel Dörfler	for (; vnode->parent && vnode->parent != vnode; vnode = vnode->parent) {
767da63fa92SAxel Dörfler		offset += strlen(vnode->name) + 1;
768da63fa92SAxel Dörfler	}
769da63fa92SAxel Dörfler
770da63fa92SAxel Dörfler	// construct full path name
77180f6ef8bSAxel Dörfler
7727dbbb04aSAxel Dörfler	for (vnode = leaf; vnode->parent && vnode->parent != vnode;
7737dbbb04aSAxel Dörfler			vnode = vnode->parent) {
774da63fa92SAxel Dörfler		size_t length = strlen(vnode->name);
775da63fa92SAxel Dörfler		size_t start = offset - length - 1;
776da63fa92SAxel Dörfler
777da63fa92SAxel Dörfler		if (size >= offset) {
778da63fa92SAxel Dörfler			strcpy(buffer + start, vnode->name);
779da63fa92SAxel Dörfler			if (vnode != leaf)
780da63fa92SAxel Dörfler				buffer[offset - 1] = '/';
781da63fa92SAxel Dörfler		}
782da63fa92SAxel Dörfler
7837dbbb04aSAxel Dörfler		offset = start;
784da63fa92SAxel Dörfler	}
785da63fa92SAxel Dörfler}
786da63fa92SAxel Dörfler
787da63fa92SAxel Dörfler
788bb94d91dSIngo Weinholdstatic status_t
7897f12cc54SIngo Weinholddevice_read(void* _cookie, off_t offset, void* buffer, size_t* length)
790bb94d91dSIngo Weinhold{
791bb94d91dSIngo Weinhold	synchronous_io_cookie* cookie = (synchronous_io_cookie*)_cookie;
7927f12cc54SIngo Weinhold	return cookie->device->Read(cookie->cookie, offset, buffer, length);
793bb94d91dSIngo Weinhold}
794bb94d91dSIngo Weinhold
795bb94d91dSIngo Weinhold
796bb94d91dSIngo Weinholdstatic status_t
7977f12cc54SIngo Weinholddevice_write(void* _cookie, off_t offset, void* buffer, size_t* length)
798bb94d91dSIngo Weinhold{
799bb94d91dSIngo Weinhold	synchronous_io_cookie* cookie = (synchronous_io_cookie*)_cookie;
8007f12cc54SIngo Weinhold	return cookie->device->Write(cookie->cookie, offset, buffer, length);
801bb94d91dSIngo Weinhold}
802bb94d91dSIngo Weinhold
803bb94d91dSIngo Weinhold
8041c4b5b8aSAxel Dörflerstatic int
80531cf5e52SAxel Dörflerdump_node(int argc, char** argv)
8061c4b5b8aSAxel Dörfler{
8070e4ea02dSIngo Weinhold	if (argc != 2) {
8080e4ea02dSIngo Weinhold		print_debugger_command_usage(argv[0]);
8091c4b5b8aSAxel Dörfler		return 0;
8101c4b5b8aSAxel Dörfler	}
8111c4b5b8aSAxel Dörfler
81231cf5e52SAxel Dörfler	struct devfs_vnode* vnode = (struct devfs_vnode*)parse_expression(argv[1]);
8131c4b5b8aSAxel Dörfler	if (vnode == NULL) {
8141c4b5b8aSAxel Dörfler		kprintf("invalid node address\n");
8151c4b5b8aSAxel Dörfler		return 0;
8161c4b5b8aSAxel Dörfler	}
8171c4b5b8aSAxel Dörfler
8181c4b5b8aSAxel Dörfler	kprintf("DEVFS NODE: %p\n", vnode);
819294711f9SAlex Smith	kprintf(" id:          %" B_PRIdINO "\n", vnode->id);
8207dbbb04aSAxel Dörfler	kprintf(" name:        \"%s\"\n", vnode->name);
8217dbbb04aSAxel Dörfler	kprintf(" type:        %x\n", vnode->stream.type);
8227dbbb04aSAxel Dörfler	kprintf(" parent:      %p\n", vnode->parent);
8237dbbb04aSAxel Dörfler	kprintf(" dir next:    %p\n", vnode->dir_next);
8247dbbb04aSAxel Dörfler
8257dbbb04aSAxel Dörfler	if (S_ISDIR(vnode->stream.type)) {
8264be4fc6bSAlex Smith		kprintf(" dir scanned: %" B_PRId32 "\n", vnode->stream.u.dir.scanned);
8277dbbb04aSAxel Dörfler		kprintf(" contents:\n");
8287dbbb04aSAxel Dörfler
82931cf5e52SAxel Dörfler		devfs_vnode* children = vnode->stream.u.dir.dir_head;
8307dbbb04aSAxel Dörfler		while (children != NULL) {
831294711f9SAlex Smith			kprintf("   %p, id %" B_PRIdINO "\n", children, children->id);
8327dbbb04aSAxel Dörfler			children = children->dir_next;
8337dbbb04aSAxel Dörfler		}
8347dbbb04aSAxel Dörfler	} else if (S_ISLNK(vnode->stream.type)) {
8357dbbb04aSAxel Dörfler		kprintf(" symlink to:  %s\n", vnode->stream.u.symlink.path);
8367dbbb04aSAxel Dörfler	} else {
837368167edSAxel Dörfler		kprintf(" device:      %p\n", vnode->stream.u.dev.device);
8387dbbb04aSAxel Dörfler		kprintf(" partition:   %p\n", vnode->stream.u.dev.partition);
839bfc607d4SAxel Dörfler		if (vnode->stream.u.dev.partition != NULL) {
840bfc607d4SAxel Dörfler			partition_info& info = vnode->stream.u.dev.partition->info;
841bfc607d4SAxel Dörfler			kprintf("  raw device node: %p\n",
842bfc607d4SAxel Dörfler				vnode->stream.u.dev.partition->raw_device);
843294711f9SAlex Smith			kprintf("  offset:          %" B_PRIdOFF "\n", info.offset);
844294711f9SAlex Smith			kprintf("  size:            %" B_PRIdOFF "\n", info.size);
8454be4fc6bSAlex Smith			kprintf("  block size:      %" B_PRId32 "\n", info.logical_block_size);
8464be4fc6bSAlex Smith			kprintf("  session:         %" B_PRId32 "\n", info.session);
8474be4fc6bSAlex Smith			kprintf("  partition:       %" B_PRId32 "\n", info.partition);
848bfc607d4SAxel Dörfler			kprintf("  device:          %s\n", info.device);
849bfc607d4SAxel Dörfler			set_debug_variable("_raw",
850bfc607d4SAxel Dörfler				(addr_t)vnode->stream.u.dev.partition->raw_device);
851bfc607d4SAxel Dörfler		}
8527dbbb04aSAxel Dörfler	}
8531c4b5b8aSAxel Dörfler
8541c4b5b8aSAxel Dörfler	return 0;
8551c4b5b8aSAxel Dörfler}
8561c4b5b8aSAxel Dörfler
8571c4b5b8aSAxel Dörfler
8580e4ea02dSIngo Weinholdstatic int
8590e4ea02dSIngo Weinholddump_cookie(int argc, char** argv)
8600e4ea02dSIngo Weinhold{
8610e4ea02dSIngo Weinhold	if (argc != 2) {
8620e4ea02dSIngo Weinhold		print_debugger_command_usage(argv[0]);
8630e4ea02dSIngo Weinhold		return 0;
8640e4ea02dSIngo Weinhold	}
8650e4ea02dSIngo Weinhold
8660e4ea02dSIngo Weinhold	uint64 address;
8670e4ea02dSIngo Weinhold	if (!evaluate_debug_expression(argv[1], &address, false))
8680e4ea02dSIngo Weinhold		return 0;
8690e4ea02dSIngo Weinhold
8700e4ea02dSIngo Weinhold	struct devfs_cookie* cookie = (devfs_cookie*)(addr_t)address;
8710e4ea02dSIngo Weinhold
8720e4ea02dSIngo Weinhold	kprintf("DEVFS COOKIE: %p\n", cookie);
8730e4ea02dSIngo Weinhold	kprintf(" device_cookie: %p\n", cookie->device_cookie);
8740e4ea02dSIngo Weinhold
8750e4ea02dSIngo Weinhold	return 0;
8760e4ea02dSIngo Weinhold}
8770e4ea02dSIngo Weinhold
8780e4ea02dSIngo Weinhold
87980f6ef8bSAxel Dörfler//	#pragma mark - file system interface
88007fefdf4SAxel Dörfler
88107fefdf4SAxel Dörfler
88290abd04bSbeveloperstatic status_t
88331cf5e52SAxel Dörflerdevfs_mount(fs_volume* volume, const char* devfs, uint32 flags,
88431cf5e52SAxel Dörfler	const char* args, ino_t* _rootNodeID)
88552a38012Sejakowatz{
88631cf5e52SAxel Dörfler	struct devfs_vnode* vnode;
88731cf5e52SAxel Dörfler	struct devfs* fs;
88890abd04bSbeveloper	status_t err;
88952a38012Sejakowatz
89052a38012Sejakowatz	TRACE(("devfs_mount: entry\n"));
89152a38012Sejakowatz
892bc1f913eSAxel Dörfler	if (sDeviceFileSystem) {
893db55a020SAxel Dörfler		TRACE(("double mount of devfs attempted\n"));
89407f317bfSAxel Dörfler		err = B_ERROR;
89552a38012Sejakowatz		goto err;
89652a38012Sejakowatz	}
89752a38012Sejakowatz
89831cf5e52SAxel Dörfler	fs = (struct devfs*)malloc(sizeof(struct devfs));
899ea536d2bSAxel Dörfler	if (fs == NULL) {
900ded78bc1SAxel Dörfler		err = B_NO_MEMORY;
90152a38012Sejakowatz		goto err;
902c4718ea9SAdrien Destugues	}
90352a38012Sejakowatz
9047ffafac8SIngo Weinhold	volume->private_volume = fs;
9057ffafac8SIngo Weinhold	volume->ops = &kVolumeOps;
9067ffafac8SIngo Weinhold	fs->volume = volume;
9077ffafac8SIngo Weinhold	fs->id = volume->id;
90852a38012Sejakowatz	fs->next_vnode_id = 0;
90952a38012Sejakowatz
910b0f5179aSIngo Weinhold	recursive_lock_init(&fs->lock, "devfs lock");
91152a38012Sejakowatz
912c4718ea9SAdrien Destugues	fs->vnode_hash = new(std::nothrow) NodeTable();
9136a89f804SAdrien Destugues	if (fs->vnode_hash == NULL || fs->vnode_hash->Init(DEVFS_HASH_SIZE) != B_OK) {
914ded78bc1SAxel Dörfler		err = B_NO_MEMORY;
91552a38012Sejakowatz		goto err2;
91652a38012Sejakowatz	}
91752a38012Sejakowatz
91852a38012Sejakowatz	// create a vnode
919140e3bb0SAxel Dörfler	vnode = devfs_create_vnode(fs, NULL, "");
920140e3bb0SAxel Dörfler	if (vnode == NULL) {
921ded78bc1SAxel Dörfler		err = B_NO_MEMORY;
922368167edSAxel Dörfler		goto err3;
92352a38012Sejakowatz	}
92452a38012Sejakowatz
92552a38012Sejakowatz	// set it up
926140e3bb0SAxel Dörfler	vnode->parent = vnode;
92752a38012Sejakowatz
92852a38012Sejakowatz	// create a dir stream for it to hold
929ab7516c8SAxel Dörfler	init_directory_vnode(vnode, 0755);
930140e3bb0SAxel Dörfler	fs->root_vnode = vnode;
93152a38012Sejakowatz
9326a89f804SAdrien Destugues	fs->vnode_hash->Insert(vnode);
9337ffafac8SIngo Weinhold	publish_vnode(volume, vnode->id, vnode, &kVnodeOps, vnode->stream.type, 0);
93452a38012Sejakowatz
93531cf5e52SAxel Dörfler	*_rootNodeID = vnode->id;
936bc1f913eSAxel Dörfler	sDeviceFileSystem = fs;
937ded78bc1SAxel Dörfler	return B_OK;
93852a38012Sejakowatz
93952a38012Sejakowatzerr3:
9406a89f804SAdrien Destugues	delete fs->vnode_hash;
94152a38012Sejakowatzerr2:
94280f6ef8bSAxel Dörfler	recursive_lock_destroy(&fs->lock);
94341691b99SAxel Dörfler	free(fs);
94452a38012Sejakowatzerr:
94552a38012Sejakowatz	return err;
94652a38012Sejakowatz}
94752a38012Sejakowatz
948ea536d2bSAxel Dörfler
94990abd04bSbeveloperstatic status_t
95031cf5e52SAxel Dörflerdevfs_unmount(fs_volume* _volume)
95152a38012Sejakowatz{
95231cf5e52SAxel Dörfler	struct devfs* fs = (struct devfs*)_volume->private_volume;
95331cf5e52SAxel Dörfler	struct devfs_vnode* vnode;
95452a38012Sejakowatz
955243d156eSAxel Dörfler	TRACE(("devfs_unmount: entry fs = %p\n", fs));
95652a38012Sejakowatz
957a77ed12bSAxel Dörfler	recursive_lock_lock(&fs->lock);
958a77ed12bSAxel Dörfler
9595b14757aSAxel Dörfler	// release the reference to the root
9607ffafac8SIngo Weinhold	put_vnode(fs->volume, fs->root_vnode->id);
9615b14757aSAxel Dörfler
96252a38012Sejakowatz	// delete all of the vnodes
9636a89f804SAdrien Destugues	NodeTable::Iterator i(fs->vnode_hash);
9646a89f804SAdrien Destugues	while (i.HasNext()) {
9656a89f804SAdrien Destugues		vnode = i.Next();
966140e3bb0SAxel Dörfler		devfs_delete_vnode(fs, vnode, true);
96752a38012Sejakowatz	}
9686a89f804SAdrien Destugues	delete fs->vnode_hash;
96980f6ef8bSAxel Dörfler
97080f6ef8bSAxel Dörfler	recursive_lock_destroy(&fs->lock);
97141691b99SAxel Dörfler	free(fs);
97252a38012Sejakowatz
9731c4b5b8aSAxel Dörfler	return B_OK;
97452a38012Sejakowatz}
97552a38012Sejakowatz
976ea536d2bSAxel Dörfler
97790abd04bSbeveloperstatic status_t
97831cf5e52SAxel Dörflerdevfs_sync(fs_volume* _volume)
97952a38012Sejakowatz{
98052a38012Sejakowatz	TRACE(("devfs_sync: entry\n"));
98152a38012Sejakowatz
9821c4b5b8aSAxel Dörfler	return B_OK;
98352a38012Sejakowatz}
98452a38012Sejakowatz
985ea536d2bSAxel Dörfler
98690abd04bSbeveloperstatic status_t
98731cf5e52SAxel Dörflerdevfs_lookup(fs_volume* _volume, fs_vnode* _dir, const char* name, ino_t* _id)
98852a38012Sejakowatz{
98931cf5e52SAxel Dörfler	struct devfs* fs = (struct devfs*)_volume->private_volume;
99031cf5e52SAxel Dörfler	struct devfs_vnode* dir = (struct devfs_vnode*)_dir->private_node;
99131cf5e52SAxel Dörfler	struct devfs_vnode* vnode;
99268c1f3d2SAxel Dörfler	status_t status;
99352a38012Sejakowatz
994243d156eSAxel Dörfler	TRACE(("devfs_lookup: entry dir %p, name '%s'\n", dir, name));
99552a38012Sejakowatz
99675e4b869SAxel Dörfler	if (!S_ISDIR(dir->stream.type))
9977be577a3SAxel Dörfler		return B_NOT_A_DIRECTORY;
99852a38012Sejakowatz
999ab7516c8SAxel Dörfler	// Make sure the directory contents are up to date
1000ab7516c8SAxel Dörfler	scan_for_drivers_if_needed(dir);
1001dcbf2cb6SAxel Dörfler
1002ab7516c8SAxel Dörfler	RecursiveLocker locker(&fs->lock);
1003dcbf2cb6SAxel Dörfler
100452a38012Sejakowatz	// look it up
1005243d156eSAxel Dörfler	vnode = devfs_find_in_dir(dir, name);
1006dcbf2cb6SAxel Dörfler	if (vnode == NULL) {
1007a77ed12bSAxel Dörfler		// We don't have to rescan here, because thanks to node monitoring
1008a77ed12bSAxel Dörfler		// we already know it does not exist
1009a77ed12bSAxel Dörfler		return B_ENTRY_NOT_FOUND;
101052a38012Sejakowatz	}
101152a38012Sejakowatz
101249004dc7SMichael Lotz	status = get_vnode(fs->volume, vnode->id, NULL);
101368c1f3d2SAxel Dörfler	if (status < B_OK)
101468c1f3d2SAxel Dörfler		return status;
101552a38012Sejakowatz
10167be577a3SAxel Dörfler	*_id = vnode->id;
101752a38012Sejakowatz
101868c1f3d2SAxel Dörfler	return B_OK;
101952a38012Sejakowatz}
102052a38012Sejakowatz
1021ea536d2bSAxel Dörfler
102290abd04bSbeveloperstatic status_t
102331cf5e52SAxel Dörflerdevfs_get_vnode_name(fs_volume* _volume, fs_vnode* _vnode, char* buffer,
10247ffafac8SIngo Weinhold	size_t bufferSize)
102563c5cc0aSAxel Dörfler{
102631cf5e52SAxel Dörfler	struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node;
102763c5cc0aSAxel Dörfler
1028f363b723SAxel Dörfler	TRACE(("devfs_get_vnode_name: vnode = %p\n", vnode));
10297dbbb04aSAxel Dörfler
1030f363b723SAxel Dörfler	strlcpy(buffer, vnode->name, bufferSize);
103163c5cc0aSAxel Dörfler	return B_OK;
103263c5cc0aSAxel Dörfler}
103363c5cc0aSAxel Dörfler
103463c5cc0aSAxel Dörfler
103590abd04bSbeveloperstatic status_t
103631cf5e52SAxel Dörflerdevfs_get_vnode(fs_volume* _volume, ino_t id, fs_vnode* _vnode, int* _type,
103731cf5e52SAxel Dörfler	uint32* _flags, bool reenter)
103852a38012Sejakowatz{
103931cf5e52SAxel Dörfler	struct devfs* fs = (struct devfs*)_volume->private_volume;
104052a38012Sejakowatz
1041243d156eSAxel Dörfler	TRACE(("devfs_get_vnode: asking for vnode id = %Ld, vnode = %p, r %d\n", id, _vnode, reenter));
104252a38012Sejakowatz
1043db55a020SAxel Dörfler	RecursiveLocker _(fs->lock);
104452a38012Sejakowatz
10456a89f804SAdrien Destugues	struct devfs_vnode* vnode = fs->vnode_hash->Lookup(id);
1046db55a020SAxel Dörfler	if (vnode == NULL)
1047db55a020SAxel Dörfler		return B_ENTRY_NOT_FOUND;
104852a38012Sejakowatz
1049368167edSAxel Dörfler	TRACE(("devfs_get_vnode: looked it up at %p\n", vnode));
105052a38012Sejakowatz
10517ffafac8SIngo Weinhold	_vnode->private_node = vnode;
10527ffafac8SIngo Weinhold	_vnode->ops = &kVnodeOps;
10537ffafac8SIngo Weinhold	*_type = vnode->stream.type;
10547ffafac8SIngo Weinhold	*_flags = 0;
10557b285866SAxel Dörfler	return B_OK;
105652a38012Sejakowatz}
105752a38012Sejakowatz
1058ea536d2bSAxel Dörfler
105990abd04bSbeveloperstatic status_t
1060368167edSAxel Dörflerdevfs_put_vnode(fs_volume* _volume, fs_vnode* _vnode, bool reenter)
106152a38012Sejakowatz{
1062ee0a0729SAxel Dörfler#ifdef TRACE_DEVFS
1063368167edSAxel Dörfler	struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node;
106452a38012Sejakowatz
1065ee0a0729SAxel Dörfler	TRACE(("devfs_put_vnode: entry on vnode %p, id = %Ld, reenter %d\n",
1066ee0a0729SAxel Dörfler		vnode, vnode->id, reenter));
1067ee0a0729SAxel Dörfler#endif
106852a38012Sejakowatz
10691c4b5b8aSAxel Dörfler	return B_OK;
107052a38012Sejakowatz}
107152a38012Sejakowatz
1072ea536d2bSAxel Dörfler
107390abd04bSbeveloperstatic status_t
107431cf5e52SAxel Dörflerdevfs_remove_vnode(fs_volume* _volume, fs_vnode* _v, bool reenter)
107552a38012Sejakowatz{
107631cf5e52SAxel Dörfler	struct devfs* fs = (struct devfs*)_volume->private_volume;
107731cf5e52SAxel Dörfler	struct devfs_vnode* vnode = (struct devfs_vnode*)_v->private_node;
107852a38012Sejakowatz
1079243d156eSAxel Dörfler	TRACE(("devfs_removevnode: remove %p (%Ld), reenter %d\n", vnode, vnode->id, reenter));
108052a38012Sejakowatz
108180f6ef8bSAxel Dörfler	RecursiveLocker locker(&fs->lock);
108252a38012Sejakowatz
1083243d156eSAxel Dörfler	if (vnode->dir_next) {
108452a38012Sejakowatz		// can't remove node if it's linked to the dir
1085243d156eSAxel Dörfler		panic("devfs_removevnode: vnode %p asked to be removed is present in dir\n", vnode);
108652a38012Sejakowatz	}
108752a38012Sejakowatz
1088243d156eSAxel Dörfler	devfs_delete_vnode(fs, vnode, false);
108952a38012Sejakowatz
1090243d156eSAxel Dörfler	return B_OK;
109152a38012Sejakowatz}
109252a38012Sejakowatz
1093ea536d2bSAxel Dörfler
109490abd04bSbeveloperstatic status_t
1095368167edSAxel Dörflerdevfs_open(fs_volume* _volume, fs_vnode* _vnode, int openMode,
1096368167edSAxel Dörfler	void** _cookie)
109752a38012Sejakowatz{
1098368167edSAxel Dörfler	struct devfs_vnode* vnode = (struct devfs_vnode*)_vnode->private_node;
1099368167edSAxel Dörfler	struct devfs_cookie* cookie;
110075e4b869SAxel Dörfler	status_t status = B_OK;
110152a38012Sejakowatz
1102368167edSAxel Dörfler	cookie = (struct devfs_cookie*)malloc(sizeof(struct devfs_cookie));
1103ea536d2bSAxel Dörfler	if (cookie == NULL)
1104ded78bc1SAxel Dörfler		return B_NO_MEMORY;
110552a38012Sejakowatz
1106ab7516c8SAxel Dörfler	TRACE(("devfs_open: vnode %p, openMode 0x%x, cookie %p\n", vnode, openMode,
1107ab7516c8SAxel Dörfler		cookie));
1108ab7516c8SAxel Dörfler
1109368167edSAxel Dörfler	cookie->device_cookie = NULL;
1110368167edSAxel Dörfler
111175e4b869SAxel Dörfler	if (S_ISCHR(vnode->stream.type)) {
1112368167edSAxel Dörfler		BaseDevice* device = vnode->stream.u.dev.device;
1113368167edSAxel Dörfler		status = device->InitDevice();
1114a42c52c0SPhilippe Saint-Pierre		if (status != B_OK) {
1115a42c52c0SPhilippe Saint-Pierre			free(cookie);
1116368167edSAxel Dörfler			return status;
1117a42c52c0SPhilippe Saint-Pierre		}
1118368167edSAxel Dörfler
1119368167edSAxel Dörfler		char path[B_FILE_NAME_LENGTH];
1120368167edSAxel Dörfler		get_device_name(vnode, path, sizeof(path));
1121e6fdb84bSAxel Dörfler
1122368167edSAxel Dörfler		status = device->Open(path, openMode, &cookie->device_cookie);
1123368167edSAxel Dörfler		if (status != B_OK)
1124