diff --git a/sys/vfs/hammer/hammer_redo.c b/sys/vfs/hammer/hammer_redo.c index fc5a4dc..fb8ac84 100644 --- a/sys/vfs/hammer/hammer_redo.c +++ b/sys/vfs/hammer/hammer_redo.c @@ -87,8 +87,23 @@ hammer_generate_redo(hammer_transaction_t trans, hammer_inode_t ip, hammer_lock_ex(&hmp->undo_lock); /* undo had better not roll over (loose test) */ - if (hammer_undo_space(trans) < len + HAMMER_BUFSIZE*3) - hpanic("insufficient UNDO/REDO FIFO space for redo!"); + if (hammer_undo_space(trans) < len + HAMMER_BUFSIZE*3) { + /* + * The UNDO/REDO FIFO is exhausted because the flusher has + * not yet reclaimed space (the on-disk first_offset lags at + * least one full finalize cycle behind the frontend). + * + * REDO is an optional optimization, so fail the operation + * gracefully instead of panicking the kernel. The frontend + * write path also disables REDO for the inode under FIFO + * pressure (hammer_vnops.c), causing the next fsync() to + * fall back to a full flush. + */ + error = ENOSPC; + hammer_modify_volume_done(root_volume); + hammer_unlock(&hmp->undo_lock); + return(error); + } /* * Loop until the undo for the entire range has been laid down. diff --git a/sys/vfs/hammer/hammer_vnops.c b/sys/vfs/hammer/hammer_vnops.c index c8150ed..6186f17 100644 --- a/sys/vfs/hammer/hammer_vnops.c +++ b/sys/vfs/hammer/hammer_vnops.c @@ -741,7 +741,13 @@ hammer_vop_write(struct vop_write_args *ap) * flushed. */ if ((ip->flags & HAMMER_INODE_REDO) && error == 0) { - if (ip->redo_count < hammer_limit_redo) { + int64_t undospace; + + hammer_lock_sh(&hmp->undo_lock); + undospace = hammer_undo_space(&trans); + hammer_unlock(&hmp->undo_lock); + if (ip->redo_count < hammer_limit_redo && + undospace > (int64_t)hammer_limit_redo * 2) { bp->b_flags |= B_VFSFLAG1; error = hammer_generate_redo(&trans, ip, base_offset + offset, @@ -749,6 +755,12 @@ hammer_vop_write(struct vop_write_args *ap) bp->b_data + offset, (size_t)n); } else { + /* + * Per-inode budget exhausted or the + * UNDO/REDO FIFO is running low: disable + * REDO until the next fsync() re-enables + * it (full-flush fallback). + */ ip->flags &= ~HAMMER_INODE_REDO; } }