Fix how dirty treap is tracked

The transaction writing thread tests if the manifest and alloc treaps
are dirty.  It did this by testing if there were any dirty nodes in the
treap.

But this misses the case where the treap has been modified and all nodes
have been removed.  In that case the root references no dirty nodes but
needs to be written.

Instead let's specifically mark the treap dirty when it's modified.
From then on sync will always try to write it out.  We also integrate
updating the persistent root as part of writing the dirty nodes to the
persistent ring.  It's required and every caller did it so it was silly
to make it a separate step.

Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
Zach Brown
2017-01-12 11:02:41 -08:00
parent 30b088377f
commit a333c507fb
4 changed files with 15 additions and 17 deletions

View File

@@ -270,8 +270,7 @@ int scoutfs_alloc_dirty_ring(struct super_block *sb)
kfree(pend);
}
scoutfs_treap_dirty_ring(sal->treap);
scoutfs_treap_update_root(&super->alloc_treap_root, sal->treap);
scoutfs_treap_dirty_ring(sal->treap, &super->alloc_treap_root);
ret = 0;
out:
up_write(&sal->rwsem);

View File

@@ -612,8 +612,7 @@ int scoutfs_manifest_dirty_ring(struct super_block *sb)
struct scoutfs_super_block *super = &sbi->super;
down_write(&mani->rwsem);
scoutfs_treap_dirty_ring(mani->treap);
scoutfs_treap_update_root(&super->manifest.root, mani->treap);
scoutfs_treap_dirty_ring(mani->treap, &super->manifest.root);
up_write(&mani->rwsem);
return 0;

View File

@@ -117,6 +117,7 @@ struct scoutfs_treap {
struct scoutfs_super_block *super;
struct scoutfs_treap_ops *ops;
struct treap_ref root_ref;
bool dirty;
u64 dirty_bytes;
};
@@ -424,6 +425,7 @@ static bool mark_node_dirty(struct scoutfs_treap *treap, struct treap_ref *ref,
return false;
treap->dirty_bytes += node_ring_bytes(node);
treap->dirty = true;
node->off = tinf->dirty_off;
node->gen = tinf->dirty_gen;
@@ -1030,7 +1032,7 @@ out:
int scoutfs_treap_has_dirty(struct scoutfs_treap *treap)
{
return !!(treap->root_ref.aug_bits & SCOUTFS_TREAP_AUG_DIRTY);
return treap->dirty;
}
static void *pages_off_ptr(struct treap_info *tinf)
@@ -1135,7 +1137,8 @@ static void copy_node_to_ring(struct scoutfs_treap *treap,
*
* This is called for multiple treaps before the ring is written.
*/
int scoutfs_treap_dirty_ring(struct scoutfs_treap *treap)
int scoutfs_treap_dirty_ring(struct scoutfs_treap *treap,
struct scoutfs_treap_root *root)
{
struct treap_node *node;
unsigned bytes;
@@ -1168,7 +1171,13 @@ int scoutfs_treap_dirty_ring(struct scoutfs_treap *treap)
}
}
/* point the persistent super root at the treap we wrote to the ring */
root->ref.off = cpu_to_le64(treap->root_ref.off);
root->ref.gen = cpu_to_le64(treap->root_ref.gen);
root->ref.aug_bits = treap->root_ref.aug_bits;
treap->dirty_bytes = 0;
treap->dirty = false;
ret = 0;
out:
return ret;
@@ -1258,14 +1267,6 @@ struct scoutfs_treap *scoutfs_treap_alloc(struct super_block *sb,
return treap;
}
void scoutfs_treap_update_root(struct scoutfs_treap_root *root,
struct scoutfs_treap *treap)
{
root->ref.off = cpu_to_le64(treap->root_ref.off);
root->ref.gen = cpu_to_le64(treap->root_ref.gen);
root->ref.aug_bits = treap->root_ref.aug_bits;
}
/*
* Free all the allocated nodes in the treap and clear the root.
*/

View File

@@ -18,8 +18,6 @@ struct scoutfs_treap_ops {
struct scoutfs_treap *scoutfs_treap_alloc(struct super_block *sb,
struct scoutfs_treap_ops *ops,
struct scoutfs_treap_root *root);
void scoutfs_treap_update_root(struct scoutfs_treap_root *root,
struct scoutfs_treap *treap);
void scoutfs_treap_free(struct scoutfs_treap *treap);
void *scoutfs_treap_insert(struct scoutfs_treap *treap, void *key, u16 bytes,
@@ -38,7 +36,8 @@ void *scoutfs_treap_next(struct scoutfs_treap *treap, void *data);
void *scoutfs_treap_prev(struct scoutfs_treap *treap, void *data);
int scoutfs_treap_has_dirty(struct scoutfs_treap *treap);
int scoutfs_treap_dirty_ring(struct scoutfs_treap *treap);
int scoutfs_treap_dirty_ring(struct scoutfs_treap *treap,
struct scoutfs_treap_root *root);
int scoutfs_treap_submit_write(struct super_block *sb,
struct scoutfs_bio_completion *comp);