Skip to content

Commit 7ceff0f

Browse files
committed
libext: make it thread-safe
This patch enhances libext module to make the ext2/3/4 filesystem driver thread-safe. It mostly relies on the changes made to the OSv fork of lwext4 to add mutex-based protection where needed - osvunikernel/lwext4@44c3329. More specifically, this patch implements 3 pairs of lock()/unlock() callback functions: - inode_alloc_lock() and inode_alloc_unlock() to guard allocation of i-node numbers - block_alloc_lock() and block_alloc_unlock() to guard allocation of file blocks - bcache_alloc_lock() and bcache_alloc_unlock() to guard access to global metadata block cache The changes made to lwext4 that utilize these lock/unlock function along with locking at vnode level in VFS layer should make libext thread-safe. Various tests involving fio have been conducted to verify libext is thread-safe: ./modules/libext/test.sh '/fio --name=fiotest --directory=/data/read --size 1M --numjobs=4 --rw=read' ./modules/libext/test.sh '/fio --name=fiotest --directory=/data/randread --size 1M --numjobs=4 --rw=randread' ./modules/libext/test.sh '/fio --name=fiotest --directory=/data/write --size 1M --numjobs=4 --rw=write' ./modules/libext/test.sh '/fio --name=fiotest --directory=/data/randwrite --size 1M --numjobs=4 --rw=randwrite' In addition, this patch fixes couple of bugs in ext_internal_write() uncovered when running the fio tests. Signed-off-by: Waldemar Kozaczuk <[email protected]>
1 parent 93f1fab commit 7ceff0f

File tree

3 files changed

+137
-46
lines changed

3 files changed

+137
-46
lines changed

modules/libext/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,10 @@ or use the `test.sh`:
4848
```bash
4949
sudo fsck -n /dev/loop0
5050
```
51+
52+
## Ext2/3/4 file system documentation
53+
- https://blogs.oracle.com/linux/post/understanding-ext4-disk-layout-part-1
54+
- https://blogs.oracle.com/linux/post/understanding-ext4-disk-layout-part-2
55+
- https://adil.medium.com/ext4-filesystem-data-blocks-super-blocks-inode-structure-1afb95c8e4ab
56+
- https://adil.medium.com/ext4-filesystem-extent-flex-bg-sparse-super-83f172d694c6
57+
- https://adil.medium.com/ext4-file-system-delayed-allocation-dirty-data-blocks-35945a49fac5

modules/libext/ext_vfsops.cc

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ void free_contiguous_aligned(void* p);
2727
#include <cstddef>
2828
#include <cstdio>
2929

30+
//#define CONF_debug_ext 1
31+
#if CONF_debug_ext
32+
#define ext_debug(format,...) kprintf("[ext4] " format, ##__VA_ARGS__)
33+
#else
34+
#define ext_debug(...)
35+
#endif
36+
3037
extern "C" bool is_linear_mapped(const void *addr);
3138

