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