From dbea353b920b4ba2c7adb9d1f6c809c24b35b5ae Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Tue, 13 Oct 2020 11:34:52 -0700 Subject: [PATCH] scoutfs: bring back sort_priv Bring back sort_priv, we have need for sorting with a caller argument. Signed-off-by: Zach Brown --- kmod/src/Makefile | 1 + kmod/src/sort_priv.c | 71 ++++++++++++++++++++++++++++++++++++++++++++ kmod/src/sort_priv.h | 8 +++++ 3 files changed, 80 insertions(+) create mode 100644 kmod/src/sort_priv.c create mode 100644 kmod/src/sort_priv.h diff --git a/kmod/src/Makefile b/kmod/src/Makefile index 5af7fdd0..5bbee931 100644 --- a/kmod/src/Makefile +++ b/kmod/src/Makefile @@ -33,6 +33,7 @@ scoutfs-y += \ quorum.o \ scoutfs_trace.o \ server.o \ + sort_priv.o \ spbm.o \ srch.o \ super.o \ diff --git a/kmod/src/sort_priv.c b/kmod/src/sort_priv.c new file mode 100644 index 00000000..2acc0802 --- /dev/null +++ b/kmod/src/sort_priv.c @@ -0,0 +1,71 @@ +/* + * A copy of sort() from upstream with a priv argument that's passed + * to comparison, like list_sort(). + */ + +/* ------------------------ */ + +/* + * A fast, small, non-recursive O(nlog n) sort for the Linux kernel + * + * Jan 23 2005 Matt Mackall + */ + +#include +#include +#include +#include +#include "sort_priv.h" + +/** + * sort - sort an array of elements + * @priv: caller's pointer to pass to comparison and swap functions + * @base: pointer to data to sort + * @num: number of elements + * @size: size of each element + * @cmp_func: pointer to comparison function + * @swap_func: pointer to swap function or NULL + * + * This function does a heapsort on the given array. You may provide a + * swap_func function optimized to your element type. + * + * Sorting time is O(n log n) both on average and worst-case. While + * qsort is about 20% faster on average, it suffers from exploitable + * O(n*n) worst-case behavior and extra memory requirements that make + * it less suitable for kernel use. + */ + +void sort_priv(void *priv, void *base, size_t num, size_t size, + int (*cmp_func)(void *priv, const void *, const void *), + void (*swap_func)(void *priv, void *, void *, int size)) +{ + /* pre-scale counters for performance */ + int i = (num/2 - 1) * size, n = num * size, c, r; + + /* heapify */ + for ( ; i >= 0; i -= size) { + for (r = i; r * 2 + size < n; r = c) { + c = r * 2 + size; + if (c < n - size && + cmp_func(priv, base + c, base + c + size) < 0) + c += size; + if (cmp_func(priv, base + r, base + c) >= 0) + break; + swap_func(priv, base + r, base + c, size); + } + } + + /* sort */ + for (i = n - size; i > 0; i -= size) { + swap_func(priv, base, base + i, size); + for (r = 0; r * 2 + size < i; r = c) { + c = r * 2 + size; + if (c < i - size && + cmp_func(priv, base + c, base + c + size) < 0) + c += size; + if (cmp_func(priv, base + r, base + c) >= 0) + break; + swap_func(priv, base + r, base + c, size); + } + } +} diff --git a/kmod/src/sort_priv.h b/kmod/src/sort_priv.h new file mode 100644 index 00000000..c5fde547 --- /dev/null +++ b/kmod/src/sort_priv.h @@ -0,0 +1,8 @@ +#ifndef _SCOUTFS_SORT_PRIV_H_ +#define _SCOUTFS_SORT_PRIV_H_ + +void sort_priv(void *priv, void *base, size_t num, size_t size, + int (*cmp_func)(void *priv, const void *, const void *), + void (*swap_func)(void *priv, void *, void *, int size)); + +#endif