xref: /haiku/src/add-ons/kernel/file_systems/layers/log_overlay/log_overlay.cpp (revision d3b1caa62d83444c7c95a73cdc2094d2087fb818)
1 /*
2  * Copyright 2010, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Lotz <mmlr@mlotz.ch>
7  */
8 
9 #include <new>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include <errno.h>
15 #include <dirent.h>
16 
17 #include <fs_info.h>
18 #include <fs_interface.h>
19 
20 #include <debug.h>
21 #include <KernelExport.h>
22 
23 #include <io_requests.h>
24 
25 static const char *kLogFilePrefix = "/var/log/log_overlay";
26 
27 
28 #define DO_LOG(format, args...) \
29 	{ \
30 		char _printBuffer[256]; \
31 		int _printSize = snprintf(_printBuffer, sizeof(_printBuffer), \
32 			"%llu %ld %p: " format, system_time(), find_thread(NULL), \
33 			((fs_vnode *)vnode->private_node)->private_node, args); \
34 		if ((unsigned int)_printSize > sizeof(_printBuffer)) { \
35 			_printBuffer[sizeof(_printBuffer) - 1] = '\n'; \
36 			_printSize = sizeof(_printBuffer); \
37 		} \
38 		write((int)volume->private_volume, _printBuffer, _printSize); \
39 	}
40 
41 #define OVERLAY_CALL(op, params...) \
42 	status_t result = B_UNSUPPORTED; \
43 	fs_vnode *superVnode = (fs_vnode *)vnode->private_node; \
44 	if (superVnode->ops->op != NULL) \
45 		result = superVnode->ops->op(volume->super_volume, superVnode, params); \
46 
47 
48 static status_t
49 overlay_put_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
50 {
51 	DO_LOG("put_vnode reenter: %s\n", reenter ? "yes" : "no");
52 
53 	status_t result = B_UNSUPPORTED;
54 	fs_vnode *superVnode = (fs_vnode *)vnode->private_node;
55 	if (superVnode->ops->put_vnode != NULL) {
56 		result = superVnode->ops->put_vnode(volume->super_volume, superVnode,
57 			reenter);
58 	}
59 
60 	DO_LOG("put_vnode result: 0x%08lx\n", result);
61 	delete (fs_vnode *)vnode->private_node;
62 	return result;
63 }
64 
65 
66 static status_t
67 overlay_remove_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter)
68 {
69 	DO_LOG("remove_vnode reenter: %s\n", reenter ? "yes" : "no");
70 
71 	status_t result = B_UNSUPPORTED;
72 	fs_vnode *superVnode = (fs_vnode *)vnode->private_node;
73 	if (superVnode->ops->remove_vnode != NULL) {
74 		result = superVnode->ops->remove_vnode(volume->super_volume, superVnode,
75 			reenter);
76 	}
77 
78 	DO_LOG("remove_vnode result: 0x%08lx\n", result);
79 	delete (fs_vnode *)vnode->private_node;
80 	return result;
81 }
82 
83 
84 static status_t
85 overlay_get_super_vnode(fs_volume *volume, fs_vnode *vnode,
86 	fs_volume *superVolume, fs_vnode *_superVnode)
87 {
88 	if (volume == superVolume) {
89 		*_superVnode = *vnode;
90 		return B_OK;
91 	}
92 
93 	fs_vnode *superVnode = (fs_vnode *)vnode->private_node;
94 	if (superVnode->ops->get_super_vnode != NULL) {
95 		return superVnode->ops->get_super_vnode(volume->super_volume,
96 			superVnode, superVolume, _superVnode);
97 	}
98 
99 	*_superVnode = *superVnode;
100 	return B_OK;
101 }
102 
103 
104 static status_t
105 overlay_lookup(fs_volume *volume, fs_vnode *vnode, const char *name, ino_t *id)
106 {
107 	DO_LOG("lookup name: \"%s\"\n", name);
108 	OVERLAY_CALL(lookup, name, id)
109 	DO_LOG("lookup result: 0x%08lx; id: %llu\n", result, *id);
110 	return result;
111 }
112 
113 
114 static status_t
115 overlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer,
116 	size_t bufferSize)
117 {
118 	DO_LOG("get_vnode_name buffer: %p; buffer_size: %lu\n", buffer, bufferSize);
119 	OVERLAY_CALL(get_vnode_name, buffer, bufferSize)
120 	DO_LOG("get_vnode_name result: 0x%08lx; buffer: \"%s\"\n", result,
121 		result == B_OK ? buffer : "unsafe");
122 	return result;
123 }
124 
125 
126 static bool
127 overlay_can_page(fs_volume *volume, fs_vnode *vnode, void *cookie)
128 {
129 	DO_LOG("can_page cookie: %p\n", cookie);
130 	bool result = false;
131 	fs_vnode *superVnode = (fs_vnode *)vnode->private_node;
132 	if (superVnode->ops->can_page != NULL) {
133 		result = superVnode->ops->can_page(volume->super_volume, superVnode,
134 			cookie);
135 	}
136 
137 	DO_LOG("can_page result: %s\n", result ? "yes" : "no");
138 	return result;
139 }
140 
141 
142 static status_t
143 overlay_read_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
144 	const iovec *vecs, size_t count, size_t *numBytes)
145 {
146 	DO_LOG("read_pages cookie: %p; pos: %lld; vecs: %p; count: %lu;"
147 		" num_bytes: %lu\n", cookie, pos, vecs, count, *numBytes);
148 	OVERLAY_CALL(read_pages, cookie, pos, vecs, count, numBytes)
149 	DO_LOG("read_pages result: 0x%08lx; num_bytes: %lu\n", result, *numBytes);
150 	return result;
151 }
152 
153 
154 static status_t
155 overlay_write_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
156 	const iovec *vecs, size_t count, size_t *numBytes)
157 {
158 	DO_LOG("write_pages cookie: %p; pos: %lld; vecs: %p; count: %lu;"
159 		" num_bytes: %lu\n", cookie, pos, vecs, count, *numBytes);
160 	OVERLAY_CALL(write_pages, cookie, pos, vecs, count, numBytes)
161 	DO_LOG("write_pages result: 0x%08lx; num_bytes: %lu\n", result, *numBytes);
162 	return result;
163 }
164 
165 
166 static status_t
167 overlay_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
168 	io_request *request)
169 {
170 	DO_LOG("io cookie: %p; request: %p (write: %s; offset: %lld; length: %llu)"
171 		"\n", cookie, request, io_request_is_write(request) ? "yes" : "no",
172 		io_request_offset(request), io_request_length(request));
173 	OVERLAY_CALL(io, cookie, request)
174 	DO_LOG("io result: 0x%08lx\n", result);
175 	return result;
176 }
177 
178 
179 static status_t
180 overlay_cancel_io(fs_volume *volume, fs_vnode *vnode, void *cookie,
181 	io_request *request)
182 {
183 	DO_LOG("cancel_io cookie: %p; request: %p\n", cookie, request);
184 	OVERLAY_CALL(cancel_io, cookie, request)
185 	DO_LOG("cancel_io result: 0x%08lx\n", result);
186 	return result;
187 }
188 
189 
190 static status_t
191 overlay_get_file_map(fs_volume *volume, fs_vnode *vnode, off_t offset,
192 	size_t size, struct file_io_vec *vecs, size_t *count)
193 {
194 	DO_LOG("get_file_map offset: %lld; size: %lu; vecs: %p; count: %lu\n",
195 		offset, size, vecs, *count);
196 	OVERLAY_CALL(get_file_map, offset, size, vecs, count)
197 	DO_LOG("get_file_map result: 0x%08lx; count: %lu\n", result, *count);
198 	return result;
199 }
200 
201 
202 static status_t
203 overlay_ioctl(fs_volume *volume, fs_vnode *vnode, void *cookie, uint32 op,
204 	void *buffer, size_t length)
205 {
206 	DO_LOG("ioctl cookie: %p; op: %lu; buffer: %p; size: %lu\n", cookie, op,
207 		buffer, length);
208 	OVERLAY_CALL(ioctl, cookie, op, buffer, length)
209 	DO_LOG("ioctl result: 0x%08lx\n", result);
210 	return result;
211 }
212 
213 
214 static status_t
215 overlay_set_flags(fs_volume *volume, fs_vnode *vnode, void *cookie,
216 	int flags)
217 {
218 	DO_LOG("set_flags cookie: %p; flags: %d\n", cookie, flags);
219 	OVERLAY_CALL(set_flags, cookie, flags)
220 	DO_LOG("set_flags result: 0x%08lx\n", result);
221 	return result;
222 }
223 
224 
225 static status_t
226 overlay_select(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
227 	selectsync *sync)
228 {
229 	DO_LOG("select cookie: %p; event: %u; selectsync: %p\n", cookie, event,
230 		sync);
231 	OVERLAY_CALL(select, cookie, event, sync)
232 	DO_LOG("select result: 0x%08lx\n", result);
233 	return result;
234 }
235 
236 
237 static status_t
238 overlay_deselect(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event,
239 	selectsync *sync)
240 {
241 	DO_LOG("deselect cookie: %p; event: %u; selectsync: %p\n", cookie, event,
242 		sync);
243 	OVERLAY_CALL(deselect, cookie, event, sync)
244 	DO_LOG("deselect result: 0x%08lx\n", result);
245 	return result;
246 }
247 
248 
249 static status_t
250 overlay_fsync(fs_volume *volume, fs_vnode *vnode)
251 {
252 	DO_LOG("%s\n", "fsync");
253 
254 	status_t result = B_UNSUPPORTED;
255 	fs_vnode *superVnode = (fs_vnode *)vnode->private_node;
256 	if (superVnode->ops->fsync != NULL)
257 		result = superVnode->ops->fsync(volume->super_volume, superVnode);
258 
259 	DO_LOG("fsync result: 0x%08lx\n", result);
260 	return result;
261 }
262 
263 
264 static status_t
265 overlay_read_symlink(fs_volume *volume, fs_vnode *vnode, char *buffer,
266 	size_t *bufferSize)
267 {
268 	DO_LOG("read_symlink buffer: %p; buffer_size: %lu\n", buffer, *bufferSize);
269 	OVERLAY_CALL(read_symlink, buffer, bufferSize)
270 	DO_LOG("read_symlink result: 0x%08lx; buffer_size: %lu; \"%.*s\"\n", result,
271 		*bufferSize, result == B_OK ? (int)*bufferSize : 6,
272 		result == B_OK ? buffer : "unsafe");
273 	return result;
274 }
275 
276 
277 static status_t
278 overlay_create_symlink(fs_volume *volume, fs_vnode *vnode, const char *name,
279 	const char *path, int mode)
280 {
281 	DO_LOG("create_symlink name: \"%s\"; path: \"%s\"; mode: %u\n", name, path,
282 		mode);
283 	OVERLAY_CALL(create_symlink, name, path, mode)
284 	DO_LOG("create_symlink result: 0x%08lx\n", result);
285 	return result;
286 }
287 
288 
289 static status_t
290 overlay_link(fs_volume *volume, fs_vnode *vnode, const char *name,
291 	fs_vnode *target)
292 {
293 	DO_LOG("link name: \"%s\"; target: %p\n", name,
294 		((fs_vnode *)target->private_node)->private_node);
295 	OVERLAY_CALL(link, name, (fs_vnode *)target->private_node)
296 	DO_LOG("link result: 0x%08lx\n", result);
297 	return result;
298 }
299 
300 
301 static status_t
302 overlay_unlink(fs_volume *volume, fs_vnode *vnode, const char *name)
303 {
304 	DO_LOG("unlink name: \"%s\"\n", name);
305 	OVERLAY_CALL(unlink, name)
306 	DO_LOG("unlink result: 0x%08lx\n", result);
307 	return result;
308 }
309 
310 
311 static status_t
312 overlay_rename(fs_volume *volume, fs_vnode *vnode,
313 	const char *fromName, fs_vnode *toDir, const char *toName)
314 {
315 	DO_LOG("rename from_name: \"%s\"; to_dir: %p; to_name: \"%s\"\n",
316 		fromName, ((fs_vnode *)toDir->private_node)->private_node, toName);
317 	OVERLAY_CALL(rename, fromName, (fs_vnode *)toDir->private_node, toName)
318 	DO_LOG("rename result: 0x%08lx\n", result);
319 	return result;
320 }
321 
322 
323 static status_t
324 overlay_access(fs_volume *volume, fs_vnode *vnode, int mode)
325 {
326 	DO_LOG("access mode: %u\n", mode);
327 	OVERLAY_CALL(access, mode)
328 	DO_LOG("access result: 0x%08lx\n", result);
329 	return result;
330 }
331 
332 
333 static status_t
334 overlay_read_stat(fs_volume *volume, fs_vnode *vnode, struct stat *stat)
335 {
336 	DO_LOG("read_stat stat: %p\n", stat);
337 	OVERLAY_CALL(read_stat, stat)
338 	if (result == B_OK) {
339 		DO_LOG("read_stat result: 0x%08lx; stat(dev: %lu; ino: %llu; mode: %u;"
340 			" uid: %u; gid %u; size: %llu)\n", result, stat->st_dev,
341 			stat->st_ino, stat->st_mode, stat->st_uid, stat->st_gid,
342 			stat->st_size);
343 	} else
344 		DO_LOG("read_stat result: 0x%08lx\n", result);
345 	return result;
346 }
347 
348 
349 static status_t
350 overlay_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat,
351 	uint32 statMask)
352 {
353 	DO_LOG("write_stat stat: %p; mask: %lu\n", stat, statMask);
354 	OVERLAY_CALL(write_stat, stat, statMask)
355 	DO_LOG("write_stat result: 0x%08lx\n", result);
356 	return result;
357 }
358 
359 
360 static status_t
361 overlay_create(fs_volume *volume, fs_vnode *vnode, const char *name,
362 	int openMode, int perms, void **cookie, ino_t *newVnodeID)
363 {
364 	DO_LOG("create name: \"%s\"; open_mode: %u; perms: %u\n", name, openMode,
365 		perms);
366 	OVERLAY_CALL(create, name, openMode, perms, cookie, newVnodeID)
367 	DO_LOG("create result: 0x%08lx; cookie: %p; new_vnode_id: %llu\n", result,
368 		*cookie, *newVnodeID);
369 	return result;
370 }
371 
372 
373 static status_t
374 overlay_open(fs_volume *volume, fs_vnode *vnode, int openMode, void **cookie)
375 {
376 	DO_LOG("open open_mode: %u\n", openMode);
377 	OVERLAY_CALL(open, openMode, cookie)
378 	DO_LOG("open result: 0x%08lx; cookie: %p\n", result, *cookie);
379 	return result;
380 }
381 
382 
383 static status_t
384 overlay_close(fs_volume *volume, fs_vnode *vnode, void *cookie)
385 {
386 	DO_LOG("close cookie %p\n", cookie);
387 	OVERLAY_CALL(close, cookie)
388 	DO_LOG("close result: 0x%08lx\n", result);
389 	return result;
390 }
391 
392 
393 static status_t
394 overlay_free_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
395 {
396 	DO_LOG("free_cookie cookie %p\n", cookie);
397 	OVERLAY_CALL(free_cookie, cookie)
398 	DO_LOG("free_cookie result: 0x%08lx\n", result);
399 	return result;
400 }
401 
402 
403 static status_t
404 overlay_read(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
405 	void *buffer, size_t *length)
406 {
407 	DO_LOG("read cookie: %p; pos: %lld; buffer: %p; length: %lu\n", cookie, pos,
408 		buffer, *length);
409 	OVERLAY_CALL(read, cookie, pos, buffer, length)
410 	DO_LOG("read result: 0x%08lx; length: %lu\n", result, *length);
411 	return result;
412 }
413 
414 
415 static status_t
416 overlay_write(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
417 	const void *buffer, size_t *length)
418 {
419 	DO_LOG("write cookie: %p; pos: %lld; buffer: %p; length: %lu\n", cookie,
420 		pos, buffer, *length);
421 	OVERLAY_CALL(write, cookie, pos, buffer, length)
422 	DO_LOG("write result: 0x%08lx; length: %lu\n", result, *length);
423 	return result;
424 }
425 
426 
427 static status_t
428 overlay_create_dir(fs_volume *volume, fs_vnode *vnode, const char *name,
429 	int perms)
430 {
431 	DO_LOG("create_dir name: \"%s\"; perms: %u\n", name, perms);
432 	OVERLAY_CALL(create_dir, name, perms)
433 	DO_LOG("create_dir result: 0x%08lx\n", result);
434 	return result;
435 }
436 
437 
438 static status_t
439 overlay_remove_dir(fs_volume *volume, fs_vnode *vnode, const char *name)
440 {
441 	DO_LOG("remove_dir name: \"%s\"\n", name);
442 	OVERLAY_CALL(remove_dir, name)
443 	DO_LOG("remove_dir result: 0x%08lx\n", result);
444 	return result;
445 }
446 
447 
448 static status_t
449 overlay_open_dir(fs_volume *volume, fs_vnode *vnode, void **cookie)
450 {
451 	DO_LOG("%s\n", "open_dir");
452 	OVERLAY_CALL(open_dir, cookie)
453 	DO_LOG("open_dir result: 0x%08lx; cookie: %p\n", result, *cookie);
454 	return result;
455 }
456 
457 
458 static status_t
459 overlay_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
460 {
461 	DO_LOG("close_dir cookie: %p\n", cookie);
462 	OVERLAY_CALL(close_dir, cookie)
463 	DO_LOG("close_dir result: 0x%08lx\n", result);
464 	return result;
465 }
466 
467 
468 static status_t
469 overlay_free_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
470 {
471 	DO_LOG("free_dir_cookie cookie: %p\n", cookie);
472 	OVERLAY_CALL(free_dir_cookie, cookie)
473 	DO_LOG("free_dir_cookie result: 0x%08lx\n", result);
474 	return result;
475 }
476 
477 
478 static status_t
479 overlay_read_dir(fs_volume *volume, fs_vnode *vnode, void *cookie,
480 	struct dirent *buffer, size_t bufferSize, uint32 *num)
481 {
482 	DO_LOG("read_dir cookie: %p; buffer: %p; buffer_size: %lu\n", cookie,
483 		buffer, bufferSize);
484 	OVERLAY_CALL(read_dir, cookie, buffer, bufferSize, num);
485 	DO_LOG("read_dir result: 0x%08lx; num: %lu\n", result, *num);
486 	return result;
487 }
488 
489 
490 static status_t
491 overlay_rewind_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
492 {
493 	DO_LOG("rewind_dir cookie: %p\n", cookie);
494 	OVERLAY_CALL(rewind_dir, cookie)
495 	DO_LOG("rewind_dir result: 0x%08lx\n", result);
496 	return result;
497 }
498 
499 
500 static status_t
501 overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie)
502 {
503 	DO_LOG("%s\n", "open_attr_dir");
504 	OVERLAY_CALL(open_attr_dir, cookie)
505 	DO_LOG("open_attr_dir result: 0x%08lx; cookie: %p\n", result, *cookie);
506 	return result;
507 }
508 
509 
510 static status_t
511 overlay_close_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
512 {
513 	DO_LOG("close_attr_dir cookie: %p\n", cookie);
514 	OVERLAY_CALL(close_attr_dir, cookie)
515 	DO_LOG("close_attr_dir result: 0x%08lx\n", result);
516 	return result;
517 }
518 
519 
520 static status_t
521 overlay_free_attr_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
522 {
523 	DO_LOG("free_attr_dir_cookie cookie: %p\n", cookie);
524 	OVERLAY_CALL(free_attr_dir_cookie, cookie)
525 	DO_LOG("free_attr_dir_cookie result: 0x%08lx\n", result);
526 	return result;
527 }
528 
529 
530 static status_t
531 overlay_read_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie,
532 	struct dirent *buffer, size_t bufferSize, uint32 *num)
533 {
534 	DO_LOG("read_attr_dir cookie: %p; buffer: %p; buffer_size: %lu\n", cookie,
535 		buffer, bufferSize);
536 	OVERLAY_CALL(read_attr_dir, cookie, buffer, bufferSize, num);
537 	DO_LOG("read_attr_dir result: 0x%08lx; num: %lu\n", result, *num);
538 	return result;
539 }
540 
541 
542 static status_t
543 overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie)
544 {
545 	DO_LOG("rewind_attr_dir cookie: %p\n", cookie);
546 	OVERLAY_CALL(rewind_attr_dir, cookie)
547 	DO_LOG("rewind_attr_dir result: 0x%08lx\n", result);
548 	return result;
549 }
550 
551 
552 static status_t
553 overlay_create_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
554 	uint32 type, int openMode, void **cookie)
555 {
556 	DO_LOG("create_attr name: \"%s\"; type: 0x%08lx; open_mode: %u\n", name,
557 		type, openMode);
558 	OVERLAY_CALL(create_attr, name, type, openMode, cookie)
559 	DO_LOG("create_attr result: 0x%08lx; cookie: %p\n", result, *cookie);
560 	return result;
561 }
562 
563 
564 static status_t
565 overlay_open_attr(fs_volume *volume, fs_vnode *vnode, const char *name,
566 	int openMode, void **cookie)
567 {
568 	DO_LOG("open_attr name: \"%s\"; open_mode: %u\n", name, openMode);
569 	OVERLAY_CALL(open_attr, name, openMode, cookie)
570 	DO_LOG("open_attr result: 0x%08lx; cookie: %p\n", result, *cookie);
571 	return result;
572 }
573 
574 
575 static status_t
576 overlay_close_attr(fs_volume *volume, fs_vnode *vnode, void *cookie)
577 {
578 	DO_LOG("close_attr cookie: %p\n", cookie);
579 	OVERLAY_CALL(close_attr, cookie)
580 	DO_LOG("close_attr result: 0x%08lx\n", result);
581 	return result;
582 }
583 
584 
585 static status_t
586 overlay_free_attr_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
587 {
588 	DO_LOG("free_attr_cookie cookie: %p\n", cookie);
589 	OVERLAY_CALL(free_attr_cookie, cookie)
590 	DO_LOG("free_attr_cookie result: 0x%08lx\n", result);
591 	return result;
592 }
593 
594 
595 static status_t
596 overlay_read_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
597 	void *buffer, size_t *length)
598 {
599 	DO_LOG("read_attr cookie: %p; pos: %lld; buffer: %p; length: %lu\n", cookie,
600 		pos, buffer, *length);
601 	OVERLAY_CALL(read_attr, cookie, pos, buffer, length)
602 	DO_LOG("read_attr result: 0x%08lx; length: %lu\n", result, *length);
603 	return result;
604 }
605 
606 
607 static status_t
608 overlay_write_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
609 	const void *buffer, size_t *length)
610 {
611 	DO_LOG("write_attr cookie: %p; pos: %lld; buffer: %p; length: %lu\n",
612 		cookie, pos, buffer, *length);
613 	OVERLAY_CALL(write_attr, cookie, pos, buffer, length)
614 	DO_LOG("write_attr result: 0x%08lx; length: %lu\n", result, *length);
615 	return result;
616 }
617 
618 
619 static status_t
620 overlay_read_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie,
621 	struct stat *stat)
622 {
623 	DO_LOG("read_attr_stat cookie: %p; stat: %p\n", cookie, stat);
624 	OVERLAY_CALL(read_attr_stat, cookie, stat)
625 	if (result == B_OK) {
626 		DO_LOG("read_attr_stat result: 0x%08lx; stat(dev: %lu; ino: %llu;"
627 			" mode: %u; uid: %u; gid %u; size: %llu; type: 0x%08lx)\n", result,
628 			stat->st_dev, stat->st_ino, stat->st_mode, stat->st_uid,
629 			stat->st_gid, stat->st_size, stat->st_type);
630 	} else
631 		DO_LOG("read_attr_stat result: 0x%08lx\n", result);
632 	return result;
633 }
634 
635 
636 static status_t
637 overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie,
638 	const struct stat *stat, int statMask)
639 {
640 	DO_LOG("write_attr_stat cookie: %p; stat: %p; mask: %u\n", cookie, stat,
641 		statMask);
642 	OVERLAY_CALL(write_attr_stat, cookie, stat, statMask)
643 	DO_LOG("write_attr_stat result: 0x%08lx\n", result);
644 	return result;
645 }
646 
647 
648 static status_t
649 overlay_rename_attr(fs_volume *volume, fs_vnode *vnode,
650 	const char *fromName, fs_vnode *toVnode, const char *toName)
651 {
652 	DO_LOG("rename_attr from_name: \"%s\"; to_vnode: %p; to_name: \"%s\"\n",
653 		fromName, ((fs_vnode *)toVnode->private_node)->private_node, toName);
654 	OVERLAY_CALL(rename_attr, fromName, (fs_vnode *)toVnode->private_node,
655 		toName)
656 	DO_LOG("rename_attr result: 0x%08lx\n", result);
657 	return result;
658 }
659 
660 
661 static status_t
662 overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name)
663 {
664 	DO_LOG("remove_attr name: \"%s\"\n", name);
665 	OVERLAY_CALL(remove_attr, name)
666 	DO_LOG("remove_attr result: 0x%08lx\n", result);
667 	return result;
668 }
669 
670 
671 static status_t
672 overlay_create_special_node(fs_volume *volume, fs_vnode *vnode,
673 	const char *name, fs_vnode *subVnode, mode_t mode, uint32 flags,
674 	fs_vnode *_superVnode, ino_t *nodeID)
675 {
676 	DO_LOG("create_special_node name: \"%s\"; sub_vnode: %p; mode: %u;"
677 		" flags: %lu\n", name, subVnode->private_node, mode, flags);
678 	OVERLAY_CALL(create_special_node, name, (fs_vnode *)subVnode->private_node,
679 		mode, flags, _superVnode, nodeID)
680 	DO_LOG("create_special_node result: 0x%08lx; super_vnode: %p;"
681 		" node_id: %llu\n", result, _superVnode->private_node, *nodeID);
682 	return result;
683 }
684 
685 
686 static fs_vnode_ops sOverlayVnodeOps = {
687 	&overlay_lookup,
688 	&overlay_get_vnode_name,
689 
690 	&overlay_put_vnode,
691 	&overlay_remove_vnode,
692 
693 	&overlay_can_page,
694 	&overlay_read_pages,
695 	&overlay_write_pages,
696 
697 	&overlay_io,
698 	&overlay_cancel_io,
699 
700 	&overlay_get_file_map,
701 
702 	/* common */
703 	&overlay_ioctl,
704 	&overlay_set_flags,
705 	&overlay_select,
706 	&overlay_deselect,
707 	&overlay_fsync,
708 
709 	&overlay_read_symlink,
710 	&overlay_create_symlink,
711 	&overlay_link,
712 	&overlay_unlink,
713 	&overlay_rename,
714 
715 	&overlay_access,
716 	&overlay_read_stat,
717 	&overlay_write_stat,
718 	NULL,	// fs_preallocate
719 
720 	/* file */
721 	&overlay_create,
722 	&overlay_open,
723 	&overlay_close,
724 	&overlay_free_cookie,
725 	&overlay_read,
726 	&overlay_write,
727 
728 	/* directory */
729 	&overlay_create_dir,
730 	&overlay_remove_dir,
731 	&overlay_open_dir,
732 	&overlay_close_dir,
733 	&overlay_free_dir_cookie,
734 	&overlay_read_dir,
735 	&overlay_rewind_dir,
736 
737 	/* attribute directory operations */
738 	&overlay_open_attr_dir,
739 	&overlay_close_attr_dir,
740 	&overlay_free_attr_dir_cookie,
741 	&overlay_read_attr_dir,
742 	&overlay_rewind_attr_dir,
743 
744 	/* attribute operations */
745 	&overlay_create_attr,
746 	&overlay_open_attr,
747 	&overlay_close_attr,
748 	&overlay_free_attr_cookie,
749 	&overlay_read_attr,
750 	&overlay_write_attr,
751 
752 	&overlay_read_attr_stat,
753 	&overlay_write_attr_stat,
754 	&overlay_rename_attr,
755 	&overlay_remove_attr,
756 
757 	/* support for node and FS layers */
758 	&overlay_create_special_node,
759 	&overlay_get_super_vnode
760 };
761 
762 
763 //	#pragma mark - volume ops
764 
765 
766 #define DO_VOLUME_LOG(format, args...) \
767 	{ \
768 		char _printBuffer[256]; \
769 		int _printSize = snprintf(_printBuffer, sizeof(_printBuffer), \
770 			"%llu %ld %p: " format, system_time(), find_thread(NULL), \
771 			volume->super_volume, args); \
772 		if ((unsigned int)_printSize > sizeof(_printBuffer)) { \
773 			_printBuffer[sizeof(_printBuffer) - 1] = '\n'; \
774 			_printSize = sizeof(_printBuffer); \
775 		} \
776 		write((int)volume->private_volume, _printBuffer, _printSize); \
777 	}
778 
779 #define OVERLAY_VOLUME_CALL(op, params...) \
780 	status_t result = B_UNSUPPORTED; \
781 	if (volume->super_volume->ops->op != NULL) \
782 		result = volume->super_volume->ops->op(volume->super_volume, params); \
783 
784 
785 static status_t
786 overlay_unmount(fs_volume *volume)
787 {
788 	if (volume->super_volume != NULL
789 		&& volume->super_volume->ops != NULL
790 		&& volume->super_volume->ops->unmount != NULL)
791 		volume->super_volume->ops->unmount(volume->super_volume);
792 
793 	close((int)volume->private_volume);
794 	return B_OK;
795 }
796 
797 
798 static status_t
799 overlay_read_fs_info(fs_volume *volume, struct fs_info *info)
800 {
801 	DO_VOLUME_LOG("%s\n", "read_fs_info");
802 	OVERLAY_VOLUME_CALL(read_fs_info, info)
803 	DO_VOLUME_LOG("read_fs_info result: 0x%08lx; info(dev: %lu; root: %llu;"
804 		" flags: %lu; block_size: %lld; io_size: %lld; total_blocks: %lld;"
805 		" free_blocks: %lld; total_nodes: %lld; free_nodes: %lld;"
806 		" device_name: \"%s\"; volume_name: \"%s\"; fsh_name: \"%s\")\n",
807 		result, info->dev, info->root, info->flags, info->block_size,
808 		info->io_size, info->total_blocks, info->free_blocks,
809 		info->total_nodes, info->free_nodes, info->device_name,
810 		info->volume_name, info->fsh_name);
811 	return result;
812 }
813 
814 
815 static status_t
816 overlay_write_fs_info(fs_volume *volume, const struct fs_info *info,
817 	uint32 mask)
818 {
819 	DO_VOLUME_LOG("write_fs_info info: %p; mask: %lu\n", info, mask);
820 	OVERLAY_VOLUME_CALL(write_fs_info, info, mask)
821 	DO_VOLUME_LOG("write_fs_info result: 0x%08lx\n", result);
822 	return result;
823 }
824 
825 
826 static status_t
827 overlay_sync(fs_volume *volume)
828 {
829 	DO_VOLUME_LOG("%s\n", "sync");
830 	status_t result = B_UNSUPPORTED;
831 	if (volume->super_volume->ops->sync != NULL)
832 		result = volume->super_volume->ops->sync(volume->super_volume);
833 	DO_VOLUME_LOG("sync result: 0x%08lx\n", result);
834 	return result;
835 }
836 
837 
838 static status_t
839 overlay_get_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode, int *type,
840 	uint32 *flags, bool reenter)
841 {
842 	DO_VOLUME_LOG("get_vnode id: %llu; vnode: %p; type*: %p; flags*: %p;"
843 		" reenter: %d\n", id, vnode, type, flags, reenter);
844 
845 	if (volume->super_volume->ops->get_vnode == NULL) {
846 		DO_VOLUME_LOG("get_vnode %s\n", "not supported");
847 		return B_UNSUPPORTED;
848 	}
849 
850 	fs_vnode *superVnode = new(std::nothrow) fs_vnode;
851 	if (superVnode == NULL) {
852 		DO_VOLUME_LOG("get_vnode %s\n", "no memory");
853 		return B_NO_MEMORY;
854 	}
855 
856 	status_t result = volume->super_volume->ops->get_vnode(volume->super_volume,
857 		id, superVnode, type, flags, reenter);
858 	if (result != B_OK) {
859 		DO_VOLUME_LOG("get_vnode result: 0x%08lx\n", result);
860 		delete superVnode;
861 		return result;
862 	}
863 
864 	vnode->private_node = superVnode;
865 	vnode->ops = &sOverlayVnodeOps;
866 
867 	DO_VOLUME_LOG("get_vnode result: 0x%08lx; super_vnode: %p\n", result,
868 		superVnode->private_node);
869 	return B_OK;
870 }
871 
872 
873 static status_t
874 overlay_open_index_dir(fs_volume *volume, void **cookie)
875 {
876 	DO_VOLUME_LOG("%s\n", "open_index_dir");
877 	OVERLAY_VOLUME_CALL(open_index_dir, cookie)
878 	DO_VOLUME_LOG("open_index_dir result: 0x%08lx; cookie: %p\n", result,
879 		*cookie);
880 	return result;
881 }
882 
883 
884 static status_t
885 overlay_close_index_dir(fs_volume *volume, void *cookie)
886 {
887 	DO_VOLUME_LOG("close_index_dir cookie: %p\n", cookie);
888 	OVERLAY_VOLUME_CALL(close_index_dir, cookie)
889 	DO_VOLUME_LOG("close_index_dir result: 0x%08lx\n", result);
890 	return result;
891 }
892 
893 
894 static status_t
895 overlay_free_index_dir_cookie(fs_volume *volume, void *cookie)
896 {
897 	DO_VOLUME_LOG("free_index_dir_cookie cookie: %p\n", cookie);
898 	OVERLAY_VOLUME_CALL(free_index_dir_cookie, cookie)
899 	DO_VOLUME_LOG("free_index_dir_cookie result: 0x%08lx\n", result);
900 	return result;
901 }
902 
903 
904 static status_t
905 overlay_read_index_dir(fs_volume *volume, void *cookie, struct dirent *buffer,
906 	size_t bufferSize, uint32 *num)
907 {
908 	DO_VOLUME_LOG("read_index_dir cookie: %p; buffer: %p; buffer_size: %lu\n",
909 		cookie, buffer, bufferSize);
910 	OVERLAY_VOLUME_CALL(read_index_dir, cookie, buffer, bufferSize, num)
911 	DO_VOLUME_LOG("read_index_dir result: 0x%08lx; num: %lu\n", result, *num);
912 	return result;
913 }
914 
915 
916 static status_t
917 overlay_rewind_index_dir(fs_volume *volume, void *cookie)
918 {
919 	DO_VOLUME_LOG("rewind_index_dir cookie: %p\n", cookie);
920 	OVERLAY_VOLUME_CALL(rewind_index_dir, cookie)
921 	DO_VOLUME_LOG("rewind_index_dir result: 0x%08lx\n", result);
922 	return result;
923 }
924 
925 
926 static status_t
927 overlay_create_index(fs_volume *volume, const char *name, uint32 type,
928 	uint32 flags)
929 {
930 	DO_VOLUME_LOG("create_index name: \"%s\"; type: %lu; flags: %lu\n", name,
931 		type, flags);
932 	OVERLAY_VOLUME_CALL(create_index, name, type, flags)
933 	DO_VOLUME_LOG("create_index result: 0x%08lx\n", result);
934 	return result;
935 }
936 
937 
938 static status_t
939 overlay_remove_index(fs_volume *volume, const char *name)
940 {
941 	DO_VOLUME_LOG("remove_index name: \"%s\"\n", name);
942 	OVERLAY_VOLUME_CALL(remove_index, name)
943 	DO_VOLUME_LOG("remove_index result: 0x%08lx\n", result);
944 	return result;
945 }
946 
947 
948 static status_t
949 overlay_read_index_stat(fs_volume *volume, const char *name, struct stat *stat)
950 {
951 	DO_VOLUME_LOG("read_index_stat name: \"%s\"; stat: %p\n", name, stat);
952 	OVERLAY_VOLUME_CALL(read_index_stat, name, stat)
953 	if (result == B_OK) {
954 		DO_VOLUME_LOG("read_index_stat result: 0x%08lx; stat(dev: %lu;"
955 			" ino: %llu; mode: %u; uid: %u; gid %u; size: %llu;"
956 			" type: 0x%08lx)\n", result, stat->st_dev, stat->st_ino,
957 			stat->st_mode, stat->st_uid, stat->st_gid, stat->st_size,
958 			stat->st_type);
959 	} else
960 		DO_VOLUME_LOG("read_index_stat result: 0x%08lx\n", result);
961 	return result;
962 }
963 
964 
965 static status_t
966 overlay_open_query(fs_volume *volume, const char *query, uint32 flags,
967 	port_id port, uint32 token, void **cookie)
968 {
969 	DO_VOLUME_LOG("open_query query: \"%s\"; flags: %lu; port: %ld;"
970 		" token: %lu\n", query, flags, port, token);
971 	OVERLAY_VOLUME_CALL(open_query, query, flags, port, token, cookie)
972 	DO_VOLUME_LOG("open_query result: 0x%08lx; cookie: %p\n", result, *cookie);
973 	return result;
974 }
975 
976 
977 static status_t
978 overlay_close_query(fs_volume *volume, void *cookie)
979 {
980 	DO_VOLUME_LOG("close_query cookie: %p\n", cookie);
981 	OVERLAY_VOLUME_CALL(close_query, cookie)
982 	DO_VOLUME_LOG("close_query result: 0x%08lx\n", result);
983 	return result;
984 }
985 
986 
987 static status_t
988 overlay_free_query_cookie(fs_volume *volume, void *cookie)
989 {
990 	DO_VOLUME_LOG("free_query_cookie cookie: %p\n", cookie);
991 	OVERLAY_VOLUME_CALL(free_query_cookie, cookie)
992 	DO_VOLUME_LOG("free_query_cookie result: 0x%08lx\n", result);
993 	return result;
994 }
995 
996 
997 static status_t
998 overlay_read_query(fs_volume *volume, void *cookie, struct dirent *buffer,
999 	size_t bufferSize, uint32 *num)
1000 {
1001 	DO_VOLUME_LOG("read_query cookie: %p; buffer: %p; buffer_size: %lu\n",
1002 		cookie, buffer, bufferSize);
1003 	OVERLAY_VOLUME_CALL(read_query, cookie, buffer, bufferSize, num)
1004 	DO_VOLUME_LOG("read_query result: 0x%08lx; num: %lu\n", result, *num);
1005 	return result;
1006 }
1007 
1008 
1009 static status_t
1010 overlay_rewind_query(fs_volume *volume, void *cookie)
1011 {
1012 	DO_VOLUME_LOG("rewind_query cookie: %p\n", cookie);
1013 	OVERLAY_VOLUME_CALL(rewind_query, cookie)
1014 	DO_VOLUME_LOG("rewind_query result: 0x%08lx\n", result);
1015 	return result;
1016 }
1017 
1018 
1019 static status_t
1020 overlay_all_layers_mounted(fs_volume *volume)
1021 {
1022 	return B_OK;
1023 }
1024 
1025 
1026 static status_t
1027 overlay_create_sub_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode)
1028 {
1029 	fs_vnode *superVnode = new(std::nothrow) fs_vnode;
1030 	if (superVnode == NULL)
1031 		return B_NO_MEMORY;
1032 
1033 	*superVnode = *vnode;
1034 	vnode->private_node = superVnode;
1035 	vnode->ops = &sOverlayVnodeOps;
1036 	return B_OK;
1037 }
1038 
1039 
1040 static status_t
1041 overlay_delete_sub_vnode(fs_volume *volume, fs_vnode *vnode)
1042 {
1043 	delete (fs_vnode *)vnode->private_node;
1044 	return B_OK;
1045 }
1046 
1047 
1048 static fs_volume_ops sOverlayVolumeOps = {
1049 	&overlay_unmount,
1050 
1051 	&overlay_read_fs_info,
1052 	&overlay_write_fs_info,
1053 	&overlay_sync,
1054 
1055 	&overlay_get_vnode,
1056 	&overlay_open_index_dir,
1057 	&overlay_close_index_dir,
1058 	&overlay_free_index_dir_cookie,
1059 	&overlay_read_index_dir,
1060 	&overlay_rewind_index_dir,
1061 
1062 	&overlay_create_index,
1063 	&overlay_remove_index,
1064 	&overlay_read_index_stat,
1065 
1066 	&overlay_open_query,
1067 	&overlay_close_query,
1068 	&overlay_free_query_cookie,
1069 	&overlay_read_query,
1070 	&overlay_rewind_query,
1071 
1072 	&overlay_all_layers_mounted,
1073 	&overlay_create_sub_vnode,
1074 	&overlay_delete_sub_vnode
1075 };
1076 
1077 
1078 //	#pragma mark - filesystem module
1079 
1080 
1081 static status_t
1082 overlay_mount(fs_volume *volume, const char *device, uint32 flags,
1083 	const char *args, ino_t *rootID)
1084 {
1085 	char filename[256];
1086 	snprintf(filename, sizeof(filename), "%s%s", kLogFilePrefix, device);
1087 	filename[sizeof(filename) - 1] = 0;
1088 
1089 	int filenameLength = strlen(filename);
1090 	for (int i = strlen(kLogFilePrefix); i < filenameLength; i++) {
1091 		if (filename[i] == '/')
1092 			filename[i] = '_';
1093 	}
1094 
1095 	int fd = creat(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1096 	if (fd < 0)
1097 		return errno;
1098 
1099 	volume->private_volume = (void *)fd;
1100 	volume->ops = &sOverlayVolumeOps;
1101 	return B_OK;
1102 }
1103 
1104 
1105 static status_t
1106 overlay_std_ops(int32 op, ...)
1107 {
1108 	switch (op) {
1109 		case B_MODULE_INIT:
1110 		case B_MODULE_UNINIT:
1111 			return B_OK;
1112 		default:
1113 			return B_ERROR;
1114 	}
1115 }
1116 
1117 
1118 static file_system_module_info sOverlayFileSystem = {
1119 	{
1120 		"file_systems/log_overlay" B_CURRENT_FS_API_VERSION,
1121 		0,
1122 		overlay_std_ops,
1123 	},
1124 
1125 	"log_overlay",						// short_name
1126 	"Logging Overlay File System",		// pretty_name
1127 	0,									// DDM flags
1128 
1129 	// scanning
1130 	NULL, // identify_partition
1131 	NULL, // scan_partition
1132 	NULL, // free_identify_partition_cookie
1133 	NULL, // free_partition_content_cookie
1134 
1135 	// general operations
1136 	&overlay_mount,
1137 
1138 	// capability querying
1139 	NULL, // get_supported_operations
1140 
1141 	NULL, // validate_resize
1142 	NULL, // validate_move
1143 	NULL, // validate_set_content_name
1144 	NULL, // validate_set_content_parameters
1145 	NULL, // validate_initialize
1146 
1147 	// shadow partition modification
1148 	NULL, // shadow_changed
1149 
1150 	// writing
1151 	NULL, // defragment
1152 	NULL, // repair
1153 	NULL, // resize
1154 	NULL, // move
1155 	NULL, // set_content_name
1156 	NULL, // set_content_parameters
1157 	NULL // initialize
1158 };
1159 
1160 module_info *modules[] = {
1161 	(module_info *)&sOverlayFileSystem,
1162 	NULL,
1163 };
1164