MAX_IDR_MASK is another weirdness in the idr interface. As idr covers whole positive integer range, it's defined as 0x7fffffff or INT_MAX. Its usage in idr_find(), idr_replace() and idr_remove() is bizarre. They basically mask off the sign bit and operate on the rest, so if the caller, by accident, passes in a negative number, the sign bit will be masked off and the remaining part will be used as if that was the input, which is worse than crashing. The constant is visible in idr.h and there are several users in the kernel. * drivers/i2c/i2c-core.c:i2c_add_numbered_adapter() Basically used to test if adap->nr is a negative number which isn't -1 and returns -EINVAL if so. idr_alloc() already has negative @start checking (w/ WARN_ON_ONCE), so this can go away. * drivers/infiniband/core/cm.c:cm_alloc_id() drivers/infiniband/hw/mlx4/cm.c:id_map_alloc() Used to wrap cyclic @start. Can be replaced with max(next, 0). Note that this type of cyclic allocation using idr is buggy. These are prone to spurious -ENOSPC failure after the first wraparound. * fs/super.c:get_anon_bdev() The ID allocated from ida is masked off before being tested whether it's inside valid range. ida allocated ID can never be a negative number and the masking is unnecessary. Update idr_*() functions to fail with -EINVAL when negative @id is specified and update other MAX_IDR_MASK users as described above. This leaves MAX_IDR_MASK without any user, remove it and relocate other MAX_IDR_* constants to lib/idr.c. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Jean Delvare <khali@linux-fr.org> Cc: Roland Dreier <roland@kernel.org> Cc: Sean Hefty <sean.hefty@intel.com> Cc: Hal Rosenstock <hal.rosenstock@gmail.com> Cc: "Marciniszyn, Mike" <mike.marciniszyn@intel.com> Cc: Jack Morgenstein <jackm@dev.mellanox.co.il> Cc: Or Gerlitz <ogerlitz@mellanox.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Acked-by: Wolfram Sang <wolfram@the-dreams.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
196 lines
5.7 KiB
C
196 lines
5.7 KiB
C
/*
|
|
* include/linux/idr.h
|
|
*
|
|
* 2002-10-18 written by Jim Houston jim.houston@ccur.com
|
|
* Copyright (C) 2002 by Concurrent Computer Corporation
|
|
* Distributed under the GNU GPL license version 2.
|
|
*
|
|
* Small id to pointer translation service avoiding fixed sized
|
|
* tables.
|
|
*/
|
|
|
|
#ifndef __IDR_H__
|
|
#define __IDR_H__
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/bitops.h>
|
|
#include <linux/init.h>
|
|
#include <linux/rcupdate.h>
|
|
|
|
#if BITS_PER_LONG == 32
|
|
# define IDR_BITS 5
|
|
# define IDR_FULL 0xfffffffful
|
|
/* We can only use two of the bits in the top level because there is
|
|
only one possible bit in the top level (5 bits * 7 levels = 35
|
|
bits, but you only use 31 bits in the id). */
|
|
# define TOP_LEVEL_FULL (IDR_FULL >> 30)
|
|
#elif BITS_PER_LONG == 64
|
|
# define IDR_BITS 6
|
|
# define IDR_FULL 0xfffffffffffffffful
|
|
/* We can only use two of the bits in the top level because there is
|
|
only one possible bit in the top level (6 bits * 6 levels = 36
|
|
bits, but you only use 31 bits in the id). */
|
|
# define TOP_LEVEL_FULL (IDR_FULL >> 62)
|
|
#else
|
|
# error "BITS_PER_LONG is not 32 or 64"
|
|
#endif
|
|
|
|
#define IDR_SIZE (1 << IDR_BITS)
|
|
#define IDR_MASK ((1 << IDR_BITS)-1)
|
|
|
|
struct idr_layer {
|
|
unsigned long bitmap; /* A zero bit means "space here" */
|
|
struct idr_layer __rcu *ary[1<<IDR_BITS];
|
|
int count; /* When zero, we can release it */
|
|
int layer; /* distance from leaf */
|
|
struct rcu_head rcu_head;
|
|
};
|
|
|
|
struct idr {
|
|
struct idr_layer __rcu *top;
|
|
struct idr_layer *id_free;
|
|
int layers; /* only valid w/o concurrent changes */
|
|
int id_free_cnt;
|
|
spinlock_t lock;
|
|
};
|
|
|
|
#define IDR_INIT(name) \
|
|
{ \
|
|
.lock = __SPIN_LOCK_UNLOCKED(name.lock), \
|
|
}
|
|
#define DEFINE_IDR(name) struct idr name = IDR_INIT(name)
|
|
|
|
/**
|
|
* DOC: idr sync
|
|
* idr synchronization (stolen from radix-tree.h)
|
|
*
|
|
* idr_find() is able to be called locklessly, using RCU. The caller must
|
|
* ensure calls to this function are made within rcu_read_lock() regions.
|
|
* Other readers (lock-free or otherwise) and modifications may be running
|
|
* concurrently.
|
|
*
|
|
* It is still required that the caller manage the synchronization and
|
|
* lifetimes of the items. So if RCU lock-free lookups are used, typically
|
|
* this would mean that the items have their own locks, or are amenable to
|
|
* lock-free access; and that the items are freed by RCU (or only freed after
|
|
* having been deleted from the idr tree *and* a synchronize_rcu() grace
|
|
* period).
|
|
*/
|
|
|
|
/*
|
|
* This is what we export.
|
|
*/
|
|
|
|
void *idr_find(struct idr *idp, int id);
|
|
int idr_pre_get(struct idr *idp, gfp_t gfp_mask);
|
|
int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id);
|
|
void idr_preload(gfp_t gfp_mask);
|
|
int idr_alloc(struct idr *idp, void *ptr, int start, int end, gfp_t gfp_mask);
|
|
int idr_for_each(struct idr *idp,
|
|
int (*fn)(int id, void *p, void *data), void *data);
|
|
void *idr_get_next(struct idr *idp, int *nextid);
|
|
void *idr_replace(struct idr *idp, void *ptr, int id);
|
|
void idr_remove(struct idr *idp, int id);
|
|
void idr_free(struct idr *idp, int id);
|
|
void idr_destroy(struct idr *idp);
|
|
void idr_init(struct idr *idp);
|
|
|
|
/**
|
|
* idr_preload_end - end preload section started with idr_preload()
|
|
*
|
|
* Each idr_preload() should be matched with an invocation of this
|
|
* function. See idr_preload() for details.
|
|
*/
|
|
static inline void idr_preload_end(void)
|
|
{
|
|
preempt_enable();
|
|
}
|
|
|
|
/**
|
|
* idr_get_new - allocate new idr entry
|
|
* @idp: idr handle
|
|
* @ptr: pointer you want associated with the id
|
|
* @id: pointer to the allocated handle
|
|
*
|
|
* Simple wrapper around idr_get_new_above() w/ @starting_id of zero.
|
|
*/
|
|
static inline int idr_get_new(struct idr *idp, void *ptr, int *id)
|
|
{
|
|
return idr_get_new_above(idp, ptr, 0, id);
|
|
}
|
|
|
|
/**
|
|
* idr_for_each_entry - iterate over an idr's elements of a given type
|
|
* @idp: idr handle
|
|
* @entry: the type * to use as cursor
|
|
* @id: id entry's key
|
|
*/
|
|
#define idr_for_each_entry(idp, entry, id) \
|
|
for (id = 0, entry = (typeof(entry))idr_get_next((idp), &(id)); \
|
|
entry != NULL; \
|
|
++id, entry = (typeof(entry))idr_get_next((idp), &(id)))
|
|
|
|
void __idr_remove_all(struct idr *idp); /* don't use */
|
|
|
|
/**
|
|
* idr_remove_all - remove all ids from the given idr tree
|
|
* @idp: idr handle
|
|
*
|
|
* If you're trying to destroy @idp, calling idr_destroy() is enough.
|
|
* This is going away. Don't use.
|
|
*/
|
|
static inline void __deprecated idr_remove_all(struct idr *idp)
|
|
{
|
|
__idr_remove_all(idp);
|
|
}
|
|
|
|
/*
|
|
* IDA - IDR based id allocator, use when translation from id to
|
|
* pointer isn't necessary.
|
|
*
|
|
* IDA_BITMAP_LONGS is calculated to be one less to accommodate
|
|
* ida_bitmap->nr_busy so that the whole struct fits in 128 bytes.
|
|
*/
|
|
#define IDA_CHUNK_SIZE 128 /* 128 bytes per chunk */
|
|
#define IDA_BITMAP_LONGS (IDA_CHUNK_SIZE / sizeof(long) - 1)
|
|
#define IDA_BITMAP_BITS (IDA_BITMAP_LONGS * sizeof(long) * 8)
|
|
|
|
struct ida_bitmap {
|
|
long nr_busy;
|
|
unsigned long bitmap[IDA_BITMAP_LONGS];
|
|
};
|
|
|
|
struct ida {
|
|
struct idr idr;
|
|
struct ida_bitmap *free_bitmap;
|
|
};
|
|
|
|
#define IDA_INIT(name) { .idr = IDR_INIT((name).idr), .free_bitmap = NULL, }
|
|
#define DEFINE_IDA(name) struct ida name = IDA_INIT(name)
|
|
|
|
int ida_pre_get(struct ida *ida, gfp_t gfp_mask);
|
|
int ida_get_new_above(struct ida *ida, int starting_id, int *p_id);
|
|
void ida_remove(struct ida *ida, int id);
|
|
void ida_destroy(struct ida *ida);
|
|
void ida_init(struct ida *ida);
|
|
|
|
int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
|
|
gfp_t gfp_mask);
|
|
void ida_simple_remove(struct ida *ida, unsigned int id);
|
|
|
|
/**
|
|
* ida_get_new - allocate new ID
|
|
* @ida: idr handle
|
|
* @p_id: pointer to the allocated handle
|
|
*
|
|
* Simple wrapper around ida_get_new_above() w/ @starting_id of zero.
|
|
*/
|
|
static inline int ida_get_new(struct ida *ida, int *p_id)
|
|
{
|
|
return ida_get_new_above(ida, 0, p_id);
|
|
}
|
|
|
|
void __init idr_init_cache(void);
|
|
|
|
#endif /* __IDR_H__ */
|