From 28e27159b92e5411c53f97749dbaf317083fc26a Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Wed, 20 Jan 2010 05:01:28 +0000 Subject: [PATCH] Adding a log_overlay filesystem layer. It passes through all calls to the other layer(s) and logs a timestamp, the thread id, the super volume or super vnode and interesting bits about call arguments/results to a file (in /var/log). This can be used for example to debug filesystems without having to manually add debug output to all the calls, or to analyze access patterns. To add the logging layer just mount the layer with whatever actual filesystem you have: mount -t "bfs:log_overlay" /dev/disk/usb/0/0/0 /mountpoint This would then create the logfile /var/log/log_overlay_dev_disk_usb_0_0_0. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35194 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/file_systems/layers/Jamfile | 1 + .../file_systems/layers/log_overlay/Jamfile | 7 + .../layers/log_overlay/log_overlay.cpp | 1162 +++++++++++++++++ 3 files changed, 1170 insertions(+) create mode 100644 src/add-ons/kernel/file_systems/layers/log_overlay/Jamfile create mode 100644 src/add-ons/kernel/file_systems/layers/log_overlay/log_overlay.cpp diff --git a/src/add-ons/kernel/file_systems/layers/Jamfile b/src/add-ons/kernel/file_systems/layers/Jamfile index 9422350146..6968335402 100644 --- a/src/add-ons/kernel/file_systems/layers/Jamfile +++ b/src/add-ons/kernel/file_systems/layers/Jamfile @@ -1,4 +1,5 @@ SubDir HAIKU_TOP src add-ons kernel file_systems layers ; SubInclude HAIKU_TOP src add-ons kernel file_systems layers attribute_overlay ; +SubInclude HAIKU_TOP src add-ons kernel file_systems layers log_overlay ; SubInclude HAIKU_TOP src add-ons kernel file_systems layers write_overlay ; diff --git a/src/add-ons/kernel/file_systems/layers/log_overlay/Jamfile b/src/add-ons/kernel/file_systems/layers/log_overlay/Jamfile new file mode 100644 index 0000000000..f44a506134 --- /dev/null +++ b/src/add-ons/kernel/file_systems/layers/log_overlay/Jamfile @@ -0,0 +1,7 @@ +SubDir HAIKU_TOP src add-ons kernel file_systems layers log_overlay ; + +UsePrivateKernelHeaders ; + +KernelAddon log_overlay : + log_overlay.cpp + ; diff --git a/src/add-ons/kernel/file_systems/layers/log_overlay/log_overlay.cpp b/src/add-ons/kernel/file_systems/layers/log_overlay/log_overlay.cpp new file mode 100644 index 0000000000..91985c0f9f --- /dev/null +++ b/src/add-ons/kernel/file_systems/layers/log_overlay/log_overlay.cpp @@ -0,0 +1,1162 @@ +/* + * Copyright 2010, Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +static const char *kLogFilePrefix = "/var/log/log_overlay"; + + +#define DO_LOG(format, args...) \ + { \ + char _printBuffer[256]; \ + int _printSize = snprintf(_printBuffer, sizeof(_printBuffer), \ + "%llu %ld %p: " format, system_time(), find_thread(NULL), \ + ((fs_vnode *)vnode->private_node)->private_node, args); \ + if ((unsigned int)_printSize > sizeof(_printBuffer)) { \ + _printBuffer[sizeof(_printBuffer) - 1] = '\n'; \ + _printSize = sizeof(_printBuffer); \ + } \ + write((int)volume->private_volume, _printBuffer, _printSize); \ + } + +#define OVERLAY_CALL(op, params...) \ + status_t result = B_UNSUPPORTED; \ + fs_vnode *superVnode = (fs_vnode *)vnode->private_node; \ + if (superVnode->ops->op != NULL) \ + result = superVnode->ops->op(volume->super_volume, superVnode, params); \ + + +static status_t +overlay_put_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter) +{ + DO_LOG("put_vnode reenter: %s\n", reenter ? "yes" : "no"); + + status_t result = B_UNSUPPORTED; + fs_vnode *superVnode = (fs_vnode *)vnode->private_node; + if (superVnode->ops->put_vnode != NULL) { + result = superVnode->ops->put_vnode(volume->super_volume, superVnode, + reenter); + } + + DO_LOG("put_vnode result: 0x%08lx\n", result); + delete (fs_vnode *)vnode->private_node; + return result; +} + + +static status_t +overlay_remove_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter) +{ + DO_LOG("remove_vnode reenter: %s\n", reenter ? "yes" : "no"); + + status_t result = B_UNSUPPORTED; + fs_vnode *superVnode = (fs_vnode *)vnode->private_node; + if (superVnode->ops->remove_vnode != NULL) { + result = superVnode->ops->remove_vnode(volume->super_volume, superVnode, + reenter); + } + + DO_LOG("remove_vnode result: 0x%08lx\n", result); + delete (fs_vnode *)vnode->private_node; + return result; +} + + +static status_t +overlay_get_super_vnode(fs_volume *volume, fs_vnode *vnode, + fs_volume *superVolume, fs_vnode *_superVnode) +{ + if (volume == superVolume) { + *_superVnode = *vnode; + return B_OK; + } + + fs_vnode *superVnode = (fs_vnode *)vnode->private_node; + if (superVnode->ops->get_super_vnode != NULL) { + return superVnode->ops->get_super_vnode(volume->super_volume, + superVnode, superVolume, _superVnode); + } + + *_superVnode = *superVnode; + return B_OK; +} + + +static status_t +overlay_lookup(fs_volume *volume, fs_vnode *vnode, const char *name, ino_t *id) +{ + DO_LOG("lookup name: \"%s\"\n", name); + OVERLAY_CALL(lookup, name, id) + DO_LOG("lookup result: 0x%08lx; id: %llu\n", result, *id); + return result; +} + + +static status_t +overlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer, + size_t bufferSize) +{ + DO_LOG("get_vnode_name buffer: %p; buffer_size: %lu\n", buffer, bufferSize); + OVERLAY_CALL(get_vnode_name, buffer, bufferSize) + DO_LOG("get_vnode_name result: 0x%08lx; buffer: \"%s\"\n", result, + result == B_OK ? buffer : "unsafe"); + return result; +} + + +static bool +overlay_can_page(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + DO_LOG("can_page cookie: %p\n", cookie); + bool result = false; + fs_vnode *superVnode = (fs_vnode *)vnode->private_node; + if (superVnode->ops->can_page != NULL) { + result = superVnode->ops->can_page(volume->super_volume, superVnode, + cookie); + } + + DO_LOG("can_page result: %s\n", result ? "yes" : "no"); + return result; +} + + +static status_t +overlay_read_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, + const iovec *vecs, size_t count, size_t *numBytes) +{ + DO_LOG("read_pages cookie: %p; pos: %lld; vecs: %p; count: %lu;" + " num_bytes: %lu\n", cookie, pos, vecs, count, *numBytes); + OVERLAY_CALL(read_pages, cookie, pos, vecs, count, numBytes) + DO_LOG("read_pages result: 0x%08lx; num_bytes: %lu\n", result, *numBytes); + return result; +} + + +static status_t +overlay_write_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, + const iovec *vecs, size_t count, size_t *numBytes) +{ + DO_LOG("write_pages cookie: %p; pos: %lld; vecs: %p; count: %lu;" + " num_bytes: %lu\n", cookie, pos, vecs, count, *numBytes); + OVERLAY_CALL(write_pages, cookie, pos, vecs, count, numBytes) + DO_LOG("write_pages result: 0x%08lx; num_bytes: %lu\n", result, *numBytes); + return result; +} + + +static status_t +overlay_io(fs_volume *volume, fs_vnode *vnode, void *cookie, + io_request *request) +{ + DO_LOG("io cookie: %p; request: %p (write: %s; offset: %lld; length: %llu)" + "\n", cookie, request, io_request_is_write(request) ? "yes" : "no", + io_request_offset(request), io_request_length(request)); + OVERLAY_CALL(io, cookie, request) + DO_LOG("io result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_cancel_io(fs_volume *volume, fs_vnode *vnode, void *cookie, + io_request *request) +{ + DO_LOG("cancel_io cookie: %p; request: %p\n", cookie, request); + OVERLAY_CALL(cancel_io, cookie, request) + DO_LOG("cancel_io result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_get_file_map(fs_volume *volume, fs_vnode *vnode, off_t offset, + size_t size, struct file_io_vec *vecs, size_t *count) +{ + DO_LOG("get_file_map offset: %lld; size: %lu; vecs: %p; count: %lu\n", + offset, size, vecs, *count); + OVERLAY_CALL(get_file_map, offset, size, vecs, count) + DO_LOG("get_file_map result: 0x%08lx; count: %lu\n", result, *count); + return result; +} + + +static status_t +overlay_ioctl(fs_volume *volume, fs_vnode *vnode, void *cookie, ulong op, + void *buffer, size_t length) +{ + DO_LOG("ioctl cookie: %p; op: %lu; buffer: %p; size: %lu\n", cookie, op, + buffer, length); + OVERLAY_CALL(ioctl, cookie, op, buffer, length) + DO_LOG("ioctl result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_set_flags(fs_volume *volume, fs_vnode *vnode, void *cookie, + int flags) +{ + DO_LOG("set_flags cookie: %p; flags: %d\n", cookie, flags); + OVERLAY_CALL(set_flags, cookie, flags) + DO_LOG("set_flags result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_select(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event, + selectsync *sync) +{ + DO_LOG("select cookie: %p; event: %u; selectsync: %p\n", cookie, event, + sync); + OVERLAY_CALL(select, cookie, event, sync) + DO_LOG("select result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_deselect(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event, + selectsync *sync) +{ + DO_LOG("deselect cookie: %p; event: %u; selectsync: %p\n", cookie, event, + sync); + OVERLAY_CALL(deselect, cookie, event, sync) + DO_LOG("deselect result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_fsync(fs_volume *volume, fs_vnode *vnode) +{ + DO_LOG("%s\n", "fsync"); + + status_t result = B_UNSUPPORTED; + fs_vnode *superVnode = (fs_vnode *)vnode->private_node; + if (superVnode->ops->fsync != NULL) + result = superVnode->ops->fsync(volume->super_volume, superVnode); + + DO_LOG("fsync result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_read_symlink(fs_volume *volume, fs_vnode *vnode, char *buffer, + size_t *bufferSize) +{ + DO_LOG("read_symlink buffer: %p; buffer_size: %lu\n", buffer, *bufferSize); + OVERLAY_CALL(read_symlink, buffer, bufferSize) + DO_LOG("read_symlink result: 0x%08lx; buffer_size: %lu; \"%.*s\"\n", result, + *bufferSize, result == B_OK ? (int)*bufferSize : 6, + result == B_OK ? buffer : "unsafe"); + return result; +} + + +static status_t +overlay_create_symlink(fs_volume *volume, fs_vnode *vnode, const char *name, + const char *path, int mode) +{ + DO_LOG("create_symlink name: \"%s\"; path: \"%s\"; mode: %u\n", name, path, + mode); + OVERLAY_CALL(create_symlink, name, path, mode) + DO_LOG("create_symlink result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_link(fs_volume *volume, fs_vnode *vnode, const char *name, + fs_vnode *target) +{ + DO_LOG("link name: \"%s\"; target: %p\n", name, + ((fs_vnode *)target->private_node)->private_node); + OVERLAY_CALL(link, name, (fs_vnode *)target->private_node) + DO_LOG("link result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_unlink(fs_volume *volume, fs_vnode *vnode, const char *name) +{ + DO_LOG("unlink name: \"%s\"\n", name); + OVERLAY_CALL(unlink, name) + DO_LOG("unlink result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_rename(fs_volume *volume, fs_vnode *vnode, + const char *fromName, fs_vnode *toDir, const char *toName) +{ + DO_LOG("rename from_name: \"%s\"; to_dir: %p; to_name: \"%s\"\n", + fromName, ((fs_vnode *)toDir->private_node)->private_node, toName); + OVERLAY_CALL(rename, fromName, (fs_vnode *)toDir->private_node, toName) + DO_LOG("rename result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_access(fs_volume *volume, fs_vnode *vnode, int mode) +{ + DO_LOG("access mode: %u\n", mode); + OVERLAY_CALL(access, mode) + DO_LOG("access result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_read_stat(fs_volume *volume, fs_vnode *vnode, struct stat *stat) +{ + DO_LOG("read_stat stat: %p\n", stat); + OVERLAY_CALL(read_stat, stat) + if (result == B_OK) { + DO_LOG("read_stat result: 0x%08lx; stat(dev: %lu; ino: %llu; mode: %u;" + " uid: %u; gid %u; size: %llu)\n", result, stat->st_dev, + stat->st_ino, stat->st_mode, stat->st_uid, stat->st_gid, + stat->st_size); + } else + DO_LOG("read_stat result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat, + uint32 statMask) +{ + DO_LOG("write_stat stat: %p; mask: %lu\n", stat, statMask); + OVERLAY_CALL(write_stat, stat, statMask) + DO_LOG("write_stat result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_create(fs_volume *volume, fs_vnode *vnode, const char *name, + int openMode, int perms, void **cookie, ino_t *newVnodeID) +{ + DO_LOG("create name: \"%s\"; open_mode: %u; perms: %u\n", name, openMode, + perms); + OVERLAY_CALL(create, name, openMode, perms, cookie, newVnodeID) + DO_LOG("create result: 0x%08lx; cookie: %p; new_vnode_id: %llu\n", result, + *cookie, *newVnodeID); + return result; +} + + +static status_t +overlay_open(fs_volume *volume, fs_vnode *vnode, int openMode, void **cookie) +{ + DO_LOG("open open_mode: %u\n", openMode); + OVERLAY_CALL(open, openMode, cookie) + DO_LOG("open result: 0x%08lx; cookie: %p\n", result, *cookie); + return result; +} + + +static status_t +overlay_close(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + DO_LOG("close cookie %p\n", cookie); + OVERLAY_CALL(close, cookie) + DO_LOG("close result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_free_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + DO_LOG("free_cookie cookie %p\n", cookie); + OVERLAY_CALL(free_cookie, cookie) + DO_LOG("free_cookie result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_read(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, + void *buffer, size_t *length) +{ + DO_LOG("read cookie: %p; pos: %lld; buffer: %p; length: %lu\n", cookie, pos, + buffer, *length); + OVERLAY_CALL(read, cookie, pos, buffer, length) + DO_LOG("read result: 0x%08lx; length: %lu\n", result, *length); + return result; +} + + +static status_t +overlay_write(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, + const void *buffer, size_t *length) +{ + DO_LOG("write cookie: %p; pos: %lld; buffer: %p; length: %lu\n", cookie, + pos, buffer, *length); + OVERLAY_CALL(write, cookie, pos, buffer, length) + DO_LOG("write result: 0x%08lx; length: %lu\n", result, *length); + return result; +} + + +static status_t +overlay_create_dir(fs_volume *volume, fs_vnode *vnode, const char *name, + int perms) +{ + DO_LOG("create_dir name: \"%s\"; perms: %u\n", name, perms); + OVERLAY_CALL(create_dir, name, perms) + DO_LOG("create_dir result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_remove_dir(fs_volume *volume, fs_vnode *vnode, const char *name) +{ + DO_LOG("remove_dir name: \"%s\"\n", name); + OVERLAY_CALL(remove_dir, name) + DO_LOG("remove_dir result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_open_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) +{ + DO_LOG("%s\n", "open_dir"); + OVERLAY_CALL(open_dir, cookie) + DO_LOG("open_dir result: 0x%08lx; cookie: %p\n", result, *cookie); + return result; +} + + +static status_t +overlay_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + DO_LOG("close_dir cookie: %p\n", cookie); + OVERLAY_CALL(close_dir, cookie) + DO_LOG("close_dir result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_free_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + DO_LOG("free_dir_cookie cookie: %p\n", cookie); + OVERLAY_CALL(free_dir_cookie, cookie) + DO_LOG("free_dir_cookie result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_read_dir(fs_volume *volume, fs_vnode *vnode, void *cookie, + struct dirent *buffer, size_t bufferSize, uint32 *num) +{ + DO_LOG("read_dir cookie: %p; buffer: %p; buffer_size: %lu\n", cookie, + buffer, bufferSize); + OVERLAY_CALL(read_dir, cookie, buffer, bufferSize, num); + DO_LOG("read_dir result: 0x%08lx; num: %lu\n", result, *num); + return result; +} + + +static status_t +overlay_rewind_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + DO_LOG("rewind_dir cookie: %p\n", cookie); + OVERLAY_CALL(rewind_dir, cookie) + DO_LOG("rewind_dir result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) +{ + DO_LOG("%s\n", "open_attr_dir"); + OVERLAY_CALL(open_attr_dir, cookie) + DO_LOG("open_attr_dir result: 0x%08lx; cookie: %p\n", result, *cookie); + return result; +} + + +static status_t +overlay_close_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + DO_LOG("close_attr_dir cookie: %p\n", cookie); + OVERLAY_CALL(close_attr_dir, cookie) + DO_LOG("close_attr_dir result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_free_attr_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + DO_LOG("free_attr_dir_cookie cookie: %p\n", cookie); + OVERLAY_CALL(free_attr_dir_cookie, cookie) + DO_LOG("free_attr_dir_cookie result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_read_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie, + struct dirent *buffer, size_t bufferSize, uint32 *num) +{ + DO_LOG("read_attr_dir cookie: %p; buffer: %p; buffer_size: %lu\n", cookie, + buffer, bufferSize); + OVERLAY_CALL(read_attr_dir, cookie, buffer, bufferSize, num); + DO_LOG("read_attr_dir result: 0x%08lx; num: %lu\n", result, *num); + return result; +} + + +static status_t +overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + DO_LOG("rewind_attr_dir cookie: %p\n", cookie); + OVERLAY_CALL(rewind_attr_dir, cookie) + DO_LOG("rewind_attr_dir result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_create_attr(fs_volume *volume, fs_vnode *vnode, const char *name, + uint32 type, int openMode, void **cookie) +{ + DO_LOG("create_attr name: \"%s\"; type: 0x%08lx; open_mode: %u\n", name, + type, openMode); + OVERLAY_CALL(create_attr, name, type, openMode, cookie) + DO_LOG("create_attr result: 0x%08lx; cookie: %p\n", result, *cookie); + return result; +} + + +static status_t +overlay_open_attr(fs_volume *volume, fs_vnode *vnode, const char *name, + int openMode, void **cookie) +{ + DO_LOG("open_attr name: \"%s\"; open_mode: %u\n", name, openMode); + OVERLAY_CALL(open_attr, name, openMode, cookie) + DO_LOG("open_attr result: 0x%08lx; cookie: %p\n", result, *cookie); + return result; +} + + +static status_t +overlay_close_attr(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + DO_LOG("close_attr cookie: %p\n", cookie); + OVERLAY_CALL(close_attr, cookie) + DO_LOG("close_attr result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_free_attr_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) +{ + DO_LOG("free_attr_cookie cookie: %p\n", cookie); + OVERLAY_CALL(free_attr_cookie, cookie) + DO_LOG("free_attr_cookie result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_read_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, + void *buffer, size_t *length) +{ + DO_LOG("read_attr cookie: %p; pos: %lld; buffer: %p; length: %lu\n", cookie, + pos, buffer, *length); + OVERLAY_CALL(read_attr, cookie, pos, buffer, length) + DO_LOG("read_attr result: 0x%08lx; length: %lu\n", result, *length); + return result; +} + + +static status_t +overlay_write_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, + const void *buffer, size_t *length) +{ + DO_LOG("write_attr cookie: %p; pos: %lld; buffer: %p; length: %lu\n", + cookie, pos, buffer, *length); + OVERLAY_CALL(write_attr, cookie, pos, buffer, length) + DO_LOG("write_attr result: 0x%08lx; length: %lu\n", result, *length); + return result; +} + + +static status_t +overlay_read_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie, + struct stat *stat) +{ + DO_LOG("read_attr_stat cookie: %p; stat: %p\n", cookie, stat); + OVERLAY_CALL(read_attr_stat, cookie, stat) + if (result == B_OK) { + DO_LOG("read_attr_stat result: 0x%08lx; stat(dev: %lu; ino: %llu;" + " mode: %u; uid: %u; gid %u; size: %llu; type: 0x%08lx)\n", result, + stat->st_dev, stat->st_ino, stat->st_mode, stat->st_uid, + stat->st_gid, stat->st_size, stat->st_type); + } else + DO_LOG("read_attr_stat result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie, + const struct stat *stat, int statMask) +{ + DO_LOG("write_attr_stat cookie: %p; stat: %p; mask: %u\n", cookie, stat, + statMask); + OVERLAY_CALL(write_attr_stat, cookie, stat, statMask) + DO_LOG("write_attr_stat result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_rename_attr(fs_volume *volume, fs_vnode *vnode, + const char *fromName, fs_vnode *toVnode, const char *toName) +{ + DO_LOG("rename_attr from_name: \"%s\"; to_vnode: %p; to_name: \"%s\"\n", + fromName, ((fs_vnode *)toVnode->private_node)->private_node, toName); + OVERLAY_CALL(rename_attr, fromName, (fs_vnode *)toVnode->private_node, + toName) + DO_LOG("rename_attr result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name) +{ + DO_LOG("remove_attr name: \"%s\"\n", name); + OVERLAY_CALL(remove_attr, name) + DO_LOG("remove_attr result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_create_special_node(fs_volume *volume, fs_vnode *vnode, + const char *name, fs_vnode *subVnode, mode_t mode, uint32 flags, + fs_vnode *_superVnode, ino_t *nodeID) +{ + DO_LOG("create_special_node name: \"%s\"; sub_vnode: %p; mode: %u;" + " flags: %lu\n", name, subVnode->private_node, mode, flags); + OVERLAY_CALL(create_special_node, name, (fs_vnode *)subVnode->private_node, + mode, flags, _superVnode, nodeID) + DO_LOG("create_special_node result: 0x%08lx; super_vnode: %p;" + " node_id: %llu\n", result, _superVnode->private_node, *nodeID); + return result; +} + + +static fs_vnode_ops sOverlayVnodeOps = { + &overlay_lookup, + &overlay_get_vnode_name, + + &overlay_put_vnode, + &overlay_remove_vnode, + + &overlay_can_page, + &overlay_read_pages, + &overlay_write_pages, + + &overlay_io, + &overlay_cancel_io, + + &overlay_get_file_map, + + /* common */ + &overlay_ioctl, + &overlay_set_flags, + &overlay_select, + &overlay_deselect, + &overlay_fsync, + + &overlay_read_symlink, + &overlay_create_symlink, + &overlay_link, + &overlay_unlink, + &overlay_rename, + + &overlay_access, + &overlay_read_stat, + &overlay_write_stat, + + /* file */ + &overlay_create, + &overlay_open, + &overlay_close, + &overlay_free_cookie, + &overlay_read, + &overlay_write, + + /* directory */ + &overlay_create_dir, + &overlay_remove_dir, + &overlay_open_dir, + &overlay_close_dir, + &overlay_free_dir_cookie, + &overlay_read_dir, + &overlay_rewind_dir, + + /* attribute directory operations */ + &overlay_open_attr_dir, + &overlay_close_attr_dir, + &overlay_free_attr_dir_cookie, + &overlay_read_attr_dir, + &overlay_rewind_attr_dir, + + /* attribute operations */ + &overlay_create_attr, + &overlay_open_attr, + &overlay_close_attr, + &overlay_free_attr_cookie, + &overlay_read_attr, + &overlay_write_attr, + + &overlay_read_attr_stat, + &overlay_write_attr_stat, + &overlay_rename_attr, + &overlay_remove_attr, + + /* support for node and FS layers */ + &overlay_create_special_node, + &overlay_get_super_vnode +}; + + +// #pragma mark - volume ops + + +#define DO_VOLUME_LOG(format, args...) \ + { \ + char _printBuffer[256]; \ + int _printSize = snprintf(_printBuffer, sizeof(_printBuffer), \ + "%llu %ld %p: " format, system_time(), find_thread(NULL), \ + volume->super_volume, args); \ + if ((unsigned int)_printSize > sizeof(_printBuffer)) { \ + _printBuffer[sizeof(_printBuffer) - 1] = '\n'; \ + _printSize = sizeof(_printBuffer); \ + } \ + write((int)volume->private_volume, _printBuffer, _printSize); \ + } + +#define OVERLAY_VOLUME_CALL(op, params...) \ + status_t result = B_UNSUPPORTED; \ + if (volume->super_volume->ops->op != NULL) \ + result = volume->super_volume->ops->op(volume->super_volume, params); \ + + +static status_t +overlay_unmount(fs_volume *volume) +{ + if (volume->super_volume != NULL + && volume->super_volume->ops != NULL + && volume->super_volume->ops->unmount != NULL) + volume->super_volume->ops->unmount(volume->super_volume); + + close((int)volume->private_volume); + return B_OK; +} + + +static status_t +overlay_read_fs_info(fs_volume *volume, struct fs_info *info) +{ + DO_VOLUME_LOG("%s\n", "read_fs_info"); + OVERLAY_VOLUME_CALL(read_fs_info, info) + DO_VOLUME_LOG("read_fs_info result: 0x%08lx; info(dev: %lu; root: %llu;" + " flags: %lu; block_size: %lld; io_size: %lld; total_blocks: %lld;" + " free_blocks: %lld; total_nodes: %lld; free_nodes: %lld;" + " device_name: \"%s\"; volume_name: \"%s\"; fsh_name: \"%s\")\n", + result, info->dev, info->root, info->flags, info->block_size, + info->io_size, info->total_blocks, info->free_blocks, + info->total_nodes, info->free_nodes, info->device_name, + info->volume_name, info->fsh_name); + return result; +} + + +static status_t +overlay_write_fs_info(fs_volume *volume, const struct fs_info *info, + uint32 mask) +{ + DO_VOLUME_LOG("write_fs_info info: %p; mask: %lu\n", info, mask); + OVERLAY_VOLUME_CALL(write_fs_info, info, mask) + DO_VOLUME_LOG("write_fs_info result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_sync(fs_volume *volume) +{ + DO_VOLUME_LOG("%s\n", "sync"); + status_t result = B_UNSUPPORTED; + if (volume->super_volume->ops->sync != NULL) + result = volume->super_volume->ops->sync(volume->super_volume); + DO_VOLUME_LOG("sync result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_get_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode, int *type, + uint32 *flags, bool reenter) +{ + DO_VOLUME_LOG("get_vnode id: %llu; vnode: %p; type*: %p; flags*: %p;" + " reenter: %d\n", id, vnode, type, flags, reenter); + + if (volume->super_volume->ops->get_vnode == NULL) { + DO_VOLUME_LOG("get_vnode %s\n", "not supported"); + return B_UNSUPPORTED; + } + + fs_vnode *superVnode = new(std::nothrow) fs_vnode; + if (superVnode == NULL) { + DO_VOLUME_LOG("get_vnode %s\n", "no memory"); + return B_NO_MEMORY; + } + + status_t result = volume->super_volume->ops->get_vnode(volume->super_volume, + id, superVnode, type, flags, reenter); + if (result != B_OK) { + DO_VOLUME_LOG("get_vnode result: 0x%08lx\n", result); + delete superVnode; + return result; + } + + vnode->private_node = superVnode; + vnode->ops = &sOverlayVnodeOps; + + DO_VOLUME_LOG("get_vnode result: 0x%08lx; super_vnode: %p\n", result, + superVnode->private_node); + return B_OK; +} + + +static status_t +overlay_open_index_dir(fs_volume *volume, void **cookie) +{ + DO_VOLUME_LOG("%s\n", "open_index_dir"); + OVERLAY_VOLUME_CALL(open_index_dir, cookie) + DO_VOLUME_LOG("open_index_dir result: 0x%08lx; cookie: %p\n", result, + *cookie); + return result; +} + + +static status_t +overlay_close_index_dir(fs_volume *volume, void *cookie) +{ + DO_VOLUME_LOG("close_index_dir cookie: %p\n", cookie); + OVERLAY_VOLUME_CALL(close_index_dir, cookie) + DO_VOLUME_LOG("close_index_dir result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_free_index_dir_cookie(fs_volume *volume, void *cookie) +{ + DO_VOLUME_LOG("free_index_dir_cookie cookie: %p\n", cookie); + OVERLAY_VOLUME_CALL(free_index_dir_cookie, cookie) + DO_VOLUME_LOG("free_index_dir_cookie result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_read_index_dir(fs_volume *volume, void *cookie, struct dirent *buffer, + size_t bufferSize, uint32 *num) +{ + DO_VOLUME_LOG("read_index_dir cookie: %p; buffer: %p; buffer_size: %lu\n", + cookie, buffer, bufferSize); + OVERLAY_VOLUME_CALL(read_index_dir, cookie, buffer, bufferSize, num) + DO_VOLUME_LOG("read_index_dir result: 0x%08lx; num: %lu\n", result, *num); + return result; +} + + +static status_t +overlay_rewind_index_dir(fs_volume *volume, void *cookie) +{ + DO_VOLUME_LOG("rewind_index_dir cookie: %p\n", cookie); + OVERLAY_VOLUME_CALL(rewind_index_dir, cookie) + DO_VOLUME_LOG("rewind_index_dir result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_create_index(fs_volume *volume, const char *name, uint32 type, + uint32 flags) +{ + DO_VOLUME_LOG("create_index name: \"%s\"; type: %lu; flags: %lu\n", name, + type, flags); + OVERLAY_VOLUME_CALL(create_index, name, type, flags) + DO_VOLUME_LOG("create_index result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_remove_index(fs_volume *volume, const char *name) +{ + DO_VOLUME_LOG("remove_index name: \"%s\"\n", name); + OVERLAY_VOLUME_CALL(remove_index, name) + DO_VOLUME_LOG("remove_index result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_read_index_stat(fs_volume *volume, const char *name, struct stat *stat) +{ + DO_VOLUME_LOG("read_index_stat name: \"%s\"; stat: %p\n", name, stat); + OVERLAY_VOLUME_CALL(read_index_stat, name, stat) + if (result == B_OK) { + DO_VOLUME_LOG("read_index_stat result: 0x%08lx; stat(dev: %lu;" + " ino: %llu; mode: %u; uid: %u; gid %u; size: %llu;" + " type: 0x%08lx)\n", result, stat->st_dev, stat->st_ino, + stat->st_mode, stat->st_uid, stat->st_gid, stat->st_size, + stat->st_type); + } else + DO_VOLUME_LOG("read_index_stat result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_open_query(fs_volume *volume, const char *query, uint32 flags, + port_id port, uint32 token, void **cookie) +{ + DO_VOLUME_LOG("open_query query: \"%s\"; flags: %lu; port: %ld;" + " token: %lu\n", query, flags, port, token); + OVERLAY_VOLUME_CALL(open_query, query, flags, port, token, cookie) + DO_VOLUME_LOG("open_query result: 0x%08lx; cookie: %p\n", result, *cookie); + return result; +} + + +static status_t +overlay_close_query(fs_volume *volume, void *cookie) +{ + DO_VOLUME_LOG("close_query cookie: %p\n", cookie); + OVERLAY_VOLUME_CALL(close_query, cookie) + DO_VOLUME_LOG("close_query result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_free_query_cookie(fs_volume *volume, void *cookie) +{ + DO_VOLUME_LOG("free_query_cookie cookie: %p\n", cookie); + OVERLAY_VOLUME_CALL(free_query_cookie, cookie) + DO_VOLUME_LOG("free_query_cookie result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_read_query(fs_volume *volume, void *cookie, struct dirent *buffer, + size_t bufferSize, uint32 *num) +{ + DO_VOLUME_LOG("read_query cookie: %p; buffer: %p; buffer_size: %lu\n", + cookie, buffer, bufferSize); + OVERLAY_VOLUME_CALL(read_query, cookie, buffer, bufferSize, num) + DO_VOLUME_LOG("read_query result: 0x%08lx; num: %lu\n", result, *num); + return result; +} + + +static status_t +overlay_rewind_query(fs_volume *volume, void *cookie) +{ + DO_VOLUME_LOG("rewind_query cookie: %p\n", cookie); + OVERLAY_VOLUME_CALL(rewind_query, cookie) + DO_VOLUME_LOG("rewind_query result: 0x%08lx\n", result); + return result; +} + + +static status_t +overlay_all_layers_mounted(fs_volume *volume) +{ + return B_OK; +} + + +static status_t +overlay_create_sub_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode) +{ + fs_vnode *superVnode = new(std::nothrow) fs_vnode; + if (superVnode == NULL) + return B_NO_MEMORY; + + *superVnode = *vnode; + vnode->private_node = superVnode; + vnode->ops = &sOverlayVnodeOps; + return B_OK; +} + + +static status_t +overlay_delete_sub_vnode(fs_volume *volume, fs_vnode *vnode) +{ + delete (fs_vnode *)vnode->private_node; + return B_OK; +} + + +static fs_volume_ops sOverlayVolumeOps = { + &overlay_unmount, + + &overlay_read_fs_info, + &overlay_write_fs_info, + &overlay_sync, + + &overlay_get_vnode, + &overlay_open_index_dir, + &overlay_close_index_dir, + &overlay_free_index_dir_cookie, + &overlay_read_index_dir, + &overlay_rewind_index_dir, + + &overlay_create_index, + &overlay_remove_index, + &overlay_read_index_stat, + + &overlay_open_query, + &overlay_close_query, + &overlay_free_query_cookie, + &overlay_read_query, + &overlay_rewind_query, + + &overlay_all_layers_mounted, + &overlay_create_sub_vnode, + &overlay_delete_sub_vnode +}; + + +// #pragma mark - filesystem module + + +static status_t +overlay_mount(fs_volume *volume, const char *device, uint32 flags, + const char *args, ino_t *rootID) +{ + char filename[256]; + snprintf(filename, sizeof(filename), "%s%s", kLogFilePrefix, device); + filename[sizeof(filename) - 1] = 0; + + int filenameLength = strlen(filename); + for (int i = strlen(kLogFilePrefix); i < filenameLength; i++) { + if (filename[i] == '/') + filename[i] = '_'; + } + + int fd = creat(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd < 0) + return errno; + + volume->private_volume = (void *)fd; + volume->ops = &sOverlayVolumeOps; + return B_OK; +} + + +static status_t +overlay_std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + case B_MODULE_UNINIT: + return B_OK; + default: + return B_ERROR; + } +} + + +static file_system_module_info sOverlayFileSystem = { + { + "file_systems/log_overlay"B_CURRENT_FS_API_VERSION, + 0, + overlay_std_ops, + }, + + "log_overlay", // short_name + "Logging Overlay File System", // pretty_name + 0, // DDM flags + + // scanning + NULL, // identify_partition + NULL, // scan_partition + NULL, // free_identify_partition_cookie + NULL, // free_partition_content_cookie + + // general operations + &overlay_mount, + + // capability querying + NULL, // get_supported_operations + + NULL, // validate_resize + NULL, // validate_move + NULL, // validate_set_content_name + NULL, // validate_set_content_parameters + NULL, // validate_initialize + + // shadow partition modification + NULL, // shadow_changed + + // writing + NULL, // defragment + NULL, // repair + NULL, // resize + NULL, // move + NULL, // set_content_name + NULL, // set_content_parameters + NULL // initialize +}; + +module_info *modules[] = { + (module_info *)&sOverlayFileSystem, + NULL, +};