Author: hselasky
Date: Thu Jan 21 14:57:45 2016
New Revision: 294505
URL: https://svnweb.freebsd.org/changeset/base/294505

Log:
  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

Modified:
  head/sys/compat/linuxkpi/common/include/linux/idr.h
  head/sys/compat/linuxkpi/common/src/linux_idr.c
  head/sys/sys/param.h

Modified: head/sys/compat/linuxkpi/common/include/linux/idr.h
==============================================================================
--- head/sys/compat/linuxkpi/common/include/linux/idr.h Thu Jan 21 14:50:28 
2016        (r294504)
+++ head/sys/compat/linuxkpi/common/include/linux/idr.h Thu Jan 21 14:57:45 
2016        (r294505)
@@ -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_ */

Modified: head/sys/compat/linuxkpi/common/src/linux_idr.c
==============================================================================
--- head/sys/compat/linuxkpi/common/src/linux_idr.c     Thu Jan 21 14:50:28 
2016        (r294504)
+++ head/sys/compat/linuxkpi/common/src/linux_idr.c     Thu Jan 21 14:57:45 
2016        (r294505)
@@ -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 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 
        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);
+}

Modified: head/sys/sys/param.h
==============================================================================
--- head/sys/sys/param.h        Thu Jan 21 14:50:28 2016        (r294504)
+++ head/sys/sys/param.h        Thu Jan 21 14:57:45 2016        (r294505)
@@ -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,
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to