From 932915322ed75b469e2d4756eae942ec3b987be6 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Fri, 11 Jul 2008 05:44:23 +0000 Subject: [PATCH] HAMMER 61C/Many: Stabilization * Clean up flusher sequencing for the mirroring, pruning, and reblocking code. Check free space and don't let the buffer cache implode. --- sys/vfs/hammer/hammer.h | 15 +++++---- sys/vfs/hammer/hammer_flusher.c | 27 +++++++++++++-- sys/vfs/hammer/hammer_mirror.c | 60 +++++++++++++++++++++++---------- sys/vfs/hammer/hammer_prune.c | 22 ++++++------ sys/vfs/hammer/hammer_reblock.c | 34 ++++++++++--------- sys/vfs/hammer/hammer_vnops.c | 24 ++++++------- 6 files changed, 118 insertions(+), 64 deletions(-) diff --git a/sys/vfs/hammer/hammer.h b/sys/vfs/hammer/hammer.h index 2f3f980c41..0023c7e030 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.111 2008/07/11 01:22:29 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/hammer.h,v 1.112 2008/07/11 05:44:23 dillon Exp $ */ /* * This header file contains structures used internally by the HAMMERFS @@ -722,10 +722,11 @@ struct hammer_sync_info { /* * checkspace slop (8MB chunks), higher numbers are more conservative. */ -#define HAMMER_CHECKSPACE_SLOP_REBLOCK 25 -#define HAMMER_CHECKSPACE_SLOP_WRITE 20 -#define HAMMER_CHECKSPACE_SLOP_CREATE 20 -#define HAMMER_CHECKSPACE_SLOP_REMOVE 10 +#define HAMMER_CHKSPC_REBLOCK 25 +#define HAMMER_CHKSPC_MIRROR 20 +#define HAMMER_CHKSPC_WRITE 20 +#define HAMMER_CHKSPC_CREATE 20 +#define HAMMER_CHKSPC_REMOVE 10 #if defined(_KERNEL) @@ -1081,8 +1082,10 @@ int hammer_signal_check(hammer_mount_t hmp); void hammer_flusher_create(hammer_mount_t hmp); void hammer_flusher_destroy(hammer_mount_t hmp); void hammer_flusher_sync(hammer_mount_t hmp); -void hammer_flusher_async(hammer_mount_t hmp); +int hammer_flusher_async(hammer_mount_t hmp); +void hammer_flusher_wait(hammer_mount_t hmp, int seq); int hammer_flusher_meta_limit(hammer_mount_t hmp); +int hammer_flusher_meta_halflimit(hammer_mount_t hmp); int hammer_flusher_undo_exhausted(hammer_transaction_t trans, int quarter); void hammer_flusher_clean_loose_ios(hammer_mount_t hmp); void hammer_flusher_finalize(hammer_transaction_t trans, int final); diff --git a/sys/vfs/hammer/hammer_flusher.c b/sys/vfs/hammer/hammer_flusher.c index 9ffeb45586..53513a90be 100644 --- a/sys/vfs/hammer/hammer_flusher.c +++ b/sys/vfs/hammer/hammer_flusher.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_flusher.c,v 1.35 2008/07/11 01:22:29 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/hammer_flusher.c,v 1.36 2008/07/11 05:44:23 dillon Exp $ */ /* * HAMMER dependancy flusher thread @@ -81,13 +81,26 @@ hammer_flusher_sync(hammer_mount_t hmp) /* * Sync all inodes pending on the flusher - return immediately. */ -void +int hammer_flusher_async(hammer_mount_t hmp) { + int seq; + if (hmp->flusher.td) { + seq = hmp->flusher.next; if (hmp->flusher.signal++ == 0) wakeup(&hmp->flusher.signal); + } else { + seq = hmp->flusher.done; } + return(seq); +} + +void +hammer_flusher_wait(hammer_mount_t hmp, int seq) +{ + while ((int)(seq - hmp->flusher.done) > 0) + tsleep(&hmp->flusher.done, 0, "hmrfls", 0); } void @@ -597,3 +610,13 @@ hammer_flusher_meta_limit(hammer_mount_t hmp) return(0); } +int +hammer_flusher_meta_halflimit(hammer_mount_t hmp) +{ + if (hmp->locked_dirty_space + hmp->io_running_space > + hammer_limit_dirtybufspace / 2) { + return(1); + } + return(0); +} + diff --git a/sys/vfs/hammer/hammer_mirror.c b/sys/vfs/hammer/hammer_mirror.c index 16df3fd055..74daef4e4a 100644 --- a/sys/vfs/hammer/hammer_mirror.c +++ b/sys/vfs/hammer/hammer_mirror.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_mirror.c,v 1.11 2008/07/11 01:22:29 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/hammer_mirror.c,v 1.12 2008/07/11 05:44:23 dillon Exp $ */ /* * HAMMER mirroring ioctls - serialize and deserialize modifications made @@ -132,6 +132,15 @@ retry: error = hammer_btree_first(&cursor); while (error == 0) { + /* + * Yield to more important tasks + */ + if (error == 0) { + error = hammer_signal_check(trans->hmp); + if (error) + break; + } + /* * An internal node can be returned in mirror-filtered * mode and indicates that the scan is returning a skip @@ -210,20 +219,6 @@ retry: } - /* - * Yield to more important tasks - */ - if ((error = hammer_signal_check(trans->hmp)) != 0) - break; - if (trans->hmp->sync_lock.wanted) { - tsleep(trans, 0, "hmrslo", hz / 10); - } - if (trans->hmp->locked_dirty_space + - trans->hmp->io_running_space > hammer_limit_dirtybufspace) { - hammer_flusher_async(trans->hmp); - tsleep(trans, 0, "hmrslo", hz / 10); - } - /* * The core code exports the data to userland. */ @@ -312,11 +307,14 @@ hammer_ioc_mirror_write(hammer_transaction_t trans, hammer_inode_t ip, union hammer_ioc_mrecord_any mrec; struct hammer_cursor cursor; u_int32_t localization; + int checkspace_count = 0; int error; int bytes; char *uptr; + int seq; localization = (u_int32_t)mirror->pfs_id << 16; + seq = trans->hmp->flusher.act; /* * Validate the mirror structure and relocalize the tracking keys. @@ -350,7 +348,35 @@ hammer_ioc_mirror_write(hammer_transaction_t trans, hammer_inode_t ip, * Loop until our input buffer has been exhausted. */ while (error == 0 && - mirror->count + sizeof(mrec.head) <= mirror->size) { + mirror->count + sizeof(mrec.head) <= mirror->size) { + + /* + * Don't blow out the buffer cache. Leave room for frontend + * cache as well. + */ + if (hammer_flusher_meta_halflimit(trans->hmp) || + hammer_flusher_undo_exhausted(trans, 1)) { + hammer_unlock_cursor(&cursor, 0); + hammer_flusher_wait(trans->hmp, seq); + hammer_lock_cursor(&cursor, 0); + seq = hammer_flusher_async(trans->hmp); + } + + /* + * If there is insufficient free space it may be due to + * reserved bigblocks, which flushing might fix. + */ + if (hammer_checkspace(trans->hmp, HAMMER_CHKSPC_MIRROR)) { + if (++checkspace_count == 10) { + error = ENOSPC; + break; + } + hammer_unlock_cursor(&cursor, 0); + hammer_flusher_wait(trans->hmp, seq); + hammer_lock_cursor(&cursor, 0); + seq = hammer_flusher_async(trans->hmp); + } + /* * Acquire and validate header @@ -669,8 +695,6 @@ hammer_mirror_delete_at_cursor(hammer_cursor_t cursor, elm = &cursor->node->ondisk->elms[cursor->index]; KKASSERT(elm->leaf.base.btype == HAMMER_BTREE_TYPE_RECORD); - kprintf("mirror_delete %016llx %016llx\n", elm->leaf.base.obj_id, elm->leaf.base.key); - trans = cursor->trans; hammer_sync_lock_sh(trans); diff --git a/sys/vfs/hammer/hammer_prune.c b/sys/vfs/hammer/hammer_prune.c index 3b83b7a06d..d92696ef99 100644 --- a/sys/vfs/hammer/hammer_prune.c +++ b/sys/vfs/hammer/hammer_prune.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_prune.c,v 1.13 2008/07/11 01:22:29 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/hammer_prune.c,v 1.14 2008/07/11 05:44:23 dillon Exp $ */ #include "hammer.h" @@ -60,6 +60,7 @@ hammer_ioc_prune(hammer_transaction_t trans, hammer_inode_t ip, int error; int isdir; int elm_array_size; + int seq; if (prune->nelms < 0 || prune->nelms > HAMMER_MAX_PRUNE_ELMS) return(EINVAL); @@ -92,6 +93,8 @@ hammer_ioc_prune(hammer_transaction_t trans, hammer_inode_t ip, goto failed; prune->elms = copy_elms; + seq = trans->hmp->flusher.act; + /* * Scan backwards. Retries typically occur if a deadlock is detected. */ @@ -140,11 +143,6 @@ retry: */ if ((error = hammer_signal_check(trans->hmp)) != 0) break; - if (hammer_flusher_meta_limit(trans->hmp) || - hammer_flusher_undo_exhausted(trans, 2)) { - error = EWOULDBLOCK; - break; - } if (prune->stat_oldest_tid > elm->base.create_tid) prune->stat_oldest_tid = elm->base.create_tid; @@ -204,15 +202,19 @@ retry: } } ++prune->stat_scanrecords; + + if (hammer_flusher_meta_halflimit(trans->hmp) || + hammer_flusher_undo_exhausted(trans, 1)) { + hammer_unlock_cursor(&cursor, 0); + hammer_flusher_wait(trans->hmp, seq); + hammer_lock_cursor(&cursor, 0); + seq = hammer_flusher_async(trans->hmp); + } error = hammer_btree_iterate_reverse(&cursor); } if (error == ENOENT) error = 0; hammer_done_cursor(&cursor); - if (error == EWOULDBLOCK) { - hammer_flusher_sync(trans->hmp); - goto retry; - } if (error == EDEADLK) goto retry; if (error == EINTR) { diff --git a/sys/vfs/hammer/hammer_reblock.c b/sys/vfs/hammer/hammer_reblock.c index b60e3c3ca0..8ae2a3ea78 100644 --- a/sys/vfs/hammer/hammer_reblock.c +++ b/sys/vfs/hammer/hammer_reblock.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_reblock.c,v 1.26 2008/07/11 01:22:29 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/hammer_reblock.c,v 1.27 2008/07/11 05:44:23 dillon Exp $ */ /* * HAMMER reblocker - This code frees up fragmented physical space @@ -61,8 +61,9 @@ hammer_ioc_reblock(hammer_transaction_t trans, hammer_inode_t ip, { struct hammer_cursor cursor; hammer_btree_elm_t elm; - int error; int checkspace_count; + int error; + int seq; if ((reblock->key_beg.localization | reblock->key_end.localization) & HAMMER_LOCALIZE_PSEUDOFS_MASK) { @@ -77,6 +78,7 @@ hammer_ioc_reblock(hammer_transaction_t trans, hammer_inode_t ip, reblock->key_cur.localization += ip->obj_localization; checkspace_count = 0; + seq = trans->hmp->flusher.act; retry: error = hammer_init_cursor(trans, &cursor, NULL, NULL); if (error) { @@ -126,27 +128,19 @@ retry: if ((error = hammer_signal_check(trans->hmp)) != 0) break; - /* - * If we build up too much meta-data we have to wait for - * a flush cycle. - */ - if (hammer_flusher_meta_limit(trans->hmp) || - hammer_flusher_undo_exhausted(trans, 2)) { - error = EWOULDBLOCK; - break; - } - /* * If there is insufficient free space it may be due to * reserved bigblocks, which flushing might fix. */ - if (hammer_checkspace(trans->hmp, HAMMER_CHECKSPACE_SLOP_REBLOCK)) { + if (hammer_checkspace(trans->hmp, HAMMER_CHKSPC_REBLOCK)) { if (++checkspace_count == 10) { error = ENOSPC; - } else { - error = EWOULDBLOCK; + break; } - break; + hammer_unlock_cursor(&cursor, 0); + hammer_flusher_wait(trans->hmp, seq); + hammer_lock_cursor(&cursor, 0); + seq = hammer_flusher_async(trans->hmp); } /* @@ -158,6 +152,14 @@ retry: hammer_sync_lock_sh(trans); error = hammer_reblock_helper(reblock, &cursor, elm); hammer_sync_unlock(trans); + + if (hammer_flusher_meta_halflimit(trans->hmp) || + hammer_flusher_undo_exhausted(trans, 1)) { + hammer_unlock_cursor(&cursor, 0); + hammer_flusher_wait(trans->hmp, seq); + hammer_lock_cursor(&cursor, 0); + seq = hammer_flusher_async(trans->hmp); + } if (error == 0) { cursor.flags |= HAMMER_CURSOR_ATEDISK; error = hammer_btree_iterate(&cursor); diff --git a/sys/vfs/hammer/hammer_vnops.c b/sys/vfs/hammer/hammer_vnops.c index 9cffcc41f3..98bdcc1242 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.85 2008/07/10 04:44:33 dillon Exp $ + * $DragonFly: src/sys/vfs/hammer/hammer_vnops.c,v 1.86 2008/07/11 05:44:23 dillon Exp $ */ #include @@ -352,7 +352,7 @@ hammer_vop_write(struct vop_write_args *ap) int blksize; int blkmask; - if ((error = hammer_checkspace(hmp, HAMMER_CHECKSPACE_SLOP_WRITE)) != 0) + if ((error = hammer_checkspace(hmp, HAMMER_CHKSPC_WRITE)) != 0) break; blksize = hammer_blocksize(uio->uio_offset); @@ -580,7 +580,7 @@ hammer_vop_ncreate(struct vop_ncreate_args *ap) if (dip->flags & HAMMER_INODE_RO) return (EROFS); - if ((error = hammer_checkspace(dip->hmp, HAMMER_CHECKSPACE_SLOP_CREATE)) != 0) + if ((error = hammer_checkspace(dip->hmp, HAMMER_CHKSPC_CREATE)) != 0) return (error); /* @@ -977,7 +977,7 @@ hammer_vop_nlink(struct vop_nlink_args *ap) return (EROFS); if (ip->flags & HAMMER_INODE_RO) return (EROFS); - if ((error = hammer_checkspace(dip->hmp, HAMMER_CHECKSPACE_SLOP_CREATE)) != 0) + if ((error = hammer_checkspace(dip->hmp, HAMMER_CHKSPC_CREATE)) != 0) return (error); /* @@ -1026,7 +1026,7 @@ hammer_vop_nmkdir(struct vop_nmkdir_args *ap) if (dip->flags & HAMMER_INODE_RO) return (EROFS); - if ((error = hammer_checkspace(dip->hmp, HAMMER_CHECKSPACE_SLOP_CREATE)) != 0) + if ((error = hammer_checkspace(dip->hmp, HAMMER_CHKSPC_CREATE)) != 0) return (error); /* @@ -1095,7 +1095,7 @@ hammer_vop_nmknod(struct vop_nmknod_args *ap) if (dip->flags & HAMMER_INODE_RO) return (EROFS); - if ((error = hammer_checkspace(dip->hmp, HAMMER_CHECKSPACE_SLOP_CREATE)) != 0) + if ((error = hammer_checkspace(dip->hmp, HAMMER_CHKSPC_CREATE)) != 0) return (error); /* @@ -1440,7 +1440,7 @@ hammer_vop_nremove(struct vop_nremove_args *ap) dip = VTOI(ap->a_dvp); if (hammer_nohistory(dip) == 0 && - (error = hammer_checkspace(dip->hmp, HAMMER_CHECKSPACE_SLOP_REMOVE)) != 0) { + (error = hammer_checkspace(dip->hmp, HAMMER_CHKSPC_REMOVE)) != 0) { return (error); } @@ -1481,7 +1481,7 @@ hammer_vop_nrename(struct vop_nrename_args *ap) return (EROFS); if (ip->flags & HAMMER_INODE_RO) return (EROFS); - if ((error = hammer_checkspace(fdip->hmp, HAMMER_CHECKSPACE_SLOP_CREATE)) != 0) + if ((error = hammer_checkspace(fdip->hmp, HAMMER_CHKSPC_CREATE)) != 0) return (error); hammer_start_transaction(&trans, fdip->hmp); @@ -1597,7 +1597,7 @@ hammer_vop_nrmdir(struct vop_nrmdir_args *ap) dip = VTOI(ap->a_dvp); if (hammer_nohistory(dip) == 0 && - (error = hammer_checkspace(dip->hmp, HAMMER_CHECKSPACE_SLOP_REMOVE)) != 0) { + (error = hammer_checkspace(dip->hmp, HAMMER_CHKSPC_REMOVE)) != 0) { return (error); } @@ -1634,7 +1634,7 @@ hammer_vop_setattr(struct vop_setattr_args *ap) if (ip->flags & HAMMER_INODE_RO) return (EROFS); if (hammer_nohistory(ip) == 0 && - (error = hammer_checkspace(ip->hmp, HAMMER_CHECKSPACE_SLOP_REMOVE)) != 0) { + (error = hammer_checkspace(ip->hmp, HAMMER_CHKSPC_REMOVE)) != 0) { return (error); } @@ -1835,7 +1835,7 @@ hammer_vop_nsymlink(struct vop_nsymlink_args *ap) if (dip->flags & HAMMER_INODE_RO) return (EROFS); - if ((error = hammer_checkspace(dip->hmp, HAMMER_CHECKSPACE_SLOP_CREATE)) != 0) + if ((error = hammer_checkspace(dip->hmp, HAMMER_CHKSPC_CREATE)) != 0) return (error); /* @@ -1923,7 +1923,7 @@ hammer_vop_nwhiteout(struct vop_nwhiteout_args *ap) dip = VTOI(ap->a_dvp); if (hammer_nohistory(dip) == 0 && - (error = hammer_checkspace(dip->hmp, HAMMER_CHECKSPACE_SLOP_CREATE)) != 0) { + (error = hammer_checkspace(dip->hmp, HAMMER_CHKSPC_CREATE)) != 0) { return (error); } -- 2.41.0