Received: by 10.223.164.202 with SMTP id h10csp382135wrb; Thu, 30 Nov 2017 11:57:26 -0800 (PST) X-Google-Smtp-Source: AGs4zMYEbu3EUAw2xH1nQHGl7gNP6+Bdz2Hu4Bmgr4Mr9oJfwZayRDHi+1Ad+FowC4DW5oOArIgN X-Received: by 10.99.167.6 with SMTP id d6mr3385609pgf.100.1512071846592; Thu, 30 Nov 2017 11:57:26 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1512071846; cv=none; d=google.com; s=arc-20160816; b=fN6FulXDMYiyzbcLOvpUvYQuAvRwC2K9PfQmugo2W5CAlWjJje8q/TC6WLQdY14h2B T2mFNdeEH2qC4w6RjNQFi+KDzfvRUuhogPHgYj9RyUKoIFp6In7FHCZ4m9+JQ1GEaF97 C2h6SP+EvZejBgAg5oL6IBMN2Wwu74nzm+49Z/0fau7Z/ZOLXBEHYOXLhDbtg6KwSX09 VY6k9xrZ348Df40n009MQpjHo8ItNPBx2KYMGrbNpyagXw5+gSocWaTdvy0bHdum2N14 L+encl6JnQuHn/N66iwxWk0wgCOcOGrX9A8sRIuxHm7wt6hsBj/8VidjR4qds4tpvDlW 1ShQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:message-id:date:from :references:in-reply-to:mime-version:dkim-signature :arc-authentication-results; bh=BhINRHnBm6JNI5D/qXd5DT18BQxy+QU9SoEEVaa/RsI=; b=iJek+7y7/klkAjQJFaRvoZU/Lh+By+vJ2UBlRRTewihpjSRMGRAHZxKEhiUiAajKzw wBSfZJVk751GkuJLHjqYomX8S9Z0P2havZ8+o7tkXixzYsK27+WRkI4BtKA1vZjq9vve 3O4x5HPF6cxhiMWwajVQuSRCkMqk7rtHTNm71iknVzO4EJoLH2I14kSDD6h7ZpR8XjXe ZWyyM1w8tKwN6DZmT3eOdV0Wgg9gBHNDr94tPMiLKqD5GnMtGF8NvJu41Dh8m+fwkqij iq3imopbEmN5o8BJ3SVhgisUsP8emcqgPh3ungxv2r48f5GMCZy5C/oImokJzrycZIss z49Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ffwll.ch header.s=google header.b=KKkSezlL; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m11si3710762pll.635.2017.11.30.11.57.13; Thu, 30 Nov 2017 11:57:26 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@ffwll.ch header.s=google header.b=KKkSezlL; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751394AbdK3T4q (ORCPT + 99 others); Thu, 30 Nov 2017 14:56:46 -0500 Received: from mail-io0-f196.google.com ([209.85.223.196]:40270 "EHLO mail-io0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751303AbdK3T4o (ORCPT ); Thu, 30 Nov 2017 14:56:44 -0500 Received: by mail-io0-f196.google.com with SMTP id d21so8811297ioe.7 for ; Thu, 30 Nov 2017 11:56:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ffwll.ch; s=google; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=BhINRHnBm6JNI5D/qXd5DT18BQxy+QU9SoEEVaa/RsI=; b=KKkSezlLUBNjdHL1eWZEOyl750zUO9HLo6yqCZ3cR58WStuKU7tmGOj69erYTecFRH 2GtYDKOJP8mpwkhtvIW789+/hsZEzbQm2QCPxahagH/iW3+NI5QBQlo2DJzigVdvaxHk I1bVe9AY8tEFiE/k140PFjZXnAS+ebQsrcF7k= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=BhINRHnBm6JNI5D/qXd5DT18BQxy+QU9SoEEVaa/RsI=; b=EiVfGFSY1Gru5ozAJbj0TVcfAJy+eSq2ovoQCca8yRk6dxWEgo/HXQCPcg6RcGzp9i s933npQ7qSsZRh9WqDZXkGiA/wvlBvP7flK7htlHJj2ioW1egTshyb/mSsPUeSWaaDgJ pibi/CuRNxTR35cUCqvPIF6NJtN7LJW3Tok8bGajkBrZA0ENtDN5vYnuHTwE3agJlGry se9eB24cEZWvd9SQjNwkLEHeFF/c94g6CZiX2YcDhtpauEbb9v01T/aEan9osWRcjNvs pBAjgpOY/K79Q+GOL5cPdf80+jE6FHbBVW3v0Ay8DDG4KoilZbhb0agWyEO6MWO3GNRb Z0MQ== X-Gm-Message-State: AJaThX7R1mKpZ5T70kP097niGJiasyCSgzrl59V79HtpfpJIQGuq1r+l m9w47/WalDXZa1f7BLk/6otWo5IaK41A9NMUm6l42Q== X-Received: by 10.107.144.136 with SMTP id s130mr9104175iod.29.1512071804066; Thu, 30 Nov 2017 11:56:44 -0800 (PST) MIME-Version: 1.0 Received: by 10.79.165.88 with HTTP; Thu, 30 Nov 2017 11:56:43 -0800 (PST) X-Originating-IP: [2a02:168:5635:0:39d2:f87e:2033:9f6] In-Reply-To: <20171130173630.GA15948@bombadil.infradead.org> References: <20171130173630.GA15948@bombadil.infradead.org> From: Daniel Vetter Date: Thu, 30 Nov 2017 20:56:43 +0100 Message-ID: Subject: Re: [RFC] Rebasing the IDR To: Matthew Wilcox Cc: Linux Kernel Mailing List , Tejun Heo , Eric Biggers , Chris Mi , dri-devel Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Adding dri-devel, I think a pile of those are in drm. On Thu, Nov 30, 2017 at 6:36 PM, Matthew Wilcox wrote: > About 40 of the approximately 180 users of the IDR in the kernel are > "1-based" instead of "0-based". That is, they never want to have ID 0 > allocated; they want to see IDs allocated between 1 and N. Usually, that's > expressed like this: > > /* Get the user-visible handle using idr. */ > ret = idr_alloc(&file_priv->object_idr, obj, 1, 0, GFP_KERNEL); > > The current implementation of this grieves me. You see, we mark each > node of the radix tree according to whether it has any free entries > or not, and entry 0 is always free! If we've already allocated 10,000 > entries from this IDR, and see this call, we'll walk all the way down > the left side of the tree looking for entry 1, get to the bottom, > see that entries 1-63 are allocated, then walk up to the next level, > see that 64-4095 are allocated, walk up to the next level, see that > 8192-12287 has a free entry, and then start walking down again. > > It'd be somewhere around two to three times quicker to know not to > look down the left hand side of the tree, see that 1-8191 are used and > start looking in the range 8192-12287. I considered a function like > idr_reserve(idr, N) to reserve the first N entries (we have at least one > consumer in the tree that is 2-based, not 1-based), but that struck me > as inelegant. We also have the cool optimisation that if there's only > one element in the radix tree at offset 0, then we don't even need > to allocate a node to store it, we just store it right in the head. > And that optimisation was never available to the 1-based users. > > I've come up with this solution instead, idr_base. It's free in terms > of memory consumption on 64-bit as it fits in the gap at the end of the > struct idr. Essentially, we just subtract off idr_base when looking > up the ID, and add it back on when reporting the ID. We need to do some > saturating arithmetic in idr_get_next(), because starting a walk at 4 > billion or negative 8 quintillion doesn't work out terribly well. > > It does require the user to call idr_init_base() instead of idr_init(). > That should be a relatively small conversion effort. Opinions? Feedback? > Better test cases for the test-suite (ahem)? Just quick context on why we do this: We need to marshal/demarshal NULL in a ton of our ioctls, mapping that to 0 is natural. And yes I very much like this, and totally fine with trading an idr_init_base when we can nuke the explicit index ranges at every alloc side instead. So if you give me an idr_alloc function that doesn't take a range as icing, that would be great. Cheers, Daniel > > diff --git a/include/linux/idr.h b/include/linux/idr.h > index 91d27a9bcdf4..a657b1f925f8 100644 > --- a/include/linux/idr.h > +++ b/include/linux/idr.h > @@ -18,6 +18,7 @@ > > struct idr { > struct radix_tree_root idr_rt; > + unsigned int idr_base; > unsigned int idr_next; > }; > > @@ -30,9 +31,10 @@ struct idr { > /* Set the IDR flag and the IDR_FREE tag */ > #define IDR_RT_MARKER ((__force gfp_t)(3 << __GFP_BITS_SHIFT)) > > -#define IDR_INIT \ > -{ \ > - .idr_rt = RADIX_TREE_INIT(IDR_RT_MARKER) \ > +#define IDR_INIT { \ > + .idr_rt = RADIX_TREE_INIT(IDR_RT_MARKER), \ > + .idr_base = 0, \ > + .idr_next = 0, \ > } > #define DEFINE_IDR(name) struct idr name = IDR_INIT > > @@ -123,12 +125,20 @@ static inline int __must_check idr_alloc_u32(struct idr *idr, void *ptr, > > static inline void *idr_remove(struct idr *idr, unsigned long id) > { > - return radix_tree_delete_item(&idr->idr_rt, id, NULL); > + return radix_tree_delete_item(&idr->idr_rt, id - idr->idr_base, NULL); > } > > static inline void idr_init(struct idr *idr) > { > INIT_RADIX_TREE(&idr->idr_rt, IDR_RT_MARKER); > + idr->idr_base = 0; > + idr->idr_next = 0; > +} > + > +static inline void idr_init_base(struct idr *idr, int base) > +{ > + INIT_RADIX_TREE(&idr->idr_rt, IDR_RT_MARKER); > + idr->idr_base = base; > idr->idr_next = 0; > } > > @@ -163,7 +173,7 @@ static inline void idr_preload_end(void) > */ > static inline void *idr_find(const struct idr *idr, unsigned long id) > { > - return radix_tree_lookup(&idr->idr_rt, id); > + return radix_tree_lookup(&idr->idr_rt, id - idr->idr_base); > } > > /** > diff --git a/lib/idr.c b/lib/idr.c > index 1aaeb5a8c426..a1d3531bd62f 100644 > --- a/lib/idr.c > +++ b/lib/idr.c > @@ -33,21 +33,22 @@ int idr_alloc_ul(struct idr *idr, void *ptr, unsigned long *nextid, > { > struct radix_tree_iter iter; > void __rcu **slot; > + int base = idr->idr_base; > > if (WARN_ON_ONCE(radix_tree_is_internal_node(ptr))) > return -EINVAL; > if (WARN_ON_ONCE(!(idr->idr_rt.gfp_mask & ROOT_IS_IDR))) > idr->idr_rt.gfp_mask |= IDR_RT_MARKER; > > - radix_tree_iter_init(&iter, *nextid); > - slot = idr_get_free(&idr->idr_rt, &iter, gfp, max); > + radix_tree_iter_init(&iter, *nextid - base); > + slot = idr_get_free(&idr->idr_rt, &iter, gfp, max - base); > if (IS_ERR(slot)) > return PTR_ERR(slot); > > radix_tree_iter_replace(&idr->idr_rt, &iter, slot, ptr); > radix_tree_iter_tag_clear(&idr->idr_rt, &iter, IDR_FREE); > > - *nextid = iter.index; > + *nextid = iter.index + base; > return 0; > } > EXPORT_SYMBOL_GPL(idr_alloc_ul); > @@ -143,13 +144,14 @@ int idr_for_each(const struct idr *idr, > { > struct radix_tree_iter iter; > void __rcu **slot; > + int base = idr->idr_base; > > radix_tree_for_each_slot(slot, &idr->idr_rt, &iter, 0) { > int ret; > > if (WARN_ON_ONCE(iter.index > INT_MAX)) > break; > - ret = fn(iter.index, rcu_dereference_raw(*slot), data); > + ret = fn(iter.index + base, rcu_dereference_raw(*slot), data); > if (ret) > return ret; > } > @@ -172,15 +174,19 @@ void *idr_get_next(struct idr *idr, int *nextid) > { > struct radix_tree_iter iter; > void __rcu **slot; > + int base = idr->idr_base; > + int id = *nextid; > > - slot = radix_tree_iter_find(&idr->idr_rt, &iter, *nextid); > + id = (id < base) ? 0 : id - base; > + slot = radix_tree_iter_find(&idr->idr_rt, &iter, id); > if (!slot) > return NULL; > + id = iter.index + base; > > - if (WARN_ON_ONCE(iter.index > INT_MAX)) > + if (WARN_ON_ONCE(id > INT_MAX)) > return NULL; > > - *nextid = iter.index; > + *nextid = id; > return rcu_dereference_raw(*slot); > } > EXPORT_SYMBOL(idr_get_next); > @@ -199,12 +205,15 @@ void *idr_get_next_ul(struct idr *idr, unsigned long *nextid) > { > struct radix_tree_iter iter; > void __rcu **slot; > + unsigned long base = idr->idr_base; > + unsigned long id = *nextid; > > - slot = radix_tree_iter_find(&idr->idr_rt, &iter, *nextid); > + id = (id < base) ? 0 : id - base; > + slot = radix_tree_iter_find(&idr->idr_rt, &iter, id); > if (!slot) > return NULL; > > - *nextid = iter.index; > + *nextid = iter.index + base; > return rcu_dereference_raw(*slot); > } > EXPORT_SYMBOL(idr_get_next_ul); > @@ -231,6 +240,7 @@ void *idr_replace(struct idr *idr, void *ptr, unsigned long id) > > if (WARN_ON_ONCE(radix_tree_is_internal_node(ptr))) > return ERR_PTR(-EINVAL); > + id -= idr->idr_base; > > entry = __radix_tree_lookup(&idr->idr_rt, id, &node, &slot); > if (!slot || radix_tree_tag_get(&idr->idr_rt, id, IDR_FREE)) > diff --git a/tools/testing/radix-tree/idr-test.c b/tools/testing/radix-tree/idr-test.c > index 36437ade429c..44ef9eba5a7a 100644 > --- a/tools/testing/radix-tree/idr-test.c > +++ b/tools/testing/radix-tree/idr-test.c > @@ -153,11 +153,12 @@ void idr_nowait_test(void) > idr_destroy(&idr); > } > > -void idr_get_next_test(void) > +void idr_get_next_test(int base) > { > unsigned long i; > int nextid; > DEFINE_IDR(idr); > + idr_init_base(&idr, base); > > int indices[] = {4, 7, 9, 15, 65, 128, 1000, 99999, 0}; > > @@ -244,7 +245,9 @@ void idr_checks(void) > idr_alloc_test(); > idr_null_test(); > idr_nowait_test(); > - idr_get_next_test(); > + idr_get_next_test(0); > + idr_get_next_test(1); > + idr_get_next_test(4); > } > > /* -- Daniel Vetter Software Engineer, Intel Corporation +41 (0) 79 365 57 48 - http://blog.ffwll.ch From 1585513438790301793@xxx Thu Nov 30 17:37:24 +0000 2017 X-GM-THRID: 1585513438790301793 X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread