ifneq ($(KERNELRELEASE),)
# kbuild part
-CFLAGS += -Werror -DDUMP
+EXTRA_CFLAGS += -Werror -DDUMP
obj-m += lafs.o
lafs-y := super.o io.o roll.o dir.o inode.o index.o block.o file.o link.o dir-avl.o \
else
-KERNELDIR := /home/src/lafs-2.6.23
+KERNELDIR := /home/src/lafs-2.6.27
all::
$(MAKE) -C $(KERNELDIR) ARCH=i386 M=`pwd`
nm lafs.o | grep ' T ' | grep -v lafs_
This is good as it motivates the code to handle block splitting in
the Btree. But it shouldn't happen.
+ ....
+ Block spliting might work - it doesn't crash at least.
+ But
+ After deleting all files, the tree is full of stuff.
+ Lots of inode data/InoIdx blocks.
+ Many but not all a Pinned. The others are OnFree
+ The Pinned ones have outstanding references.
+ Others
+
+ ....
+ Problem with the block splitting, when adding an index block.
+ The index block is initially empty - we need to find things by looking
+ at children. But we don't. We BUG_ON the iphys==0.
+ In general, when we add a block below and index block and before we incorporate,
+ the block must be found by finding the first indexed block and looking to
+ see if there is a 'next' block that contains the address we need.
+ FIXED
+
+ But if we truncate a file while an index block is pinned and dirty,
+ we spin on trying to incorporate it, which should make it empty.
+
--------------------------------------------------
I don't remember what this is about.....
CLEANABLE: 0/5 y=32777 u=7
int err = 0;
struct fs *fs = fs_from_inode(b->inode);
+ if (!test_bit(B_PhysValid, &b->flags))
+ b->physaddr = 0;
+
if (test_bit(B_Index, &b->flags))
BUG_ON(b->parent == NULL && !test_bit(B_Root, &b->flags));
else
if (!b->b.parent) {
printk("erase with no parent: %s\n", strblk(&b->b));
}
- printk("Eraseblock for %s\n", strblk(&b->b));
+ dprintk("Eraseblock for %s\n", strblk(&b->b));
if (b->b.physaddr == 0 &&
b->b.fileaddr == 0 &&
LAFSI(b->b.inode)->depth == 0) {
{
static char ans[200];
ans[0] = 0;
- if (test_bit(B_Index, &b->flags)) strcat(ans, "Index,");
+ if (test_bit(B_Index, &b->flags)) sprintf(ans, "Index(%d),", iblk(b)->depth);
if (test_bit(B_Alloc, &b->flags)) strcat(ans, "Alloc,");
if (test_bit(B_Pinned, &b->flags)) {
strcat(ans, "Pinned,");
int j;
struct block *b2;
int credits = 0;
+
if (depth > 20) { printk("... aborting at %d\n", depth); BUG();return 0;}
printk("%*s", depth, "");
if (test_bit(B_Index, &b->flags)) {
list_for_each_entry(b, &ib->children, siblings) {
+ BUG_ON(b->parent != ib);
credits += print_tree(b, depth+2);
}
} else if (LAFSI(b->inode)->type == TypeInodeFile &&
dprintk("Block %d/%d idx=%d\n", (int)b->inode->i_ino, (int)b->fileaddr,
test_bit(B_Index, &b->flags));
-//printk("(");
+dprintk("(");
if (!test_bit(B_Pinned, &b->flags))
/* Haven't refiled since we cleared that */ ;
else if (!!test_bit(B_Phase1, &b->flags) == oldphase) {
WARN_ON(1);
/* FIXME is this possible? */
}
-//printk(")");
+dprintk(")");
putref(b);
// lafs_dump_tree();
if (list_empty(&fs->phase_leafs[oldphase])) {
void lafs_cluster_wait_all(struct fs *fs);
lafs_cluster_flush(fs, 0);
lafs_cluster_wait_all(fs);
+ lafs_clusters_done(fs);
}
cnt++;
#if 0
*/
int err = PTR_ERR(ino);
ino = NULL;
- //printk("iget gives error %d\n", err);
+ dprintk("iget gives error %d\n", err);
if (err != -EAGAIN) {
/* inode not found */
tc->desc++;
* of 4 depending on which in the circular list the
* block is for.
*/
-static int cluster_end_io(struct bio *bio, unsigned int len, int err,
+static void cluster_end_io(struct bio *bio, int err,
int which, int header)
{
/* FIXME how to handle errors? */
struct wc *wc = bio->bi_private;
int wake = 0;
- dprintk("end_io len=%d err=%d which=%d header=%d\n",
- len, err, which, header);
- if (bio->bi_size)
- return 1;
+ dprintk("end_io err=%d which=%d header=%d\n",
+ err, which, header);
if (atomic_dec_and_test(&wc->pending_cnt[which]))
wake++;
schedule_work(&fs->done_work);
wake_up(&wc->pending_wait);
}
- return 0;
}
-static int cluster_endio_data_0(struct bio *bio, unsigned int len, int err)
+static void cluster_endio_data_0(struct bio *bio, int err)
{
- return cluster_end_io(bio, len, err, 0, 0);
+ cluster_end_io(bio, err, 0, 0);
}
-static int cluster_endio_data_1(struct bio *bio, unsigned int len, int err)
+static void cluster_endio_data_1(struct bio *bio, int err)
{
- return cluster_end_io(bio, len, err, 1, 0);
+ cluster_end_io(bio, err, 1, 0);
}
-static int cluster_endio_data_2(struct bio *bio, unsigned int len, int err)
+static void cluster_endio_data_2(struct bio *bio, int err)
{
- return cluster_end_io(bio, len, err, 2, 0);
+ cluster_end_io(bio, err, 2, 0);
}
-static int cluster_endio_data_3(struct bio *bio, unsigned int len, int err)
+static void cluster_endio_data_3(struct bio *bio, int err)
{
- return cluster_end_io(bio, len, err, 3, 0);
+ cluster_end_io(bio, err, 3, 0);
}
-static int cluster_endio_header_0(struct bio *bio, unsigned int len, int err)
+static void cluster_endio_header_0(struct bio *bio, int err)
{
- return cluster_end_io(bio, len, err, 0, 1);
+ cluster_end_io(bio, err, 0, 1);
}
-static int cluster_endio_header_1(struct bio *bio, unsigned int len, int err)
+static void cluster_endio_header_1(struct bio *bio, int err)
{
- return cluster_end_io(bio, len, err, 1, 1);
+ cluster_end_io(bio, err, 1, 1);
}
-static int cluster_endio_header_2(struct bio *bio, unsigned int len, int err)
+static void cluster_endio_header_2(struct bio *bio, int err)
{
- return cluster_end_io(bio, len, err, 2, 1);
+ cluster_end_io(bio, err, 2, 1);
}
-static int cluster_endio_header_3(struct bio *bio, unsigned int len, int err)
+static void cluster_endio_header_3(struct bio *bio, int err)
{
- return cluster_end_io(bio, len, err, 3, 1);
+ cluster_end_io(bio, err, 3, 1);
}
bio_end_io_t *lafs_cluster_endio_choose(int which, int header)
/* If any block is dirty, flush the cluster so that
* writeback completes.
*/
- struct inode *ino = page->mapping->host;
- struct fs *fs = fs_from_inode(ino);
- int bits = PAGE_SHIFT - ino->i_blkbits;
- int i;
+ struct inode *ino;
+ struct address_space *mapping;
+ struct fs *fs;
+ int bits;
+// int i;
+ mapping = page->mapping;
+ if (!mapping)
+ return;
+ ino = mapping->host;
+ fs = fs_from_inode(ino);
+ bits = PAGE_SHIFT - ino->i_blkbits;
+
+#if 0
for (i=0; i < (1<<bits); i++) {
struct datablock *b = lafs_get_block(ino, i, page,
GFP_KERNEL);
}
putdref(b);
}
+#else
+ if (!lafs_cluster_empty(fs, 0))
+ lafs_cluster_flush(fs, 0);
+#endif
}
struct file_operations lafs_file_file_operations = {
new->b.inode = ino;
new->depth = depth;
new->b.physaddr = phys;
+ set_bit(B_PhysValid, &new->b.flags);
ib = ihash_lookup(ino, addr, depth, new);
if (ib != new)
b->parent = NULL;
spin_lock(&b->inode->i_mapping->private_lock);
list_del_init(&b->siblings);
+ if (test_bit(B_InoIdx, &b->flags) && 0 &&
+ !test_bit(B_Root, &b->flags) &&
+ LAFSI(b->inode)->iblock == iblk(b)) {
+ LAFSI(b->inode)->iblock = NULL;
+ BUG_ON(LAFSI(b->inode)->dblock->b.parent != iblk(next));
+ next = &LAFSI(b->inode)->dblock->b;
+ }
spin_unlock(&b->inode->i_mapping->private_lock);
if (test_bit(B_Index, &b->flags)) {
//printk("7a");
if (test_and_clear_bit(B_NICredit, &b->flags))
credits++;
lafs_space_return(fs, credits);
- if (b->inode->i_ino == 0 && b->fileaddr == 0) printk("E Dropped credit for %s\n", strblk(b));
+ if (b->inode->i_ino == 0 && b->fileaddr == 0)
+ printk("E Dropped credit for %s\n", strblk(b));
}
if (test_bit(B_Index, &b->flags) &&
!test_bit(B_Pinned, &b->flags)) {
if (free_me)
kfree(b);
if (next) {
+ BUG_ON(dnext);
b = next;
next = NULL;
} else {
struct fs *fs = fs_from_inode(ino);
int err = 0;
+ dprintk("MAKE_IBLOCK %d\n", (int)ino->i_ino);
+
BUG_ON(lai->dblock == NULL);
BUG_ON(atomic_read(&lai->dblock->b.refcnt) == 0);
retry:
new->b.fileaddr = 0;
new->b.physaddr = lai->dblock->b.physaddr;
+ set_bit(B_PhysValid, &new->b.flags);
new->b.inode = ino;
new->depth = lai->depth;
/* Note: this doesn't get hashed until the index
* find the appropriate index, find the relevant index block,
* load it, and see what's there...
*/
+ dprintk("LEAF FIND %d %d\n", (int)inode->i_ino, (int)li->depth);
depth = li->depth - 1;
buf = map_dblock(li->dblock);
iphys = index_lookup(buf + li->metadata_size,
&iaddr, next);
unmap_dblock(li->dblock, buf);
- /* FIXME if there is corruption, iphys could be zero which will
- * cause problems soon.
- * Actually, this could happen during truncate if indexes are
- * incorporated quickly??? But we should never look for
- * one of those blocks, should we?
+
+ /* If the index block hasn't been incorporated yet,
+ * then we might have found an iaddr before the one we
+ * really want, or even iaddr and iphys might be 0 if
+ * this is a new index block that is totally unincorporated.
*/
- BUG_ON(iphys==0);
ib = iblock_get(inode, iaddr, depth, iphys);
dprintk("lafs_leaf_find: first block at %llu\n",
(unsigned long long) iphys);
- if (!ib)
- return ERR_PTR(-ENOMEM);
+ if (!ib) {
+ if (iphys)
+ return ERR_PTR(-ENOMEM);
+ /* li is empty, but child is no longer around!! */
+ BUG();
+ }
if (! test_bit(B_Linked, &ib->b.flags)) {
/* need to check for peers */
b->b.physaddr = leaf_lookup(buf+offset,
b->b.inode->i_sb->s_blocksize - offset,
ib->b.fileaddr, b->b.fileaddr, NULL);
+ set_bit(B_PhysValid, &b->b.flags);
unmap_iblock(ib, buf);
}
dprintk("lafs_find_block: lookup for %lu of %lu at %lu found %llu\n",
!test_bit(B_Realloc, &blk->flags) &&
phys != 0)
printk("something missing %s\n", strblk(blk));
- BUG_ON(!test_bit(B_UnincCredit, &blk->flags));
+// BUG_ON(!test_bit(B_UnincCredit, &blk->flags));
BUG_ON(!test_bit(B_Dirty, &blk->flags) &&
!test_bit(B_Realloc, &blk->flags) &&
phys != 0);
break;
BUG_ON(i == fs->maxsnapshot);
blk->physaddr = phys; /* superblock doesn't get counted in summaries */
+ set_bit(B_PhysValid, &blk->flags);
fs->ss[i].root_addr = phys;
lai = LAFSI(blk->inode);
if (i == 0 && lai->md.fs.usagetable > 1)
clear_bit(B_Prealloc, &blk->flags);
blk->physaddr = phys;
+ set_bit(B_PhysValid, &blk->flags);
if (test_bit(B_Dirty, &blk->flags) || phys == 0) {
- if (!test_bit(B_Dirty, &p->b.flags) && !test_bit(B_Credit, &p->b.flags))
+ if (!test_bit(B_Dirty, &p->b.flags) && !test_bit(B_Credit, &p->b.flags)) {
printk("Oh dear: %s\n", strblk(blk));
+ printk(".......: %s\n", strblk(&p->b));
+ }
lafs_dirty_iblock(p);
} else {
if (!test_and_set_bit(B_Realloc, &p->b.flags)) {
printk(" for %s\n", strblk(blk));
BUG();
}
- else if (p->b.inode->i_ino == 0 && p->b.fileaddr == 0) printk("F Dropped credit for %s\n", strblk(&p->b));
+ else if (p->b.inode->i_ino == 0 && p->b.fileaddr == 0)
+ printk("F Dropped credit for %s\n", strblk(&p->b));
}
if (!test_and_set_bit(B_UnincCredit, &p->b.flags))
if (!test_and_clear_bit(B_ICredit, &p->b.flags))
void lafs_clear_inode(struct inode *ino)
{
struct lafs_inode *li = LAFSI(ino);
- dprintk("CLEAR INODE\n");
+ dprintk("CLEAR INODE %d\n", (int)ino->i_ino);
li->type = 0;
{
struct fs *fs = fs_from_inode(ino);
struct datablock *b;
- dprintk("DELETE INODE\n");
+ dprintk("DELETE INODE %d\n",(int)ino->i_ino);
if (ino->i_mode == 0) {
/* There never was an inode here,
* let it.
*/
+ /* FIXME I need some sort of lock to safely walk
+ * down this list */
while (!list_empty(&ib->children) && !fs->checkpointing) {
ib2 = ib;
while (ib2->depth > 1 && !list_empty(&ib2->children)) {
*/
getiref(ib2);
lafs_incorporate_loop(fs, ib2);
+ /* FIXME should the be implicit in lafs_incorporate_loop,
+ */
+ lafs_erase_iblock(ib2);
putiref(ib2);
printk(".");
+ if (!list_empty(&ib2->b.siblings)) {
+ printk("looping on %s %s\n", strblk(&ib2->b),
+ list_empty(&ib2->children)?"empty":"Full");
+ BUG();
+ }
}
if (fs->checkpointing)
return 2; /* means "Try again after the checkpoint" */
return -1;
}
-static int
-bi_complete(struct bio *bio, unsigned int bytes_done, int error)
+static void bi_complete(struct bio *bio, int error)
{
- if (bio->bi_size)
- return 1;
-
complete((struct completion*)bio->bi_private);
- return 0;
}
int
}
-static int
-bi_async_complete(struct bio *bio, unsigned int bytes_done, int error)
+static void
+bi_async_complete(struct bio *bio, int error)
{
struct async_complete *ac = bio->bi_private;
- if (bio->bi_size)
- return 1;
if (test_bit(BIO_UPTODATE, &bio->bi_flags))
ac->state = 3;
ac->state = 4;
bio_put(bio);
lafs_wake_cleaner(ac->fs);
- return 0;
}
static void
return -EAGAIN;
}
-static int
-bi_write_done(struct bio *bio, unsigned int bytes_done, int error)
+static void
+bi_write_done(struct bio *bio, int error)
{
struct fs *fs = bio->bi_private;
- if (bio->bi_size)
- return 1;
+
if (atomic_dec_and_test(&fs->sb_writes_pending))
wake_up(&fs->sb_writes_wait);
bio_put(bio);
/* FIXME didn't do anything with error */
- return 0;
}
void
}
-static int
-block_loaded(struct bio *bio, unsigned int bytes_done, int error)
+static void
+block_loaded(struct bio *bio, int error)
{
struct block *b = bio->bi_private;
- if (bio->bi_size)
- return 1;
dprintk("loaded %d of %d\n", (int)b->fileaddr, (int)b->inode->i_ino);
if (test_bit(BIO_UPTODATE, &bio->bi_flags)) {
} else dprintk("Block with no page!!\n");
/* FIXME signal error for index block */
lafs_iounlock_block(b, B_IOLock);
- return 0;
}
-static int
-block_loaded_nounlock(struct bio *bio, unsigned int bytes_done, int error)
+static void
+block_loaded_nounlock(struct bio *bio, int error)
{
struct block *b = bio->bi_private;
- if (bio->bi_size)
- return 1;
dprintk("loaded %d of %d\n", (int)b->fileaddr, (int)b->inode->i_ino);
if (test_bit(BIO_UPTODATE, &bio->bi_flags)) {
} else dprintk("Block with no page!!\n");
lafs_iounlock_block(b, 0);
- return 0;
}
int __must_check
struct page *page;
int offset;
+ if (!test_bit(B_PhysValid, &b->flags))
+ b->physaddr = 0;
if (test_bit(B_Valid, &b->flags))
return 0;
lafs_iolock_block(b);
if (test_bit(B_Index, &b->flags)) {
struct indexblock *ib = iblk(b);
if (b->physaddr == 0) {
+ BUG();
/* I think this is really an error FIXME */
memset(ib->data, 0, b->inode->i_sb->s_blocksize);
lafs_iounlock_block(b, unlock ? B_IOLock : 0);
*/
void lafs_refile(struct block *b, int dec);
+extern spinlock_t lafs_hash_lock;
static inline struct block *getref(struct block *b)
{
if (atomic_read(&b->refcnt) == 0) {
if (test_bit(B_Index, &b->flags)) {
if (spin_is_locked(&b->inode->i_data.private_lock))
ok = 1;
+ if (spin_is_locked(&lafs_hash_lock))
+ ok = 1;
// FIXME more tests - just when is this allowed?
} else {
struct datablock *db = dblk(b);
phys = decode48(b);
if (phys != 0)
break;
+ icnt--;
}
u=0; i=0;
ncnt = 0;
- BUG_ON(ucnt == 0 || icnt == 0);
+ BUG_ON(ucnt == 0);
uaddr = ui->pending_addr[0].fileaddr;
b = buf + 6;
iaddr = decode32(b);
iaddr = decode32(b);
} else
iaddr = 0xffffffff;
-
+
if (uaddr == iaddr) {
/* replacement */
if (ui->pending_addr[u].physaddr)
void lafs_incorporate(struct fs *fs, struct indexblock *ib)
{
int offset; /* start of block where indexing is */
- struct indexblock *new = NULL, *tofree = NULL;
+ struct indexblock *new = NULL;
int rv;
char *buf;
struct uninc uit, *spareui, **uip;
/* There is nothing in this block any more.
* If it is an inode, clear it, else punch a hole
*/
+ printk("incorp to empty off=%d %s\n", (int)offset, strblk(&ib->b));
lafs_iblock_free(new);
if (offset) {
buf = map_iblock(ib);
set_bit(B_ICredit, &new->b.flags);
lafs_dirty_iblock(new); // or Realloc?? FIXME
- ib = new;
- if (tofree)
- putiref(tofree);
- tofree = new;
+ printk("Just Grew %s\n", strblk(&new->b));
+ putiref(new);
goto retry;
}
//printk("Done Incorp %s\n", strblk(&ib->b));
lafs_space_return(fs, uit.credits);
kfree(spareui);
- if (tofree)
- putiref(tofree);
}
void lafs_incorporate_loop(struct fs *fs, struct indexblock *ib)
struct datablock *ob1, *ob2;
int shift = b->b.inode->i_blkbits - 4;
struct orphan_md *om = &LAFSI(fs->orphans)->md.orphan;
- struct orphan *or, *lastor;
+ struct orphan *or, *lastor, last;
int ent, lastent;
u32 bnum;
lastor = map_dblock_2(ob2);
lastent = (om->nextfree-1) & ((1<<shift)-1);
dprintk("lastor=%p lastent=%d\n", lastor, lastent);
+ last = lastor[lastent];
+ lastor[lastent].type = 0;
+ unmap_dblock_2(ob2, lastor);
/* FIXME these should not create the block if it doesn't exist */
- bfs = lafs_get_block(fs->ss[0].root, le32_to_cpu(lastor[lastent].filesys),
+ bfs = lafs_get_block(fs->ss[0].root, le32_to_cpu(last.filesys),
NULL, GFP_KERNEL);
if (bfs && bfs->my_inode)
bi = lafs_get_block(bfs->my_inode,
- le32_to_cpu(lastor[lastent].inum),
+ le32_to_cpu(last.inum),
NULL, GFP_KERNEL);
else bi = NULL;
putdref(bfs);
if (bi && bi->my_inode)
bbl = lafs_get_block(bi->my_inode,
- le32_to_cpu(lastor[lastent].addr),
+ le32_to_cpu(last.addr),
NULL, GFP_KERNEL);
else bbl = NULL;
putdref(bi);
dprintk("O bfs=%p(%p) bi=%p bbl=%p lastent=%d fs=%d in=%d a=%d\n",
bfs, bfs->my_inode, bi, bbl, lastent,
- le32_to_cpu(lastor[lastent].filesys),
- le32_to_cpu(lastor[lastent].inum),
- le32_to_cpu(lastor[lastent].addr)
+ le32_to_cpu(last.filesys),
+ le32_to_cpu(last.inum),
+ le32_to_cpu(last.addr)
);
if (!bbl) {
putdref(ob2);
BUG_ON(bbl->orphan_slot != om->nextfree-1);
or = map_dblock(ob1);
- or[ent] = lastor[lastent];
+ or[ent] = last;
bbl->orphan_slot = b->orphan_slot;
putdref(bbl);
- lastor[lastent].type = 0;
lafs_dirty_dblock(ob1);
lafs_dirty_dblock(ob2);
- unmap_dblock_2(ob2, lastor);
unmap_dblock(ob1, or);
putdref(ob1); /* no longer hold a reservation reference
return -ENOMEM;
set_bit(B_Root, &b->b.flags);
b->b.physaddr = fs->ss[0].root_addr;
+ set_bit(B_PhysValid, &b->b.flags);
err = lafs_load_block(&b->b, 0);
//printk("2 %d\n", err);
if (err)
put_page(p);
return err;
}
- sb = nd.dentry->d_sb;
+ sb = nd.path.dentry->d_sb;
err = -EINVAL;
if (sb->s_type != &lafs_fs_type)
goto fail;
fs->ss[s].root = iget_locked(sb, 1);
b = lafs_get_block(fs->ss[s].root, 0, NULL, GFP_KERNEL);
b->b.physaddr = fs->ss[s].root_addr;
+ set_bit(B_PhysValid, &b->b.flags);
BUG_ON(test_bit(B_Valid, &b->b.flags));
printk("ss root at %llu\n", b->b.physaddr);
err = lafs_load_block(&b->b, 0);
goto fail;
}
up_write(&fs->prime_sb->s_umount);
- path_release(&nd);
+ path_put(&nd.path);
put_page(p);
simple_set_mnt(mnt, sb);
return 0;
fail:
put_page(p);
- path_release(&nd);
+ path_put(&nd.path);
return err;
}
struct lafs_inode *lai = LAFSI(ino);
lai = LAFSI(lai->filesys);
spin_lock(&lai->vfs_inode.i_lock);
- printk("LSA: %d -> ", (int)lai->md.fs.ablocks_used);
+// printk("LSA: %d -> ", (int)lai->md.fs.ablocks_used);
if (lai->md.fs.blocks_allowed &&
diff > 0 &&
lai->md.fs.cblocks_used +
else
lai->md.fs.ablocks_used += diff;
- printk(" %d\n", (int)lai->md.fs.ablocks_used);
+// printk(" %d\n", (int)lai->md.fs.ablocks_used);
spin_unlock(&lai->vfs_inode.i_lock);
if (err)
return err;
echo 0 > /sys/module/lafs/parameters/lafs_trace
echo cleanable > /sys/module/lafs/parameters/dump
echo usage > /sys/module/lafs/parameters/dump
+echo 1 > /sys/module/lafs/parameters/lafs_trace
sync
sleep 3
ls -fi /mnt/1/adir
qemu -hda hda -hdb $dir/../../code2/fred -hdc $dir/../../code2/frog \
-net nic,model=ne2k_pci -net user \
-m 256 -serial stdio \
- -kernel /home/src/lafs-2.6.23/arch/i386/boot/bzImage \
+ -kernel /home/src/lafs-2.6.27/arch/i386/boot/bzImage \
-append "root=/dev/hda1 console=ttyS0" -tftp /tmp/tftp