From a25b6324d2265e54ae1120444b75c1afe30f57f2 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Mon, 13 Aug 2018 14:21:49 -0700 Subject: [PATCH] scoutfs: maintain free_blocks in one place The free_blocks counter in the super is meant to track the number of total blocks in the primary free extent index. Callers of extent manipulation were trying to keep it in sync with the extents. Segment allocation was allocating extents manually using a cursor. It forgot to update free_blocks. Segment freeing then freed the segment as an extent which did update free_blocks. This created ever accumulating free blocks over time which eventually pushed it greater than total blocks and caused df to report negative usage. This updates the free_blocks count in server extent io which is the only place we update the extent items themselves. This ensures that we'll keep the count in sync with the extent items. Callers don't have to worry about it. Signed-off-by: Zach Brown T# with '#' will be ignored, and an empty message aborts the commit. --- kmod/src/server.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/kmod/src/server.c b/kmod/src/server.c index 1947a8bf..2ee1be3e 100644 --- a/kmod/src/server.c +++ b/kmod/src/server.c @@ -120,6 +120,10 @@ static int init_extent_from_btree_key(struct scoutfs_extent *ext, u8 type, * This is called by the extent core on behalf of the server who holds * the appropriate locks to protect the many btree items that can be * accessed on behalf of one extent operation. + * + * The free_blocks count in the super tracks the number of blocks in + * the primary extent index. We update it here instead of expecting + * callers to remember. */ static int server_extent_io(struct super_block *sb, int op, struct scoutfs_extent *ext, void *data) @@ -192,6 +196,13 @@ static int server_extent_io(struct super_block *sb, int op, } } + if (ret == 0 && ext->type == SCOUTFS_FREE_EXTENT_BLKNO_TYPE) { + if (op == SEI_INSERT) + le64_add_cpu(&super->free_blocks, ext->len); + else if (op == SEI_DELETE) + le64_add_cpu(&super->free_blocks, -ext->len); + } + return ret; } @@ -209,7 +220,6 @@ static int alloc_extent(struct super_block *sb, u64 blocks, u64 *start, u64 *len) { struct server_info *server = SCOUTFS_SB(sb)->server_info; - struct scoutfs_super_block *super = &SCOUTFS_SB(sb)->super; struct scoutfs_extent ext; int ret; @@ -244,7 +254,6 @@ static int alloc_extent(struct super_block *sb, u64 blocks, goto out; trace_scoutfs_server_alloc_extent_allocated(sb, &ext); - le64_add_cpu(&super->free_blocks, -ext.len); *start = ext.start; *len = ext.len; @@ -278,7 +287,6 @@ struct pending_free_extent { */ static int apply_pending_frees(struct super_block *sb) { - struct scoutfs_super_block *super = &SCOUTFS_SB(sb)->super; struct server_info *server = SCOUTFS_SB(sb)->server_info; struct pending_free_extent *pfe; struct pending_free_extent *tmp; @@ -298,7 +306,6 @@ static int apply_pending_frees(struct super_block *sb) break; } - le64_add_cpu(&super->free_blocks, pfe->len); list_del_init(&pfe->head); kfree(pfe); }