]> git.proxmox.com Git - mirror_zfs.git/blobdiff - module/splat/splat-linux.c
Update README: run autogen first
[mirror_zfs.git] / module / splat / splat-linux.c
index 5303df4e034d9d8e13bd79e156d5489a23fe0be0..1565d74a3c6ff5026021911fbc9367180078f16c 100644 (file)
@@ -1,11 +1,11 @@
-/*****************************************************************************\
+/*
  *  Copyright (C) 2011 Lawrence Livermore National Security, LLC.
  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
  *  UCRL-CODE-235197
  *
  *  This file is part of the SPL, Solaris Porting Layer.
- *  For details, see <http://github.com/behlendorf/spl/>.
+ *  For details, see <http://zfsonlinux.org/>.
  *
  *  The SPL is free software; you can redistribute it and/or modify it
  *  under the terms of the GNU General Public License as published by the
  *  with the SPL.  If not, see <http://www.gnu.org/licenses/>.
  *****************************************************************************
  *  Solaris Porting LAyer Tests (SPLAT) Kernel Compatibility Tests.
-\*****************************************************************************/
+ */
 
 #include <sys/kmem.h>
+#include <linux/mm_compat.h>
 #include "splat-internal.h"
 
 #define SPLAT_LINUX_NAME               "linux"
 #define SPLAT_LINUX_DESC               "Kernel Compatibility Tests"
 
 #define SPLAT_LINUX_TEST1_ID           0x1001
-#define SPLAT_LINUX_TEST1_NAME         "shrink_dcache"
-#define SPLAT_LINUX_TEST1_DESC         "Shrink dcache test"
-
-#define SPLAT_LINUX_TEST2_ID           0x1002
-#define SPLAT_LINUX_TEST2_NAME         "shrink_icache"
-#define SPLAT_LINUX_TEST2_DESC         "Shrink icache test"
-
-#define SPLAT_LINUX_TEST3_ID           0x1003
-#define SPLAT_LINUX_TEST3_NAME         "shrinker"
-#define SPLAT_LINUX_TEST3_DESC         "Shrinker test"
-
+#define SPLAT_LINUX_TEST1_NAME         "shrinker"
+#define SPLAT_LINUX_TEST1_DESC         "Shrinker test"
 
 /*
- * Attempt to shrink the dcache memory.  This is simply a functional
- * to ensure we can correctly call the shrinker.  We don't check that
- * the cache actually decreased because we have no control over what
- * else may be running on the system.  This avoid false positives.
+ * Wait queue used to eliminate race between dropping of slab
+ * and execution of the shrinker callback
  */
-static int
-splat_linux_test1(struct file *file, void *arg)
-{
-       int remain_before;
-       int remain_after;
-
-       remain_before = shrink_dcache_memory(0, GFP_KERNEL);
-       remain_after = shrink_dcache_memory(KMC_REAP_CHUNK, GFP_KERNEL);
-
-       splat_vprint(file, SPLAT_LINUX_TEST1_NAME,
-           "Shrink dcache memory, remain %d -> %d\n",
-           remain_before, remain_after);
-
-       return 0;
-}
-
-/*
- * Attempt to shrink the icache memory.  This is simply a functional
- * to ensure we can correctly call the shrinker.  We don't check that
- * the cache actually decreased because we have no control over what
- * else may be running on the system.  This avoid false positives.
- */
-static int
-splat_linux_test2(struct file *file, void *arg)
-{
-       int remain_before;
-       int remain_after;
-
-       remain_before = shrink_icache_memory(0, GFP_KERNEL);
-       remain_after = shrink_icache_memory(KMC_REAP_CHUNK, GFP_KERNEL);
-
-       splat_vprint(file, SPLAT_LINUX_TEST2_NAME,
-           "Shrink icache memory, remain %d -> %d\n",
-           remain_before, remain_after);
-
-       return 0;
-}
+DECLARE_WAIT_QUEUE_HEAD(shrinker_wait);
 
 SPL_SHRINKER_CALLBACK_FWD_DECLARE(splat_linux_shrinker_fn);
 SPL_SHRINKER_DECLARE(splat_linux_shrinker, splat_linux_shrinker_fn, 1);
 static unsigned long splat_linux_shrinker_size = 0;
 static struct file *splat_linux_shrinker_file = NULL;
 
-static int
+static spl_shrinker_t
 __splat_linux_shrinker_fn(struct shrinker *shrink, struct shrink_control *sc)
 {
        static int failsafe = 0;
+       static unsigned long last_splat_linux_shrinker_size = 0;
+       unsigned long size;
+       spl_shrinker_t count;
+
+       /*
+        * shrinker_size can only decrease or stay the same between callbacks
+        * in the same run, so Reset failsafe whenever shrinker increases
+        * as this indicates a new run.
+        */
+       if (last_splat_linux_shrinker_size < splat_linux_shrinker_size)
+               failsafe = 0;
+
+       last_splat_linux_shrinker_size = splat_linux_shrinker_size;
 
        if (sc->nr_to_scan) {
-               splat_linux_shrinker_size = splat_linux_shrinker_size -
-                   MIN(sc->nr_to_scan, splat_linux_shrinker_size);
+               size = MIN(sc->nr_to_scan, splat_linux_shrinker_size);
+               splat_linux_shrinker_size -= size;
 
-               splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST3_NAME,
+               splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST1_NAME,
                    "Reclaimed %lu objects, size now %lu\n",
-                   sc->nr_to_scan, splat_linux_shrinker_size);
+                   size, splat_linux_shrinker_size);
+
+#ifdef HAVE_SPLIT_SHRINKER_CALLBACK
+               count = size;
+#else
+               count = splat_linux_shrinker_size;
+#endif /* HAVE_SPLIT_SHRINKER_CALLBACK */
+
        } else {
-               splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST3_NAME,
+               count = splat_linux_shrinker_size;
+               splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST1_NAME,
                    "Cache size is %lu\n", splat_linux_shrinker_size);
        }
 
        /* Far more calls than expected abort drop_slab as a failsafe */
