From patchwork Wed Nov 22 23:25:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kent Overstreet X-Patchwork-Id: 13465564 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 22691C61D97 for ; Wed, 22 Nov 2023 23:25:43 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id A0DAE6B05F3; Wed, 22 Nov 2023 18:25:34 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 96FFD6B05F6; Wed, 22 Nov 2023 18:25:34 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 774C96B05F8; Wed, 22 Nov 2023 18:25:34 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0016.hostedemail.com [216.40.44.16]) by kanga.kvack.org (Postfix) with ESMTP id 5F2B96B05F3 for ; Wed, 22 Nov 2023 18:25:34 -0500 (EST) Received: from smtpin05.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay10.hostedemail.com (Postfix) with ESMTP id 37ABBC16DA for ; Wed, 22 Nov 2023 23:25:34 +0000 (UTC) X-FDA: 81487174188.05.93E6DD6 Received: from out-187.mta0.migadu.com (out-187.mta0.migadu.com [91.218.175.187]) by imf29.hostedemail.com (Postfix) with ESMTP id 6B613120019 for ; Wed, 22 Nov 2023 23:25:32 +0000 (UTC) Authentication-Results: imf29.hostedemail.com; dkim=pass header.d=linux.dev header.s=key1 header.b="L/6Ssih/"; spf=pass (imf29.hostedemail.com: domain of kent.overstreet@linux.dev designates 91.218.175.187 as permitted sender) smtp.mailfrom=kent.overstreet@linux.dev; dmarc=pass (policy=none) header.from=linux.dev ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1700695532; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=1NMfXBsonhz+ezAg3sKaNXQeyap2g8yZZq48bhQ7Wec=; b=M9LC4I0mlHEq8ERhyqeIyIMhOZrJhpWaCDqYn8K1yy+s9l4leUsl/tA2yum8xZfLQY1PBf NMSQDV9FFrRoyIC8zQc+Mw8a/hMkR6wA0lRB0Kg0guHhlM5pp8EbQkNV82Q7aD5Yb6PILE 5E7czxVtFk+dtO33WZ6vbZzZzINsFjU= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1700695532; a=rsa-sha256; cv=none; b=NbtZ/UugSvR004T0JmUZCY/bYna+97sPOtccxO2CrwUvktDgB8y09RBWrNLAmYouRD1FUi AKvEA46sdcxAgnXhctdYb/PNAa480IZs7/IWz2pI3glsZtMTZPF1HwzefQsIF1hjRse4d9 30YoEB/PZDbjNPu4fKqUSyqESuJMqSk= ARC-Authentication-Results: i=1; imf29.hostedemail.com; dkim=pass header.d=linux.dev header.s=key1 header.b="L/6Ssih/"; spf=pass (imf29.hostedemail.com: domain of kent.overstreet@linux.dev designates 91.218.175.187 as permitted sender) smtp.mailfrom=kent.overstreet@linux.dev; dmarc=pass (policy=none) header.from=linux.dev X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1700695531; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=1NMfXBsonhz+ezAg3sKaNXQeyap2g8yZZq48bhQ7Wec=; b=L/6Ssih/O7QhT9069T31VThCTNukc3MMvLU+/VMAZ3jnXRJbm6rGc+TMETY0offdQtngVp 6jDxcKMISPFQdNLC7MDtwdDuraODTV+7GC8ozeT/P6g2dMkS3qcUJPEzMFbmowqy23RWPc TvwAmvR6OWymxacMWlUCPuncKjfbn0Y= From: Kent Overstreet To: linux-mm@kvack.org, linux-kernel@vger.kernel.org Cc: Daniel Hill , Kent Overstreet Subject: [PATCH 7/7] bcachefs: add counters for failed shrinker reclaim Date: Wed, 22 Nov 2023 18:25:12 -0500 Message-ID: <20231122232515.177833-8-kent.overstreet@linux.dev> In-Reply-To: <20231122232515.177833-1-kent.overstreet@linux.dev> References: <20231122232515.177833-1-kent.overstreet@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT X-Rspamd-Queue-Id: 6B613120019 X-Rspam-User: X-Stat-Signature: b44pgfjmpesg7hn4szdu9citndqcwj9p X-Rspamd-Server: rspam03 X-HE-Tag: 1700695532-759344 X-HE-Meta: U2FsdGVkX1+ttRMmsBarg1bHgh4PQnsCnTqLTCHjhOXj0dCMHfFovuaZy2KXw/eAhf+3oxYj3mRXLZgb2DxedJkI0ieiRwvhIrfxj69lbrYh6dONzBsKKwKBMQxaMKvAfvsuSgxi4NNNURUmKGcq1gSvhgXBrq3pHHFvXQEgDUpwAvArXgsBcELB7Gae27uzNuH+TpfUZSu1ReOV+VPuiYMFTnHFTMHXSMyg8MAJgTxCzx7r3y0CvAd75VTrhJFzVMrv6rJx9EZFphUnC+3SwDeVGeAvuHrrdOv09585QA5n8U3q0Wz3y9Nv/qrthjncSX9EfOtGjAJvXkb1FQ8rGkhScTzunj5lejZjPW8VLfK5eYZiBcwhxekm220+6Q352b9H61oW/EuPoS3QlPpfIvyW3sCQ30xsOPR2oAKZxcSbUmSMnI0bPtbXmZBHfuMN46QM4xF2PbDd1N0oqJFyJvxxzNrkututsPSevtNw9z4gW0tn//JMg0+SqJ0M5goWkyIpEx3VVXrqZ3K5Fx3cjsAjft2SHbm1JJFRF9/i9ijvnCNuW25WStLEk2WTds+6G9l29zGPC9J7wqjabyiL3Xqqcc4eanBnzEZbkONIyvxGoXe6eGxcB2qCpTnTjvXx4fq7ZvsJ1555PF9LKPUN96KnNcVvmrBP/SK/txHwr+WkxpMdJapT/rCYO57b5H+9zWcDXjnywS8JiWZIzGGTAbFg8+Ooi9Byt6uqPwxXAFrF9LvEASGbQIzvf+38GN6N3IDXCmTiwwvQ0/BBudK58Pzr28UwYBnL0DUeqb+Ic2LH7/XlObq8vATzTJRNq1CIrDvwXaXOCxFXb6R+ZX1T5kHPTyccW7holBgYnv+fNzjd5GX1iTOQ+QgohTxZlkzy0Yi+fhkM5SrBkCPvMZ+cg6N+p6pPz7KSK6djc5CnGcW56x419bDpFy0W/77TV1Ea194Yf9hUsnCv3i7DpDR 1LNmthKR 4sPgLx13Tz3njJPPfg6qNyHnLFQ1qD63j3/f6lsLedzZji5/JOXAEVn9+hWADbTYdTzv4NIP8NOgu3H4YglOdxs7v2bhpYZ2Qf6toEfBBv52rlCw= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: From: Daniel Hill This adds distinct counters for every reason the btree node shrinker can fail to free an object - if our shrinker isn't making progress, this will tell us why. Signed-off-by: Daniel Hill Signed-off-by: Kent Overstreet --- fs/bcachefs/btree_cache.c | 91 +++++++++++++++++++++++++++++---------- fs/bcachefs/btree_cache.h | 2 +- fs/bcachefs/btree_types.h | 10 +++++ fs/bcachefs/sysfs.c | 2 +- 4 files changed, 81 insertions(+), 24 deletions(-) diff --git a/fs/bcachefs/btree_cache.c b/fs/bcachefs/btree_cache.c index aab279dff944..72dea90e12fa 100644 --- a/fs/bcachefs/btree_cache.c +++ b/fs/bcachefs/btree_cache.c @@ -15,6 +15,12 @@ #include #include +#define BTREE_CACHE_NOT_FREED_INCREMENT(counter) \ +do { \ + if (shrinker_counter) \ + bc->not_freed_##counter++; \ +} while (0) + const char * const bch2_btree_node_flags[] = { #define x(f) #f, BTREE_FLAGS() @@ -202,7 +208,7 @@ static inline struct btree *btree_cache_find(struct btree_cache *bc, * this version is for btree nodes that have already been freed (we're not * reaping a real btree node) */ -static int __btree_node_reclaim(struct bch_fs *c, struct btree *b, bool flush) +static int __btree_node_reclaim(struct bch_fs *c, struct btree *b, bool flush, bool shrinker_counter) { struct btree_cache *bc = &c->btree_cache; int ret = 0; @@ -212,38 +218,64 @@ static int __btree_node_reclaim(struct bch_fs *c, struct btree *b, bool flush) if (b->flags & ((1U << BTREE_NODE_dirty)| (1U << BTREE_NODE_read_in_flight)| (1U << BTREE_NODE_write_in_flight))) { - if (!flush) + if (!flush) { + if (btree_node_dirty(b)) + BTREE_CACHE_NOT_FREED_INCREMENT(dirty); + else if (btree_node_read_in_flight(b)) + BTREE_CACHE_NOT_FREED_INCREMENT(read_in_flight); + else if (btree_node_write_in_flight(b)) + BTREE_CACHE_NOT_FREED_INCREMENT(write_in_flight); return -BCH_ERR_ENOMEM_btree_node_reclaim; + } /* XXX: waiting on IO with btree cache lock held */ bch2_btree_node_wait_on_read(b); bch2_btree_node_wait_on_write(b); } - if (!six_trylock_intent(&b->c.lock)) + if (!six_trylock_intent(&b->c.lock)) { + BTREE_CACHE_NOT_FREED_INCREMENT(lock_intent); return -BCH_ERR_ENOMEM_btree_node_reclaim; + } - if (!six_trylock_write(&b->c.lock)) + if (!six_trylock_write(&b->c.lock)) { + BTREE_CACHE_NOT_FREED_INCREMENT(lock_write); goto out_unlock_intent; + } /* recheck under lock */ if (b->flags & ((1U << BTREE_NODE_read_in_flight)| (1U << BTREE_NODE_write_in_flight))) { - if (!flush) + if (!flush) { + if (btree_node_read_in_flight(b)) + BTREE_CACHE_NOT_FREED_INCREMENT(read_in_flight); + else if (btree_node_write_in_flight(b)) + BTREE_CACHE_NOT_FREED_INCREMENT(write_in_flight); goto out_unlock; + } six_unlock_write(&b->c.lock); six_unlock_intent(&b->c.lock); goto wait_on_io; } - if (btree_node_noevict(b) || - btree_node_write_blocked(b) || - btree_node_will_make_reachable(b)) + if (btree_node_noevict(b)) { + BTREE_CACHE_NOT_FREED_INCREMENT(noevict); + goto out_unlock; + } + if (btree_node_write_blocked(b)) { + BTREE_CACHE_NOT_FREED_INCREMENT(write_blocked); + goto out_unlock; + } + if (btree_node_will_make_reachable(b)) { + BTREE_CACHE_NOT_FREED_INCREMENT(will_make_reachable); goto out_unlock; + } if (btree_node_dirty(b)) { - if (!flush) + if (!flush) { + BTREE_CACHE_NOT_FREED_INCREMENT(dirty); goto out_unlock; + } /* * Using the underscore version because we don't want to compact * bsets after the write, since this node is about to be evicted @@ -273,14 +305,14 @@ static int __btree_node_reclaim(struct bch_fs *c, struct btree *b, bool flush) goto out; } -static int btree_node_reclaim(struct bch_fs *c, struct btree *b) +static int btree_node_reclaim(struct bch_fs *c, struct btree *b, bool shrinker_counter) { - return __btree_node_reclaim(c, b, false); + return __btree_node_reclaim(c, b, false, shrinker_counter); } static int btree_node_write_and_reclaim(struct bch_fs *c, struct btree *b) { - return __btree_node_reclaim(c, b, true); + return __btree_node_reclaim(c, b, true, false); } static unsigned long bch2_btree_cache_scan(struct shrinker *shrink, @@ -328,11 +360,12 @@ static unsigned long bch2_btree_cache_scan(struct shrinker *shrink, if (touched >= nr) goto out; - if (!btree_node_reclaim(c, b)) { + if (!btree_node_reclaim(c, b, true)) { btree_node_data_free(c, b); six_unlock_write(&b->c.lock); six_unlock_intent(&b->c.lock); freed++; + bc->freed++; } } restart: @@ -341,9 +374,11 @@ static unsigned long bch2_btree_cache_scan(struct shrinker *shrink, if (btree_node_accessed(b)) { clear_btree_node_accessed(b); - } else if (!btree_node_reclaim(c, b)) { + bc->not_freed_access_bit++; + } else if (!btree_node_reclaim(c, b, true)) { freed++; btree_node_data_free(c, b); + bc->freed++; bch2_btree_node_hash_remove(bc, b); six_unlock_write(&b->c.lock); @@ -400,7 +435,7 @@ static void bch2_btree_cache_shrinker_to_text(struct seq_buf *s, struct shrinker size_t buflen = seq_buf_get_buf(s, &cbuf); struct printbuf out = PRINTBUF_EXTERN(cbuf, buflen); - bch2_btree_cache_to_text(&out, c); + bch2_btree_cache_to_text(&out, &c->btree_cache); seq_buf_commit(s, out.pos); } @@ -564,7 +599,7 @@ static struct btree *btree_node_cannibalize(struct bch_fs *c) struct btree *b; list_for_each_entry_reverse(b, &bc->live, list) - if (!btree_node_reclaim(c, b)) + if (!btree_node_reclaim(c, b, false)) return b; while (1) { @@ -600,7 +635,7 @@ struct btree *bch2_btree_node_mem_alloc(struct btree_trans *trans, bool pcpu_rea * disk node. Check the freed list before allocating a new one: */ list_for_each_entry(b, freed, list) - if (!btree_node_reclaim(c, b)) { + if (!btree_node_reclaim(c, b, false)) { list_del_init(&b->list); goto got_node; } @@ -626,7 +661,7 @@ struct btree *bch2_btree_node_mem_alloc(struct btree_trans *trans, bool pcpu_rea * the list. Check if there's any freed nodes there: */ list_for_each_entry(b2, &bc->freeable, list) - if (!btree_node_reclaim(c, b2)) { + if (!btree_node_reclaim(c, b2, false)) { swap(b->data, b2->data); swap(b->aux_data, b2->aux_data); btree_node_to_freedlist(bc, b2); @@ -1222,9 +1257,21 @@ void bch2_btree_node_to_text(struct printbuf *out, struct bch_fs *c, const struc stats.failed); } -void bch2_btree_cache_to_text(struct printbuf *out, const struct bch_fs *c) +void bch2_btree_cache_to_text(struct printbuf *out, const struct btree_cache *bc) { - prt_printf(out, "nr nodes:\t\t%u\n", c->btree_cache.used); - prt_printf(out, "nr dirty:\t\t%u\n", atomic_read(&c->btree_cache.dirty)); - prt_printf(out, "cannibalize lock:\t%p\n", c->btree_cache.alloc_lock); + prt_printf(out, "nr nodes:\t\t%u\n", bc->used); + prt_printf(out, "nr dirty:\t\t%u\n", atomic_read(&bc->dirty)); + prt_printf(out, "cannibalize lock:\t%p\n", bc->alloc_lock); + + prt_printf(out, "freed:\t\t\t\t%u\n", bc->freed); + prt_printf(out, "not freed, dirty:\t\t%u\n", bc->not_freed_dirty); + prt_printf(out, "not freed, write in flight:\t%u\n", bc->not_freed_write_in_flight); + prt_printf(out, "not freed, read in flight:\t%u\n", bc->not_freed_read_in_flight); + prt_printf(out, "not freed, lock intent failed:\t%u\n", bc->not_freed_lock_intent); + prt_printf(out, "not freed, lock write failed:\t%u\n", bc->not_freed_lock_write); + prt_printf(out, "not freed, access bit:\t\t%u\n", bc->not_freed_access_bit); + prt_printf(out, "not freed, no evict failed:\t%u\n", bc->not_freed_noevict); + prt_printf(out, "not freed, write blocked:\t%u\n", bc->not_freed_write_blocked); + prt_printf(out, "not freed, will make reachable:\t%u\n", bc->not_freed_will_make_reachable); + } diff --git a/fs/bcachefs/btree_cache.h b/fs/bcachefs/btree_cache.h index cfb80b201d61..bfe1d7482cbc 100644 --- a/fs/bcachefs/btree_cache.h +++ b/fs/bcachefs/btree_cache.h @@ -126,6 +126,6 @@ static inline struct btree *btree_node_root(struct bch_fs *c, struct btree *b) const char *bch2_btree_id_str(enum btree_id); void bch2_btree_pos_to_text(struct printbuf *, struct bch_fs *, const struct btree *); void bch2_btree_node_to_text(struct printbuf *, struct bch_fs *, const struct btree *); -void bch2_btree_cache_to_text(struct printbuf *, const struct bch_fs *); +void bch2_btree_cache_to_text(struct printbuf *, const struct btree_cache *); #endif /* _BCACHEFS_BTREE_CACHE_H */ diff --git a/fs/bcachefs/btree_types.h b/fs/bcachefs/btree_types.h index 2326bceb34f8..14983e778756 100644 --- a/fs/bcachefs/btree_types.h +++ b/fs/bcachefs/btree_types.h @@ -162,6 +162,16 @@ struct btree_cache { /* Number of elements in live + freeable lists */ unsigned used; unsigned reserve; + unsigned freed; + unsigned not_freed_lock_intent; + unsigned not_freed_lock_write; + unsigned not_freed_dirty; + unsigned not_freed_read_in_flight; + unsigned not_freed_write_in_flight; + unsigned not_freed_noevict; + unsigned not_freed_write_blocked; + unsigned not_freed_will_make_reachable; + unsigned not_freed_access_bit; atomic_t dirty; struct shrinker *shrink; diff --git a/fs/bcachefs/sysfs.c b/fs/bcachefs/sysfs.c index ab743115f169..264c46b456c2 100644 --- a/fs/bcachefs/sysfs.c +++ b/fs/bcachefs/sysfs.c @@ -402,7 +402,7 @@ SHOW(bch2_fs) bch2_btree_updates_to_text(out, c); if (attr == &sysfs_btree_cache) - bch2_btree_cache_to_text(out, c); + bch2_btree_cache_to_text(out, &c->btree_cache); if (attr == &sysfs_btree_key_cache) bch2_btree_key_cache_to_text(out, &c->btree_key_cache);