From owner-svn-src-head@freebsd.org Wed May 11 10:40:05 2016 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 98CCEB37418; Wed, 11 May 2016 10:40:05 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 66D5D1CA3; Wed, 11 May 2016 10:40:05 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u4BAe4du018143; Wed, 11 May 2016 10:40:04 GMT (envelope-from hselasky@FreeBSD.org) Received: (from hselasky@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u4BAe4eH018141; Wed, 11 May 2016 10:40:04 GMT (envelope-from hselasky@FreeBSD.org) Message-Id: <201605111040.u4BAe4eH018141@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: hselasky set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky Date: Wed, 11 May 2016 10:40:04 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r299427 - in head/sys/compat/linuxkpi/common: include/linux src X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 11 May 2016 10:40:05 -0000 Author: hselasky Date: Wed May 11 10:40:04 2016 New Revision: 299427 URL: https://svnweb.freebsd.org/changeset/base/299427 Log: Add more IDR and IDA related functions to the LinuxKPI. Obtained from: kmacy @ MFC after: 1 week Sponsored by: Mellanox Technologies Modified: head/sys/compat/linuxkpi/common/include/linux/idr.h head/sys/compat/linuxkpi/common/src/linux_idr.c Modified: head/sys/compat/linuxkpi/common/include/linux/idr.h ============================================================================== --- head/sys/compat/linuxkpi/common/include/linux/idr.h Wed May 11 10:35:15 2016 (r299426) +++ head/sys/compat/linuxkpi/common/include/linux/idr.h Wed May 11 10:40:04 2016 (r299427) @@ -63,15 +63,23 @@ struct idr { int next_cyclic_id; }; -#define DEFINE_IDR(name) \ +/* NOTE: It is the applications responsibility to destroy the IDR */ +#define DEFINE_IDR(name) \ struct idr name; \ SYSINIT(name##_idr_sysinit, SI_SUB_DRIVERS, SI_ORDER_FIRST, \ - idr_init, &(name)); + idr_init, &(name)) + +/* NOTE: It is the applications responsibility to destroy the IDA */ +#define DEFINE_IDA(name) \ + struct ida name; \ + SYSINIT(name##_ida_sysinit, SI_SUB_DRIVERS, SI_ORDER_FIRST, \ + ida_init, &(name)) #define idr_preload(x) do { } while (0) #define idr_preload_end() do { } while (0) void *idr_find(struct idr *idp, int id); +void *idr_get_next(struct idr *idp, int *nextid); int idr_pre_get(struct idr *idp, gfp_t gfp_mask); int idr_get_new(struct idr *idp, void *ptr, int *id); int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id); @@ -82,5 +90,39 @@ 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); +int idr_for_each(struct idr *idp, int (*fn)(int id, void *p, void *data), void *data); + +#define idr_for_each_entry(idp, entry, id) \ + for ((id) = 0; ((entry) = idr_get_next(idp, &(id))) != NULL; ++(id)) + +#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; +}; + +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); + +static inline int +ida_get_new(struct ida *ida, int *p_id) +{ + return (ida_get_new_above(ida, 0, p_id)); +} #endif /* _LINUX_IDR_H_ */ Modified: head/sys/compat/linuxkpi/common/src/linux_idr.c ============================================================================== --- head/sys/compat/linuxkpi/common/src/linux_idr.c Wed May 11 10:35:15 2016 (r299426) +++ head/sys/compat/linuxkpi/common/src/linux_idr.c Wed May 11 10:40:04 2016 (r299427) @@ -227,6 +227,24 @@ idr_find(struct idr *idr, int id) return (res); } +void * +idr_get_next(struct idr *idr, int *nextidp) +{ + void *res = NULL; + int id = *nextidp; + + mtx_lock(&idr->lock); + for (; id <= idr_max(idr); id++) { + res = idr_find_locked(idr, id); + if (res == NULL) + continue; + *nextidp = id; + break; + } + mtx_unlock(&idr->lock); + return (res); +} + int idr_pre_get(struct idr *idr, gfp_t gfp_mask) { @@ -487,6 +505,12 @@ idr_get_new_above(struct idr *idr, void return (retval); } +int +ida_get_new_above(struct ida *ida, int starting_id, int *p_id) +{ + return (idr_get_new_above(&ida->idr, NULL, starting_id, p_id)); +} + static int idr_alloc_locked(struct idr *idr, void *ptr, int start, int end) { @@ -540,3 +564,114 @@ idr_alloc_cyclic(struct idr *idr, void * mtx_unlock(&idr->lock); return (retval); } + +static int +idr_for_each_layer(struct idr_layer *il, int layer, + int (*f)(int id, void *p, void *data), void *data) +{ + int i, err; + + if (il == NULL) + return (0); + if (layer == 0) { + for (i = 0; i < IDR_SIZE; i++) { + if (il->ary[i] == NULL) + continue; + err = f(i, il->ary[i], data); + if (err) + return (err); + } + return (0); + } + for (i = 0; i < IDR_SIZE; i++) { + if (il->ary[i] == NULL) + continue; + err = idr_for_each_layer(il->ary[i], layer - 1, f, data); + if (err) + return (err); + } + return (0); +} + +int +idr_for_each(struct idr *idp, int (*f)(int id, void *p, void *data), void *data) +{ + int err; + + mtx_lock(&idp->lock); + err = idr_for_each_layer(idp->top, idp->layers - 1, f, data); + mtx_unlock(&idp->lock); + return (err); +} + +int +ida_pre_get(struct ida *ida, gfp_t flags) +{ + if (idr_pre_get(&ida->idr, flags) == 0) + return (0); + + if (ida->free_bitmap == NULL) { + ida->free_bitmap = + malloc(sizeof(struct ida_bitmap), M_IDR, flags); + } + return (ida->free_bitmap != NULL); +} + +int +ida_simple_get(struct ida *ida, unsigned int start, unsigned int end, + gfp_t flags) +{ + int ret, id; + unsigned int max; + + MPASS((int)start >= 0); + MPASS((int)end >= 0); + + if (end == 0) + max = 0x80000000; + else { + MPASS(end > start); + max = end - 1; + } +again: + if (!ida_pre_get(ida, flags)) + return (-ENOMEM); + + if ((ret = ida_get_new_above(ida, start, &id)) == 0) { + if (id > max) { + ida_remove(ida, id); + ret = -ENOSPC; + } else { + ret = id; + } + } + if (__predict_false(ret == -EAGAIN)) + goto again; + + return (ret); +} + +void +ida_simple_remove(struct ida *ida, unsigned int id) +{ + idr_remove(&ida->idr, id); +} + +void +ida_remove(struct ida *ida, int id) +{ + idr_remove(&ida->idr, id); +} + +void +ida_init(struct ida *ida) +{ + idr_init(&ida->idr); +} + +void +ida_destroy(struct ida *ida) +{ + idr_destroy(&ida->idr); + free(ida->free_bitmap, M_IDR); +}