Skip to content

Commit cd44966

Browse files
wkozaczuknyh
authored andcommitted
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 <[email protected]> Message-Id: <[email protected]>
1 parent 6454485 commit cd44966

File tree

17 files changed

+1256
-34
lines changed

17 files changed

+1256
-34
lines changed

Makefile

+4
Original file line numberDiff line numberDiff line change
@@ -1769,6 +1769,10 @@ fs_objs += ramfs/ramfs_vfsops.o \
17691769
fs_objs += devfs/devfs_vnops.o \
17701770
devfs/device.o
17711771

1772+
fs_objs += rofs/rofs_vfsops.o \
1773+
rofs/rofs_vnops.o \
1774+
rofs/rofs_common.o
1775+
17721776
fs_objs += procfs/procfs_vnops.o
17731777

17741778
objects += $(addprefix fs/, $(fs_objs))

fs/rofs/rofs.hh

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright (c) 2015 Carnegie Mellon University.
3+
* All Rights Reserved.
4+
*
5+
* THIS SOFTWARE IS PROVIDED "AS IS," WITH NO WARRANTIES WHATSOEVER. CARNEGIE
6+
* MELLON UNIVERSITY EXPRESSLY DISCLAIMS TO THE FULLEST EXTENT PERMITTEDBY LAW
7+
* ALL EXPRESS, IMPLIED, AND STATUTORY WARRANTIES, INCLUDING, WITHOUT
8+
* LIMITATION, THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
9+
* PURPOSE, AND NON-INFRINGEMENT OF PROPRIETARY RIGHTS.
10+
*
11+
* Released under a modified BSD license. For full terms, please see mfs.txt in
12+
* the licenses folder or contact [email protected].
13+
*
14+
* DM-0002621
15+
*
16+
* Based on https://github.com/jdroot/mfs
17+
*
18+
* Copyright (C) 2017 Waldemar Kozaczuk
19+
* Inspired by original MFS implementation by James Root from 2015
20+
*
21+
* This work is open source software, licensed under the terms of the
22+
* BSD license as described in the LICENSE file in the top-level directory.
23+
*/
24+
25+
//
26+
// The Read-Only File System (ROFS) provides simple implementation of
27+
// a file system where data from disk can only be read from and never
28+
// written to. It is simple enough for many stateless applications
29+
// deployed on OSv which only need to read code from local disk and never
30+
// write to local disk. The ROFS is inspired and shares some ideas
31+
// from the original MFS implementation by James Root from 2015.
32+
//
33+
// This initial version of ROFS operates without cache. It reads as much data
34+
// from disk as requested per uio passed in to the read function and it does
35+
// not retain/cache it for any subsequent read of the same data.
36+
//
37+
// The structure of the data on disk is explained in scripts/gen-rofs-img.py
38+
39+
#ifndef __INCLUDE_ROFS_H__
40+
#define __INCLUDE_ROFS_H__
41+
42+
#include <osv/vnode.h>
43+
#include <osv/mount.h>
44+
#include <osv/dentry.h>
45+
#include <osv/prex.h>
46+
#include <osv/buf.h>
47+
48+
#define ROFS_VERSION 1
49+
#define ROFS_MAGIC 0xDEADBEAD
50+
51+
#define ROFS_INODE_SIZE ((uint64_t)sizeof(struct rofs_inode))
52+
53+
#define ROFS_SUPERBLOCK_SIZE sizeof(struct rofs_super_block)
54+
#define ROFS_SUPERBLOCK_BLOCK 0
55+
56+
//#define ROFS_DEBUG_ENABLED 1
57+
58+
#if defined(ROFS_DEBUG_ENABLED)
59+
#define print(...) kprintf(__VA_ARGS__)
60+
#else
61+
#define print(...)
62+
#endif
63+
64+
#define ROFS_DIAGNOSTICS_ENABLED 1
65+
66+
#if defined(ROFS_DIAGNOSTICS_ENABLED)
67+
#define ROFS_STOPWATCH_START auto begin = std::chrono::high_resolution_clock::now();
68+
#define ROFS_STOPWATCH_END(total) auto end = std::chrono::high_resolution_clock::now(); \
69+
std::chrono::duration<double> sec = end - begin; \
70+
total += ((long)(sec.count() * 1000000));
71+
//TODO: Review - avoid conversions
72+
#else
73+
#define ROFS_STOPWATCH_START
74+
#define ROFS_STOPWATCH_END(...)
75+
#endif
76+
77+
extern struct vfsops rofs_vfsops;
78+
extern struct vnops rofs_vnops;
79+
80+
struct rofs_super_block {
81+
uint64_t magic;
82+
uint64_t version;
83+
uint64_t block_size;
84+
uint64_t structure_info_first_block;
85+
uint64_t structure_info_blocks_count;
86+
uint64_t directory_entries_count;
87+
uint64_t symlinks_count;
88+
uint64_t inodes_count;
89+
};
90+
91+
struct rofs_inode {
92+
mode_t mode;
93+
uint64_t inode_no;
94+
uint64_t data_offset;
95+
union {
96+
uint64_t file_size;
97+
uint64_t dir_children_count;
98+
};
99+
};
100+
101+
struct rofs_dir_entry {
102+
char *filename;
103+
uint64_t inode_no;
104+
};
105+
106+
struct rofs_info {
107+
struct rofs_super_block *sb;
108+
struct rofs_dir_entry *dir_entries;
109+
char **symlinks;
110+
struct rofs_inode *inodes;
111+
};
112+
113+
int rofs_read_blocks(struct device *device, uint64_t starting_block, uint64_t blocks_count, void *buf);
114+
115+
void rofs_set_vnode(struct vnode *vnode, struct rofs_inode *inode);
116+
117+
#endif