-       if ((++failsafe % 1000) == 0) {
-               splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST3_NAME,
+       if (failsafe > 100) {
+               splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST1_NAME,
                    "Far more calls than expected (%d), size now %lu\n",
                   failsafe, splat_linux_shrinker_size);
-               return -1;
+               return (SHRINK_STOP);
+       } else {
+               /*
+                * We only increment failsafe if it doesn't trigger.  This
+                * makes any failsafe failure persistent until the next test.
+                */
+               failsafe++;
        }
 
-       return (int)splat_linux_shrinker_size;
+       /* Shrinker has run, so signal back to test. */
+       wake_up(&shrinker_wait);
+
+       return (count);
 }
 
 SPL_SHRINKER_CALLBACK_WRAPPER(splat_linux_shrinker_fn);
@@ -140,9 +124,9 @@ splat_linux_drop_slab(struct file *file)
                         NULL };
        int rc;
 
-       rc = call_usermodehelper(argv[0], argv, envp, 1);
+       rc = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
        if (rc)
-               splat_vprint(file, SPLAT_LINUX_TEST3_NAME,
+               splat_vprint(file, SPLAT_LINUX_TEST1_NAME,
                    "Failed user helper '%s %s %s', rc = %d\n",
                    argv[0], argv[1], argv[2], rc);
 
@@ -159,7 +143,7 @@ splat_linux_drop_slab(struct file *file)
  * API and this test ensures the compatibility code is correct.
  */
 static int
-splat_linux_test3(struct file *file, void *arg)
+splat_linux_test1(struct file *file, void *arg)
 {
        int rc = -EINVAL;
 
@@ -170,8 +154,8 @@ splat_linux_test3(struct file *file, void *arg)
         * use is detected.
         */
        if (splat_linux_shrinker_size || splat_linux_shrinker_file) {
-               splat_vprint(file, SPLAT_LINUX_TEST3_NAME,
-                   "Failed due to concurrent shrinker test, rc = %d\n", rc);
+               splat_vprint(file, SPLAT_LINUX_TEST1_NAME,
+                   "Failed due to concurrent shrinker test, rc = %d\n", rc);
                return (rc);
        }
 
@@ -183,9 +167,26 @@ splat_linux_test3(struct file *file, void *arg)
        if (rc)
                goto out;
 
-       if (splat_linux_shrinker_size != 0) {
-               splat_vprint(file, SPLAT_LINUX_TEST3_NAME,
-                   "Failed cache was not shrunk to 0, size now %lu",
+       /*
+        * By the time we get here, it is possible that the shrinker has not
+        * yet run. splat_linux_drop_slab sends a signal for it to run, but
+        * there is no guarantee of when it will actually run. We wait for it
+        * to run here, terminating when either the shrinker size is now 0 or
+        * we timeout after 1 second, which should be an eternity (error).
+        */
+       rc = wait_event_timeout(shrinker_wait, !splat_linux_shrinker_size, HZ);
+       if (!rc) {
+               splat_vprint(file, SPLAT_LINUX_TEST1_NAME,
+                   "Failed cache shrinking timed out, size now %lu",
+                   splat_linux_shrinker_size);
+               rc = -ETIMEDOUT;
+       } else {
+               rc = 0;
+       }
+
+       if (!rc && splat_linux_shrinker_size != 0) {
+               splat_vprint(file, SPLAT_LINUX_TEST1_NAME,
+                   "Failed cache was not shrunk to 0, size now %lu",
                    splat_linux_shrinker_size);
                rc = -EDOM;
        }
@@ -215,12 +216,8 @@ splat_linux_init(void)
        spin_lock_init(&sub->test_lock);
        sub->desc.id = SPLAT_SUBSYSTEM_LINUX;
 
-       SPLAT_TEST_INIT(sub, SPLAT_LINUX_TEST1_NAME, SPLAT_LINUX_TEST1_DESC,
+       splat_test_init(sub, SPLAT_LINUX_TEST1_NAME, SPLAT_LINUX_TEST1_DESC,
                        SPLAT_LINUX_TEST1_ID, splat_linux_test1);
-       SPLAT_TEST_INIT(sub, SPLAT_LINUX_TEST2_NAME, SPLAT_LINUX_TEST2_DESC,
-                       SPLAT_LINUX_TEST2_ID, splat_linux_test2);
-       SPLAT_TEST_INIT(sub, SPLAT_LINUX_TEST3_NAME, SPLAT_LINUX_TEST3_DESC,
-                       SPLAT_LINUX_TEST3_ID, splat_linux_test3);
 
        return sub;
 }
@@ -229,9 +226,7 @@ void
 splat_linux_fini(splat_subsystem_t *sub)
 {
        ASSERT(sub);
-       SPLAT_TEST_FINI(sub, SPLAT_LINUX_TEST3_ID);
-       SPLAT_TEST_FINI(sub, SPLAT_LINUX_TEST2_ID);
-       SPLAT_TEST_FINI(sub, SPLAT_LINUX_TEST1_ID);
+       splat_test_fini(sub, SPLAT_LINUX_TEST1_ID);
 
        kfree(sub);
 }