-
-
Notifications
You must be signed in to change notification settings - Fork 605
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implemented Read-Only File System (ROFS)
The Read-Only File System (ROFS) is a simple implementation of a file system where data from disk can only be read from and never written to. It is simple enough for many stateless applications deployed on OSv which only need to read code from local disk and never write to local disk. The ROFS is inspired and shares some ideas from the original MFS implementation by James Root from 2015. This initial implementation of ROFS operates without cache. This means that ROFS reads as much data from disk as requested per uio passed in to the read function but it does not retain/cache it for any subsequent read of the same data. The image built with ROFS is automatically set up to mount /tmp as ramfs filesystem to allow writing of any transient data like logs. The layout of the data on disk is as follows: - Super Block (512 bytes) that contains magic number and specifies meta information including block size and location and size of tables containing i-nodes, dentries and symbolic links - Files data where each file is padded to 512 bytes block - Table of directory entries referenced by index in directory i-node (each entry holds string with direntry name and i-node number) - Table of symlinks referenced by symlink i-node (each entry holds symbolic link path string) - Table of inodes where each specifies type (dir,file,symlink) and data offset (for files it is a block on a disk, for symlinks and directories it is an offset in one of the 2 tables above) Besides ROFS implementation this patch also changes VFS main to automatically mount ROFS or ZFS. It also adds number of new metrics that are captured and output in verbose mode. The images with RFS can be built by specified fs=rofs option like so: ./scripts/build image=node-fs-example -j4 fs=rofs ./scripts/build image=openjdk9-java-base,java-example -j4 fs=rofs Potential future improvements to ROFS: - add caching layer to read ahead more data from disk in anticipation of sequantial access - add compression of file segments - memory page sharing when file mmaping (implement vnop_cache) - add LRU logic to ROFS cache Fixes #195 Signed-off-by: Waldemar Kozaczuk <jwkozaczuk@gmail.com> Message-Id: <1521695448-28564-2-git-send-email-jwkozaczuk@gmail.com>
- Loading branch information
Showing
17 changed files
with
1,256 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
/* | ||
* Copyright (c) 2015 Carnegie Mellon University. | ||
* All Rights Reserved. | ||
* | ||
* THIS SOFTWARE IS PROVIDED "AS IS," WITH NO WARRANTIES WHATSOEVER. CARNEGIE | ||
* MELLON UNIVERSITY EXPRESSLY DISCLAIMS TO THE FULLEST EXTENT PERMITTEDBY LAW | ||
* ALL EXPRESS, IMPLIED, AND STATUTORY WARRANTIES, INCLUDING, WITHOUT | ||
* LIMITATION, THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | ||
* PURPOSE, AND NON-INFRINGEMENT OF PROPRIETARY RIGHTS. | ||
* | ||
* Released under a modified BSD license. For full terms, please see mfs.txt in | ||
* the licenses folder or contact permi...@sei.cmu.edu. | ||
* | ||
* DM-0002621 | ||
* | ||
* Based on https://github.com/jdroot/mfs | ||
* | ||
* Copyright (C) 2017 Waldemar Kozaczuk | ||
* Inspired by original MFS implementation by James Root from 2015 | ||
* | ||
* This work is open source software, licensed under the terms of the | ||
* BSD license as described in the LICENSE file in the top-level directory. | ||
*/ | ||
|
||
// | ||
// The Read-Only File System (ROFS) provides simple implementation of | ||
// a file system where data from disk can only be read from and never | ||
// written to. It is simple enough for many stateless applications | ||
// deployed on OSv which only need to read code from local disk and never | ||
// write to local disk. The ROFS is inspired and shares some ideas | ||
// from the original MFS implementation by James Root from 2015. | ||
// | ||
// This initial version of ROFS operates without cache. It reads as much data | ||
// from disk as requested per uio passed in to the read function and it does | ||
// not retain/cache it for any subsequent read of the same data. | ||
// | ||
// The structure of the data on disk is explained in scripts/gen-rofs-img.py | ||
|
||
#ifndef __INCLUDE_ROFS_H__ | ||
#define __INCLUDE_ROFS_H__ | ||
|
||
#include <osv/vnode.h> | ||
#include <osv/mount.h> | ||
#include <osv/dentry.h> | ||
#include <osv/prex.h> | ||
#include <osv/buf.h> | ||
|
||
#define ROFS_VERSION 1 | ||
#define ROFS_MAGIC 0xDEADBEAD | ||
|
||
#define ROFS_INODE_SIZE ((uint64_t)sizeof(struct rofs_inode)) | ||
|
||
#define ROFS_SUPERBLOCK_SIZE sizeof(struct rofs_super_block) | ||
#define ROFS_SUPERBLOCK_BLOCK 0 | ||
|
||
//#define ROFS_DEBUG_ENABLED 1 | ||
|
||
#if defined(ROFS_DEBUG_ENABLED) | ||
#define print(...) kprintf(__VA_ARGS__) | ||
#else | ||
#define print(...) | ||
#endif | ||
|
||
#define ROFS_DIAGNOSTICS_ENABLED 1 | ||
|
||
#if defined(ROFS_DIAGNOSTICS_ENABLED) | ||
#define ROFS_STOPWATCH_START auto begin = std::chrono::high_resolution_clock::now(); | ||
#define ROFS_STOPWATCH_END(total) auto end = std::chrono::high_resolution_clock::now(); \ | ||
std::chrono::duration<double> sec = end - begin; \ | ||
total += ((long)(sec.count() * 1000000)); | ||
//TODO: Review - avoid conversions | ||
#else | ||
#define ROFS_STOPWATCH_START | ||
#define ROFS_STOPWATCH_END(...) | ||
#endif | ||
|
||
extern struct vfsops rofs_vfsops; | ||
extern struct vnops rofs_vnops; | ||
|
||
struct rofs_super_block { | ||
uint64_t magic; | ||
uint64_t version; | ||
uint64_t block_size; | ||
uint64_t structure_info_first_block; | ||
uint64_t structure_info_blocks_count; | ||
uint64_t directory_entries_count; | ||
uint64_t symlinks_count; | ||
uint64_t inodes_count; | ||
}; | ||
|
||
struct rofs_inode { | ||
mode_t mode; | ||
uint64_t inode_no; | ||
uint64_t data_offset; | ||
union { | ||
uint64_t file_size; | ||
uint64_t dir_children_count; | ||
}; | ||
}; | ||
|
||
struct rofs_dir_entry { | ||
char *filename; | ||
uint64_t inode_no; | ||
}; | ||
|
||
struct rofs_info { | ||
struct rofs_super_block *sb; | ||
struct rofs_dir_entry *dir_entries; | ||
char **symlinks; | ||
struct rofs_inode *inodes; | ||
}; | ||
|
||
int rofs_read_blocks(struct device *device, uint64_t starting_block, uint64_t blocks_count, void *buf); | ||
|
||
void rofs_set_vnode(struct vnode *vnode, struct rofs_inode *inode); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/* | ||
* Copyright (c) 2015 Carnegie Mellon University. | ||
* All Rights Reserved. | ||
* | ||
* THIS SOFTWARE IS PROVIDED "AS IS," WITH NO WARRANTIES WHATSOEVER. CARNEGIE | ||
* MELLON UNIVERSITY EXPRESSLY DISCLAIMS TO THE FULLEST EXTENT PERMITTEDBY LAW | ||
* ALL EXPRESS, IMPLIED, AND STATUTORY WARRANTIES, INCLUDING, WITHOUT | ||
* LIMITATION, THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | ||
* PURPOSE, AND NON-INFRINGEMENT OF PROPRIETARY RIGHTS. | ||
* | ||
* Released under a modified BSD license. For full terms, please see mfs.txt in | ||
* the licenses folder or contact permi...@sei.cmu.edu. | ||
* | ||
* DM-0002621 | ||
* | ||
* Based on https://github.com/jdroot/mfs | ||
* | ||
* Copyright (C) 2017 Waldemar Kozaczuk | ||
* Inspired by original MFS implementation by James Root from 2015 | ||
* | ||
* This work is open source software, licensed under the terms of the | ||
* BSD license as described in the LICENSE file in the top-level directory. | ||
*/ | ||
|
||
#include "rofs.hh" | ||
#include <osv/device.h> | ||
#include <osv/bio.h> | ||
|
||
#if defined(ROFS_DIAGNOSTICS_ENABLED) | ||
extern std::atomic<long> rofs_block_read_count; | ||
extern std::atomic<long> rofs_block_read_ms; | ||
#endif | ||
|
||
void rofs_set_vnode(struct vnode *vnode, struct rofs_inode *inode) | ||
{ | ||
off_t size = 0; | ||
if (vnode == nullptr || inode == nullptr) { | ||
return; | ||
} | ||
|
||
vnode->v_data = inode; | ||
vnode->v_ino = inode->inode_no; | ||
|
||
// Set type | ||
if (S_ISDIR(inode->mode)) { | ||
size = ROFS_INODE_SIZE; //TODO: Revisit | ||
vnode->v_type = VDIR; | ||
} else if (S_ISREG(inode->mode)) { | ||
size = inode->file_size; | ||
vnode->v_type = VREG; | ||
} else if (S_ISLNK(inode->mode)) { | ||
size = 512; // TODO: Revisit | ||
vnode->v_type = VLNK; | ||
} | ||
|
||
vnode->v_mode = 0555; | ||
vnode->v_size = size; | ||
} | ||
|
||
int | ||
rofs_read_blocks(struct device *device, uint64_t starting_block, uint64_t blocks_count, void *buf) | ||
{ | ||
ROFS_STOPWATCH_START | ||
struct bio *bio = alloc_bio(); | ||
if (!bio) | ||
return ENOMEM; | ||
|
||
bio->bio_cmd = BIO_READ; | ||
bio->bio_dev = device; | ||
bio->bio_data = buf; | ||
bio->bio_offset = starting_block << 9; | ||
bio->bio_bcount = blocks_count * BSIZE; | ||
|
||
bio->bio_dev->driver->devops->strategy(bio); | ||
int error = bio_wait(bio); | ||
|
||
destroy_bio(bio); | ||
|
||
#if defined(ROFS_DIAGNOSTICS_ENABLED) | ||
rofs_block_read_count += blocks_count; | ||
#endif | ||
ROFS_STOPWATCH_END(rofs_block_read_ms) | ||
|
||
return error; | ||
} |
Oops, something went wrong.