fs/rofs/rofs_common.cc

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright (c) 2015 Carnegie Mellon University.
3+
* All Rights Reserved.
4+
*
5+
* THIS SOFTWARE IS PROVIDED "AS IS," WITH NO WARRANTIES WHATSOEVER. CARNEGIE
6+
* MELLON UNIVERSITY EXPRESSLY DISCLAIMS TO THE FULLEST EXTENT PERMITTEDBY LAW
7+
* ALL EXPRESS, IMPLIED, AND STATUTORY WARRANTIES, INCLUDING, WITHOUT
8+
* LIMITATION, THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
9+
* PURPOSE, AND NON-INFRINGEMENT OF PROPRIETARY RIGHTS.
10+
*
11+
* Released under a modified BSD license. For full terms, please see mfs.txt in
12+
* the licenses folder or contact [email protected].
13+
*
14+
* DM-0002621
15+
*
16+
* Based on https://github.com/jdroot/mfs
17+
*
18+
* Copyright (C) 2017 Waldemar Kozaczuk
19+
* Inspired by original MFS implementation by James Root from 2015
20+
*
21+
* This work is open source software, licensed under the terms of the
22+
* BSD license as described in the LICENSE file in the top-level directory.
23+
*/
24+
25+
#include "rofs.hh"
26+
#include <osv/device.h>
27+
#include <osv/bio.h>
28+
29+
#if defined(ROFS_DIAGNOSTICS_ENABLED)
30+
extern std::atomic<long> rofs_block_read_count;
31+
extern std::atomic<long> rofs_block_read_ms;
32+
#endif
33+
34+
void rofs_set_vnode(struct vnode *vnode, struct rofs_inode *inode)
35+
{
36+
off_t size = 0;
37+
if (vnode == nullptr || inode == nullptr) {
38+
return;
39+
}
40+
41+
vnode->v_data = inode;
42+
vnode->v_ino = inode->inode_no;
43+
44+
// Set type
45+
if (S_ISDIR(inode->mode)) {
46+
size = ROFS_INODE_SIZE; //TODO: Revisit
47+
vnode->v_type = VDIR;
48+
} else if (S_ISREG(inode->mode)) {
49+
size = inode->file_size;
50+
vnode->v_type = VREG;
51+
} else if (S_ISLNK(inode->mode)) {
52+
size = 512; // TODO: Revisit
53+
vnode->v_type = VLNK;
54+
}
55+
56+
vnode->v_mode = 0555;
57+
vnode->v_size = size;
58+
}
59+
60+
int
61+
rofs_read_blocks(struct device *device, uint64_t starting_block, uint64_t blocks_count, void *buf)
62+
{
63+
ROFS_STOPWATCH_START
64+
struct bio *bio = alloc_bio();
65+
if (!bio)
66+
return ENOMEM;
67+
68+
bio->bio_cmd = BIO_READ;
69+
bio->bio_dev = device;
70+
bio->bio_data = buf;
71+
bio->bio_offset = starting_block << 9;
72+
bio->bio_bcount = blocks_count * BSIZE;
73+
74+
bio->bio_dev->driver->devops->strategy(bio);
75+
int error = bio_wait(bio);
76+
77+
destroy_bio(bio);
78+
79+
#if defined(ROFS_DIAGNOSTICS_ENABLED)
80+
rofs_block_read_count += blocks_count;
81+
#endif
82+
ROFS_STOPWATCH_END(rofs_block_read_ms)
83+
84+
return error;
85+
}

0 commit comments

Comments
 (0)