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.

Clone this repository (size: 1.3 MB): HTTPS / SSH
$ hg clone http://bitbucket.org/shapor/tux3/
commit 955: d5a5e6bba24e
parent 954: ad641145241f
branch: default
Implement the list for dirty inodes
OGAWA Hirofumi
14 months ago

Changed (Δ1.2 KB):

raw changeset »

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 = &(struct sb){ INIT_SB(dev), .super = { .volblocks = to_be_u64(150) }, };
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

Up to file-list user/btree.c:

@@ -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 = &(struct sb){ INIT_SB(dev), };
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));

Up to file-list user/dir.c:

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 = &(struct sb){ INIT_SB(dev), .super = { .volblocks = to_be_u64(150) }, };
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);

Up to file-list user/iattr.c:

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
		INIT_INODE(sb, 0x666),
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);

Up to file-list user/inode.c:

@@ -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(sb, 0), };
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
	inode_init_once(&((tuxnode_t *)mem)->vfs_inode);
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;

Up to file-list user/super.c:

@@ -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){ INIT_INODE(sb, S_IFDIR | 0755) };
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)

Up to file-list user/tux3.c:

@@ -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;

Up to file-list user/tux3.h:

@@ -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(sb, mode)				\
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(dev), };
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 = &(struct sb){ INIT_SB(dev), };
747
	struct sb *sb = rapid_sb(dev);
748
748
749
749
	sb->volmap = tux_new_volmap(sb);
750
750
	if (!sb->volmap)

Up to file-list user/xattr.c:

@@ -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++) {