int lafs_read_virtual(struct lafs *, char *, loff_t);
int lafs_sched_blk(struct lafs_blk *);
+int lafs_dirty_blk(struct lafs_dblk *);
int lafs_write_dev(struct lafs_device *dev);
int lafs_write_state(struct lafs *fs);
void lafs_incorporate(struct lafs_iblk *ib);
void lafs_cluster_allocate(struct lafs_blk *b, int cnum);
void lafs_cluster_flush(struct lafs *fs, int cnum);
+void lafs_flush_inode(struct lafs_ino *inode);
+void lafs_flush(struct lafs *lafs);
int lafs_new_segment(struct lafs *, int cnum);
struct lafs_device *lafs_dev_find(struct lafs *fs, loff_t virt);
void lafs_allocated_block(struct lafs_blk *b, loff_t addr);
return container_of(b, struct lafs_iblk, b);
}
-static inline int lafs_dirty_blk(struct lafs_blk *blk)
-{
- blk->flags |= B_Dirty;
- return lafs_sched_blk(blk);
-}
-
static inline uint64_t lafs_encode_timeval(struct timeval *tm)
{
uint64_t nano = tm->tv_usec * 1000;
struct lafs_iblk *iblock;
int inum;
struct lafs_ino *filesys;
+ struct list_head dirty; /* blocks that might be dirty, or might belong
+ * to inodes with dirty blocks.
+ */
u32 cblocks, /* data blocks which are commited to this file */
ablocks, /* data blocks that are allocated */
db->b.flags |= B_Valid;
ino = lafs_import_inode(db);
- lafs_dirty_blk(&db->b);
+ lafs_sched_blk(&db->b);
return ino;
}
struct lafs_cluster *wc;
if (!(b->flags & B_Dirty))
abort();
- if (!(b->flags & B_Sched))
- abort();
if (!(b->flags & B_Index) &&
b->ino->type == TypeInodeFile &&
b->ino->iblock == iblk(b)) {
/* InoIdx block - cannot write that, must write the
* data block instead */
- lafs_dirty_blk(&b->ino->dblock->b);
+ lafs_sched_blk(&b->ino->dblock->b);
de_sched(b);
return;
}
wc = &fs->wc[cnum];
if (wc->remaining == 0) {
- /* FIXME lafs_cluster_flush(fs, cnum) ?? */
+ lafs_cluster_flush(fs, cnum);
lafs_new_segment(fs, cnum);
if (!wc->remaining)
abort();
--- /dev/null
+
+/*
+ * mark a block for writeout eventually.
+ */
+
+#include <lafs/lafs.h>
+
+#include <stdio.h>
+#include "internal.h"
+
+int lafs_dirty_blk(struct lafs_dblk *db)
+{
+ int was_empty;
+
+ if (db->b.flags & B_Dirty)
+ return 0;
+
+ if (lafs_find_dblk(db) < 0)
+ return -1;
+
+ db->b.flags |= B_Dirty;
+ if (db->b.flags & B_Sched)
+ return 0;
+
+ trace(1, "dirty %p\n", db);
+ do {
+ was_empty = list_empty(&db->b.ino->dirty);
+ list_move_tail(&db->b.leafs, &db->b.ino->dirty);
+ db = db->b.ino->dblock;
+ } while (db && was_empty && db != db->b.ino->dblock);
+ return 0;
+}
--- /dev/null
+/*
+ * Flush all dirty blocks in an inode to write cluster
+ */
+#include <lafs/lafs.h>
+#include "internal.h"
+
+void lafs_flush_inode(struct lafs_ino *inode)
+{
+ struct lafs_blk *blk;
+ struct list_head *tmp;
+ struct lafs_ino *ino;
+ list_for_each_entry_safe(blk, tmp, &inode->dirty, leafs) {
+ if (!(blk->flags & B_Index) &&
+ blk->ino->type == TypeInodeFile &&
+ (ino = dblk(blk)->my_inode) != NULL &&
+ !list_empty(&ino->dirty))
+ lafs_flush_inode(ino);
+ else if (!(blk->flags & B_Dirty))
+ list_del_init(&blk->leafs);
+
+ if ((blk->flags & B_Dirty) &&
+ !(blk->flags & B_Sched))
+ lafs_cluster_allocate(blk, 0);
+ }
+}
+
+void lafs_flush(struct lafs *lafs)
+{
+ struct lafs_ino *fsys = lafs->ss.root;
+
+ if (fsys)
+ lafs_flush_inode(fsys);
+}
+
blk->b.physaddr = fs->ss.root_addr;
blk->my_inode = ino;
if (blk->b.physaddr == 0)
- lafs_dirty_blk(&blk->b);
+ lafs_sched_blk(&blk->b);
fs->ss.root = ino;
return ino;
}
bnum = imap->md.inodemap.size;
imap->md.inodemap.size = bnum+1;
db = lafs_dblk(imap, bnum);
- lafs_dirty_blk(&db->b);
+ lafs_sched_blk(&db->b);
memset(db->b.data, 0xff, fs->blocksize);
db->b.flags |= B_Valid;
}
lafs_load_dblk(db);
bit = find_first_bit(db->b.data, fs->blocksize);
if (bit < fs->blocksize * 8) {
- lafs_dirty_blk(&db->b);
+ lafs_sched_blk(&db->b);
clear_c_bit(bit, (unsigned char *)db->b.data);
if (*(u32*)(db->b.data) == 0
&& db->b.data[fs->blocksize-1] == 0 &&
inum -= blknum * fs->blocksize * 8;
set_c_bit(inum, (unsigned char *)db->b.data);
/* FIXME if block is now empty, possibly contract file */
- lafs_dirty_blk(&db->b);
+ lafs_sched_blk(&db->b);
return 0;
}
return 1;
clear_c_bit(inum, (unsigned char*)db->b.data);
/* FIXME if block is now empty, punch a hole */
- lafs_dirty_blk(&db->b);
+ lafs_sched_blk(&db->b);
return 0;
}
ino->fs = fs;
ino->inum = inum;
ino->filesys = parent;
+ INIT_LIST_HEAD(&ino->dirty);
if (inode_load(ino, (struct la_inode *)buf))
/* FIXME callers of this should reparent it to themselves. */
}
trace(1, "incorporate %d/%lld\n", ib->b.ino->dblock->b.ino->inum,
(long long)ib->b.ino->dblock->b.fileaddr);
- lafs_dirty_blk(&ib->b);
+ lafs_sched_blk(&ib->b);
}
lafs_load_dblk(db);
p = (void*)db->b.data;
p[seg % (fs->blocksize/2)] = __cpu_to_le16(youth);
- lafs_dirty_blk(&db->b);
+ lafs_sched_blk(&db->b);
}
int lafs_new_segment(struct lafs *fs, int cnum)
{
struct lafs *fs = blk->ino->fs;
+ blk->flags |= B_Dirty;
if (blk->flags & B_Sched)
return 0;
if (blk->parent)
blk->parent->sched_cnt++;
trace(1, "schedule %p\n", blk);
- list_add(&blk->leafs, &fs->leafs);
+ list_move_tail(&blk->leafs, &fs->leafs);
return 0;
}
cnt = __le16_to_cpu(p[seg % (fs->blocksize/2)]);
cnt += diff;
p[seg % (fs->blocksize/2)] = __cpu_to_le16(cnt);
- lafs_dirty_blk(&db->b);
+ lafs_sched_blk(&db->b);
}
printf("\n");
}
+/****** FLUSH ******/
+static char help_flush[] = "Flush out all changes to one or all files";
+static struct args args_flush[] = {
+ { "PATH", internal, -1, {NULL}, "Path to inode to flush"},
+ { "-inum", opaque, 0, {NULL}, "Inode number to flush"},
+ TERMINAL_ARG
+};
+static void c_flush(struct state *st, void **args)
+{
+ struct lafs_ino *inode;
+ if (!args[1]) {
+ lafs_flush(st->lafs);
+ lafs_cluster_flush(st->lafs, 0);
+ if (st->verbose)
+ printf("Filesystem flushed\n");
+ return;
+ }
+ if (st->lafs->ss.root == 0) {
+ printf("show inode: filesytem not ready\n");
+ return;
+ }
+ inode = lafs_get_itable(st->lafs);
+ if (args[2]) {
+ char *inostr = args[2];
+ char *endp;
+ int ino = strtoul(inostr, &endp, 10);
+ if (endp == inostr || *endp) {
+ printf("flush: %s is not a valid inode number\n",
+ inostr);
+ return;
+ }
+ if (ino)
+ inode = lafs_get_inode(inode, ino);
+ if (!inode)
+ printf("flush: cannot find inode %d\n",ino);
+ } else {
+ char *path = args[1];
+ inode = lafs_get_inode(inode, 2);
+ inode = lafs_lookup_path(inode, inode, path, NULL);
+
+ if (!inode) {
+ printf("flush: cannot find inode for %s\n", path);
+ return;
+ }
+ }
+ lafs_flush_inode(inode);
+ lafs_cluster_flush(st->lafs, 0);
+ if (st->verbose)
+ printf("Inode %d flushed\n", (int)inode->inum);
+}
+
+/***********************************************************/
/* list of all commands - preferably in alphabetical order */
#define CMD(x) {#x, c_##x, args_##x, help_##x}
static struct cmd lafs_cmds[] = {
{"?", c_help, args_help, help_help},
CMD(add_device),
CMD(exit),
+ CMD(flush),
CMD(help),
CMD(load_dev),
CMD(ls),