Skip to content

Commit

Permalink
[LibOS] Introduce inodes, rewrite chroot filesystem
Browse files Browse the repository at this point in the history
This change begins the migration to inodes: file data will be kept in a
separate structure (inode) instead of dentry. In this step, inodes are
still optional, and only the `chroot` filesystem is rewritten to use
them.

The main use case for inodes is proper handling of `rename` and `unlink`
operations. The new `chroot` filesystem should do that much better than
the old one. I also added a regression test (`rename_unlink`) that
checks various cases.

Signed-off-by: Paweł Marczewski <pawel@invisiblethingslab.com>
  • Loading branch information
pwmarcz committed Sep 10, 2021
1 parent da65584 commit 74420be
Show file tree
Hide file tree
Showing 17 changed files with 996 additions and 940 deletions.
62 changes: 61 additions & 1 deletion LibOS/shim/include/shim_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ struct shim_dentry {
/* Filesystem-specific data. Protected by `lock`. */
void* data;

/* Inode associated with this dentry. Currently optional, and only for the use of underlying
* filesystem (see `shim_inode` below). Protected by `lock`. */
struct shim_inode* inode;

/* File lock information, stored only in the main process. Protected by `lock`. See
* `shim_fs_lock.c`. */
struct fs_lock* fs_lock;
Expand All @@ -162,6 +166,41 @@ struct shim_dentry {
REFTYPE ref_count;
};

/*
* Describes a single file in Graphene filesystem.
*
* The migration to inodes is underway. Currently, the underlying filesystems may use fields in this
* structure, but should also write to corresponding fields in dentry.
*
* The fields in this structure are protected by `lock`, with the exception of fields that do not
* change (`type`, `mount`, `fs`).
*/
struct shim_inode {
/* File type: S_IFREG, S_IFDIR, S_IFLNK etc. Does not change. */
mode_t type;

/* File permissions: PERM_rwxrwxrwx, etc. */
mode_t perm;

/* File size */
file_off_t size;

/* Create/modify/access time */
time_t ctime;
time_t mtime;
time_t atime;

/* Mounted filesystem this inode belongs to. Does not change. */
struct shim_mount* mount;

/* Filesystem to use for operations on this file: this is usually `mount->fs`, but can be
* different in case of special files (such as named pipes or sockets). */
struct shim_fs* fs;

struct shim_lock lock;
REFTYPE ref_count;
};

typedef int (*readdir_callback_t)(const char* name, void* arg);

struct shim_d_ops {
Expand Down Expand Up @@ -199,7 +238,7 @@ struct shim_d_ops {
int (*set_link)(struct shim_dentry* dent, const char* link);

/* change the mode or owner of a file; the caller has to update dentry */
int (*chmod)(struct shim_dentry* dent, mode_t mode);
int (*chmod)(struct shim_dentry* dent, mode_t perm);
int (*chown)(struct shim_dentry* dent, int uid, int gid);

/* change the name of a dentry */
Expand Down Expand Up @@ -522,6 +561,9 @@ void get_dentry(struct shim_dentry* dent);
/* Decrement the reference count on dent */
void put_dentry(struct shim_dentry* dent);

void lock_two_dentries(struct shim_dentry* dent1, struct shim_dentry* dent2);
void unlock_two_dentries(struct shim_dentry* dent1, struct shim_dentry* dent2);

/*!
* \brief Get the dentry one level up
*
Expand Down Expand Up @@ -577,6 +619,9 @@ void dentry_gc(struct shim_dentry* dent);
*
* An absolute path is a combination of all names up to the global root (not including the root,
* which by convention has an empty name), separated by `/`, and beginning with `/`.
*
* TODO: It would be more natural to use a `len` parameter instead (for length without null
* terminator).
*/
int dentry_abs_path(struct shim_dentry* dent, char** path, size_t* size);

Expand All @@ -594,6 +639,9 @@ int dentry_abs_path(struct shim_dentry* dent, char** path, size_t* size);
*
* A relative path is a combination of all names up to the root of the dentry's filesystem (not
* including the root), separated by `/`. A relative path never begins with `/`.
*
* TODO: It would be more natural to use a `len` parameter instead (for length without null
* terminator).
*/
int dentry_rel_path(struct shim_dentry* dent, char** path, size_t* size);

Expand Down Expand Up @@ -647,6 +695,18 @@ bool dentry_is_ancestor(struct shim_dentry* anc, struct shim_dentry* dent);
/* XXX: Future work: current dcache never shrinks. Would be nice to be able to do something like LRU
* under space pressure, although for a single app, this may be over-kill. */

/*!
* \brief Allocate and initialize a new inode
*
* \param mount the mount the inode is under
* \param type inode type (S_IFREG, S_IFDIR, etc.)
* \param perm inode permissions (PERM_rwxrwxrwx, etc.)
*/
struct shim_inode* get_new_inode(struct shim_mount* mount, mode_t type, mode_t perm);

void get_inode(struct shim_inode* inode);
void put_inode(struct shim_inode* inode);

/*
* Hashing utilities for paths.
*
Expand Down
52 changes: 20 additions & 32 deletions LibOS/shim/include/shim_handle.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
/* Handle types. Many of these are used by a single filesystem. */
enum shim_handle_type {
/* Files: */
TYPE_FILE, /* host files, used by `chroot` filesystem */
TYPE_CHROOT, /* host files, used by `chroot` filesystem */
TYPE_DEV, /* emulated devices, used by `dev` filesystem */
TYPE_STR, /* string-based files (with data inside handle), handled by `pseudo_*`
* functions */
Expand Down Expand Up @@ -57,28 +57,8 @@ enum shim_file_type {
FILE_TTY,
};

struct shim_file_data {
struct shim_lock lock;
struct atomic_int version;
bool queried;
enum shim_file_type type;
struct atomic_int size;
struct shim_qstr host_uri;
unsigned long atime;
unsigned long mtime;
unsigned long ctime;
unsigned long nlink;
};

struct shim_file_handle {
unsigned int version;
struct shim_file_data* data;

enum shim_file_type type;
file_off_t size;
file_off_t marker;

struct sync_handle* sync;
struct shim_chroot_handle {
file_off_t pos;
};

#define FILE_HANDLE_DATA(hdl) ((hdl)->info.file.data)
Expand Down Expand Up @@ -220,6 +200,14 @@ struct shim_handle {
struct shim_fs* fs;
struct shim_dentry* dentry;

/*
* Inode associated with this handle. Currently optional, and only for the use of underlying
* filesystem (see `shim_inode` in `shim_fs.h`). Eventually, should replace `dentry` fields.
*
* This field does not change, so reading it does not require holding `lock`.
*/
struct shim_inode* inode;

/* If this handle is registered for any epoll handle, this list contains
* a shim_epoll_item object in correspondence with the epoll handle. */
LISTP_TYPE(shim_epoll_item) epolls;
Expand All @@ -238,17 +226,17 @@ struct shim_handle {
/* Type-specific fields: when accessing, ensure that `type` field is appropriate first (at least
* by using assert()) */
union {
struct shim_file_handle file; /* TYPE_FILE */
/* (no data) */ /* TYPE_DEV */
struct shim_str_handle str; /* TYPE_STR */
/* (no data) */ /* TYPE_PSEUDO */
struct shim_tmpfs_handle tmpfs; /* TYPE_TMPFS */
struct shim_chroot_handle chroot; /* TYPE_CHROOT */
/* (no data) */ /* TYPE_DEV */
struct shim_str_handle str; /* TYPE_STR */
/* (no data) */ /* TYPE_PSEUDO */
struct shim_tmpfs_handle tmpfs; /* TYPE_TMPFS */

struct shim_pipe_handle pipe; /* TYPE_PIPE */
struct shim_sock_handle sock; /* TYPE_SOCK */
struct shim_pipe_handle pipe; /* TYPE_PIPE */
struct shim_sock_handle sock; /* TYPE_SOCK */

struct shim_epoll_handle epoll; /* TYPE_EPOLL */
/* (no data) */ /* TYPE_EVENTFD */
struct shim_epoll_handle epoll; /* TYPE_EPOLL */
/* (no data) */ /* TYPE_EVENTFD */
} info;

struct shim_dir_handle dir_info;
Expand Down
26 changes: 17 additions & 9 deletions LibOS/shim/src/bookkeep/shim_handle.c
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,9 @@ void put_handle(struct shim_handle* hdl) {
if (hdl->dentry)
put_dentry(hdl->dentry);

if (hdl->inode)
put_inode(hdl->inode);

destroy_handle(hdl);
}
}
Expand Down Expand Up @@ -723,6 +726,10 @@ BEGIN_CP_FUNC(handle) {
DO_CP_MEMBER(dentry, hdl, new_hdl, dentry);
}

if (hdl->inode) {
DO_CP_MEMBER(inode, hdl, new_hdl, inode);
}

if (new_hdl->pal_handle) {
struct shim_palhdl_entry* entry;
DO_CP(palhdl, hdl->pal_handle, &entry);
Expand All @@ -733,10 +740,6 @@ BEGIN_CP_FUNC(handle) {
INIT_LISTP(&new_hdl->epolls);

switch (hdl->type) {
case TYPE_FILE:
if (hdl->info.file.sync)
DO_CP(sync_handle, hdl->info.file.sync, &new_hdl->info.file.sync);
break;
case TYPE_EPOLL:
/* `new_hdl->info.epoll.fds_count` stays the same - copied above. */
DO_CP(epoll_item, &hdl->info.epoll.fds, &new_hdl->info.epoll.fds);
Expand Down Expand Up @@ -769,6 +772,7 @@ BEGIN_RS_FUNC(handle) {

CP_REBASE(hdl->fs);
CP_REBASE(hdl->dentry);
CP_REBASE(hdl->inode);
CP_REBASE(hdl->epolls);

if (!create_lock(&hdl->lock)) {
Expand All @@ -779,10 +783,11 @@ BEGIN_RS_FUNC(handle) {
get_dentry(hdl->dentry);
}

if (hdl->inode) {
get_inode(hdl->inode);
}

switch (hdl->type) {
case TYPE_FILE:
CP_REBASE(hdl->info.file.sync);
break;
case TYPE_EPOLL: {
int ret = create_event(&hdl->info.epoll.event);
if (ret < 0) {
Expand All @@ -802,8 +807,11 @@ BEGIN_RS_FUNC(handle) {
break;
}

if (hdl->fs && hdl->fs->fs_ops && hdl->fs->fs_ops->checkin)
hdl->fs->fs_ops->checkin(hdl);
if (hdl->fs && hdl->fs->fs_ops && hdl->fs->fs_ops->checkin) {
int ret = hdl->fs->fs_ops->checkin(hdl);
if (ret < 0)
return ret;
}
}
END_RS_FUNC(handle)

Expand Down
9 changes: 6 additions & 3 deletions LibOS/shim/src/bookkeep/shim_signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -359,10 +359,13 @@ static void memfault_upcall(bool is_in_pal, PAL_NUM addr, PAL_CONTEXT* context)
internal_fault("Internal memory fault with VMA", addr, context);
}
struct shim_handle* file = vma_info.file;
if (file && file->type == TYPE_FILE) {
if (file && file->type == TYPE_CHROOT) {
/* If the mapping exceeds end of a file then return a SIGBUS. */
uintptr_t eof_in_vma = (uintptr_t)vma_info.addr
+ (file->info.file.size - vma_info.file_offset);
lock(&file->inode->lock);
file_off_t size = file->inode->size;
unlock(&file->inode->lock);

uintptr_t eof_in_vma = (uintptr_t)vma_info.addr + (size - vma_info.file_offset);
if (addr > eof_in_vma) {
info.si_signo = SIGBUS;
info.si_code = BUS_ADRERR;
Expand Down

0 comments on commit 74420be

Please sign in to comment.