From: NeilBrown Date: Fri, 25 Mar 2011 21:32:10 +0000 (+1100) Subject: Support flushing blocks without forcing them into a checkpoint. X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=080744909639b6b48be3b0dfb1fec16576b7c688;p=lafs-utils.git Support flushing blocks without forcing them into a checkpoint. Each inode has a list of blocks that are either dirty or own and inode which has a list of blocks. Then 'flush' can go through this list and flush them to a write_cluster. Signed-off-by: NeilBrown --- diff --git a/include/lafs/lafs.h b/include/lafs/lafs.h index 874d2d5..792c804 100644 --- a/include/lafs/lafs.h +++ b/include/lafs/lafs.h @@ -49,6 +49,7 @@ struct lafs_ino *lafs_import_inode(struct lafs_dblk *db); 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); @@ -56,6 +57,8 @@ int lafs_checkpoint(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); @@ -110,12 +113,6 @@ static inline struct lafs_iblk *iblk(struct lafs_blk *b) 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; diff --git a/include/lafs/struct.h b/include/lafs/struct.h index 1d90850..9e66ef5 100644 --- a/include/lafs/struct.h +++ b/include/lafs/struct.h @@ -89,6 +89,9 @@ struct lafs_ino { 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 */ diff --git a/lib/lafs_add_inode.c b/lib/lafs_add_inode.c index 9ddd6fe..62b9efc 100644 --- a/lib/lafs_add_inode.c +++ b/lib/lafs_add_inode.c @@ -20,6 +20,6 @@ struct lafs_ino *lafs_add_inode(struct lafs_ino *fsys, int inum, int type) db->b.flags |= B_Valid; ino = lafs_import_inode(db); - lafs_dirty_blk(&db->b); + lafs_sched_blk(&db->b); return ino; } diff --git a/lib/lafs_cluster_allocate.c b/lib/lafs_cluster_allocate.c index 96acc4f..3e5e627 100644 --- a/lib/lafs_cluster_allocate.c +++ b/lib/lafs_cluster_allocate.c @@ -18,8 +18,6 @@ void lafs_cluster_allocate(struct lafs_blk *b, int cnum) 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 && @@ -31,7 +29,7 @@ void lafs_cluster_allocate(struct lafs_blk *b, int cnum) 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; } @@ -40,7 +38,7 @@ void lafs_cluster_allocate(struct lafs_blk *b, int cnum) 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(); diff --git a/lib/lafs_dirty_blk.c b/lib/lafs_dirty_blk.c new file mode 100644 index 0000000..f4bb874 --- /dev/null +++ b/lib/lafs_dirty_blk.c @@ -0,0 +1,32 @@ + +/* + * mark a block for writeout eventually. + */ + +#include + +#include +#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; +} diff --git a/lib/lafs_flush_inode.c b/lib/lafs_flush_inode.c new file mode 100644 index 0000000..b84a42b --- /dev/null +++ b/lib/lafs_flush_inode.c @@ -0,0 +1,34 @@ +/* + * Flush all dirty blocks in an inode to write cluster + */ +#include +#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); +} + diff --git a/lib/lafs_get_itable.c b/lib/lafs_get_itable.c index 5356371..9c537ad 100644 --- a/lib/lafs_get_itable.c +++ b/lib/lafs_get_itable.c @@ -37,7 +37,7 @@ struct lafs_ino *lafs_get_itable(struct lafs *fs) 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; } diff --git a/lib/lafs_imap_alloc.c b/lib/lafs_imap_alloc.c index fa05481..414dd8f 100644 --- a/lib/lafs_imap_alloc.c +++ b/lib/lafs_imap_alloc.c @@ -28,7 +28,7 @@ int lafs_imap_alloc(struct lafs_ino *imap) 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; } @@ -37,7 +37,7 @@ int lafs_imap_alloc(struct lafs_ino *imap) 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 && diff --git a/lib/lafs_imap_clr.c b/lib/lafs_imap_clr.c index 94532a4..128c41a 100644 --- a/lib/lafs_imap_clr.c +++ b/lib/lafs_imap_clr.c @@ -22,6 +22,6 @@ int lafs_imap_clr(struct lafs_ino *ino, int inum) 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; } diff --git a/lib/lafs_imap_set.c b/lib/lafs_imap_set.c index 3c46394..651ffc0 100644 --- a/lib/lafs_imap_set.c +++ b/lib/lafs_imap_set.c @@ -34,6 +34,6 @@ int lafs_imap_set(struct lafs_ino *ino, int inum) 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; } diff --git a/lib/lafs_import_inode_buf.c b/lib/lafs_import_inode_buf.c index da6f167..87f0583 100644 --- a/lib/lafs_import_inode_buf.c +++ b/lib/lafs_import_inode_buf.c @@ -26,6 +26,7 @@ struct lafs_ino *lafs_import_inode_buf(struct lafs *fs, 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. */ diff --git a/lib/lafs_incorporate.c b/lib/lafs_incorporate.c index ef5b414..626aded 100644 --- a/lib/lafs_incorporate.c +++ b/lib/lafs_incorporate.c @@ -55,5 +55,5 @@ void lafs_incorporate(struct lafs_iblk *ib) } 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); } diff --git a/lib/lafs_new_segment.c b/lib/lafs_new_segment.c index 2930b00..38c84d8 100644 --- a/lib/lafs_new_segment.c +++ b/lib/lafs_new_segment.c @@ -26,7 +26,7 @@ void set_youth(struct lafs *fs, int dev, loff_t seg, int youth) 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) diff --git a/lib/lafs_sched_blk.c b/lib/lafs_sched_blk.c index 150f0f0..2a740f3 100644 --- a/lib/lafs_sched_blk.c +++ b/lib/lafs_sched_blk.c @@ -13,6 +13,7 @@ int lafs_sched_blk(struct lafs_blk *blk) { struct lafs *fs = blk->ino->fs; + blk->flags |= B_Dirty; if (blk->flags & B_Sched) return 0; @@ -25,6 +26,6 @@ int lafs_sched_blk(struct lafs_blk *blk) 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; } diff --git a/lib/lafs_segment_count.c b/lib/lafs_segment_count.c index 930c7ed..a332c2f 100644 --- a/lib/lafs_segment_count.c +++ b/lib/lafs_segment_count.c @@ -39,7 +39,7 @@ void segment_count(struct lafs *fs, int dev, loff_t seg, int diff) 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); } diff --git a/tools/lafs.c b/tools/lafs.c index c7fe06e..94c2ee9 100644 --- a/tools/lafs.c +++ b/tools/lafs.c @@ -1542,12 +1542,65 @@ static void c_ls(struct state *st, void **args) 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),