From: Matthew Dillon Date: Sun, 30 Dec 2007 08:49:20 +0000 (+0000) Subject: HAMMER 12/many - buffer cache sync, buffer cache interactions, misc fixes. X-Git-Tag: v2.0.1~1519 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/0b07555568dd51216abf92a42c87d4af4e2362c0 HAMMER 12/many - buffer cache sync, buffer cache interactions, misc fixes. As of this commit all vnops work, the filesystem remains consistent across umount/remount, and the 'cpdup / /mnt/root' test succeeds. There is still a ton of work to do but this is a major milestone. * Get sync and umount working properly. Properly sync out in-memory records and inode updates, and properly release buffer cache buffers so the kernel can throw them away. * Modifications to buffers backed by the buffer cache ensure that any asynchronous writes complete to avoid a modify-write race. * Fix miscellanious reference counting bugs. * Fix two insertion bugs for internal B-Tree nodes that were causing the code to blow up. --- diff --git a/sys/vfs/hammer/hammer.h b/sys/vfs/hammer/hammer.h index e077daf91e..862126fc56 100644 --- a/sys/vfs/hammer/hammer.h +++ b/sys/vfs/hammer/hammer.h @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/vfs/hammer/hammer.h,v 1.15 2007/12/30 00:47:22 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/hammer.h,v 1.16 2007/12/30 08:49:20 dillon Exp $ */ /* * This header file contains structures used internally by the HAMMERFS @@ -87,8 +87,9 @@ typedef struct hammer_transaction *hammer_transaction_t; * HAMMER locks */ struct hammer_lock { - int refs; - int lockcount; + int refs; /* active references delay writes */ + int modifying; /* indicates buffer being modified */ + int lockcount; /* lock count for exclusive/shared access */ int wanted; struct thread *locktd; }; @@ -99,6 +100,12 @@ hammer_islocked(struct hammer_lock *lock) return(lock->lockcount != 0); } +static __inline int +hammer_isactive(struct hammer_lock *lock) +{ + return(lock->refs != 0); +} + static __inline int hammer_islastref(struct hammer_lock *lock) { @@ -164,6 +171,10 @@ typedef struct hammer_inode *hammer_inode_t; #define HAMMER_INODE_DELETED 0x0080 /* inode ready for deletion */ #define HAMMER_INODE_DELONDISK 0x0100 /* delete synchronized to disk */ +#define HAMMER_INODE_MODMASK (HAMMER_INODE_DDIRTY|HAMMER_INODE_RDIRTY| \ + HAMMER_INODE_ITIMES|HAMMER_INODE_FLUSH| \ + HAMMER_INODE_DELETED) + #define HAMMER_MAX_INODE_CURSORS 4 /* @@ -602,6 +613,8 @@ void hammer_io_release(struct hammer_io *io, int flush); int hammer_io_checkflush(hammer_io_t io); void hammer_io_notify_cluster(hammer_cluster_t cluster); void hammer_io_flush(struct hammer_io *io, struct hammer_sync_info *info); +void hammer_io_intend_modify(struct hammer_io *io); +void hammer_io_modify_done(struct hammer_io *io); #endif @@ -612,18 +625,45 @@ static __inline void hammer_modify_volume(struct hammer_volume *volume) { volume->io.modified = 1; + ++volume->io.lock.modifying; + if (volume->io.released) + hammer_io_intend_modify(&volume->io); +} + +static __inline void +hammer_modify_volume_done(struct hammer_volume *volume) +{ + hammer_io_modify_done(&volume->io); } static __inline void hammer_modify_supercl(struct hammer_supercl *supercl) { supercl->io.modified = 1; + ++supercl->io.lock.modifying; + if (supercl->io.released) + hammer_io_intend_modify(&supercl->io); +} + +static __inline void +hammer_modify_supercl_done(struct hammer_supercl *supercl) +{ + hammer_io_modify_done(&supercl->io); } static __inline void hammer_modify_cluster(struct hammer_cluster *cluster) { cluster->io.modified = 1; + ++cluster->io.lock.modifying; + if (cluster->io.released) + hammer_io_intend_modify(&cluster->io); +} + +static __inline void +hammer_modify_cluster_done(struct hammer_cluster *cluster) +{ + hammer_io_modify_done(&cluster->io); } static __inline void @@ -631,6 +671,15 @@ hammer_modify_buffer(struct hammer_buffer *buffer) { hammer_io_notify_cluster(buffer->cluster); buffer->io.modified = 1; + ++buffer->io.lock.modifying; + if (buffer->io.released) + hammer_io_intend_modify(&buffer->io); +} + +static __inline void +hammer_modify_buffer_done(struct hammer_buffer *buffer) +{ + hammer_io_modify_done(&buffer->io); } static __inline void @@ -639,6 +688,12 @@ hammer_modify_node(struct hammer_node *node) hammer_modify_buffer(node->buffer); } +static __inline void +hammer_modify_node_done(struct hammer_node *node) +{ + hammer_modify_buffer_done(node->buffer); +} + /* * Return the cluster-relative byte offset of an element within a buffer */ diff --git a/sys/vfs/hammer/hammer_btree.c b/sys/vfs/hammer/hammer_btree.c index 1840c532d1..322e9dcb52 100644 --- a/sys/vfs/hammer/hammer_btree.c +++ b/sys/vfs/hammer/hammer_btree.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/vfs/hammer/hammer_btree.c,v 1.12 2007/12/30 00:47:22 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/hammer_btree.c,v 1.13 2007/12/30 08:49:20 dillon Exp $ */ /* @@ -414,6 +414,7 @@ hammer_btree_insert(hammer_cursor_t cursor, hammer_btree_elm_t elm) * Remember that the right-hand boundary is not included in the * count. */ + hammer_modify_node(cursor->node); node = cursor->node->ondisk; i = cursor->index; KKASSERT(node->type == HAMMER_BTREE_TYPE_LEAF); @@ -424,18 +425,19 @@ hammer_btree_insert(hammer_cursor_t cursor, hammer_btree_elm_t elm) } node->elms[i] = *elm; ++node->count; - hammer_modify_node(cursor->node); + hammer_modify_node_done(cursor->node); /* * Adjust the sub-tree count in the parent. note that the parent * may be in a different cluster. */ if (cursor->parent) { + hammer_modify_node(cursor->parent); parent = cursor->parent->ondisk; i = cursor->parent_index; ++parent->elms[i].internal.subtree_count; + hammer_modify_node_done(cursor->parent); KKASSERT(parent->elms[i].internal.subtree_count <= node->count); - hammer_modify_node(cursor->parent); } return(0); } @@ -485,12 +487,13 @@ hammer_btree_delete(hammer_cursor_t cursor) i = cursor->index; KKASSERT(ondisk->type == HAMMER_BTREE_TYPE_LEAF); + hammer_modify_node(node); if (i + 1 != ondisk->count) { bcopy(&ondisk->elms[i+1], &ondisk->elms[i], (ondisk->count - i - 1) * sizeof(ondisk->elms[0])); } --ondisk->count; - hammer_modify_node(node); + hammer_modify_node_done(node); if (cursor->parent != NULL) { /* * Adjust parent's notion of the leaf's count. subtree_count @@ -499,11 +502,12 @@ hammer_btree_delete(hammer_cursor_t cursor) * the count below 0. */ parent = cursor->parent; + hammer_modify_node(parent); elm = &parent->ondisk->elms[cursor->parent_index]; if (elm->internal.subtree_count) --elm->internal.subtree_count; + hammer_modify_node_done(parent); KKASSERT(elm->internal.subtree_count <= ondisk->count); - hammer_modify_node(parent); } /* @@ -725,10 +729,11 @@ btree_search(hammer_cursor_t cursor, int flags) cursor->index = 0; return(ENOENT); } + hammer_modify_node(cursor->node); save = node->elms[0].subtree_type; node->elms[0].base = *cursor->left_bound; node->elms[0].subtree_type = save; - hammer_modify_node(cursor->node); + hammer_modify_node_done(cursor->node); } else if (i == node->count) { /* * Terminate early if not inserting and the key is @@ -751,8 +756,9 @@ btree_search(hammer_cursor_t cursor, int flags) */ if (hammer_btree_cmp(&node->elms[i].base, cursor->right_bound) != 0) { - node->elms[i].base = *cursor->right_bound; hammer_modify_node(cursor->node); + node->elms[i].base = *cursor->right_bound; + hammer_modify_node_done(cursor->node); } --i; } else { @@ -985,6 +991,7 @@ btree_split_internal(hammer_cursor_t cursor) if (parent == NULL) return(error); hammer_lock_ex(&parent->lock); + hammer_modify_node(parent); ondisk = parent->ondisk; ondisk->count = 1; ondisk->parent = 0; @@ -995,6 +1002,7 @@ btree_split_internal(hammer_cursor_t cursor) ondisk->elms[1].base = node->cluster->clu_btree_end; made_root = 1; parent_index = 0; /* index of current node in parent */ + hammer_modify_node_done(parent); } else { made_root = 0; parent = cursor->parent; @@ -1032,6 +1040,8 @@ btree_split_internal(hammer_cursor_t cursor) * * elm is the new separator. */ + hammer_modify_node(new_node); + hammer_modify_node(node); ondisk = node->ondisk; elm = &ondisk->elms[split]; bcopy(elm, &new_node->ondisk->elms[0], @@ -1047,6 +1057,7 @@ btree_split_internal(hammer_cursor_t cursor) * a new root its parent pointer may have changed. */ elm->internal.subtree_offset = 0; + elm->internal.rec_offset = 0; ondisk->count = split; /* @@ -1056,6 +1067,7 @@ btree_split_internal(hammer_cursor_t cursor) * * Remember that base.count does not include the right-hand boundary. */ + hammer_modify_node(parent); ondisk = parent->ondisk; KKASSERT(ondisk->count != HAMMER_BTREE_INT_ELMS); ondisk->elms[parent_index].internal.subtree_count = split; @@ -1066,7 +1078,10 @@ btree_split_internal(hammer_cursor_t cursor) parent_elm->internal.subtree_offset = new_node->node_offset; parent_elm->internal.subtree_count = new_node->ondisk->count; parent_elm->internal.subtree_type = new_node->ondisk->type; + parent_elm->internal.subtree_vol_no = 0; + parent_elm->internal.rec_offset = 0; ++ondisk->count; + hammer_modify_node_done(parent); /* * The children of new_node need their parent pointer set to new_node. @@ -1083,8 +1098,9 @@ btree_split_internal(hammer_cursor_t cursor) * The cluster's root pointer may have to be updated. */ if (made_root) { - node->cluster->ondisk->clu_btree_root = parent->node_offset; hammer_modify_cluster(node->cluster); + node->cluster->ondisk->clu_btree_root = parent->node_offset; + hammer_modify_cluster_done(node->cluster); node->ondisk->parent = parent->node_offset; if (cursor->parent) { hammer_unlock(&cursor->parent->lock); @@ -1092,10 +1108,9 @@ btree_split_internal(hammer_cursor_t cursor) } cursor->parent = parent; /* lock'd and ref'd */ } + hammer_modify_node_done(new_node); + hammer_modify_node_done(node); - hammer_modify_node(node); - hammer_modify_node(new_node); - hammer_modify_node(parent); /* * Ok, now adjust the cursor depending on which element the original @@ -1173,6 +1188,7 @@ btree_split_leaf(hammer_cursor_t cursor) if (parent == NULL) return(error); hammer_lock_ex(&parent->lock); + hammer_modify_node(parent); ondisk = parent->ondisk; ondisk->count = 1; ondisk->parent = 0; @@ -1181,6 +1197,7 @@ btree_split_leaf(hammer_cursor_t cursor) ondisk->elms[0].internal.subtree_type = leaf->ondisk->type; ondisk->elms[0].internal.subtree_offset = leaf->node_offset; ondisk->elms[1].base = leaf->cluster->clu_btree_end; + hammer_modify_node_done(parent); made_root = 1; parent_index = 0; /* insertion point in parent */ } else { @@ -1217,6 +1234,8 @@ btree_split_leaf(hammer_cursor_t cursor) * Create the new node. P become the left-hand boundary in the * new node. Copy the right-hand boundary as well. */ + hammer_modify_node(leaf); + hammer_modify_node(new_leaf); ondisk = leaf->ondisk; elm = &ondisk->elms[split]; bcopy(elm, &new_leaf->ondisk->elms[0], (ondisk->count - split) * esize); @@ -1241,6 +1260,7 @@ btree_split_leaf(hammer_cursor_t cursor) * Remember that base.count does not include the right-hand boundary. * We are copying parent_index+1 to parent_index+2, not +0 to +1. */ + hammer_modify_node(parent); ondisk = parent->ondisk; KKASSERT(ondisk->count != HAMMER_BTREE_INT_ELMS); ondisk->elms[parent_index].internal.subtree_count = split; @@ -1251,14 +1271,18 @@ btree_split_leaf(hammer_cursor_t cursor) parent_elm->internal.subtree_offset = new_leaf->node_offset; parent_elm->internal.subtree_count = new_leaf->ondisk->count; parent_elm->internal.subtree_type = new_leaf->ondisk->type; + parent_elm->internal.subtree_vol_no = 0; + parent_elm->internal.rec_offset = 0; ++ondisk->count; + hammer_modify_node_done(parent); /* * The cluster's root pointer may have to be updated. */ if (made_root) { - leaf->cluster->ondisk->clu_btree_root = parent->node_offset; hammer_modify_cluster(leaf->cluster); + leaf->cluster->ondisk->clu_btree_root = parent->node_offset; + hammer_modify_cluster_done(leaf->cluster); leaf->ondisk->parent = parent->node_offset; if (cursor->parent) { hammer_unlock(&cursor->parent->lock); @@ -1266,10 +1290,8 @@ btree_split_leaf(hammer_cursor_t cursor) } cursor->parent = parent; /* lock'd and ref'd */ } - - hammer_modify_node(leaf); - hammer_modify_node(new_leaf); - hammer_modify_node(parent); + hammer_modify_node_done(leaf); + hammer_modify_node_done(new_leaf); /* * Ok, now adjust the cursor depending on which element the original @@ -1329,11 +1351,12 @@ btree_remove(hammer_cursor_t cursor) * allowed to be empty so convert it to a leaf node. */ if (cursor->parent == NULL) { + hammer_modify_node(cursor->node); ondisk = cursor->node->ondisk; KKASSERT(ondisk->parent == 0); ondisk->type = HAMMER_BTREE_TYPE_LEAF; ondisk->count = 0; - hammer_modify_node(cursor->node); + hammer_modify_node_done(cursor->node); kprintf("EMPTY ROOT OF ROOT CLUSTER -> LEAF\n"); return(0); } @@ -1415,12 +1438,13 @@ btree_remove(hammer_cursor_t cursor) #if 0 kprintf("BTREE_REMOVE: Removing element %d\n", cursor->index); #endif + hammer_modify_node(node); ondisk = node->ondisk; i = cursor->index; bcopy(&ondisk->elms[i+1], &ondisk->elms[i], (ondisk->count - i) * sizeof(ondisk->elms[0])); --ondisk->count; - hammer_modify_node(cursor->node); + hammer_modify_node_done(node); /* * Adjust the parent-parent's (now parent) reference to the parent @@ -1429,13 +1453,15 @@ btree_remove(hammer_cursor_t cursor) if ((parent = cursor->parent) != NULL) { elm = &parent->ondisk->elms[cursor->parent_index]; if (elm->internal.subtree_count != ondisk->count) { - elm->internal.subtree_count = ondisk->count; hammer_modify_node(parent); + elm->internal.subtree_count = ondisk->count; + hammer_modify_node_done(parent); } if (elm->subtree_type != HAMMER_BTREE_TYPE_CLUSTER && elm->subtree_type != ondisk->type) { - elm->subtree_type = ondisk->type; hammer_modify_node(parent); + elm->subtree_type = ondisk->type; + hammer_modify_node_done(parent); } } @@ -1470,10 +1496,11 @@ btree_set_parent(hammer_node_t node, hammer_btree_elm_t elm) child = hammer_get_node(node->cluster, elm->internal.subtree_offset, &error); if (error == 0) { + hammer_modify_node(child); hammer_lock_ex(&child->lock); child->ondisk->parent = node->node_offset; - hammer_modify_node(child); hammer_unlock(&child->lock); + hammer_modify_node_done(child); hammer_rel_node(child); } break; @@ -1488,14 +1515,15 @@ btree_set_parent(hammer_node_t node, hammer_btree_elm_t elm) hammer_rel_volume(volume, 0); if (error) break; + hammer_modify_cluster(cluster); hammer_lock_ex(&cluster->io.lock); cluster->ondisk->clu_btree_parent_offset = node->node_offset; hammer_unlock(&cluster->io.lock); + hammer_modify_cluster_done(cluster); KKASSERT(cluster->ondisk->clu_btree_parent_clu_no == node->cluster->clu_no); KKASSERT(cluster->ondisk->clu_btree_parent_vol_no == node->cluster->volume->vol_no); - hammer_modify_cluster(cluster); hammer_rel_cluster(cluster, 0); break; default: @@ -1655,10 +1683,11 @@ btree_rebalance(hammer_cursor_t cursor) &error, &subchild_buffer, XXX); if (subchild) { + hammer_modify_buffer(subchild_buffer); subchild->base.parent = hammer_bclu_offset(child_buffer[i], child); - hammer_modify_buffer(subchild_buffer); + hammer_modify_buffer_done(subchild_buffer); } /* XXX error */ } diff --git a/sys/vfs/hammer/hammer_cursor.c b/sys/vfs/hammer/hammer_cursor.c index a7edbb298d..ad574d3b8f 100644 --- a/sys/vfs/hammer/hammer_cursor.c +++ b/sys/vfs/hammer/hammer_cursor.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/vfs/hammer/hammer_cursor.c,v 1.7 2007/12/30 00:47:22 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/hammer_cursor.c,v 1.8 2007/12/30 08:49:20 dillon Exp $ */ /* @@ -67,6 +67,7 @@ hammer_init_cursor_hmp(hammer_cursor_t cursor, hammer_mount_t hmp) } if (error == 0) error = hammer_load_cursor_parent(cursor); + KKASSERT(error == 0); return(error); } @@ -88,6 +89,7 @@ hammer_init_cursor_cluster(hammer_cursor_t cursor, hammer_cluster_t cluster) hammer_lock_ex(&cursor->node->lock); error = hammer_load_cursor_parent(cursor); } + KKASSERT(error == 0); return(error); } @@ -116,6 +118,7 @@ hammer_init_cursor_ip(hammer_cursor_t cursor, hammer_inode_t ip) } else { error = hammer_init_cursor_hmp(cursor, ip->hmp); } + KKASSERT(error == 0); return(error); } @@ -454,6 +457,7 @@ hammer_cursor_toroot(hammer_cursor_t cursor) cursor->node = hammer_get_node(cluster, cluster->ondisk->clu_btree_root, &error); cursor->index = 0; + hammer_lock_ex(&cursor->node->lock); hammer_rel_cluster(cluster, 0); if (error == 0) error = hammer_load_cursor_parent(cursor); @@ -511,9 +515,11 @@ hammer_cursor_down(hammer_cursor_t cursor) clu_no = elm->internal.subtree_clu_no; volume = hammer_get_volume(node->cluster->volume->hmp, vol_no, &error); + KKASSERT(error != EINVAL); if (error) return(error); cluster = hammer_get_cluster(volume, clu_no, &error, 0); + KKASSERT(error != EINVAL); hammer_rel_volume(volume, 0); if (error) return(error); diff --git a/sys/vfs/hammer/hammer_inode.c b/sys/vfs/hammer/hammer_inode.c index 27050ed9ce..676a22053f 100644 --- a/sys/vfs/hammer/hammer_inode.c +++ b/sys/vfs/hammer/hammer_inode.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/vfs/hammer/hammer_inode.c,v 1.13 2007/12/30 00:47:22 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/hammer_inode.c,v 1.14 2007/12/30 08:49:20 dillon Exp $ */ #include "hammer.h" @@ -233,8 +233,9 @@ loop: if (*errorp == 0) { ip->ino_rec = cursor.record->inode; ip->ino_data = cursor.data->inode; + } else if (cursor.node) { + hammer_cache_node(cursor.node, &ip->cache); } - hammer_cache_node(cursor.node, &ip->cache); hammer_done_cursor(&cursor); /* @@ -413,8 +414,9 @@ retry: ip->flags &= ~(HAMMER_INODE_RDIRTY|HAMMER_INODE_DDIRTY| HAMMER_INODE_DELONDISK); if ((ip->flags & HAMMER_INODE_ONDISK) == 0) { - ++ip->hmp->rootvol->ondisk->vol0_stat_inodes; hammer_modify_volume(ip->hmp->rootvol); + ++ip->hmp->rootvol->ondisk->vol0_stat_inodes; + hammer_modify_volume_done(ip->hmp->rootvol); ip->flags |= HAMMER_INODE_ONDISK; } } @@ -509,8 +511,8 @@ hammer_sync_inode_callback(hammer_record_t rec, void *data) } if (error) { - kprintf("hammer_sync_inode_callback: sync failed rec %p\n", - rec); + kprintf("hammer_sync_inode_callback: sync failed rec %p, error %d\n", + rec, error); hammer_drop_mem_record(rec, 0); return(-error); } @@ -552,14 +554,14 @@ hammer_sync_inode(hammer_inode_t ip, int waitfor, int handle_delete) if (ip->vp) vtruncbuf(ip->vp, 0, HAMMER_BUFSIZE); error = hammer_ip_delete_range_all(&trans, ip); - kprintf("delete_range_all error %d\n", error); KKASSERT(RB_EMPTY(&ip->rec_tree)); ip->flags &= ~HAMMER_INODE_TID; ip->ino_rec.base.base.delete_tid = trans.tid; hammer_modify_inode(&trans, ip, HAMMER_INODE_DELETED | HAMMER_INODE_TID); - --ip->hmp->rootvol->ondisk->vol0_stat_inodes; hammer_modify_volume(ip->hmp->rootvol); + --ip->hmp->rootvol->ondisk->vol0_stat_inodes; + hammer_modify_volume_done(ip->hmp->rootvol); } /* diff --git a/sys/vfs/hammer/hammer_io.c b/sys/vfs/hammer/hammer_io.c index 13e42e879d..af40b275ac 100644 --- a/sys/vfs/hammer/hammer_io.c +++ b/sys/vfs/hammer/hammer_io.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/vfs/hammer/hammer_io.c,v 1.8 2007/12/30 00:47:22 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/hammer_io.c,v 1.9 2007/12/30 08:49:20 dillon Exp $ */ /* * IO Primitives and buffer cache management @@ -101,9 +101,10 @@ hammer_close_cluster(hammer_cluster_t cluster) tsleep(cluster, 0, "hmrdep", 0); if (cluster->state == HAMMER_CLUSTER_OPEN) { cluster->state = HAMMER_CLUSTER_IDLE; + hammer_modify_cluster(cluster); cluster->ondisk->clu_flags &= ~HAMMER_CLUF_OPEN; + hammer_modify_cluster_done(cluster); kprintf("CLOSE CLUSTER\n"); - hammer_modify_cluster(cluster); } } @@ -169,6 +170,8 @@ hammer_io_new(struct vnode *devvp, struct hammer_io *io) * This guarentees (inasmuch as the OS can) that the cluster recovery code * will see a cluster marked open if a crash occured while the filesystem * still had dirty buffers associated with that cluster. + * + * XXX */ void hammer_io_notify_cluster(hammer_cluster_t cluster) @@ -180,12 +183,11 @@ hammer_io_notify_cluster(hammer_cluster_t cluster) if (cluster->state == HAMMER_CLUSTER_IDLE) { if (io->released) regetblk(io->bp); + io->released = 1; kprintf("MARK CLUSTER OPEN\n"); cluster->ondisk->clu_flags |= HAMMER_CLUF_OPEN; cluster->state = HAMMER_CLUSTER_ASYNC; - hammer_modify_cluster(cluster); bawrite(io->bp); - io->released = 1; /* leave cluster marked as modified */ } hammer_unlock(&cluster->io.lock); @@ -286,45 +288,92 @@ hammer_io_flush(struct hammer_io *io, struct hammer_sync_info *info) struct buf *bp; int error; +again: if ((bp = io->bp) == NULL) return; if (bp->b_flags & B_DELWRI) io->modified = 1; - if (io->modified == 0) - return; + + /* + * We can't initiate a write while the buffer is being modified + * by someone. + */ + while (io->lock.modifying) { + io->lock.wanted = 1; + kprintf("DELAYING IO FLUSH BP %p TYPE %d REFS %d modifying %d\n", + bp, io->type, io->lock.refs, io->lock.modifying); + tsleep(&io->lock, 0, "hmrfls", 0); + } hammer_lock_ex(&io->lock); + if (io->lock.modifying || io->bp == NULL) { + hammer_unlock(&io->lock); + goto again; + } - if ((bp = io->bp) != NULL && io->modified) { - if (io->released) - regetblk(bp); - io->released = 1; + /* + * Acquire ownership of the buffer cache buffer so we can flush it + * out. + */ + if (io->released) { + if (io->modified == 0) + goto done; + regetblk(bp); + } + io->released = 1; - /* - * We own the bp now - */ - if (info->waitfor & MNT_WAIT) { - io->modified = 0; - error = bwrite(bp); - if (error) - info->error = error; - } else if (io->lock.refs == 1) { - io->modified = 0; - bawrite(bp); - } else { - /* - * structure is in-use, don't race the write, but - * also set B_LOCKED so we know something tried to - * flush it. - */ - kprintf("DELAYING IO FLUSH BP %p TYPE %d REFS %d\n", - bp, io->type, io->lock.refs); - bp->b_flags |= B_LOCKED; - bqrelse(bp); - } + /* + * Return the bp to the system, issuing I/O if necessary. The + * system will issue a callback to us when it actually wants to + * throw the bp away. + */ + if (io->modified == 0) { + bqrelse(bp); + } else if (info->waitfor & MNT_WAIT) { + io->modified = 0; + error = bwrite(bp); + if (error) + info->error = error; + } else { + io->modified = 0; + bawrite(bp); } +done: hammer_unlock(&io->lock); } +/* + * Called prior to any modifications being made to ondisk data. This + * forces the caller to wait for any writes to complete. We explicitly + * avoid the write-modify race. + * + * This routine is only called on hammer structures which are already + * actively referenced. + */ +void +hammer_io_intend_modify(struct hammer_io *io) +{ + KKASSERT(io->lock.refs != 0 && io->bp != NULL); + if (io->released) { + hammer_lock_ex(&io->lock); + if (io->released) { + regetblk(io->bp); + io->released = 0; + BUF_KERNPROC(io->bp); + } + hammer_unlock(&io->lock); + } +} + +void +hammer_io_modify_done(struct hammer_io *io) +{ + KKASSERT(io->lock.modifying > 0); + --io->lock.modifying; + if (io->lock.wanted && io->lock.modifying == 0) { + io->lock.wanted = 0; + wakeup(&io->lock); + } +} /* * HAMMER_BIOOPS diff --git a/sys/vfs/hammer/hammer_object.c b/sys/vfs/hammer/hammer_object.c index e0db60a4f8..ac89adc446 100644 --- a/sys/vfs/hammer/hammer_object.c +++ b/sys/vfs/hammer/hammer_object.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/vfs/hammer/hammer_object.c,v 1.11 2007/12/30 00:47:22 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/hammer_object.c,v 1.12 2007/12/30 08:49:20 dillon Exp $ */ #include "hammer.h" @@ -500,15 +500,17 @@ hammer_ip_sync_data(hammer_transaction_t trans, hammer_inode_t ip, /* * Fill everything in and insert our B-Tree node. */ + hammer_modify_buffer(cursor.record_buffer); rec->base.base = cursor.key_beg; rec->base.data_crc = crc32(data, bytes); rec->base.rec_id = 0; /* XXX */ rec->base.data_offset = hammer_bclu_offset(cursor.data_buffer, bdata); rec->base.data_len = bytes; - hammer_modify_buffer(cursor.record_buffer); + hammer_modify_buffer_done(cursor.record_buffer); - bcopy(data, bdata, bytes); hammer_modify_buffer(cursor.data_buffer); + bcopy(data, bdata, bytes); + hammer_modify_buffer_done(cursor.data_buffer); elm.leaf.base = cursor.key_beg; elm.leaf.rec_offset = hammer_bclu_offset(cursor.record_buffer, rec); @@ -595,6 +597,7 @@ hammer_ip_sync_record(hammer_record_t record, struct hammer_cursor **spike) * * XXX assign rec_id here */ + hammer_modify_buffer(cursor.record_buffer); *rec = record->rec; if (bdata) { rec->base.data_crc = crc32(record->data, @@ -614,13 +617,13 @@ hammer_ip_sync_record(hammer_record_t record, struct hammer_cursor **spike) * Data separate from record */ rec->base.data_offset = hammer_bclu_offset(cursor.data_buffer,bdata); - bcopy(record->data, bdata, rec->base.data_len); hammer_modify_buffer(cursor.data_buffer); + bcopy(record->data, bdata, rec->base.data_len); + hammer_modify_buffer_done(cursor.data_buffer); } } rec->base.rec_id = 0; /* XXX */ - - hammer_modify_buffer(cursor.record_buffer); + hammer_modify_buffer_done(cursor.record_buffer); elm.leaf.base = cursor.key_beg; elm.leaf.rec_offset = hammer_bclu_offset(cursor.record_buffer, rec); @@ -710,6 +713,7 @@ hammer_write_record(hammer_cursor_t cursor, hammer_record_ondisk_t orec, * * XXX assign rec_id here */ + hammer_modify_buffer(cursor->record_buffer); *nrec = *orec; nrec->base.data_offset = 0; if (bdata) { @@ -728,13 +732,13 @@ hammer_write_record(hammer_cursor_t cursor, hammer_record_ondisk_t orec, * Data separate from record */ nrec->base.data_offset = hammer_bclu_offset(cursor->data_buffer, bdata); - bcopy(data, bdata, nrec->base.data_len); hammer_modify_buffer(cursor->data_buffer); + bcopy(data, bdata, nrec->base.data_len); + hammer_modify_buffer_done(cursor->data_buffer); } } nrec->base.rec_id = 0; /* XXX */ - - hammer_modify_buffer(cursor->record_buffer); + hammer_modify_buffer_done(cursor->record_buffer); elm.leaf.base = nrec->base.base; elm.leaf.rec_offset = hammer_bclu_offset(cursor->record_buffer, nrec); @@ -1236,11 +1240,13 @@ hammer_ip_delete_record(hammer_cursor_t cursor, hammer_tid_t tid) hmp = cursor->node->cluster->volume->hmp; if (error == 0) { - elm = &cursor->node->ondisk->elms[cursor->index]; - cursor->record->base.base.delete_tid = tid; - elm->leaf.base.delete_tid = tid; hammer_modify_buffer(cursor->record_buffer); + cursor->record->base.base.delete_tid = tid; + hammer_modify_buffer_done(cursor->record_buffer); hammer_modify_node(cursor->node); + elm = &cursor->node->ondisk->elms[cursor->index]; + elm->leaf.base.delete_tid = tid; + hammer_modify_node_done(cursor->node); } /* diff --git a/sys/vfs/hammer/hammer_ondisk.c b/sys/vfs/hammer/hammer_ondisk.c index edcad37bf2..2428005181 100644 --- a/sys/vfs/hammer/hammer_ondisk.c +++ b/sys/vfs/hammer/hammer_ondisk.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/vfs/hammer/hammer_ondisk.c,v 1.12 2007/12/30 00:47:22 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/hammer_ondisk.c,v 1.13 2007/12/30 08:49:20 dillon Exp $ */ /* * Manage HAMMER's on-disk structures. These routines are primarily @@ -675,8 +675,6 @@ hammer_rel_supercl(hammer_supercl_t supercl, int flush) * CLUSTERS * ************************************************************************ * - * Manage clusters. Note that a cluster holds a reference to its - * associated volume. */ hammer_cluster_t hammer_get_cluster(hammer_volume_t volume, int32_t clu_no, @@ -805,6 +803,7 @@ hammer_load_cluster(hammer_cluster_t cluster, int isnew) hammer_volume_ondisk_t voldisk; int32_t nbuffers; + hammer_modify_cluster(cluster); ondisk = cluster->ondisk; voldisk = volume->ondisk; @@ -848,14 +847,19 @@ hammer_load_cluster(hammer_cluster_t cluster, int isnew) ondisk->clu_btree_parent_clu_no = -2; ondisk->clu_btree_parent_offset = -2; ondisk->clu_btree_parent_clu_gen = -2; + hammer_modify_cluster_done(cluster); croot = hammer_alloc_btree(cluster, &error); if (error == 0) { + hammer_modify_node(croot); bzero(croot->ondisk, sizeof(*croot->ondisk)); croot->ondisk->count = 0; croot->ondisk->type = HAMMER_BTREE_TYPE_LEAF; - ondisk->clu_btree_root = croot->node_offset; + hammer_modify_node_done(croot); hammer_modify_cluster(cluster); + ondisk->clu_btree_root = croot->node_offset; + hammer_modify_cluster_done(cluster); + hammer_rel_node(croot); } } hammer_unlock(&cluster->io.lock); @@ -1440,6 +1444,8 @@ hammer_flush_node(hammer_node_t node) } } kfree(node, M_HAMMER); + } else { + kprintf("Cannot flush node: %p\n", node); } } @@ -1500,6 +1506,7 @@ hammer_alloc_cluster(hammer_mount_t hmp, hammer_cluster_t cluster_hint, clu_no = HAMMER_ALIST_BLOCK_NONE; break; } + hammer_modify_volume(volume); if (clu_hint == -1) { clu_hint = volume->clu_iterator; clu_no = hammer_alist_alloc_fwd(&volume->alist, 1, @@ -1516,10 +1523,9 @@ hammer_alloc_cluster(hammer_mount_t hmp, hammer_cluster_t cluster_hint, 1, clu_hint); } } - if (clu_no != HAMMER_ALIST_BLOCK_NONE) { - hammer_modify_volume(volume); + hammer_modify_volume_done(volume); + if (clu_no != HAMMER_ALIST_BLOCK_NONE) break; - } hammer_rel_volume(volume, 0); volume = NULL; *errorp = ENOSPC; @@ -1549,10 +1555,12 @@ hammer_init_cluster(hammer_cluster_t cluster, hammer_base_elm_t left_bound, { hammer_cluster_ondisk_t ondisk = cluster->ondisk; + hammer_modify_cluster(cluster); ondisk->clu_btree_beg = *left_bound; ondisk->clu_btree_end = *right_bound; cluster->clu_btree_beg = ondisk->clu_btree_beg; cluster->clu_btree_end = ondisk->clu_btree_end; + hammer_modify_cluster_done(cluster); } /* @@ -1561,7 +1569,9 @@ hammer_init_cluster(hammer_cluster_t cluster, hammer_base_elm_t left_bound, void hammer_free_cluster(hammer_cluster_t cluster) { + hammer_modify_cluster(cluster); hammer_alist_free(&cluster->volume->alist, cluster->clu_no, 1); + hammer_modify_cluster_done(cluster); } /* @@ -1591,6 +1601,7 @@ hammer_alloc_btree(hammer_cluster_t cluster, int *errorp) /* * Allocate a B-Tree element */ + hammer_modify_cluster(cluster); buffer = NULL; live = &cluster->alist_btree; elm_no = hammer_alist_alloc_fwd(live, 1, cluster->ondisk->idx_index); @@ -1605,13 +1616,12 @@ hammer_alloc_btree(hammer_cluster_t cluster, int *errorp) *errorp = ENOSPC; if (buffer) hammer_rel_buffer(buffer, 0); - hammer_modify_cluster(cluster); + hammer_modify_cluster_done(cluster); return(NULL); } } cluster->ondisk->idx_index = elm_no; KKASSERT((elm_no & HAMMER_FSBUF_BLKMASK) < HAMMER_BTREE_NODES); - hammer_modify_cluster(cluster); /* * Load and return the B-Tree element @@ -1622,12 +1632,15 @@ hammer_alloc_btree(hammer_cluster_t cluster, int *errorp) btree.nodes[elm_no & HAMMER_FSBUF_BLKMASK]); node = hammer_get_node(cluster, node_offset, errorp); if (node) { + hammer_modify_node(node); bzero(node->ondisk, sizeof(*node->ondisk)); + hammer_modify_node_done(node); } else { hammer_alist_free(live, elm_no, 1); hammer_rel_node(node); node = NULL; } + hammer_modify_cluster_done(cluster); if (buffer) hammer_rel_buffer(buffer, 0); return(node); @@ -1648,6 +1661,7 @@ hammer_alloc_data(hammer_cluster_t cluster, int32_t bytes, * Deal with large data blocks. The blocksize is HAMMER_BUFSIZE * for these allocations. */ + hammer_modify_cluster(cluster); if ((bytes & HAMMER_BUFMASK) == 0) { nblks = bytes / HAMMER_BUFSIZE; /* only one block allowed for now (so buffer can hold it) */ @@ -1657,10 +1671,12 @@ hammer_alloc_data(hammer_cluster_t cluster, int32_t bytes, cluster->ondisk->idx_ldata, 1); if (buf_no == HAMMER_ALIST_BLOCK_NONE) { *errorp = ENOSPC; + hammer_modify_cluster_done(cluster); return(NULL); } hammer_adjust_stats(cluster, HAMMER_FSBUF_DATA, nblks); cluster->ondisk->idx_ldata = buf_no; + hammer_modify_cluster_done(cluster); buffer = *bufferp; *bufferp = hammer_get_buffer(cluster, buf_no, -1, errorp); if (buffer) @@ -1686,12 +1702,12 @@ hammer_alloc_data(hammer_cluster_t cluster, int32_t bytes, elm_no = hammer_alist_alloc(live, nblks); if (elm_no == HAMMER_ALIST_BLOCK_NONE) { *errorp = ENOSPC; - hammer_modify_cluster(cluster); + hammer_modify_cluster_done(cluster); return(NULL); } } cluster->ondisk->idx_index = elm_no; - hammer_modify_cluster(cluster); + hammer_modify_cluster_done(cluster); /* * Load and return the B-Tree element @@ -1707,8 +1723,10 @@ hammer_alloc_data(hammer_cluster_t cluster, int32_t bytes, } KKASSERT(buffer->ondisk->head.buf_type == HAMMER_FSBUF_DATA); KKASSERT((elm_no & HAMMER_FSBUF_BLKMASK) < HAMMER_DATA_NODES); + hammer_modify_buffer(buffer); item = &buffer->ondisk->data.data[elm_no & HAMMER_FSBUF_BLKMASK]; bzero(item, nblks * HAMMER_DATA_BLKSIZE); + hammer_modify_buffer_done(buffer); *errorp = 0; return(item); } @@ -1726,6 +1744,7 @@ hammer_alloc_record(hammer_cluster_t cluster, /* * Allocate a record element */ + hammer_modify_cluster(cluster); live = &cluster->alist_record; elm_no = hammer_alist_alloc_rev(live, 1, cluster->ondisk->idx_record); if (elm_no == HAMMER_ALIST_BLOCK_NONE) @@ -1738,15 +1757,15 @@ hammer_alloc_record(hammer_cluster_t cluster, kprintf("hammer_alloc_record elm again %08x\n", elm_no); if (elm_no == HAMMER_ALIST_BLOCK_NONE) { *errorp = ENOSPC; - hammer_modify_cluster(cluster); + hammer_modify_cluster_done(cluster); return(NULL); } } cluster->ondisk->idx_record = elm_no; - hammer_modify_cluster(cluster); + hammer_modify_cluster_done(cluster); /* - * Load and return the B-Tree element + * Load and return the record element */ buf_no = elm_no / HAMMER_FSBUF_MAXBLKS; buffer = *bufferp; @@ -1759,8 +1778,10 @@ hammer_alloc_record(hammer_cluster_t cluster, } KKASSERT(buffer->ondisk->head.buf_type == HAMMER_FSBUF_RECORDS); KKASSERT((elm_no & HAMMER_FSBUF_BLKMASK) < HAMMER_RECORD_NODES); + hammer_modify_buffer(buffer); item = &buffer->ondisk->record.recs[elm_no & HAMMER_FSBUF_BLKMASK]; bzero(item, sizeof(union hammer_record_ondisk)); + hammer_modify_buffer_done(buffer); *errorp = 0; return(item); } @@ -1772,13 +1793,14 @@ hammer_free_data_ptr(hammer_buffer_t buffer, void *data, int bytes) int32_t nblks; hammer_alist_t live; + hammer_modify_cluster(buffer->cluster); if ((bytes & HAMMER_BUFMASK) == 0) { nblks = bytes / HAMMER_BUFSIZE; KKASSERT(nblks == 1 && data == (void *)buffer->ondisk); hammer_alist_free(&buffer->cluster->alist_master, buffer->buf_no, nblks); hammer_adjust_stats(buffer->cluster, HAMMER_FSBUF_DATA, -nblks); - hammer_modify_cluster(buffer->cluster); + hammer_modify_cluster_done(buffer->cluster); return; } @@ -1790,7 +1812,7 @@ hammer_free_data_ptr(hammer_buffer_t buffer, void *data, int bytes) nblks /= HAMMER_DATA_BLKSIZE; live = &buffer->cluster->alist_mdata; hammer_alist_free(live, elm_no, nblks); - hammer_modify_cluster(buffer->cluster); + hammer_modify_cluster_done(buffer->cluster); } void @@ -1799,12 +1821,13 @@ hammer_free_record_ptr(hammer_buffer_t buffer, union hammer_record_ondisk *rec) int32_t elm_no; hammer_alist_t live; + hammer_modify_cluster(buffer->cluster); elm_no = rec - &buffer->ondisk->record.recs[0]; KKASSERT(elm_no >= 0 && elm_no < HAMMER_BTREE_NODES); elm_no += buffer->buf_no * HAMMER_FSBUF_MAXBLKS; live = &buffer->cluster->alist_record; hammer_alist_free(live, elm_no, 1); - hammer_modify_cluster(buffer->cluster); + hammer_modify_cluster_done(buffer->cluster); } void @@ -1815,13 +1838,14 @@ hammer_free_btree(hammer_cluster_t cluster, int32_t bclu_offset) hammer_alist_t live; int32_t elm_no; + hammer_modify_cluster(cluster); elm_no = bclu_offset / HAMMER_BUFSIZE * HAMMER_FSBUF_MAXBLKS; fsbuf_offset -= offsetof(union hammer_fsbuf_ondisk, btree.nodes[0]); live = &cluster->alist_btree; KKASSERT(fsbuf_offset >= 0 && fsbuf_offset % blksize == 0); elm_no += fsbuf_offset / blksize; hammer_alist_free(live, elm_no, 1); - hammer_modify_cluster(cluster); + hammer_modify_cluster_done(cluster); } void @@ -1834,13 +1858,14 @@ hammer_free_data(hammer_cluster_t cluster, int32_t bclu_offset, int32_t bytes) int32_t buf_no; int32_t nblks; + hammer_modify_cluster(cluster); if ((bytes & HAMMER_BUFMASK) == 0) { nblks = bytes / HAMMER_BUFSIZE; KKASSERT(nblks == 1 && (bclu_offset & HAMMER_BUFMASK) == 0); buf_no = bclu_offset / HAMMER_BUFSIZE; hammer_alist_free(&cluster->alist_master, buf_no, nblks); hammer_adjust_stats(cluster, HAMMER_FSBUF_DATA, -nblks); - hammer_modify_cluster(cluster); + hammer_modify_cluster_done(cluster); return; } @@ -1852,7 +1877,7 @@ hammer_free_data(hammer_cluster_t cluster, int32_t bclu_offset, int32_t bytes) KKASSERT(fsbuf_offset >= 0 && fsbuf_offset % blksize == 0); elm_no += fsbuf_offset / blksize; hammer_alist_free(live, elm_no, nblks); - hammer_modify_cluster(cluster); + hammer_modify_cluster_done(cluster); } void @@ -1863,13 +1888,14 @@ hammer_free_record(hammer_cluster_t cluster, int32_t bclu_offset) hammer_alist_t live; int32_t elm_no; + hammer_modify_cluster(cluster); elm_no = bclu_offset / HAMMER_BUFSIZE * HAMMER_FSBUF_MAXBLKS; fsbuf_offset -= offsetof(union hammer_fsbuf_ondisk, record.recs[0]); live = &cluster->alist_record; KKASSERT(fsbuf_offset >= 0 && fsbuf_offset % blksize == 0); elm_no += fsbuf_offset / blksize; hammer_alist_free(live, elm_no, 1); - hammer_modify_cluster(cluster); + hammer_modify_cluster_done(cluster); } @@ -1887,26 +1913,24 @@ alloc_new_buffer(hammer_cluster_t cluster, hammer_alist_t live, int32_t buf_no; int isfwd; - start = start / HAMMER_FSBUF_MAXBLKS; /* convert to buf_no */ + if (*bufferp) + hammer_rel_buffer(*bufferp, 0); + *bufferp = NULL; + start = start / HAMMER_FSBUF_MAXBLKS; /* convert to buf_no */ isfwd = (type != HAMMER_FSBUF_RECORDS); buf_no = hammer_alloc_master(cluster, 1, start, isfwd); if (buf_no == HAMMER_ALIST_BLOCK_NONE) { *errorp = ENOSPC; - *bufferp = NULL; return; } - hammer_modify_cluster(cluster); - /* * The new buffer must be initialized (type != 0) regardless of * whether we already have it cached or not, so don't try to * optimize the cached buffer check. Just call hammer_get_buffer(). */ buffer = hammer_get_buffer(cluster, buf_no, type, errorp); - if (*bufferp) - hammer_rel_buffer(*bufferp, 0); *bufferp = buffer; /* @@ -1917,8 +1941,10 @@ alloc_new_buffer(hammer_cluster_t cluster, hammer_alist_t live, if (buffer) { kprintf("alloc_new_buffer buf_no %d type %016llx nelms %d\n", buf_no, type, nelements); + hammer_modify_buffer(buffer); /*XXX*/ hammer_alist_free(live, buf_no * HAMMER_FSBUF_MAXBLKS, nelements); + hammer_modify_buffer_done(buffer); /*XXX*/ hammer_adjust_stats(cluster, type, 1); } } @@ -1927,9 +1953,9 @@ alloc_new_buffer(hammer_cluster_t cluster, hammer_alist_t live, * Sync dirty buffers to the media */ -/* - * Sync the entire filesystem. - */ +static int hammer_sync_scan1(struct mount *mp, struct vnode *vp, void *data); +static int hammer_sync_scan2(struct mount *mp, struct vnode *vp, void *data); + int hammer_sync_hmp(hammer_mount_t hmp, int waitfor) { @@ -1938,11 +1964,48 @@ hammer_sync_hmp(hammer_mount_t hmp, int waitfor) info.error = 0; info.waitfor = waitfor; + vmntvnodescan(hmp->mp, VMSC_GETVP|VMSC_NOWAIT, + hammer_sync_scan1, hammer_sync_scan2, &info); + RB_SCAN(hammer_vol_rb_tree, &hmp->rb_vols_root, NULL, hammer_sync_volume, &info); return(info.error); } +static int +hammer_sync_scan1(struct mount *mp, struct vnode *vp, void *data) +{ + struct hammer_inode *ip; + + ip = VTOI(vp); + if (vp->v_type == VNON || ((ip->flags & HAMMER_INODE_MODMASK) == 0 && + RB_EMPTY(&vp->v_rbdirty_tree))) { + return(-1); + } + return(0); +} + +static int +hammer_sync_scan2(struct mount *mp, struct vnode *vp, void *data) +{ + struct hammer_sync_info *info = data; + struct hammer_inode *ip; + int error; + + ip = VTOI(vp); + if (vp->v_type == VNON || vp->v_type == VBAD || + ((ip->flags & HAMMER_INODE_MODMASK) == 0 && + RB_EMPTY(&vp->v_rbdirty_tree))) { + return(0); + } + if (vp->v_type != VCHR) { + error = VOP_FSYNC(vp, info->waitfor); + if (error) + info->error = error; + } + return(0); +} + int hammer_sync_volume(hammer_volume_t volume, void *data) { @@ -1962,13 +2025,18 @@ hammer_sync_cluster(hammer_cluster_t cluster, void *data) { struct hammer_sync_info *info = data; - if (cluster->state != HAMMER_CLUSTER_IDLE) { - RB_SCAN(hammer_buf_rb_tree, &cluster->rb_bufs_root, NULL, - hammer_sync_buffer, info); + RB_SCAN(hammer_buf_rb_tree, &cluster->rb_bufs_root, NULL, + hammer_sync_buffer, info); + switch(cluster->state) { + case HAMMER_CLUSTER_OPEN: + case HAMMER_CLUSTER_IDLE: if (hammer_ref_cluster(cluster) == 0) { hammer_io_flush(&cluster->io, info); hammer_rel_cluster(cluster, 0); } + break; + default: + break; } return(0); } @@ -1988,69 +2056,6 @@ hammer_sync_buffer(hammer_buffer_t buffer, void *data) return(0); } -#if 0 - -/* - * Flush various tracking structures to disk - */ - -/* - * Flush various tracking structures to disk - */ -void -flush_all_volumes(void) -{ - hammer_volume_t vol; - - for (vol = VolBase; vol; vol = vol->next) - flush_volume(vol); -} - -void -flush_volume(hammer_volume_t vol) -{ - hammer_supercl_t supercl; - hammer_cluster_t cl; - - for (supercl = vol->supercl_base; supercl; supercl = supercl->next) - flush_supercl(supercl); - for (cl = vol->cluster_base; cl; cl = cl->next) - flush_cluster(cl); - writehammerbuf(vol, vol->ondisk, 0); -} - -void -flush_supercl(hammer_supercl_t supercl) -{ - int64_t supercl_offset; - - supercl_offset = supercl->scl_offset; - writehammerbuf(supercl->volume, supercl->ondisk, supercl_offset); -} - -void -flush_cluster(hammer_cluster_t cl) -{ - hammer_buffer_t buf; - int64_t cluster_offset; - - for (buf = cl->buffer_base; buf; buf = buf->next) - flush_buffer(buf); - cluster_offset = cl->clu_offset; - writehammerbuf(cl->volume, cl->ondisk, cluster_offset); -} - -void -flush_buffer(hammer_buffer_t buf) -{ - int64_t buffer_offset; - - buffer_offset = buf->buf_offset + buf->cluster->clu_offset; - writehammerbuf(buf->volume, buf->ondisk, buffer_offset); -} - -#endif - /* * Generic buffer initialization */ @@ -2136,6 +2141,7 @@ hammer_alloc_master(hammer_cluster_t cluster, int nblks, { int32_t buf_no; + hammer_modify_cluster(cluster); if (isfwd) { buf_no = hammer_alist_alloc_fwd(&cluster->alist_master, nblks, start); @@ -2151,6 +2157,7 @@ hammer_alloc_master(hammer_cluster_t cluster, int nblks, nblks, HAMMER_ALIST_BLOCK_MAX); } } + hammer_modify_cluster_done(cluster); /* * Recover space from empty record, b-tree, and data a-lists. @@ -2165,6 +2172,10 @@ hammer_alloc_master(hammer_cluster_t cluster, int nblks, static void hammer_adjust_stats(hammer_cluster_t cluster, u_int64_t buf_type, int nblks) { + hammer_modify_cluster(cluster); + hammer_modify_volume(cluster->volume); + hammer_modify_volume(cluster->volume->hmp->rootvol); + switch(buf_type) { case HAMMER_FSBUF_BTREE: cluster->ondisk->stat_idx_bufs += nblks; @@ -2182,9 +2193,9 @@ hammer_adjust_stats(hammer_cluster_t cluster, u_int64_t buf_type, int nblks) cluster->volume->hmp->rootvol->ondisk->vol0_stat_rec_bufs += nblks; break; } - hammer_modify_cluster(cluster); - hammer_modify_volume(cluster->volume); - hammer_modify_volume(cluster->volume->hmp->rootvol); + hammer_modify_cluster_done(cluster); + hammer_modify_volume_done(cluster->volume); + hammer_modify_volume_done(cluster->volume->hmp->rootvol); } /* @@ -2268,11 +2279,12 @@ buffer_alist_alloc_fwd(void *info, int32_t blk, int32_t radix, if (buffer) { KKASSERT(buffer->ondisk->head.buf_type != 0); + hammer_modify_buffer(buffer); r = hammer_alist_alloc_fwd(&buffer->alist, count, atblk - blk); if (r != HAMMER_ALIST_BLOCK_NONE) r += blk; + hammer_modify_buffer_done(buffer); *fullp = hammer_alist_isfull(&buffer->alist); - hammer_modify_buffer(buffer); hammer_rel_buffer(buffer, 0); } else { r = HAMMER_ALIST_BLOCK_NONE; @@ -2294,12 +2306,12 @@ buffer_alist_alloc_rev(void *info, int32_t blk, int32_t radix, buffer = hammer_get_buffer(cluster, buf_no, 0, &error); if (buffer) { KKASSERT(buffer->ondisk->head.buf_type != 0); - + hammer_modify_buffer(buffer); r = hammer_alist_alloc_rev(&buffer->alist, count, atblk - blk); if (r != HAMMER_ALIST_BLOCK_NONE) r += blk; + hammer_modify_buffer_done(buffer); *fullp = hammer_alist_isfull(&buffer->alist); - hammer_modify_buffer(buffer); hammer_rel_buffer(buffer, 0); } else { r = HAMMER_ALIST_BLOCK_NONE; @@ -2321,10 +2333,11 @@ buffer_alist_free(void *info, int32_t blk, int32_t radix, buffer = hammer_get_buffer(cluster, buf_no, 0, &error); if (buffer) { KKASSERT(buffer->ondisk->head.buf_type != 0); + hammer_modify_buffer(buffer); hammer_alist_free(&buffer->alist, base_blk, count); + hammer_modify_buffer_done(buffer); *emptyp = hammer_alist_isempty(&buffer->alist); /* XXX don't bother updating the buffer is completely empty? */ - hammer_modify_buffer(buffer); hammer_rel_buffer(buffer, 0); } else { *emptyp = 0; @@ -2382,11 +2395,12 @@ super_alist_alloc_fwd(void *info, int32_t blk, int32_t radix, scl_no = blk / HAMMER_SCL_MAXCLUSTERS; supercl = hammer_get_supercl(volume, scl_no, &error, 0); if (supercl) { + hammer_modify_supercl(supercl); r = hammer_alist_alloc_fwd(&supercl->alist, count, atblk - blk); if (r != HAMMER_ALIST_BLOCK_NONE) r += blk; + hammer_modify_supercl_done(supercl); *fullp = hammer_alist_isfull(&supercl->alist); - hammer_modify_supercl(supercl); hammer_rel_supercl(supercl, 0); } else { r = HAMMER_ALIST_BLOCK_NONE; @@ -2408,11 +2422,12 @@ super_alist_alloc_rev(void *info, int32_t blk, int32_t radix, scl_no = blk / HAMMER_SCL_MAXCLUSTERS; supercl = hammer_get_supercl(volume, scl_no, &error, 0); if (supercl) { + hammer_modify_supercl(supercl); r = hammer_alist_alloc_rev(&supercl->alist, count, atblk - blk); if (r != HAMMER_ALIST_BLOCK_NONE) r += blk; + hammer_modify_supercl_done(supercl); *fullp = hammer_alist_isfull(&supercl->alist); - hammer_modify_supercl(supercl); hammer_rel_supercl(supercl, 0); } else { r = HAMMER_ALIST_BLOCK_NONE; @@ -2433,9 +2448,10 @@ super_alist_free(void *info, int32_t blk, int32_t radix, scl_no = blk / HAMMER_SCL_MAXCLUSTERS; supercl = hammer_get_supercl(volume, scl_no, &error, 0); if (supercl) { + hammer_modify_supercl(supercl); hammer_alist_free(&supercl->alist, base_blk, count); + hammer_modify_supercl_done(supercl); *emptyp = hammer_alist_isempty(&supercl->alist); - hammer_modify_supercl(supercl); hammer_rel_supercl(supercl, 0); } else { *emptyp = 0; diff --git a/sys/vfs/hammer/hammer_spike.c b/sys/vfs/hammer/hammer_spike.c index 6ee7271008..7b00a340f6 100644 --- a/sys/vfs/hammer/hammer_spike.c +++ b/sys/vfs/hammer/hammer_spike.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/vfs/hammer/Attic/hammer_spike.c,v 1.2 2007/12/29 09:01:27 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/Attic/hammer_spike.c,v 1.3 2007/12/30 08:49:20 dillon Exp $ */ #include "hammer.h" @@ -155,6 +155,7 @@ hammer_spike(struct hammer_cursor **spikep) hammer_node_ondisk_t ondisk; hammer_btree_elm_t elm; + hammer_modify_node(spike->parent); ondisk = spike->parent->ondisk; elm = &ondisk->elms[spike->parent_index]; elm->internal.subtree_type = HAMMER_BTREE_TYPE_CLUSTER; @@ -162,18 +163,19 @@ hammer_spike(struct hammer_cursor **spikep) elm->internal.subtree_clu_no = ncluster->clu_no; elm->internal.subtree_vol_no = ncluster->volume->vol_no; elm->internal.subtree_count = onode->ondisk->count; /*XXX*/ - hammer_modify_node(spike->parent); + hammer_modify_node_done(spike->parent); hammer_flush_node(onode); } { hammer_cluster_ondisk_t ondisk; + hammer_modify_cluster(ncluster); ondisk = ncluster->ondisk; ondisk->clu_btree_parent_vol_no = ocluster->volume->vol_no; ondisk->clu_btree_parent_clu_no = ocluster->clu_no; ondisk->clu_btree_parent_offset = spike->parent->node_offset; ondisk->clu_btree_parent_clu_gen = ocluster->ondisk->clu_gen; - hammer_modify_cluster(ncluster); + hammer_modify_cluster_done(ncluster); } /* diff --git a/sys/vfs/hammer/hammer_subs.c b/sys/vfs/hammer/hammer_subs.c index 54029ac3b7..167d78ed40 100644 --- a/sys/vfs/hammer/hammer_subs.c +++ b/sys/vfs/hammer/hammer_subs.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/vfs/hammer/hammer_subs.c,v 1.7 2007/11/27 07:48:52 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/hammer_subs.c,v 1.8 2007/12/30 08:49:20 dillon Exp $ */ /* * HAMMER structural locking @@ -56,6 +56,7 @@ hammer_lock_ex(struct hammer_lock *lock) } lock->locktd = td; } + KKASSERT(lock->lockcount >= 0); ++lock->lockcount; crit_exit(); } @@ -75,12 +76,12 @@ hammer_lock_ex_try(struct hammer_lock *lock) return(EAGAIN); lock->locktd = td; } + KKASSERT(lock->lockcount >= 0); ++lock->lockcount; crit_exit(); return(0); } - void hammer_lock_sh(struct hammer_lock *lock) { @@ -142,6 +143,7 @@ hammer_unlock(struct hammer_lock *lock) void hammer_ref(struct hammer_lock *lock) { + KKASSERT(lock->refs >= 0); crit_enter(); ++lock->refs; crit_exit(); @@ -150,8 +152,8 @@ hammer_ref(struct hammer_lock *lock) void hammer_unref(struct hammer_lock *lock) { - crit_enter(); KKASSERT(lock->refs > 0); + crit_enter(); --lock->refs; crit_exit(); } diff --git a/sys/vfs/hammer/hammer_transaction.c b/sys/vfs/hammer/hammer_transaction.c index 7d004ab348..5c0937282e 100644 --- a/sys/vfs/hammer/hammer_transaction.c +++ b/sys/vfs/hammer/hammer_transaction.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/vfs/hammer/hammer_transaction.c,v 1.4 2007/12/29 09:01:27 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/hammer_transaction.c,v 1.5 2007/12/30 08:49:20 dillon Exp $ */ #include "hammer.h" @@ -69,13 +69,14 @@ hammer_alloc_tid(hammer_transaction_t trans) getnanotime(&ts); tid = ts.tv_sec * 1000000000LL + ts.tv_nsec; + hammer_modify_volume(trans->rootvol); ondisk = trans->rootvol->ondisk; if (tid < ondisk->vol0_nexttid) tid = ondisk->vol0_nexttid; if (tid == 0xFFFFFFFFFFFFFFFFULL) panic("hammer_start_transaction: Ran out of TIDs!"); ondisk->vol0_nexttid = tid + 1; - hammer_modify_volume(trans->rootvol); + hammer_modify_volume_done(trans->rootvol); return(tid); } @@ -86,8 +87,9 @@ hammer_alloc_recid(hammer_transaction_t trans) hammer_volume_ondisk_t ondisk; hammer_tid_t recid; + hammer_modify_volume(trans->rootvol); ondisk = trans->rootvol->ondisk; recid = ++ondisk->vol0_recid; - hammer_modify_volume(trans->rootvol); + hammer_modify_volume_done(trans->rootvol); return(recid); } diff --git a/sys/vfs/hammer/hammer_vnops.c b/sys/vfs/hammer/hammer_vnops.c index 3eee9cdeea..0341f86b4d 100644 --- a/sys/vfs/hammer/hammer_vnops.c +++ b/sys/vfs/hammer/hammer_vnops.c @@ -31,7 +31,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/sys/vfs/hammer/hammer_vnops.c,v 1.11 2007/12/30 00:47:22 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/hammer_vnops.c,v 1.12 2007/12/30 08:49:20 dillon Exp $ */ #include @@ -428,6 +428,8 @@ hammer_vop_ncreate(struct vop_ncreate_args *ap) */ error = hammer_create_inode(&trans, ap->a_vap, ap->a_cred, dip, &nip); + if (error) + kprintf("hammer_create_inode error %d\n", error); if (error) { hammer_abort_transaction(&trans); *ap->a_vpp = NULL; @@ -439,6 +441,8 @@ hammer_vop_ncreate(struct vop_ncreate_args *ap) * bump the inode's link count. */ error = hammer_ip_add_directory(&trans, dip, nch->ncp, nip); + if (error) + kprintf("hammer_ip_add_directory error %d\n", error); /* * Finish up. @@ -591,6 +595,7 @@ hammer_vop_nresolve(struct vop_nresolve_args *ap) * records for the purposes of the search. */ error = hammer_ip_first(&cursor, dip); + rec = NULL; while (error == 0) { error = hammer_ip_resolve_data(&cursor); if (error) @@ -719,6 +724,8 @@ hammer_vop_nmkdir(struct vop_nmkdir_args *ap) * returned inode will be referenced but not locked. */ error = hammer_create_inode(&trans, ap->a_vap, ap->a_cred, dip, &nip); + if (error) + kprintf("hammer_mkdir error %d\n", error); if (error) { hammer_abort_transaction(&trans); *ap->a_vpp = NULL; @@ -730,6 +737,8 @@ hammer_vop_nmkdir(struct vop_nmkdir_args *ap) * bump the inode's link count. */ error = hammer_ip_add_directory(&trans, dip, nch->ncp, nip); + if (error) + kprintf("hammer_mkdir (add) error %d\n", error); /* * Finish up.