Home | History | Annotate | Line # | Download | only in linux
linux_idr.c revision 1.1.2.10
      1   1.1.2.1  riastrad /*	$NetBSD: linux_idr.c,v 1.1.2.10 2013/12/30 04:52:11 riastradh Exp $	*/
      2   1.1.2.1  riastrad 
      3   1.1.2.1  riastrad /*-
      4   1.1.2.1  riastrad  * Copyright (c) 2013 The NetBSD Foundation, Inc.
      5   1.1.2.1  riastrad  * All rights reserved.
      6   1.1.2.1  riastrad  *
      7   1.1.2.1  riastrad  * This code is derived from software contributed to The NetBSD Foundation
      8   1.1.2.1  riastrad  * by Taylor R. Campbell.
      9   1.1.2.1  riastrad  *
     10   1.1.2.1  riastrad  * Redistribution and use in source and binary forms, with or without
     11   1.1.2.1  riastrad  * modification, are permitted provided that the following conditions
     12   1.1.2.1  riastrad  * are met:
     13   1.1.2.1  riastrad  * 1. Redistributions of source code must retain the above copyright
     14   1.1.2.1  riastrad  *    notice, this list of conditions and the following disclaimer.
     15   1.1.2.1  riastrad  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1.2.1  riastrad  *    notice, this list of conditions and the following disclaimer in the
     17   1.1.2.1  riastrad  *    documentation and/or other materials provided with the distribution.
     18   1.1.2.1  riastrad  *
     19   1.1.2.1  riastrad  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.1.2.1  riastrad  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.1.2.1  riastrad  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.1.2.1  riastrad  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.1.2.1  riastrad  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.1.2.1  riastrad  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.1.2.1  riastrad  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.1.2.1  riastrad  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.1.2.1  riastrad  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.1.2.1  riastrad  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.1.2.1  riastrad  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1.2.1  riastrad  */
     31   1.1.2.1  riastrad 
     32   1.1.2.1  riastrad #include <sys/cdefs.h>
     33   1.1.2.1  riastrad __KERNEL_RCSID(0, "$NetBSD: linux_idr.c,v 1.1.2.10 2013/12/30 04:52:11 riastradh Exp $");
     34   1.1.2.1  riastrad 
     35   1.1.2.1  riastrad #include <sys/param.h>
     36   1.1.2.1  riastrad #include <sys/atomic.h>
     37  1.1.2.10  riastrad #include <sys/mutex.h>
     38  1.1.2.10  riastrad #include <sys/pserialize.h>
     39   1.1.2.1  riastrad 
     40   1.1.2.4  riastrad #include <linux/err.h>
     41   1.1.2.1  riastrad #include <linux/idr.h>
     42  1.1.2.10  riastrad #include <linux/slab.h>
     43   1.1.2.1  riastrad 
     44  1.1.2.10  riastrad struct idr_state {
     45  1.1.2.10  riastrad 	size_t			is_n_allocated;
     46  1.1.2.10  riastrad 	size_t			is_n_used;
     47  1.1.2.10  riastrad 	void			**is_data;
     48   1.1.2.1  riastrad };
     49   1.1.2.1  riastrad 
     50  1.1.2.10  riastrad void
     51  1.1.2.10  riastrad idr_init(struct idr *idr)
     52   1.1.2.1  riastrad {
     53   1.1.2.1  riastrad 
     54  1.1.2.10  riastrad 	mutex_init(&idr->idr_lock, MUTEX_DEFAULT, IPL_VM);
     55  1.1.2.10  riastrad 	idr->idr_psz = pserialize_create();
     56  1.1.2.10  riastrad 	idr->idr_state = kmalloc(sizeof(*idr->idr_state), GFP_KERNEL);
     57  1.1.2.10  riastrad 	KASSERT(idr->idr_state != NULL);
     58  1.1.2.10  riastrad 	idr->idr_state->is_n_allocated = 1;
     59  1.1.2.10  riastrad 	idr->idr_state->is_n_used = 0;
     60  1.1.2.10  riastrad 	idr->idr_state->is_data = kcalloc(1, sizeof(void *), GFP_KERNEL);
     61  1.1.2.10  riastrad 	KASSERT(idr->idr_state->is_data != NULL);
     62  1.1.2.10  riastrad 	idr->idr_temp = NULL;
     63   1.1.2.1  riastrad }
     64   1.1.2.1  riastrad 
     65  1.1.2.10  riastrad static struct idr_state *
     66  1.1.2.10  riastrad idr_state(struct idr *idr)
     67   1.1.2.1  riastrad {
     68  1.1.2.10  riastrad 	struct idr_state *const is = idr->idr_state;
     69   1.1.2.1  riastrad 
     70  1.1.2.10  riastrad 	membar_consumer();		/* match state */
     71  1.1.2.10  riastrad 
     72  1.1.2.10  riastrad 	return is;
     73   1.1.2.1  riastrad }
     74   1.1.2.1  riastrad 
     75   1.1.2.1  riastrad void
     76  1.1.2.10  riastrad idr_destroy(struct idr *idr)
     77   1.1.2.1  riastrad {
     78  1.1.2.10  riastrad 	struct idr_state *const is = idr_state(idr);
     79   1.1.2.1  riastrad 
     80  1.1.2.10  riastrad 	kfree(is->is_data);
     81  1.1.2.10  riastrad 	kfree(is);
     82  1.1.2.10  riastrad 	KASSERT(idr->idr_temp == NULL);
     83  1.1.2.10  riastrad 
     84  1.1.2.10  riastrad 	pserialize_destroy(idr->idr_psz);
     85  1.1.2.10  riastrad 	mutex_destroy(&idr->idr_lock);
     86   1.1.2.1  riastrad }
     87   1.1.2.1  riastrad 
     88  1.1.2.10  riastrad static void **
     89  1.1.2.10  riastrad idr_find_ptr(struct idr *idr, int id)
     90   1.1.2.1  riastrad {
     91  1.1.2.10  riastrad 	if (id < 0)
     92  1.1.2.10  riastrad 		return NULL;
     93   1.1.2.1  riastrad 
     94  1.1.2.10  riastrad 	struct idr_state *const is = idr_state(idr);
     95  1.1.2.10  riastrad 	if (is->is_n_used <= id)
     96  1.1.2.10  riastrad 		return NULL;
     97  1.1.2.10  riastrad 
     98  1.1.2.10  riastrad 	return &is->is_data[id];
     99   1.1.2.1  riastrad }
    100   1.1.2.1  riastrad 
    101   1.1.2.1  riastrad void *
    102   1.1.2.1  riastrad idr_find(struct idr *idr, int id)
    103   1.1.2.1  riastrad {
    104  1.1.2.10  riastrad 	void **const ptr = idr_find_ptr(idr, id);
    105  1.1.2.10  riastrad 
    106  1.1.2.10  riastrad 	if (ptr == NULL)
    107  1.1.2.10  riastrad 		return NULL;
    108   1.1.2.1  riastrad 
    109  1.1.2.10  riastrad 	void *const datum = *ptr;
    110   1.1.2.1  riastrad 
    111  1.1.2.10  riastrad 	membar_consumer();		/* match datum */
    112  1.1.2.10  riastrad 	return datum;
    113   1.1.2.1  riastrad }
    114   1.1.2.1  riastrad 
    115   1.1.2.4  riastrad void *
    116   1.1.2.4  riastrad idr_replace(struct idr *idr, void *replacement, int id)
    117   1.1.2.4  riastrad {
    118  1.1.2.10  riastrad 	void **const ptr = idr_find_ptr(idr, id);
    119   1.1.2.4  riastrad 
    120  1.1.2.10  riastrad 	if (ptr == NULL)
    121  1.1.2.10  riastrad 		return ERR_PTR(-ENOENT);
    122  1.1.2.10  riastrad 
    123  1.1.2.10  riastrad 	void *const datum = *ptr;
    124  1.1.2.10  riastrad 
    125  1.1.2.10  riastrad 	membar_producer();		/* match datum */
    126  1.1.2.10  riastrad 	*ptr = replacement;
    127   1.1.2.4  riastrad 
    128  1.1.2.10  riastrad 	return datum;
    129   1.1.2.4  riastrad }
    130   1.1.2.4  riastrad 
    131   1.1.2.1  riastrad void
    132   1.1.2.1  riastrad idr_remove(struct idr *idr, int id)
    133   1.1.2.1  riastrad {
    134  1.1.2.10  riastrad 	if (id < 0)
    135  1.1.2.10  riastrad 		return;
    136   1.1.2.1  riastrad 
    137  1.1.2.10  riastrad 	struct idr_state *const is = idr_state(idr);
    138  1.1.2.10  riastrad 
    139  1.1.2.10  riastrad 	if (is->is_n_used < id)
    140  1.1.2.10  riastrad 		return;
    141  1.1.2.10  riastrad 
    142  1.1.2.10  riastrad 	is->is_data[id] = NULL;
    143  1.1.2.10  riastrad 
    144  1.1.2.10  riastrad 	if ((id + 1) == is->is_n_used) {
    145  1.1.2.10  riastrad 		while ((0 < id--) && (is->is_data[id] == NULL))
    146  1.1.2.10  riastrad 			continue;
    147  1.1.2.10  riastrad 		is->is_n_used = id;
    148  1.1.2.10  riastrad 	}
    149   1.1.2.1  riastrad }
    150   1.1.2.1  riastrad 
    151   1.1.2.3  riastrad void
    152   1.1.2.3  riastrad idr_remove_all(struct idr *idr)
    153   1.1.2.3  riastrad {
    154  1.1.2.10  riastrad 	struct idr_state *const is = idr_state(idr);
    155   1.1.2.3  riastrad 
    156  1.1.2.10  riastrad 	is->is_n_used = 0;
    157   1.1.2.3  riastrad }
    158   1.1.2.3  riastrad 
    159   1.1.2.1  riastrad int
    160  1.1.2.10  riastrad idr_pre_get(struct idr *idr, gfp_t gfp)
    161   1.1.2.1  riastrad {
    162  1.1.2.10  riastrad 	struct idr_state *old_is, *new_is, *temp_is;
    163  1.1.2.10  riastrad 	size_t n_used;
    164   1.1.2.1  riastrad 
    165  1.1.2.10  riastrad 	old_is = idr_state(idr);
    166  1.1.2.10  riastrad 	n_used = old_is->is_n_used;
    167  1.1.2.10  riastrad 
    168  1.1.2.10  riastrad 	new_is = kmalloc(sizeof(*new_is), gfp);
    169  1.1.2.10  riastrad 	if (new_is == NULL)
    170  1.1.2.10  riastrad 		return 0;
    171  1.1.2.10  riastrad 	new_is->is_data = kcalloc((n_used + 1), sizeof(*new_is->is_data), gfp);
    172  1.1.2.10  riastrad 	if (new_is->is_data == NULL) {
    173  1.1.2.10  riastrad 		kfree(new_is);
    174  1.1.2.10  riastrad 		return 0;
    175   1.1.2.6  riastrad 	}
    176   1.1.2.1  riastrad 
    177  1.1.2.10  riastrad 	new_is->is_n_allocated = (n_used + 1);
    178  1.1.2.10  riastrad 
    179  1.1.2.10  riastrad 	membar_producer();		/* match temp */
    180  1.1.2.10  riastrad 
    181  1.1.2.10  riastrad 	/*
    182  1.1.2.10  riastrad 	 * If someone already put one in, replace it -- we're probably
    183  1.1.2.10  riastrad 	 * more up-to-date.
    184  1.1.2.10  riastrad 	 */
    185  1.1.2.10  riastrad 	temp_is = atomic_swap_ptr(&idr->idr_temp, new_is);
    186  1.1.2.10  riastrad 	if (temp_is != NULL) {
    187  1.1.2.10  riastrad 		membar_consumer();	/* match temp */
    188  1.1.2.10  riastrad 		kfree(temp_is->is_data);
    189  1.1.2.10  riastrad 		kfree(temp_is);
    190  1.1.2.10  riastrad 	}
    191   1.1.2.6  riastrad 
    192   1.1.2.1  riastrad 	return 1;
    193   1.1.2.1  riastrad }
    194   1.1.2.1  riastrad 
    195   1.1.2.1  riastrad int
    196  1.1.2.10  riastrad idr_get_new_above(struct idr *idr, void *datum, int min_id, int *idp)
    197   1.1.2.1  riastrad {
    198  1.1.2.10  riastrad 	struct idr_state *is = idr_state(idr);
    199  1.1.2.10  riastrad 	const size_t n_used = is->is_n_used;
    200  1.1.2.10  riastrad 	const size_t n_allocated = is->is_n_allocated;
    201  1.1.2.10  riastrad 	int id;
    202  1.1.2.10  riastrad 
    203  1.1.2.10  riastrad 	if (min_id < 0)
    204  1.1.2.10  riastrad 		min_id = 0;
    205  1.1.2.10  riastrad 
    206  1.1.2.10  riastrad 	for (id = min_id; id < n_used; id++)
    207  1.1.2.10  riastrad 		if (is->is_data[id] == NULL)
    208  1.1.2.10  riastrad 			goto win;
    209  1.1.2.10  riastrad 	if (id < n_allocated) {
    210  1.1.2.10  riastrad 		is->is_n_used++;
    211  1.1.2.10  riastrad 		goto win;
    212  1.1.2.10  riastrad 	}
    213  1.1.2.10  riastrad 
    214  1.1.2.10  riastrad 	struct idr_state *const it = atomic_swap_ptr(&idr->idr_temp, NULL);
    215  1.1.2.10  riastrad 	if (it == NULL)
    216  1.1.2.10  riastrad 		return -EAGAIN;
    217  1.1.2.10  riastrad 
    218  1.1.2.10  riastrad 	membar_consumer();		/* match temp */
    219  1.1.2.10  riastrad 	if (id < it->is_n_allocated) {
    220  1.1.2.10  riastrad 		(void)memcpy(it->is_data, is->is_data, sizeof(void *) *
    221  1.1.2.10  riastrad 		    n_used);
    222  1.1.2.10  riastrad 		it->is_n_used = (is->is_n_used + 1);
    223  1.1.2.10  riastrad 		membar_producer();	/* match state */
    224  1.1.2.10  riastrad 		idr->idr_state = it;
    225  1.1.2.10  riastrad 		pserialize_perform(idr->idr_psz);
    226  1.1.2.10  riastrad 		kfree(is->is_data);
    227  1.1.2.10  riastrad 		kfree(is);
    228  1.1.2.10  riastrad 		is = it;
    229  1.1.2.10  riastrad 		goto win;
    230  1.1.2.10  riastrad 	}
    231  1.1.2.10  riastrad 
    232  1.1.2.10  riastrad win:	membar_producer();		/* match datum */
    233  1.1.2.10  riastrad 	is->is_data[id] = datum;
    234  1.1.2.10  riastrad 	*idp = id;
    235  1.1.2.10  riastrad 	return 0;
    236   1.1.2.1  riastrad }
    237   1.1.2.5  riastrad 
    238   1.1.2.5  riastrad int
    239   1.1.2.5  riastrad idr_for_each(struct idr *idr, int (*proc)(int, void *, void *), void *arg)
    240   1.1.2.5  riastrad {
    241  1.1.2.10  riastrad 	struct idr_state *const is = idr_state(idr);
    242  1.1.2.10  riastrad 	int id;
    243   1.1.2.5  riastrad 	int error = 0;
    244   1.1.2.5  riastrad 
    245  1.1.2.10  riastrad 	for (id = 0; id < is->is_n_used; id++) {
    246  1.1.2.10  riastrad 		void *const datum = is->is_data[id];
    247  1.1.2.10  riastrad 
    248  1.1.2.10  riastrad 		membar_consumer();	/* match datum */
    249  1.1.2.10  riastrad 		error = (*proc)(id, datum, arg);
    250   1.1.2.5  riastrad 		if (error)
    251   1.1.2.5  riastrad 			break;
    252   1.1.2.5  riastrad 	}
    253   1.1.2.5  riastrad 
    254   1.1.2.5  riastrad 	return error;
    255   1.1.2.5  riastrad }
    256