shapor / tux3 (http://shapor.com/tux3)
Tux3 is a write-anywhere, atomic commit, btree-based versioning filesystem. It is the spiritual and moral successor of Tux2, the most famous filesystem that was never released. The main purpose of Tux3 is to embody Daniel Phillips's new ideas on storage data versioning. The secondary goal is to provide a more efficient snapshotting and replication method for the Zumastor NAS project, and a tertiary goal is to be better than ZFS.
| commit 955: | d5a5e6bba24e |
| parent 954: | ad641145241f |
| branch: | default |
14 months ago
Changed (Δ1.2 KB):
user/balloc.c (1 lines added, 1 lines removed)
user/btree.c (1 lines added, 1 lines removed)
user/commit.c (2 lines added, 4 lines removed)
user/dir.c (1 lines added, 3 lines removed)
user/filemap.c (2 lines added, 4 lines removed)
user/iattr.c (7 lines added, 5 lines removed)
user/inode.c (11 lines added, 5 lines removed)
user/kernel/super.c (5 lines added, 1 lines removed)
user/kernel/tux3.h (3 lines added, 0 lines removed)
user/super.c (1 lines added, 1 lines removed)
user/tux3.c (2 lines added, 4 lines removed)
user/tux3.h (40 lines added, 21 lines removed)
user/tux3fuse.c (1 lines added, 1 lines removed)
user/tux3graph.c (1 lines added, 1 lines removed)
user/xattr.c (8 lines added, 11 lines removed)
Up to file-list user/balloc.c:
| … | … | @@ -49,7 +49,7 @@ int main(int argc, char *argv[]) |
49 |
49 |
free(bitmap); |
50 |
50 |
} |
51 |
51 |
struct dev *dev = &(struct dev){ .bits = 3 }; |
52 |
struct sb *sb = |
|
52 |
struct sb *sb = rapid_sb(dev, .super = { .volblocks = to_be_u64(150) }); |
|
53 |
53 |
struct inode *bitmap = rapid_open_inode(sb, NULL, 0); |
54 |
54 |
sb->freeblocks = from_be_u64(sb->super.volblocks); |
55 |
55 |
sb->nextalloc = from_be_u64(sb->super.volblocks); // this should wrap around to zero |
| … | … | @@ -161,7 +161,7 @@ static void tree_expand_test(struct curs |
161 |
161 |
int main(int argc, char *argv[]) |
162 |
162 |
{ |
163 |
163 |
struct dev *dev = &(struct dev){ .bits = 6 }; |
164 |
struct sb *sb = |
|
164 |
struct sb *sb = rapid_sb(dev); |
|
165 |
165 |
sb->volmap = rapid_open_inode(sb, NULL, 0); |
166 |
166 |
sb->logmap = rapid_open_inode(sb, dev_errio, 0); |
167 |
167 |
init_buffers(dev, 1 << 20, 0); |
Up to file-list user/commit.c:
| … | … | @@ -135,12 +135,10 @@ int main(int argc, char *argv[]) |
135 |
135 |
assert(!ftruncate(fd, volsize)); |
136 |
136 |
struct dev *dev = &(struct dev){ .fd = fd, .bits = 12 }; |
137 |
137 |
init_buffers(dev, 1 << 20, 0); |
138 |
struct sb *sb = &(struct sb){ |
|
139 |
INIT_SB(dev), |
|
138 |
struct sb *sb = rapid_sb(dev, |
|
140 |
139 |
.max_inodes_per_block = 64, |
141 |
140 |
.entries_per_node = 20, |
142 |
.volblocks = volsize >> dev->bits, |
|
143 |
}; |
|
141 |
.volblocks = volsize >> dev->bits); |
|
144 |
142 |
sb->volmap = rapid_open_inode(sb, NULL, 0); |
145 |
143 |
sb->logmap = rapid_open_inode(sb, dev_errio, 0); |
146 |
144 |
assert(!make_tux3(sb)); |
41 |
41 |
#include "tux3.h" /* include user/tux3.h, not user/kernel/tux3.h */ |
42 |
42 |
#include "hexdump.c" |
43 |
43 |
|
44 |
#define mark_inode_dirty(x) |
|
45 |
||
46 |
44 |
#ifndef trace |
47 |
45 |
#define trace trace_off |
48 |
46 |
#endif |
| … | … | @@ -82,7 +80,7 @@ int filldir(void *entry, char *name, uns |
82 |
80 |
int main(int argc, char *argv[]) |
83 |
81 |
{ |
84 |
82 |
struct dev *dev = &(struct dev){ .bits = 8 }; |
85 |
struct sb *sb = |
|
83 |
struct sb *sb = rapid_sb(dev, .super = { .volblocks = to_be_u64(150) }); |
|
86 |
84 |
struct inode *dir = rapid_open_inode(sb, NULL, S_IFDIR); |
87 |
85 |
init_buffers(dev, 1 << 20, 0); |
88 |
86 |
struct buffer_head *buffer; |
Up to file-list user/filemap.c:
| … | … | @@ -175,12 +175,10 @@ int main(int argc, char *argv[]) |
175 |
175 |
if (fdsize64(fd, &size)) |
176 |
176 |
error("fdsize64 failed for '%s' (%s)", name, strerror(errno)); |
177 |
177 |
struct dev *dev = &(struct dev){ .fd = fd, .bits = 8 }; |
178 |
struct sb *sb = &(struct sb){ |
|
179 |
INIT_SB(dev), |
|
178 |
struct sb *sb = rapid_sb(dev, |
|
180 |
179 |
.max_inodes_per_block = 64, |
181 |
180 |
.entries_per_node = 20, |
182 |
.volblocks = size >> dev->bits, |
|
183 |
}; |
|
181 |
.volblocks = size >> dev->bits); |
|
184 |
182 |
sb->volmap = rapid_open_inode(sb, NULL, 0); |
185 |
183 |
sb->logmap = rapid_open_inode(sb, NULL, 0); |
186 |
184 |
sb->bitmap = rapid_open_inode(sb, filemap_extent_io, 0); |
21 |
21 |
int main(int argc, char *argv[]) |
22 |
22 |
{ |
23 |
23 |
unsigned abits = DATA_BTREE_BIT|CTIME_SIZE_BIT|MODE_OWNER_BIT|LINK_COUNT_BIT|MTIME_BIT; |
24 |
struct sb *sb = &(struct sb){ .version = 0, .blocksize = 1 << 9, }; |
|
25 |
struct inode *inode = &(struct inode){ |
|
26 |
|
|
24 |
struct dev *dev = &(struct dev){ .bits = 9 }; |
|
25 |
struct sb *sb = rapid_sb(dev, .version = 0); |
|
26 |
struct inode *inode = rapid_open_inode(sb, NULL, 0x666, |
|
27 |
27 |
.present = abits, .i_uid = 0x12121212, .i_gid = 0x34343434, |
28 |
.btree = { .root = { .block = 0xcaba1f00dULL, .depth = 3 } }, |
|
29 |
28 |
.i_size = 0x123456789ULL, |
30 |
29 |
.i_ctime = spectime(0xdec0debeadULL), |
31 |
.i_mtime = spectime(0xbadfaced00dULL) |
|
30 |
.i_mtime = spectime(0xbadfaced00dULL)); |
|
31 |
inode->btree = (struct btree){ |
|
32 |
.root = { .block = 0xcaba1f00dULL, .depth = 3 } |
|
33 |
}; |
|
32 |
34 |
|
33 |
35 |
char attrs[1000] = { }; |
34 |
36 |
printf("%i attributes starting from %i\n", MAX_ATTRS - MIN_ATTR, MIN_ATTR); |
| … | … | @@ -21,7 +21,7 @@ struct inode *new_inode(struct sb *sb) |
21 |
21 |
struct inode *inode = malloc(sizeof(*inode)); |
22 |
22 |
if (!inode) |
23 |
23 |
goto error; |
24 |
*inode = (struct inode){ INIT_INODE( |
|
24 |
*inode = (struct inode){ INIT_INODE(*inode, sb, 0), }; |
|
25 |
25 |
inode->map = new_map(sb->dev, NULL); |
26 |
26 |
if (!inode->map) |
27 |
27 |
goto error_map; |
| … | … | @@ -274,7 +274,15 @@ int tuxsync(struct inode *inode) |
274 |
274 |
int err; |
275 |
275 |
if ((err = tuxflush(inode))) |
276 |
276 |
return err; |
277 |
#if 0 |
|
278 |
if (!list_empty(&inode->dirty)) { |
|
279 |
list_del_init(&inode->dirty); |
|
280 |
return save_inode(inode); |
|
281 |
} |
|
282 |
return 0; |
|
283 |
#else |
|
277 |
284 |
return save_inode(inode); |
285 |
#endif |
|
278 |
286 |
} |
279 |
287 |
|
280 |
288 |
void tuxclose(struct inode *inode) |
| … | … | @@ -302,12 +310,10 @@ int main(int argc, char *argv[]) |
302 |
310 |
error("fdsize64 failed for '%s' (%s)", name, strerror(errno)); |
303 |
311 |
struct dev *dev = &(struct dev){ .fd = fd, .bits = 12 }; |
304 |
312 |
init_buffers(dev, 1 << 20, 0); |
305 |
struct sb *sb = &(struct sb){ |
|
306 |
INIT_SB(dev), |
|
313 |
struct sb *sb = rapid_sb(dev, |
|
307 |
314 |
.max_inodes_per_block = 64, |
308 |
315 |
.entries_per_node = 20, |
309 |
.volblocks = size >> dev->bits, |
|
310 |
}; |
|
316 |
.volblocks = size >> dev->bits); |
|
311 |
317 |
sb->volmap = rapid_open_inode(sb, NULL, 0); |
312 |
318 |
sb->logmap = rapid_open_inode(sb, NULL, 0); |
313 |
319 |
Up to file-list user/kernel/super.c:
| … | … | @@ -12,7 +12,9 @@ static struct kmem_cache *tux_inode_cach |
12 |
12 |
|
13 |
13 |
static void tux3_inode_init_once(void *mem) |
14 |
14 |
{ |
15 |
|
|
15 |
tuxnode_t *tuxi = mem; |
|
16 |
INIT_LIST_HEAD(&tuxi->dirty); |
|
17 |
inode_init_once(&tuxi->vfs_inode); |
|
16 |
18 |
} |
17 |
19 |
|
18 |
20 |
static int __init tux3_init_inodecache(void) |
| … | … | @@ -39,6 +41,7 @@ static struct inode *tux3_alloc_inode(st |
39 |
41 |
tuxi->btree = (struct btree){ }; |
40 |
42 |
tuxi->present = 0; |
41 |
43 |
tuxi->xcache = NULL; |
44 |
BUG_ON(!list_empty(&tuxi->dirty)); |
|
42 |
45 |
|
43 |
46 |
/* uninitialized stuff by alloc_inode() */ |
44 |
47 |
tuxi->vfs_inode.i_version = 1; |
| … | … | @@ -157,6 +160,7 @@ static int tux3_fill_super(struct super_ |
157 |
160 |
sb->s_time_gran = 1; |
158 |
161 |
|
159 |
162 |
mutex_init(&sbi->loglock); |
163 |
INIT_LIST_HEAD(&sbi->dirty_inodes); |
|
160 |
164 |
|
161 |
165 |
err = -EIO; |
162 |
166 |
blocksize = sb_min_blocksize(sb, BLOCK_SIZE); |
Up to file-list user/kernel/tux3.h:
| … | … | @@ -321,6 +321,7 @@ struct sb { |
321 |
321 |
unsigned char *logpos, *logtop; /* Where to emit next log entry */ |
322 |
322 |
struct mutex loglock; /* serialize log entries (spinlock me) */ |
323 |
323 |
struct stash defree; /* defer extent frees until affer commit */ |
324 |
struct list_head dirty_inodes; /* dirty inodes list */ |
|
324 |
325 |
#ifdef __KERNEL__ |
325 |
326 |
struct super_block *vfs_sb; /* Generic kernel superblock */ |
326 |
327 |
#else |
| … | … | @@ -350,6 +351,7 @@ typedef struct { |
350 |
351 |
inum_t inum; /* Inode number. Fixme: also in generic inode */ |
351 |
352 |
unsigned present; /* Attributes decoded from or to be encoded to inode table */ |
352 |
353 |
struct xcache *xcache; /* Extended attribute cache */ |
354 |
struct list_head dirty; /* link for dirty inodes */ |
|
353 |
355 |
struct inode vfs_inode; /* Generic kernel inode */ |
354 |
356 |
} tuxnode_t; |
355 |
357 |
|
| … | … | @@ -396,6 +398,7 @@ typedef struct inode { |
396 |
398 |
inum_t inum; |
397 |
399 |
unsigned present; |
398 |
400 |
struct xcache *xcache; |
401 |
struct list_head dirty; |
|
399 |
402 |
struct sb *i_sb; |
400 |
403 |
map_t *map; |
401 |
404 |
loff_t i_size; |
| … | … | @@ -75,7 +75,7 @@ static int clear_other_magic(struct sb * |
75 |
75 |
|
76 |
76 |
int make_tux3(struct sb *sb) |
77 |
77 |
{ |
78 |
struct inode *dir = &(struct inode){ |
|
78 |
struct inode *dir = &(struct inode){ .i_sb = sb, .i_mode = S_IFDIR | 0755 }; |
|
79 |
79 |
|
80 |
80 |
int err = clear_other_magic(sb); |
81 |
81 |
if (err) |
| … | … | @@ -70,13 +70,11 @@ int main(int argc, const char *argv[]) |
70 |
70 |
struct dev *dev = &(struct dev){ fd, .bits = blockbits }; |
71 |
71 |
init_buffers(dev, 1 << 20, 1); |
72 |
72 |
|
73 |
struct sb *sb = &(struct sb){ |
|
74 |
INIT_SB(dev), |
|
73 |
struct sb *sb = rapid_sb(dev, |
|
75 |
74 |
.max_inodes_per_block = 64, |
76 |
75 |
.entries_per_node = 20, |
77 |
76 |
.volblocks = volsize >> dev->bits, |
78 |
.freeblocks = volsize >> dev->bits, |
|
79 |
}; |
|
77 |
.freeblocks = volsize >> dev->bits); |
|
80 |
78 |
sb->volmap = tux_new_volmap(sb); |
81 |
79 |
if (!sb->volmap) |
82 |
80 |
goto eek; |
| … | … | @@ -178,35 +178,54 @@ struct tux_iattr { |
178 |
178 |
void change_begin(struct sb *sb); |
179 |
179 |
void change_end(struct sb *sb); |
180 |
180 |
|
181 |
#define INIT_INODE( |
|
181 |
#define INIT_INODE(inode, sb, mode) \ |
|
182 |
182 |
.i_sb = sb, \ |
183 |
183 |
.i_mode = mode, \ |
184 |
184 |
.i_mutex = __MUTEX_INITIALIZER, \ |
185 |
185 |
.i_version = 1, \ |
186 |
.i_nlink = 1 |
|
186 |
.i_nlink = 1, \ |
|
187 |
.dirty = LIST_HEAD_INIT((inode).dirty) |
|
187 |
188 |
|
188 |
#define rapid_open_inode(sb, io, mode) ({ \ |
|
189 |
struct inode *__inode = &(struct inode){ \ |
|
190 |
INIT_INODE(sb, mode), \ |
|
191 |
.btree = { \ |
|
192 |
.lock = __RWSEM_INITIALIZER, \ |
|
193 |
}, \ |
|
194 |
}; \ |
|
195 |
__inode->map = new_map((sb)->dev, io); \ |
|
196 |
assert(__inode->map); \ |
|
197 |
__inode->map->inode = __inode; \ |
|
198 |
__inode; \ |
|
199 |
}) |
|
189 |
#define INIT_SB(sb, dev) \ |
|
190 |
.dev = dev, \ |
|
191 |
.blockbits = (dev)->bits, \ |
|
192 |
.blocksize = 1 << (dev)->bits, \ |
|
193 |
.blockmask = ((1 << (dev)->bits) - 1), \ |
|
194 |
.delta_lock = __RWSEM_INITIALIZER, \ |
|
195 |
.loglock = __MUTEX_INITIALIZER, \ |
|
196 |
.dirty_inodes = LIST_HEAD_INIT((sb).dirty_inodes) |
|
200 |
197 |
|
201 |
#define INIT_SB(dev) \ |
|
202 |
.dev = dev, \ |
|
203 |
.blockbits = (dev)->bits, \ |
|
204 |
.blocksize = 1 << (dev)->bits, \ |
|
205 |
.blockmask = ((1 << (dev)->bits) - 1), \ |
|
206 |
.delta_lock = __RWSEM_INITIALIZER, \ |
|
207 |
.loglock = __MUTEX_INITIALIZER |
|
198 |
#define rapid_open_inode(sb, io, mode, init_defs...) ({ \ |
|
199 |
struct inode *__inode = &(struct inode){}; \ |
|
200 |
*__inode = (struct inode){ \ |
|
201 |
INIT_INODE(*__inode, sb, mode), \ |
|
202 |
.btree = { \ |
|
203 |
.lock = __RWSEM_INITIALIZER, \ |
|
204 |
}, \ |
|
205 |
init_defs \ |
|
206 |
}; \ |
|
207 |
__inode->map = new_map((sb)->dev, io); \ |
|
208 |
assert(__inode->map); \ |
|
209 |
__inode->map->inode = __inode; \ |
|
210 |
__inode; \ |
|
211 |
}) |
|
212 |
||
213 |
#define rapid_sb(dev, init_defs...) ({ \ |
|
214 |
struct sb *__sb = &(struct sb){}; \ |
|
215 |
*__sb = (struct sb){ \ |
|
216 |
INIT_SB(*__sb, dev), \ |
|
217 |
init_defs \ |
|
218 |
}; \ |
|
219 |
__sb; \ |
|
220 |
}); |
|
208 |
221 |
|
209 |
222 |
enum { DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK }; |
210 |
223 |
typedef int (filldir_t)(void *dirent, char *name, unsigned namelen, loff_t offset, unsigned inode, unsigned type); |
211 |
224 |
|
225 |
static inline void mark_inode_dirty(struct inode *inode) |
|
226 |
{ |
|
227 |
if (list_empty(&inode->dirty)) |
|
228 |
list_add_tail(&inode->dirty, &inode->i_sb->dirty_inodes); |
|
229 |
} |
|
230 |
||
212 |
231 |
#endif |
Up to file-list user/tux3fuse.c:
| … | … | @@ -367,7 +367,7 @@ static void tux3_init(void *data, struct |
367 |
367 |
*dev = (struct dev){ .fd = fd, .bits = 12 }; |
368 |
368 |
init_buffers(dev, 1<<20, 1); |
369 |
369 |
sb = malloc(sizeof(*sb)); |
370 |
*sb = (struct sb){ INIT_SB( |
|
370 |
*sb = (struct sb){ INIT_SB(*sb, dev), }; |
|
371 |
371 |
sb->volmap = tux_new_volmap(sb); |
372 |
372 |
if (!sb->volmap) |
373 |
373 |
goto eek; |
Up to file-list user/tux3graph.c:
| … | … | @@ -744,7 +744,7 @@ int main(int argc, const char *argv[]) |
744 |
744 |
}; |
745 |
745 |
init_buffers(dev, 1 << 20, 1); |
746 |
746 |
|
747 |
struct sb *sb = |
|
747 |
struct sb *sb = rapid_sb(dev); |
|
748 |
748 |
|
749 |
749 |
sb->volmap = tux_new_volmap(sb); |
750 |
750 |
if (!sb->volmap) |
| … | … | @@ -30,21 +30,18 @@ int main(int argc, char *argv[]) |
30 |
30 |
struct dev *dev = &(struct dev){ .bits = 8, .fd = open(argv[1], O_CREAT|O_RDWR, S_IRWXU) }; |
31 |
31 |
ftruncate(dev->fd, 1 << 24); |
32 |
32 |
init_buffers(dev, 1 << 20, 0); |
33 |
struct sb *sb = &(struct sb){ |
|
34 |
INIT_SB(dev), |
|
33 |
struct sb *sb = rapid_sb(dev, |
|
35 |
34 |
.version = 0, |
36 |
35 |
.atomref_base = 1 << 10, |
37 |
36 |
.unatom_base = 1 << 11, |
38 |
.atomgen = 1 |
|
37 |
.atomgen = 1); |
|
38 |
struct inode *inode = rapid_open_inode(sb, NULL, S_IFDIR | 0x666, |
|
39 |
.present = abits, .i_uid = 0x12121212, .i_gid = 0x34343434, |
|
40 |
.i_ctime = spectime(0xdec0debeadULL), |
|
41 |
.i_mtime = spectime(0xbadfaced00dULL)); |
|
42 |
inode->btree = (struct btree){ |
|
43 |
.root = { .block = 0xcaba1f00dULL, .depth = 3 } |
|
39 |
44 |
}; |
40 |
struct inode *inode = &(struct inode){ |
|
41 |
INIT_INODE(sb, S_IFDIR | 0x666), |
|
42 |
.present = abits, .i_uid = 0x12121212, .i_gid = 0x34343434, |
|
43 |
.btree = { .root = { .block = 0xcaba1f00dULL, .depth = 3 } }, |
|
44 |
.i_ctime = spectime(0xdec0debeadULL), |
|
45 |
.i_mtime = spectime(0xbadfaced00dULL) }; |
|
46 |
inode->map = new_map(dev, NULL); |
|
47 |
inode->map->inode = inode; |
|
48 |
45 |
sb->atable = inode; |
49 |
46 |
|
50 |
47 |
for (int i = 0; i < 2; i++) { |
