Received: by 2002:a05:6358:7058:b0:131:369:b2a3 with SMTP id 24csp342815rwp; Wed, 12 Jul 2023 14:20:47 -0700 (PDT) X-Google-Smtp-Source: APBJJlHrJrJjD5yHOzZ2kl+ekHLB+a4liFwMDs1di/VUChKbxo1KMF+o/1I3xCNx6Fu7wugQYrPk X-Received: by 2002:a17:906:5a72:b0:98e:4b2:2e83 with SMTP id my50-20020a1709065a7200b0098e04b22e83mr18831873ejc.50.1689196846970; Wed, 12 Jul 2023 14:20:46 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1689196846; cv=none; d=google.com; s=arc-20160816; b=qErw4ZvG5Ep3ySWjxA8vIYLF7P8dIfXKnBHwLi/w1Vw/LRjM36esxku8TUxDEm9xFY 2P+GMn06+r/iXyFIcbQt+pvQCUbk1WxxNUT7SXXNDdG1MML/GPtOeeyrBpojkPBcQs+k tsG9v4MxSorszUhS0vsRJ40yp0RmZ7YT8K2CKB2tmo3bqDm0EOy44tS7HUeWeb/j6bks lKWN4eFq1OtJbQr4g5Z24nqW5bRzMIItZqgNz/p5EtlhmNTuETfXDADFfyocN14kc9z/ I1hLK16JAH0qPrnxmHf+pRDyJ0vg/31e0mM7PwmQKGKHNJc/TjqkCiwwcMkjlB6f/426 lDUw== 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=; fh=62OdPrF/gCdQkD+I1rh/oiSz2CPC/MeKrKL1hL+29TY=; b=uCWXh9eFVymBUWTAJQtG6zEWXz42TZ29TlIyjmLUbon5CpnZaqwZxjIFPkbQgDVt/j IrkEgMHQ2VCp34mKmHdA6PSaM8jScgbhGqNlHQ3qg/whoTnnWKkse+ZZsBxVd9yZEN8P IgeOJdvQ6SLKS48DPMrwOK+vz7No9NVWGEksExWjtyLKv6BqPkJ9nHxfs5tC3yCmmLVR jtZx9apwj+FmKpIUT9VT7gz/ySvut2gb8sARB3pCm70xHFjPtxGHwpQ7cGASEnjGN0cv YvT9x7rzl9QrMhK+xqii/IEVERIfJkaxEOSf9Dka9ZGgUIGSsDbzTi1pOvfXtlwCZjZM 9SWg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linux.dev header.s=key1 header.b="ar1/5lc8"; 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 n21-20020a170906841500b00988a5cdbfa7si5158598ejx.889.2023.07.12.14.20.22; Wed, 12 Jul 2023 14:20:46 -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="ar1/5lc8"; 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 S233126AbjGLVOV (ORCPT + 99 others); Wed, 12 Jul 2023 17:14:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37818 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232977AbjGLVN7 (ORCPT ); Wed, 12 Jul 2023 17:13:59 -0400 Received: from out-36.mta1.migadu.com (out-36.mta1.migadu.com [IPv6:2001:41d0:203:375::24]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 91CB31FD2 for ; Wed, 12 Jul 2023 14:12:24 -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=1689196308; 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=ar1/5lc8IAM7Z8BzOkLoU2YlkHGHAS4kG+QX0/lExGk2OoopvseIafuYmBhl6W1Zx04myh UrotI8xhx5WzEasXrp5tb/o83g6LqYA7F97RfuOWZzOD0DukizF0612so6eQyI/eC2mleu VRzaexEyVeM+X9m529dxxdoNvTHItdc= From: Kent Overstreet To: linux-bcachefs@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Kent Overstreet , Kent Overstreet Subject: [PATCH 20/20] lib/generic-radix-tree.c: Add peek_prev() Date: Wed, 12 Jul 2023 17:11:15 -0400 Message-Id: <20230712211115.2174650-21-kent.overstreet@linux.dev> In-Reply-To: <20230712211115.2174650-1-kent.overstreet@linux.dev> References: <20230712211115.2174650-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=unavailable 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