Received: by 2002:a05:6358:9144:b0:117:f937:c515 with SMTP id r4csp6102236rwr; Tue, 9 May 2023 10:12:20 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ7FMfFU1vclSSbDCYUbBx2sciWX1Wqk/vaSkBi+AY3LOZNir81J2aN9WfBcd5jbxtudUCCp X-Received: by 2002:a17:90a:ba98:b0:250:ac7f:a76e with SMTP id t24-20020a17090aba9800b00250ac7fa76emr3181564pjr.6.1683652340405; Tue, 09 May 2023 10:12:20 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1683652340; cv=none; d=google.com; s=arc-20160816; b=hdYxBWNgwTBZfCZhO/Ysw42kp15nMYB9bkCn2exMDyrvJme8K8/9rWIvpg2TSxQAqS lNUNuzU66xPGoOexLENFq5KRo+EPll7BnxZzQQM9dT2i/yqyCSSXyymcf40/CsHk2Uga NQhrXwgjbwS8pSPW7FzT4vYNOzmYhY+M58XJU4F1JKxp3YA9IqMqgbnPuVfYg14knxob 17oaPl32NB1HkSidgtoyJhM1dzL7QfaEDui4Kf7Rk0Zw0J+KOZgb1Cnc41cle05/1tRR 0qyrJV08/D3Dhc9zQ7BvuDt1bOdPhVg0rd0LRe9Kto5L37uF+JzCiBlhqxLEB4Mpov7I H6kQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=+ZhmCl+n4yHEwTa1THztHgqHnTTx5bTorYdBdx9eWUk=; b=onfgMOsa71FxXqyh+I0UNBObwVBMFn81HIk1reZTZJgvosINqJoA92DOTrGMyElPKH PAbSH3qtfpo9ySrMHu8A1x9pq+uYexb1lpKCZ3U/7olj/R7hNX8Ajy9FRzmitLCFijR4 xHm3yOuKRU/+/3Ry1b0VFaAxECzovMW/gwTCn9J1yvgU1xfrDlinP1PEjSIQVvytIhy4 tIF8H4YP0qSyNDyd9yryVgsV8VevzCVb75mIFmTrlkvJW8IZYSUi5uYxWaM5z7J4USs/ fP5lLImcT4z1aYXILjE9rEahUuUFBnLgcoaor1gVcsjhPfjsP+rC7aNFOcA3a7a6ck+4 Vrmg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linux.dev header.s=key1 header.b=AnOcSonl; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linux.dev Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id 6-20020a17090a190600b0022915b6dd7asi13461686pjg.145.2023.05.09.10.12.08; Tue, 09 May 2023 10:12:20 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linux.dev header.s=key1 header.b=AnOcSonl; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linux.dev Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235193AbjEIRAY (ORCPT + 99 others); Tue, 9 May 2023 13:00:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42258 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234954AbjEIQ7Q (ORCPT ); Tue, 9 May 2023 12:59:16 -0400 Received: from out-22.mta1.migadu.com (out-22.mta1.migadu.com [IPv6:2001:41d0:203:375::16]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 95687FA for ; Tue, 9 May 2023 09:57:40 -0700 (PDT) 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=1683651457; 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=+ZhmCl+n4yHEwTa1THztHgqHnTTx5bTorYdBdx9eWUk=; b=AnOcSonlgfJwVL1TfpYCrbzb3btH35FbKemYRBb7Tu6SNotf+y3JjRuDfJ26u2TA5Ga1Xu WMjtnAl0/RYF0F/+W96E3Zb9Pwc42jua50CeTq8jkOPIADAjkuqMarQVzkNNGhQyHCJQWM qzXJsyauJIJIQ/Y3wqhmN1555VfHPNs= From: Kent Overstreet To: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-bcachefs@vger.kernel.org Cc: Kent Overstreet , Kent Overstreet Subject: [PATCH 27/32] lib/generic-radix-tree.c: Add peek_prev() Date: Tue, 9 May 2023 12:56:52 -0400 Message-Id: <20230509165657.1735798-28-kent.overstreet@linux.dev> In-Reply-To: <20230509165657.1735798-1-kent.overstreet@linux.dev> References: <20230509165657.1735798-1-kent.overstreet@linux.dev> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Migadu-Flow: FLOW_OUT X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Kent Overstreet This patch adds genradix_peek_prev(), genradix_iter_rewind(), and genradix_for_each_reverse(), for iterating backwards over a generic radix tree. Signed-off-by: Kent Overstreet Signed-off-by: Kent Overstreet --- include/linux/generic-radix-tree.h | 61 +++++++++++++++++++++++++++++- lib/generic-radix-tree.c | 59 +++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 1 deletion(-) diff --git a/include/linux/generic-radix-tree.h b/include/linux/generic-radix-tree.h index f6cd0f909d..c74b737699 100644 --- a/include/linux/generic-radix-tree.h +++ b/include/linux/generic-radix-tree.h @@ -117,6 +117,11 @@ static inline size_t __idx_to_offset(size_t idx, size_t obj_size) #define __genradix_cast(_radix) (typeof((_radix)->type[0]) *) #define __genradix_obj_size(_radix) sizeof((_radix)->type[0]) +#define __genradix_objs_per_page(_radix) \ + (PAGE_SIZE / sizeof((_radix)->type[0])) +#define __genradix_page_remainder(_radix) \ + (PAGE_SIZE % sizeof((_radix)->type[0])) + #define __genradix_idx_to_offset(_radix, _idx) \ __idx_to_offset(_idx, __genradix_obj_size(_radix)) @@ -180,7 +185,25 @@ void *__genradix_iter_peek(struct genradix_iter *, struct __genradix *, size_t); #define genradix_iter_peek(_iter, _radix) \ (__genradix_cast(_radix) \ __genradix_iter_peek(_iter, &(_radix)->tree, \ - PAGE_SIZE / __genradix_obj_size(_radix))) + __genradix_objs_per_page(_radix))) + +void *__genradix_iter_peek_prev(struct genradix_iter *, struct __genradix *, + size_t, size_t); + +/** + * genradix_iter_peek - get first entry at or below iterator's current + * position + * @_iter: a genradix_iter + * @_radix: genradix being iterated over + * + * If no more entries exist at or below @_iter's current position, returns NULL + */ +#define genradix_iter_peek_prev(_iter, _radix) \ + (__genradix_cast(_radix) \ + __genradix_iter_peek_prev(_iter, &(_radix)->tree, \ + __genradix_objs_per_page(_radix), \ + __genradix_obj_size(_radix) + \ + __genradix_page_remainder(_radix))) static inline void __genradix_iter_advance(struct genradix_iter *iter, size_t obj_size) @@ -203,6 +226,25 @@ static inline void __genradix_iter_advance(struct genradix_iter *iter, #define genradix_iter_advance(_iter, _radix) \ __genradix_iter_advance(_iter, __genradix_obj_size(_radix)) +static inline void __genradix_iter_rewind(struct genradix_iter *iter, + size_t obj_size) +{ + if (iter->offset == 0 || + iter->offset == SIZE_MAX) { + iter->offset = SIZE_MAX; + return; + } + + if ((iter->offset & (PAGE_SIZE - 1)) == 0) + iter->offset -= PAGE_SIZE % obj_size; + + iter->offset -= obj_size; + iter->pos--; +} + +#define genradix_iter_rewind(_iter, _radix) \ + __genradix_iter_rewind(_iter, __genradix_obj_size(_radix)) + #define genradix_for_each_from(_radix, _iter, _p, _start) \ for (_iter = genradix_iter_init(_radix, _start); \ (_p = genradix_iter_peek(&_iter, _radix)) != NULL; \ @@ -220,6 +262,23 @@ static inline void __genradix_iter_advance(struct genradix_iter *iter, #define genradix_for_each(_radix, _iter, _p) \ genradix_for_each_from(_radix, _iter, _p, 0) +#define genradix_last_pos(_radix) \ + (SIZE_MAX / PAGE_SIZE * __genradix_objs_per_page(_radix) - 1) + +/** + * genradix_for_each_reverse - iterate over entry in a genradix, reverse order + * @_radix: genradix to iterate over + * @_iter: a genradix_iter to track current position + * @_p: pointer to genradix entry type + * + * On every iteration, @_p will point to the current entry, and @_iter.pos + * will be the current entry's index. + */ +#define genradix_for_each_reverse(_radix, _iter, _p) \ + for (_iter = genradix_iter_init(_radix, genradix_last_pos(_radix));\ + (_p = genradix_iter_peek_prev(&_iter, _radix)) != NULL;\ + genradix_iter_rewind(&_iter, _radix)) + int __genradix_prealloc(struct __genradix *, size_t, gfp_t); /** diff --git a/lib/generic-radix-tree.c b/lib/generic-radix-tree.c index 7dfa88282b..41f1bcdc44 100644 --- a/lib/generic-radix-tree.c +++ b/lib/generic-radix-tree.c @@ -1,4 +1,5 @@ +#include #include #include #include @@ -212,6 +213,64 @@ void *__genradix_iter_peek(struct genradix_iter *iter, } EXPORT_SYMBOL(__genradix_iter_peek); +void *__genradix_iter_peek_prev(struct genradix_iter *iter, + struct __genradix *radix, + size_t objs_per_page, + size_t obj_size_plus_page_remainder) +{ + struct genradix_root *r; + struct genradix_node *n; + unsigned level, i; + + if (iter->offset == SIZE_MAX) + return NULL; + +restart: + r = READ_ONCE(radix->root); + if (!r) + return NULL; + + n = genradix_root_to_node(r); + level = genradix_root_to_depth(r); + + if (ilog2(iter->offset) >= genradix_depth_shift(level)) { + iter->offset = genradix_depth_size(level); + iter->pos = (iter->offset >> PAGE_SHIFT) * objs_per_page; + + iter->offset -= obj_size_plus_page_remainder; + iter->pos--; + } + + while (level) { + level--; + + i = (iter->offset >> genradix_depth_shift(level)) & + (GENRADIX_ARY - 1); + + while (!n->children[i]) { + size_t objs_per_ptr = genradix_depth_size(level); + + iter->offset = round_down(iter->offset, objs_per_ptr); + iter->pos = (iter->offset >> PAGE_SHIFT) * objs_per_page; + + if (!iter->offset) + return NULL; + + iter->offset -= obj_size_plus_page_remainder; + iter->pos--; + + if (!i) + goto restart; + --i; + } + + n = n->children[i]; + } + + return &n->data[iter->offset & (PAGE_SIZE - 1)]; +} +EXPORT_SYMBOL(__genradix_iter_peek_prev); + static void genradix_free_recurse(struct genradix_node *n, unsigned level) { if (level) { -- 2.40.1