xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/server/haiku/HaikuKernelFileSystem.cpp (revision 28627b28aa84c2a1c0a07cf514782c514f9c672e)
1 /*
2  * Copyright 2007-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "HaikuKernelFileSystem.h"
7 
8 #include <string.h>
9 
10 #include <new>
11 
12 #include <fs_interface.h>
13 
14 #include <AutoLocker.h>
15 
16 #include <block_cache.h>
17 #include <condition_variable.h>
18 #include <file_cache.h>
19 
20 #include "HaikuKernelIORequest.h"
21 #include "HaikuKernelVolume.h"
22 
23 
24 // IORequestHashDefinition
25 struct HaikuKernelFileSystem::IORequestHashDefinition {
26 	typedef int32					KeyType;
27 	typedef	HaikuKernelIORequest	ValueType;
28 
HashKeyHaikuKernelFileSystem::IORequestHashDefinition29 	size_t HashKey(int32 key) const
30 		{ return key; }
HashHaikuKernelFileSystem::IORequestHashDefinition31 	size_t Hash(const HaikuKernelIORequest* value) const
32 		{ return value->id; }
CompareHaikuKernelFileSystem::IORequestHashDefinition33 	bool Compare(int32 key, const HaikuKernelIORequest* value) const
34 		{ return value->id == key; }
GetLinkHaikuKernelFileSystem::IORequestHashDefinition35 	HaikuKernelIORequest*& GetLink(HaikuKernelIORequest* value) const
36 			{ return value->hashLink; }
37 };
38 
39 
40 // IORequestTable
41 struct HaikuKernelFileSystem::IORequestTable
42 	: public BOpenHashTable<IORequestHashDefinition> {
43 	typedef int32					KeyType;
44 	typedef	HaikuKernelIORequest	ValueType;
45 
HashKeyHaikuKernelFileSystem::IORequestTable46 	size_t HashKey(int32 key) const
47 		{ return key; }
HashHaikuKernelFileSystem::IORequestTable48 	size_t Hash(const HaikuKernelIORequest* value) const
49 		{ return value->id; }
CompareHaikuKernelFileSystem::IORequestTable50 	bool Compare(int32 key, const HaikuKernelIORequest* value) const
51 		{ return value->id == key; }
GetLinkHaikuKernelFileSystem::IORequestTable52 	HaikuKernelIORequest*& GetLink(HaikuKernelIORequest* value) const
53 			{ return value->hashLink; }
54 };
55 
56 
57 // NodeCapabilitiesHashDefinition
58 struct HaikuKernelFileSystem::NodeCapabilitiesHashDefinition {
59 	typedef fs_vnode_ops*					KeyType;
60 	typedef	HaikuKernelNode::Capabilities	ValueType;
61 
HashKeyHaikuKernelFileSystem::NodeCapabilitiesHashDefinition62 	size_t HashKey(fs_vnode_ops* key) const
63 		{ return (size_t)(addr_t)key; }
HashHaikuKernelFileSystem::NodeCapabilitiesHashDefinition64 	size_t Hash(const ValueType* value) const
65 		{ return HashKey(value->ops); }
CompareHaikuKernelFileSystem::NodeCapabilitiesHashDefinition66 	bool Compare(fs_vnode_ops* key, const ValueType* value) const
67 		{ return value->ops == key; }
GetLinkHaikuKernelFileSystem::NodeCapabilitiesHashDefinition68 	ValueType*& GetLink(ValueType* value) const
69 		{ return value->hashLink; }
70 };
71 
72 
73 // NodeCapabilitiesTable
74 struct HaikuKernelFileSystem::NodeCapabilitiesTable
75 	: public BOpenHashTable<NodeCapabilitiesHashDefinition> {
76 };
77 
78 
79 // constructor
HaikuKernelFileSystem(const char * fsName,file_system_module_info * fsModule)80 HaikuKernelFileSystem::HaikuKernelFileSystem(const char* fsName,
81 	file_system_module_info* fsModule)
82 	:
83 	FileSystem(fsName),
84 	fFSModule(fsModule),
85 	fIORequests(NULL),
86 	fNodeCapabilities(NULL),
87 	fLock("HaikuKernelFileSystem")
88 {
89 	_InitCapabilities();
90 }
91 
92 
93 // destructor
~HaikuKernelFileSystem()94 HaikuKernelFileSystem::~HaikuKernelFileSystem()
95 {
96 	// call the kernel module uninitialization
97 	if (fFSModule->info.std_ops)
98 		fFSModule->info.std_ops(B_MODULE_UNINIT);
99 
100 	delete fIORequests;
101 	delete fNodeCapabilities;
102 
103 // TODO: Call the cleanup methods (condition vars, block cache)!
104 }
105 
106 
107 // Init
108 status_t
Init()109 HaikuKernelFileSystem::Init()
110 {
111 	status_t error = fLock.InitCheck();
112 	if (error != B_OK)
113 		RETURN_ERROR(error);
114 
115 	// init condition variables
116 	condition_variable_init();
117 // TODO: Call the cleanup methods, if something goes wrong!
118 
119 	// init block cache
120 	error = block_cache_init();
121 	if (error != B_OK)
122 		RETURN_ERROR(error);
123 
124 	// init file map
125 	error = file_map_init();
126 	if (error != B_OK)
127 		RETURN_ERROR(error);
128 
129 	// create I/O request map
130 	fIORequests = new(std::nothrow) IORequestTable;
131 	if (fIORequests == NULL)
132 		RETURN_ERROR(B_NO_MEMORY);
133 
134 	error = fIORequests->Init();
135 	if (error != B_OK)
136 		RETURN_ERROR(error);
137 
138 	// create the node capabilites map
139 	fNodeCapabilities = new(std::nothrow) NodeCapabilitiesTable;
140 	if (fNodeCapabilities == NULL)
141 		RETURN_ERROR(B_NO_MEMORY);
142 
143 	error = fNodeCapabilities->Init();
144 	if (error != B_OK)
145 		RETURN_ERROR(error);
146 
147 	// call the kernel module initialization (if any)
148 	if (!fFSModule->info.std_ops)
149 		return B_OK;
150 
151 	error = fFSModule->info.std_ops(B_MODULE_INIT);
152 	if (error != B_OK)
153 		RETURN_ERROR(error);
154 
155 	return B_OK;
156 }
157 
158 
159 // CreateVolume
160 status_t
CreateVolume(Volume ** _volume,dev_t id)161 HaikuKernelFileSystem::CreateVolume(Volume** _volume, dev_t id)
162 {
163 	// check initialization and parameters
164 	if (!fFSModule || !_volume)
165 		return B_BAD_VALUE;
166 
167 	// create and init the volume
168 	HaikuKernelVolume* volume
169 		= new(std::nothrow) HaikuKernelVolume(this, id, fFSModule);
170 	if (!volume)
171 		return B_NO_MEMORY;
172 
173 	status_t error = volume->Init();
174 	if (error != B_OK) {
175 		delete volume;
176 		return error;
177 	}
178 
179 	*_volume = volume;
180 	return B_OK;
181 }
182 
183 
184 // DeleteVolume
185 status_t
DeleteVolume(Volume * volume)186 HaikuKernelFileSystem::DeleteVolume(Volume* volume)
187 {
188 	if (!volume || !dynamic_cast<HaikuKernelVolume*>(volume))
189 		return B_BAD_VALUE;
190 	delete volume;
191 	return B_OK;
192 }
193 
194 
195 // AddIORequest
196 status_t
AddIORequest(HaikuKernelIORequest * request)197 HaikuKernelFileSystem::AddIORequest(HaikuKernelIORequest* request)
198 {
199 	AutoLocker<Locker> _(fLock);
200 
201 	// check, if a request with that ID is already in the map
202 	if (fIORequests->Lookup(request->id) != NULL)
203 		RETURN_ERROR(B_BAD_VALUE);
204 
205 	fIORequests->Insert(request);
206 	return B_OK;
207 }
208 
209 
210 // GetIORequest
211 HaikuKernelIORequest*
GetIORequest(int32 requestID)212 HaikuKernelFileSystem::GetIORequest(int32 requestID)
213 {
214 	AutoLocker<Locker> _(fLock);
215 
216 	HaikuKernelIORequest* request = fIORequests->Lookup(requestID);
217 	if (request != NULL)
218 		request->refCount++;
219 
220 	return request;
221 }
222 
223 
224 // PutIORequest
225 void
PutIORequest(HaikuKernelIORequest * request,int32 refCount)226 HaikuKernelFileSystem::PutIORequest(HaikuKernelIORequest* request,
227 	int32 refCount)
228 {
229 	AutoLocker<Locker> locker(fLock);
230 
231 	if ((request->refCount -= refCount) <= 0) {
232 		fIORequests->Remove(request);
233 		locker.Unlock();
234 		delete request;
235 	}
236 }
237 
238 
239 // GetVNodeCapabilities
240 HaikuKernelNode::Capabilities*
GetNodeCapabilities(fs_vnode_ops * ops)241 HaikuKernelFileSystem::GetNodeCapabilities(fs_vnode_ops* ops)
242 {
243 	AutoLocker<Locker> locker(fLock);
244 
245 	// check whether the ops are already known
246 	HaikuKernelNode::Capabilities* capabilities
247 		= fNodeCapabilities->Lookup(ops);
248 	if (capabilities != NULL) {
249 		capabilities->refCount++;
250 		return capabilities;
251 	}
252 
253 	// get the capabilities implied by the ops vector
254 	FSVNodeCapabilities nodeCapabilities;
255 	_InitNodeCapabilities(ops, nodeCapabilities);
256 
257 	// create a new object
258 	capabilities = new(std::nothrow) HaikuKernelNode::Capabilities(ops,
259 		nodeCapabilities);
260 	if (capabilities == NULL)
261 		return NULL;
262 
263 	fNodeCapabilities->Insert(capabilities);
264 
265 	return capabilities;
266 }
267 
268 
269 // PutVNodeCapabilities
270 void
PutNodeCapabilities(HaikuKernelNode::Capabilities * capabilities)271 HaikuKernelFileSystem::PutNodeCapabilities(
272 	HaikuKernelNode::Capabilities* capabilities)
273 {
274 	AutoLocker<Locker> locker(fLock);
275 
276 	if (--capabilities->refCount == 0) {
277 		fNodeCapabilities->Remove(capabilities);
278 		delete capabilities;
279 	}
280 }
281 
282 
283 // _InitCapabilities
284 void
_InitCapabilities()285 HaikuKernelFileSystem::_InitCapabilities()
286 {
287 	fCapabilities.ClearAll();
288 
289 	// FS interface type
290 	fClientFSType = CLIENT_FS_HAIKU_KERNEL;
291 
292 	// FS operations
293 	fCapabilities.Set(FS_CAPABILITY_MOUNT, fFSModule->mount);
294 }
295 
296 
297 /*static*/ void
_InitNodeCapabilities(fs_vnode_ops * ops,FSVNodeCapabilities & capabilities)298 HaikuKernelFileSystem::_InitNodeCapabilities(fs_vnode_ops* ops,
299 	FSVNodeCapabilities& capabilities)
300 {
301 	capabilities.ClearAll();
302 
303 	// vnode operations
304 	capabilities.Set(FS_VNODE_CAPABILITY_LOOKUP, ops->lookup);
305 	capabilities.Set(FS_VNODE_CAPABILITY_GET_VNODE_NAME, ops->get_vnode_name);
306 	capabilities.Set(FS_VNODE_CAPABILITY_PUT_VNODE, ops->put_vnode);
307 	capabilities.Set(FS_VNODE_CAPABILITY_REMOVE_VNODE, ops->remove_vnode);
308 
309 	// asynchronous I/O
310 	capabilities.Set(FS_VNODE_CAPABILITY_IO, ops->io);
311 	capabilities.Set(FS_VNODE_CAPABILITY_CANCEL_IO, ops->cancel_io);
312 
313 	// cache file access
314 	capabilities.Set(FS_VNODE_CAPABILITY_GET_FILE_MAP, ops->get_file_map);
315 
316 	// common operations
317 	capabilities.Set(FS_VNODE_CAPABILITY_IOCTL, ops->ioctl);
318 	capabilities.Set(FS_VNODE_CAPABILITY_SET_FLAGS, ops->set_flags);
319 	capabilities.Set(FS_VNODE_CAPABILITY_SELECT, ops->select);
320 	capabilities.Set(FS_VNODE_CAPABILITY_DESELECT, ops->deselect);
321 	capabilities.Set(FS_VNODE_CAPABILITY_FSYNC, ops->fsync);
322 
323 	capabilities.Set(FS_VNODE_CAPABILITY_READ_SYMLINK, ops->read_symlink);
324 	capabilities.Set(FS_VNODE_CAPABILITY_CREATE_SYMLINK, ops->create_symlink);
325 
326 	capabilities.Set(FS_VNODE_CAPABILITY_LINK, ops->link);
327 	capabilities.Set(FS_VNODE_CAPABILITY_UNLINK, ops->unlink);
328 	capabilities.Set(FS_VNODE_CAPABILITY_RENAME, ops->rename);
329 
330 	capabilities.Set(FS_VNODE_CAPABILITY_ACCESS, ops->access);
331 	capabilities.Set(FS_VNODE_CAPABILITY_READ_STAT, ops->read_stat);
332 	capabilities.Set(FS_VNODE_CAPABILITY_WRITE_STAT, ops->write_stat);
333 
334 	// file operations
335 	capabilities.Set(FS_VNODE_CAPABILITY_CREATE, ops->create);
336 	capabilities.Set(FS_VNODE_CAPABILITY_OPEN, ops->open);
337 	capabilities.Set(FS_VNODE_CAPABILITY_CLOSE, ops->close);
338 	capabilities.Set(FS_VNODE_CAPABILITY_FREE_COOKIE, ops->free_cookie);
339 	capabilities.Set(FS_VNODE_CAPABILITY_READ, ops->read);
340 	capabilities.Set(FS_VNODE_CAPABILITY_WRITE, ops->write);
341 
342 	// directory operations
343 	capabilities.Set(FS_VNODE_CAPABILITY_CREATE_DIR, ops->create_dir);
344 	capabilities.Set(FS_VNODE_CAPABILITY_REMOVE_DIR, ops->remove_dir);
345 	capabilities.Set(FS_VNODE_CAPABILITY_OPEN_DIR, ops->open_dir);
346 	capabilities.Set(FS_VNODE_CAPABILITY_CLOSE_DIR, ops->close_dir);
347 	capabilities.Set(FS_VNODE_CAPABILITY_FREE_DIR_COOKIE, ops->free_dir_cookie);
348 	capabilities.Set(FS_VNODE_CAPABILITY_READ_DIR, ops->read_dir);
349 	capabilities.Set(FS_VNODE_CAPABILITY_REWIND_DIR, ops->rewind_dir);
350 
351 	// attribute directory operations
352 	capabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR_DIR, ops->open_attr_dir);
353 	capabilities.Set(FS_VNODE_CAPABILITY_CLOSE_ATTR_DIR, ops->close_attr_dir);
354 	capabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_DIR_COOKIE,
355 		ops->free_attr_dir_cookie);
356 	capabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_DIR, ops->read_attr_dir);
357 	capabilities.Set(FS_VNODE_CAPABILITY_REWIND_ATTR_DIR, ops->rewind_attr_dir);
358 
359 	// attribute operations
360 	capabilities.Set(FS_VNODE_CAPABILITY_CREATE_ATTR, ops->create_attr);
361 	capabilities.Set(FS_VNODE_CAPABILITY_OPEN_ATTR, ops->open_attr);
362 	capabilities.Set(FS_VNODE_CAPABILITY_CLOSE_ATTR, ops->close_attr);
363 	capabilities.Set(FS_VNODE_CAPABILITY_FREE_ATTR_COOKIE,
364 		ops->free_attr_cookie);
365 	capabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR, ops->read_attr);
366 	capabilities.Set(FS_VNODE_CAPABILITY_WRITE_ATTR, ops->write_attr);
367 
368 	capabilities.Set(FS_VNODE_CAPABILITY_READ_ATTR_STAT, ops->read_attr_stat);
369 	capabilities.Set(FS_VNODE_CAPABILITY_WRITE_ATTR_STAT,
370 		ops->write_attr_stat);
371 	capabilities.Set(FS_VNODE_CAPABILITY_RENAME_ATTR, ops->rename_attr);
372 	capabilities.Set(FS_VNODE_CAPABILITY_REMOVE_ATTR, ops->remove_attr);
373 
374 	// support for node and FS layers
375 	capabilities.Set(FS_VNODE_CAPABILITY_CREATE_SPECIAL_NODE,
376 		ops->create_special_node);
377 	capabilities.Set(FS_VNODE_CAPABILITY_GET_SUPER_VNODE, ops->get_super_vnode);
378 }
379 
380 
381 // #pragma mark - bootstrapping
382 
383 
384 status_t
userlandfs_create_file_system(const char * fsName,image_id image,FileSystem ** _fileSystem)385 userlandfs_create_file_system(const char* fsName, image_id image,
386 	FileSystem** _fileSystem)
387 {
388 	// get the modules
389 	module_info** modules;
390 	status_t error = get_image_symbol(image, "modules", B_SYMBOL_TYPE_DATA,
391 		(void**)&modules);
392 	if (error != B_OK)
393 		RETURN_ERROR(error);
394 
395 	// module name must match "file_systems/<name>/v1"
396 	char moduleName[B_PATH_NAME_LENGTH];
397 	snprintf(moduleName, sizeof(moduleName), "file_systems/%s/v1", fsName);
398 
399 	// find the module
400 	file_system_module_info* module = NULL;
401 	for (int32 i = 0; modules[i] && modules[i]->name; i++) {
402 		if (strcmp(modules[i]->name, moduleName) == 0) {
403 			module = (file_system_module_info*)modules[i];
404 			break;
405 		}
406 	}
407 	if (!module)
408 		RETURN_ERROR(B_ERROR);
409 
410 	// create the file system
411 	HaikuKernelFileSystem* fileSystem
412 		= new(std::nothrow) HaikuKernelFileSystem(fsName, module);
413 	if (!fileSystem)
414 		RETURN_ERROR(B_NO_MEMORY);
415 
416 	error = fileSystem->Init();
417 	if (error != B_OK) {
418 		delete fileSystem;
419 		return error;
420 	}
421 
422 	*_fileSystem = fileSystem;
423 	return B_OK;
424 }
425