3239
int ext_init(void) { return 0;}
@@ -59,7 +66,7 @@ static int blockdev_bread_or_write(struct ext4_blockdev *bdev, void *buf, uint64
5966
bio->bio_dev->driver->devops->strategy(bio);
6067
int error = bio_wait(bio);
6168

62-
kprintf("[ext4] %s %ld bytes at offset %ld to %p with error:%d\n", read ? "Read" : "Wrote",
69+
ext_debug("%s %ld bytes at offset %ld to %p with error:%d\n", read ? "Read" : "Wrote",
6370
bio->bio_bcount, bio->bio_offset, bio->bio_data, error);
6471

6572
if (!is_linear_mapped(buf)) {
@@ -96,20 +103,64 @@ static struct ext4_fs ext_fs;
96103
static struct ext4_bcache ext_block_cache;
97104
extern struct vnops ext_vnops;
98105

106+
static mutex_t ext_inode_alloc_mutex;
107+
static void ext_inode_alloc_lock()
108+
{
109+
mutex_lock(&ext_inode_alloc_mutex);
110+
}
111+
112+
static void ext_inode_alloc_unlock()
113+
{
114+
mutex_unlock(&ext_inode_alloc_mutex);
115+
}
116+
117+
static mutex_t ext_block_alloc_mutex;
118+
static void ext_block_alloc_lock()
119+
{
120+
mutex_lock(&ext_block_alloc_mutex);
121+
}
122+
static void ext_block_alloc_unlock()
123+
{
124+
mutex_unlock(&ext_block_alloc_mutex);
125+
}
126+
127+
static mutex_t ext_bcache_mutex;
128+
static void ext_bcache_lock()
129+
{
130+
mutex_lock(&ext_bcache_mutex);
131+
}
132+
133+
static void ext_bcache_unlock()
134+
{
135+
mutex_unlock(&ext_bcache_mutex);
136+
}
137+
99138
static int
100139
ext_mount(struct mount *mp, const char *dev, int flags, const void *data)
101140
{
102141
struct device *device;
103142

104143
const char *dev_name = dev + 5;
105-
kprintf("[ext4] Trying to open device: [%s]\n", dev_name);
144+
ext_debug("Trying to open device: [%s]\n", dev_name);
106145
int error = device_open(dev_name, DO_RDWR, &device);
107146

108147
if (error) {
109148
kprintf("[ext4] Error opening device!\n");
110149
return error;
111150
}
112151

152+
mutex_init(&ext_inode_alloc_mutex);
153+
ext_fs.inode_alloc_lock = ext_inode_alloc_lock;
154+
ext_fs.inode_alloc_unlock = ext_inode_alloc_unlock;
155+
156+
mutex_init(&ext_block_alloc_mutex);
157+
ext_fs.block_alloc_lock = ext_block_alloc_lock;
158+
ext_fs.block_alloc_unlock = ext_block_alloc_unlock;
159+
160+
mutex_init(&ext_bcache_mutex);
161+
ext_fs.bcache_lock = ext_bcache_lock;
162+
ext_fs.bcache_unlock = ext_bcache_unlock;
163+
113164
ext4_dmask_set(DEBUG_ALL);
114165
//
115166
// Save a reference to the filesystem
@@ -119,7 +170,7 @@ ext_mount(struct mount *mp, const char *dev, int flags, const void *data)
119170
ext_blockdev.part_size = device->size;
120171
ext_blockdev.bdif->ph_bcnt = ext_blockdev.part_size / ext_blockdev.bdif->ph_bsize;
121172

122-
kprintf("[ext4] Trying to mount ext4 on device: [%s] with size:%ld\n", dev_name, device->size);
173+
ext_debug("Trying to mount ext4 on device: [%s] with size:%ld\n", dev_name, device->size);
123174
int r = ext4_block_init(&ext_blockdev);
124175
if (r != EOK)
125176
return r;
@@ -156,7 +207,6 @@ ext_mount(struct mount *mp, const char *dev, int flags, const void *data)
156207
mp->m_root->d_vnode->v_ino = EXT4_INODE_ROOT_INDEX;
157208

158209
kprintf("[ext4] Mounted ext4 on device: [%s] with code:%d\n", dev_name, r);
159-
printf("WARNING: The ext4 filesystem driver is considered alpha and is NOT thread-safe\n");
160210
return r;
161211
}
162212

@@ -169,9 +219,10 @@ ext_unmount(struct mount *mp, int flags)
169219
ext4_bcache_fini_dynamic(&ext_block_cache);
170220
}
171221

172-
r = ext4_block_fini(&ext_blockdev);
173-
kprintf("[ext4] Trying to unmount ext4 (after %d)!\n", r);
174-
return device_close((struct device*)ext_blockdev.bdif->p_user);
222+
ext4_block_fini(&ext_blockdev);
223+
r = device_close((struct device*)ext_blockdev.bdif->p_user);
224+
kprintf("[ext4] Unmounted filesystem with: %d!\n", r);
225+
return r;
175226
}
176227

177228
static int
@@ -183,7 +234,7 @@ ext_sync(struct mount *mp)
183234
static int
184235
ext_statfs(struct mount *mp, struct statfs *statp)
185236
{
186-
kprintf("[ext4] statfs\n");
237+
ext_debug("statfs\n");
187238
struct ext4_fs *fs = (struct ext4_fs *)mp->m_data;
188239
statp->f_bsize = ext4_sb_get_block_size(&fs->sb);
189240

0 commit comments

Comments
 (0)