Implement idr_preload(), idr_preload_end(), idr_alloc() and

idr_alloc_cyclic() in the LinuxKPI. Bump the FreeBSD version to
force recompilation of all KLDs due to IDR structure size change.

MFC after:	2 weeks
Sponsored by:	Mellanox Technologies
This commit is contained in:
hselasky 2016-01-21 14:57:45 +00:00
parent d16eeed462
commit a4e93c419f
3 changed files with 102 additions and 17 deletions

View File

@ -2,7 +2,7 @@
* Copyright (c) 2010 Isilon Systems, Inc.
* Copyright (c) 2010 iX Systems, Inc.
* Copyright (c) 2010 Panasas, Inc.
* Copyright (c) 2013 Mellanox Technologies, Ltd.
* Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -60,6 +60,7 @@ struct idr {
struct idr_layer *top;
struct idr_layer *free;
int layers;
int next_cyclic_id;
};
#define DEFINE_IDR(name) \
@ -67,6 +68,9 @@ struct idr {
SYSINIT(name##_idr_sysinit, SI_SUB_DRIVERS, SI_ORDER_FIRST, \
idr_init, &(name));
#define idr_preload(x) do { } while (0)
#define idr_preload_end() do { } while (0)
void *idr_find(struct idr *idp, int id);
int idr_pre_get(struct idr *idp, gfp_t gfp_mask);
int idr_get_new(struct idr *idp, void *ptr, int *id);
@ -76,5 +80,7 @@ void idr_remove(struct idr *idp, int id);
void idr_remove_all(struct idr *idp);
void idr_destroy(struct idr *idp);
void idr_init(struct idr *idp);
int idr_alloc(struct idr *idp, void *ptr, int start, int end, gfp_t);
int idr_alloc_cyclic(struct idr *idp, void *ptr, int start, int end, gfp_t);
#endif /* _LINUX_IDR_H_ */

View File

@ -2,7 +2,7 @@
* Copyright (c) 2010 Isilon Systems, Inc.
* Copyright (c) 2010 iX Systems, Inc.
* Copyright (c) 2010 Panasas, Inc.
* Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
* Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -116,21 +116,18 @@ idr_remove_all(struct idr *idr)
mtx_unlock(&idr->lock);
}
void
idr_remove(struct idr *idr, int id)
static void
idr_remove_locked(struct idr *idr, int id)
{
struct idr_layer *il;
int layer;
int idx;
id &= MAX_ID_MASK;
mtx_lock(&idr->lock);
il = idr->top;
layer = idr->layers - 1;
if (il == NULL || id > idr_max(idr)) {
mtx_unlock(&idr->lock);
if (il == NULL || id > idr_max(idr))
return;
}
/*
* Walk down the tree to this item setting bitmaps along the way
* as we know at least one item will be free along this path.
@ -152,8 +149,14 @@ idr_remove(struct idr *idr, int id)
id, idr, il);
il->ary[idx] = NULL;
il->bitmap |= 1 << idx;
}
void
idr_remove(struct idr *idr, int id)
{
mtx_lock(&idr->lock);
idr_remove_locked(idr, id);
mtx_unlock(&idr->lock);
return;
}
void *
@ -278,8 +281,8 @@ idr_get(struct idr *idr)
* Could be implemented as get_new_above(idr, ptr, 0, idp) but written
* first for simplicity sake.
*/
int
idr_get_new(struct idr *idr, void *ptr, int *idp)
static int
idr_get_new_locked(struct idr *idr, void *ptr, int *idp)
{
struct idr_layer *stack[MAX_LEVEL];
struct idr_layer *il;
@ -288,8 +291,9 @@ idr_get_new(struct idr *idr, void *ptr, int *idp)
int idx;
int id;
mtx_assert(&idr->lock, MA_OWNED);
error = -EAGAIN;
mtx_lock(&idr->lock);
/*
* Expand the tree until there is free space.
*/
@ -350,12 +354,22 @@ out:
idr, id, ptr);
}
#endif
mtx_unlock(&idr->lock);
return (error);
}
int
idr_get_new_above(struct idr *idr, void *ptr, int starting_id, int *idp)
idr_get_new(struct idr *idr, void *ptr, int *idp)
{
int retval;
mtx_lock(&idr->lock);
retval = idr_get_new_locked(idr, ptr, idp);
mtx_unlock(&idr->lock);
return (retval);
}
static int
idr_get_new_above_locked(struct idr *idr, void *ptr, int starting_id, int *idp)
{
struct idr_layer *stack[MAX_LEVEL];
struct idr_layer *il;
@ -364,8 +378,9 @@ idr_get_new_above(struct idr *idr, void *ptr, int starting_id, int *idp)
int idx, sidx;
int id;
mtx_assert(&idr->lock, MA_OWNED);
error = -EAGAIN;
mtx_lock(&idr->lock);
/*
* Compute the layers required to support starting_id and the mask
* at the top layer.
@ -457,6 +472,70 @@ out:
idr, id, ptr);
}
#endif
mtx_unlock(&idr->lock);
return (error);
}
int
idr_get_new_above(struct idr *idr, void *ptr, int starting_id, int *idp)
{
int retval;
mtx_lock(&idr->lock);
retval = idr_get_new_above_locked(idr, ptr, starting_id, idp);
mtx_unlock(&idr->lock);
return (retval);
}
static int
idr_alloc_locked(struct idr *idr, void *ptr, int start, int end)
{
int max = end > 0 ? end - 1 : INT_MAX;
int error;
int id;
mtx_assert(&idr->lock, MA_OWNED);
if (unlikely(start < 0))
return (-EINVAL);
if (unlikely(max < start))
return (-ENOSPC);
if (start == 0)
error = idr_get_new_locked(idr, ptr, &id);
else
error = idr_get_new_above_locked(idr, ptr, start, &id);
if (unlikely(error < 0))
return (error);
if (unlikely(id > max)) {
idr_remove_locked(idr, id);
return (-ENOSPC);
}
return (id);
}
int
idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp_mask)
{
int retval;
mtx_lock(&idr->lock);
retval = idr_alloc_locked(idr, ptr, start, end);
mtx_unlock(&idr->lock);
return (retval);
}
int
idr_alloc_cyclic(struct idr *idr, void *ptr, int start, int end, gfp_t gfp_mask)
{
int retval;
mtx_lock(&idr->lock);
retval = idr_alloc_locked(idr, ptr, max(start, idr->next_cyclic_id), end);
if (unlikely(retval == -ENOSPC))
retval = idr_alloc_locked(idr, ptr, start, end);
if (likely(retval >= 0))
idr->next_cyclic_id = retval + 1;
mtx_unlock(&idr->lock);
return (retval);
}

View File

@ -58,7 +58,7 @@
* in the range 5 to 9.
*/
#undef __FreeBSD_version
#define __FreeBSD_version 1100095 /* Master, propagated to newvers */
#define __FreeBSD_version 1100096 /* Master, propagated to newvers */
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,