summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/compat/linuxkpi/common/include/linux/idr.h8
-rw-r--r--sys/compat/linuxkpi/common/src/linux_idr.c109
-rw-r--r--sys/sys/param.h2
3 files changed, 102 insertions, 17 deletions
diff --git a/sys/compat/linuxkpi/common/include/linux/idr.h b/sys/compat/linuxkpi/common/include/linux/idr.h
index fc377d4..d13aeaf 100644
--- a/sys/compat/linuxkpi/common/include/linux/idr.h
+++ b/sys/compat/linuxkpi/common/include/linux/idr.h
@@ -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_ */
diff --git a/sys/compat/linuxkpi/common/src/linux_idr.c b/sys/compat/linuxkpi/common/src/linux_idr.c
index fa98622..6d9ec81 100644
--- a/sys/compat/linuxkpi/common/src/linux_idr.c
+++ b/sys/compat/linuxkpi/common/src/linux_idr.c
@@ -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);
+}
diff --git a/sys/sys/param.h b/sys/sys/param.h
index be0e737..7c03f33 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -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,
OpenPOWER on IntegriCloud