|
@@ -193,6 +193,7 @@ static struct vfsmount *zsmalloc_mnt;
|
|
|
* (see: fix_fullness_group())
|
|
|
*/
|
|
|
static const int fullness_threshold_frac = 4;
|
|
|
+static size_t huge_class_size;
|
|
|
|
|
|
struct size_class {
|
|
|
spinlock_t lock;
|
|
@@ -1407,6 +1408,25 @@ void zs_unmap_object(struct zs_pool *pool, unsigned long handle)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(zs_unmap_object);
|
|
|
|
|
|
+/**
|
|
|
+ * zs_huge_class_size() - Returns the size (in bytes) of the first huge
|
|
|
+ * zsmalloc &size_class.
|
|
|
+ * @pool: zsmalloc pool to use
|
|
|
+ *
|
|
|
+ * The function returns the size of the first huge class - any object of equal
|
|
|
+ * or bigger size will be stored in zspage consisting of a single physical
|
|
|
+ * page.
|
|
|
+ *
|
|
|
+ * Context: Any context.
|
|
|
+ *
|
|
|
+ * Return: the size (in bytes) of the first huge zsmalloc &size_class.
|
|
|
+ */
|
|
|
+size_t zs_huge_class_size(struct zs_pool *pool)
|
|
|
+{
|
|
|
+ return huge_class_size;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(zs_huge_class_size);
|
|
|
+
|
|
|
static unsigned long obj_malloc(struct size_class *class,
|
|
|
struct zspage *zspage, unsigned long handle)
|
|
|
{
|
|
@@ -2363,6 +2383,27 @@ struct zs_pool *zs_create_pool(const char *name)
|
|
|
pages_per_zspage = get_pages_per_zspage(size);
|
|
|
objs_per_zspage = pages_per_zspage * PAGE_SIZE / size;
|
|
|
|
|
|
+ /*
|
|
|
+ * We iterate from biggest down to smallest classes,
|
|
|
+ * so huge_class_size holds the size of the first huge
|
|
|
+ * class. Any object bigger than or equal to that will
|
|
|
+ * endup in the huge class.
|
|
|
+ */
|
|
|
+ if (pages_per_zspage != 1 && objs_per_zspage != 1 &&
|
|
|
+ !huge_class_size) {
|
|
|
+ huge_class_size = size;
|
|
|
+ /*
|
|
|
+ * The object uses ZS_HANDLE_SIZE bytes to store the
|
|
|
+ * handle. We need to subtract it, because zs_malloc()
|
|
|
+ * unconditionally adds handle size before it performs
|
|
|
+ * size class search - so object may be smaller than
|
|
|
+ * huge class size, yet it still can end up in the huge
|
|
|
+ * class because it grows by ZS_HANDLE_SIZE extra bytes
|
|
|
+ * right before class lookup.
|
|
|
+ */
|
|
|
+ huge_class_size -= (ZS_HANDLE_SIZE - 1);
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* size_class is used for normal zsmalloc operation such
|
|
|
* as alloc/free for that size. Although it is natural that we
|