xref: /haiku/src/add-ons/kernel/file_systems/userlandfs/server/UserlandFSServer.cpp (revision ed6250c95736c0b55da79d6e9dd01369532260c0)
1 // UserlandFSServer.cpp
2 
3 #include "UserlandFSServer.h"
4 
5 #include <new>
6 #include <stdio.h>
7 #include <string.h>
8 
9 #include <Application.h>
10 #include <Clipboard.h>
11 #include <FindDirectory.h>
12 #include <fs_interface.h>
13 #include <Locker.h>
14 #include <Path.h>
15 
16 #include "AutoDeleter.h"
17 #include "AutoLocker.h"
18 #include "beos_fs_cache.h"
19 #include "beos_fs_interface.h"
20 #include "BeOSKernelFileSystem.h"
21 #include "Compatibility.h"
22 #include "Debug.h"
23 #include "DispatcherDefs.h"
24 #include "FileSystem.h"
25 #include "FSInfo.h"
26 #include "haiku_block_cache_priv.h"
27 #include "haiku_fs_cache.h"
28 #include "HaikuKernelFileSystem.h"
29 #include "RequestThread.h"
30 #include "ServerDefs.h"
31 
32 static const int32 kRequestThreadCount = 10;
33 
34 static const int32 kMaxBlockCacheBlocks = 16384;
35 
36 // constructor
37 UserlandFSServer::UserlandFSServer(const char* signature)
38 	: BApplication(signature),
39 	  fAddOnImage(-1),
40 	  fFileSystem(NULL),
41 	  fNotificationRequestPort(NULL),
42 	  fRequestThreads(NULL),
43 	  fBlockCacheInitialized(false)
44 {
45 }
46 
47 // destructor
48 UserlandFSServer::~UserlandFSServer()
49 {
50 	if (fRequestThreads) {
51 		for (int32 i = 0; i < kRequestThreadCount; i++)
52 			fRequestThreads[i].PrepareTermination();
53 		for (int32 i = 0; i < kRequestThreadCount; i++)
54 			fRequestThreads[i].Terminate();
55 		delete[] fRequestThreads;
56 	}
57 	delete fNotificationRequestPort;
58 	delete fFileSystem;
59 	if (fBlockCacheInitialized)
60 		beos_shutdown_block_cache();
61 	if (fAddOnImage >= 0)
62 		unload_add_on(fAddOnImage);
63 }
64 
65 // Init
66 status_t
67 UserlandFSServer::Init(const char* fileSystem)
68 {
69 	// get the add-on path
70 	BPath addOnPath;
71 	status_t error = find_directory(B_USER_ADDONS_DIRECTORY, &addOnPath);
72 	if (error != B_OK)
73 		RETURN_ERROR(error);
74 	error = addOnPath.Append("userlandfs");
75 	if (error != B_OK)
76 		RETURN_ERROR(error);
77 	error = addOnPath.Append(fileSystem);
78 	if (error != B_OK)
79 		RETURN_ERROR(error);
80 
81 	// load the add-on
82 	fAddOnImage = load_add_on(addOnPath.Path());
83 	if (fAddOnImage < 0)
84 		RETURN_ERROR(fAddOnImage);
85 
86 	// create the FileSystem interface
87 	// BeOS kernel interface
88 	if (_CreateBeOSKernelInterface(fileSystem, fAddOnImage, &fFileSystem)
89 			== B_OK) {
90 		// BeOS interface
91 	} else if (_CreateHaikuKernelInterface(fileSystem, fAddOnImage,
92 			&fFileSystem) == B_OK) {
93 		// Haiku interface
94 	} else {
95 		ERROR(("Add-on doesn't has a supported interface.\n"));
96 	}
97 
98 	// create the notification request port
99 	fNotificationRequestPort = new(nothrow) RequestPort(kRequestPortSize);
100 	if (!fNotificationRequestPort)
101 		RETURN_ERROR(B_NO_MEMORY);
102 	error = fNotificationRequestPort->InitCheck();
103 	if (error != B_OK)
104 		RETURN_ERROR(error);
105 
106 	// now create the request threads
107 	fRequestThreads = new(nothrow) RequestThread[kRequestThreadCount];
108 	if (!fRequestThreads)
109 		RETURN_ERROR(B_NO_MEMORY);
110 	for (int32 i = 0; i < kRequestThreadCount; i++) {
111 		error = fRequestThreads[i].Init(fFileSystem);
112 		if (error != B_OK)
113 			RETURN_ERROR(error);
114 	}
115 
116 	// run the threads
117 	for (int32 i = 0; i < kRequestThreadCount; i++)
118 		fRequestThreads[i].Run();
119 
120 	// enter the debugger here, if desired
121 	if (gServerSettings.ShallEnterDebugger())
122 		debugger("File system ready to use.");
123 
124 	// finally register with the dispatcher
125 	error = _RegisterWithDispatcher(fileSystem);
126 	RETURN_ERROR(error);
127 }
128 
129 // GetNotificationRequestPort
130 RequestPort*
131 UserlandFSServer::GetNotificationRequestPort()
132 {
133 	if (UserlandFSServer* server = dynamic_cast<UserlandFSServer*>(be_app))
134 		return server->fNotificationRequestPort;
135 	return NULL;
136 }
137 
138 // GetFileSystem
139 FileSystem*
140 UserlandFSServer::GetFileSystem()
141 {
142 	if (UserlandFSServer* server = dynamic_cast<UserlandFSServer*>(be_app))
143 		return server->fFileSystem;
144 	return NULL;
145 }
146 
147 // _RegisterWithDispatcher
148 status_t
149 UserlandFSServer::_RegisterWithDispatcher(const char* fsName)
150 {
151 	// get the dispatcher messenger from the clipboard
152 	BMessenger messenger;
153 	BClipboard clipboard(kUserlandFSDispatcherClipboardName);
154 	if (AutoLocker<BClipboard> locker = clipboard) {
155 		status_t error = B_OK;
156 		if (BMessage* data = clipboard.Data()) {
157 			error = data->FindMessenger("messenger", &messenger);
158 			if (error != B_OK) {
159 				ERROR(("No dispatcher messenger in clipboard.\n"));
160 				return error;
161 			}
162 			if (!messenger.IsValid()) {
163 				ERROR(("Found dispatcher messenger not valid.\n"));
164 				return B_ERROR;
165 			}
166 		} else {
167 			ERROR(("Failed to get clipboard data container\n"));
168 			return B_ERROR;
169 		}
170 	} else {
171 		ERROR(("Failed to lock the clipboard.\n"));
172 		return B_ERROR;
173 	}
174 
175 	// get the port infos
176 	Port::Info infos[kRequestThreadCount + 1];
177 	infos[0] = *fNotificationRequestPort->GetPortInfo();
178 	for (int32 i = 0; i < kRequestThreadCount; i++)
179 		infos[i + 1] = *fRequestThreads[i].GetPortInfo();
180 
181 	// FS capabilities
182 	FSCapabilities capabilities;
183 	fFileSystem->GetCapabilities(capabilities);
184 
185 	// init an FS info
186 	FSInfo info;
187 	status_t error = info.SetTo(fsName, infos, kRequestThreadCount + 1,
188 		capabilities);
189 
190 	// prepare the message
191 	BMessage message(UFS_REGISTER_FS);
192 	if (error == B_OK)
193 		error = message.AddInt32("team", Team());
194 	if (error == B_OK)
195 		error = info.Archive(&message);
196 
197 	// send the message
198 	BMessage reply;
199 	error = messenger.SendMessage(&message, &reply);
200 	if (error == B_OK && reply.what != UFS_REGISTER_FS_ACK) {
201 		ERROR(("FS registration failed.\n"));
202 		error = B_ERROR;
203 	}
204 	return error;
205 }
206 
207 // _CreateBeOSKernelInterface
208 status_t
209 UserlandFSServer::_CreateBeOSKernelInterface(const char* fsName, image_id image,
210 	FileSystem** _fileSystem)
211 {
212 	// get the symbols "fs_entry" and "api_version"
213 	beos_vnode_ops* fsOps;
214 	status_t error = get_image_symbol(image, "fs_entry", B_SYMBOL_TYPE_DATA,
215 		(void**)&fsOps);
216 	if (error != B_OK)
217 		RETURN_ERROR(error);
218 	int32* apiVersion;
219 	error = get_image_symbol(image, "api_version", B_SYMBOL_TYPE_DATA,
220 		(void**)&apiVersion);
221 	if (error != B_OK)
222 		RETURN_ERROR(error);
223 
224 	// check api version
225 	if (*apiVersion != BEOS_FS_API_VERSION)
226 		RETURN_ERROR(B_ERROR);
227 
228 	// create the file system
229 	BeOSKernelFileSystem* fileSystem = new(nothrow) BeOSKernelFileSystem(fsOps);
230 	if (!fileSystem)
231 		RETURN_ERROR(B_NO_MEMORY);
232 	ObjectDeleter<BeOSKernelFileSystem> fsDeleter(fileSystem);
233 
234 	// init the block cache
235 	error = beos_init_block_cache(kMaxBlockCacheBlocks, 0);
236 	if (error != B_OK)
237 		RETURN_ERROR(error);
238 	fBlockCacheInitialized = true;
239 
240 	// everything went fine
241 	fsDeleter.Detach();
242 	*_fileSystem = fileSystem;
243 	return B_OK;
244 }
245 
246 // _CreateHaikuKernelInterface
247 status_t
248 UserlandFSServer::_CreateHaikuKernelInterface(const char* fsName,
249 	image_id image, FileSystem** _fileSystem)
250 {
251 	// get the modules
252 	module_info** modules;
253 	status_t error = get_image_symbol(image, "modules", B_SYMBOL_TYPE_DATA,
254 		(void**)&modules);
255 	if (error != B_OK)
256 		RETURN_ERROR(error);
257 
258 	// module name must match "file_systems/<name>/v1"
259 	char moduleName[B_PATH_NAME_LENGTH];
260 	snprintf(moduleName, sizeof(moduleName), "file_systems/%s/v1", fsName);
261 
262 	// find the module
263 	file_system_module_info* module = NULL;
264 	for (int32 i = 0; modules[i]->name; i++) {
265 		if (strcmp(modules[i]->name, moduleName) == 0) {
266 			module = (file_system_module_info*)modules[i];
267 			break;
268 		}
269 	}
270 	if (!module)
271 		RETURN_ERROR(B_ERROR);
272 
273 	// create the file system
274 	HaikuKernelFileSystem* fileSystem
275 		= new(nothrow) HaikuKernelFileSystem(module);
276 	if (!fileSystem)
277 		RETURN_ERROR(B_NO_MEMORY);
278 	ObjectDeleter<HaikuKernelFileSystem> fsDeleter(fileSystem);
279 
280 	// init block cache
281 	error = UserlandFS::HaikuKernelEmu::block_cache_init();
282 	if (error != B_OK)
283 		RETURN_ERROR(error);
284 
285 	// init file cache
286 	error = UserlandFS::HaikuKernelEmu::file_cache_init();
287 	if (error != B_OK)
288 		RETURN_ERROR(error);
289 
290 	// init the FS
291 	error = fileSystem->Init();
292 	if (error != B_OK)
293 		return error;
294 
295 	// everything went fine
296 	fsDeleter.Detach();
297 	*_fileSystem = fileSystem;
298 	return B_OK;
299 }
300