]> git.proxmox.com Git - mirror_spl-debian.git/commitdiff
Rework ddi_strtox calls to a native implementation which actuall supports the EINVAL...
authorBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 13 Jan 2009 17:30:59 +0000 (09:30 -0800)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 13 Jan 2009 17:30:59 +0000 (09:30 -0800)
modules/spl/spl-generic.c
modules/splat/Makefile.in
modules/splat/splat-ctl.c
modules/splat/splat-generic.c [new file with mode: 0644]
modules/splat/splat-internal.h

index d361bff92b099cf7c4dee8a8e83d3a7d8a2ee942..c09d9d4e36c335bb3db55efe526dbcce258250ee 100644 (file)
@@ -126,6 +126,11 @@ uint64_t __umoddi3(uint64_t dividend, uint64_t divisor)
 EXPORT_SYMBOL(__umoddi3);
 #endif
 
+/* NOTE: The strtoxx behavior is solely based on my reading of the Solaris
+ * ddi_strtol(9F) man page.  I have not verified the behavior of these
+ * functions against their Solaris counterparts.  It is possible that I
+ * may have misinterpretted the man page or the man page is incorrect.
+ */
 int ddi_strtoul(const char *, char **, int, unsigned long *);
 int ddi_strtol(const char *, char **, int, long *);
 int ddi_strtoull(const char *, char **, int, unsigned long long *);
@@ -133,43 +138,81 @@ int ddi_strtoll(const char *, char **, int, long long *);
 
 #define define_ddi_strtoux(type, valtype)                              \
 int ddi_strtou##type(const char *str, char **endptr,                   \
-                       int base, valtype *result)                      \
+                    int base, valtype *result)                         \
 {                                                                      \
-       valtype val;                                                    \
-       size_t len;                                                     \
+       valtype last_value, value = 0;                                  \
+       char *ptr = (char *)str;                                        \
+       int flag = 1, digit;                                            \
+                                                                       \
+       if (strlen(ptr) == 0)                                           \
+               return EINVAL;                                          \
+                                                                       \
+       /* Auto-detect base based on prefix */                          \
+       if (!base) {                                                    \
+               if (str[0] == '0') {                                    \
+                       if (tolower(str[1])=='x' && isxdigit(str[2])) { \
+                               base = 16; /* hex */                    \
+                               ptr += 2;                               \
+                       } else if (str[1] >= '0' && str[1] < 8) {       \
+                               base = 8; /* octal */                   \
+                               ptr += 1;                               \
+                       } else {                                        \
+                               return EINVAL;                          \
+                       }                                               \
+               } else {                                                \
+                       base = 10; /* decimal */                        \
+               }                                                       \
+       }                                                               \
+                                                                       \
+       while (1) {                                                     \
+               if (isdigit(*ptr))                                      \
+                       digit = *ptr - '0';                             \
+               else if (isalpha(*ptr))                                 \
+                       digit = tolower(*ptr) - 'a' + 10;               \
+               else                                                    \
+                       break;                                          \
+                                                                       \
+               if (digit >= base)                                      \
+                       break;                                          \
                                                                        \
-       len = strlen(str);                                              \
-       if (len == 0)                                                   \
-               return -EINVAL;                                         \
+               last_value = value;                                     \
+               value = value * base + digit;                           \
+               if (last_value > value) /* Overflow */                  \
+                       return ERANGE;                                  \
                                                                        \
-       val = simple_strtoul(str, endptr, (unsigned int)base);          \
-       if ((**endptr == '\0') ||                                       \
-          ((len == (size_t)(*endptr-str) + 1) && (**endptr == '\n'))) {\
-               *result = val;                                          \
-               return 0;                                               \
+               flag = 1;                                               \
+               ptr++;                                                  \
        }                                                               \
                                                                        \
-       return -EINVAL;                                                 \
+       if (flag)                                                       \
+               *result = value;                                        \
+                                                                       \
+       if (endptr)                                                     \
+               *endptr = (char *)(flag ? ptr : str);                   \
+                                                                       \
+       return 0;                                                       \
 }                                                                      \
 
 #define define_ddi_strtox(type, valtype)                               \
 int ddi_strto##type(const char *str, char **endptr,                    \
                       int base, valtype *result)                       \
-{                                                                       \
-       int ret;                                                        \
+{                                                                      \
+       int rc;                                                         \
                                                                        \
        if (*str == '-') {                                              \
-               ret = ddi_strtou##type(str+1, endptr,                   \
-                                      (unsigned int)base, result);     \
-               if (!ret)                                               \
-                       *result = -(*result);                           \
+               rc = ddi_strtou##type(str + 1, endptr, base, result);   \
+               if (!rc) {                                              \
+                       if (*endptr == str + 1)                         \
+                               *endptr = (char *)str;                  \
+                       else                                            \
+                               *result = -*result;                     \
+               }                                                       \
        } else {                                                        \
-               ret = ddi_strtou##type(str, endptr,                     \
-                                      (unsigned int)base, result);     \
+               rc = ddi_strtou##type(str, endptr, base, result);       \
        }                                                               \
                                                                        \
-       return ret;                                                     \
-}                                                                      \
+       return rc;                                                      \
+}
 
 define_ddi_strtoux(l, unsigned long)
 define_ddi_strtox(l, long)
index c31be02852e60175a03caec930444a377b96a254..33b2865c12a495e3d19a8b87ec91cbd2f122e854 100644 (file)
@@ -1,11 +1,7 @@
 # Makefile.in for splat kernel module
 
 MODULES := splat
-DISTFILES = Makefile.in \
-            splat-kmem.c splat-random.c splat-taskq.c \
-            splat-time.c splat-condvar.c  splat-mutex.c \
-            splat-rwlock.c  splat-thread.c \
-            splat-ctl.c splat-internal.h
+DISTFILES = Makefile.in *.c *.h
 EXTRA_CFLAGS = @KERNELCPPFLAGS@
 
 # Solaris Porting LAyer Tests
@@ -24,6 +20,7 @@ splat-objs += splat-vnode.o
 splat-objs += splat-kobj.o
 splat-objs += splat-atomic.o
 splat-objs += splat-list.o
+splat-objs += splat-generic.o
 
 splatmodule := splat.ko
 splatmoduledir := @kmoduledir@/kernel/lib/
index 15bc23a977b33a00b1b273841aed0d9247532bce..41a844789cc4406b395f65268f8f622bcf1f086d 100644 (file)
@@ -608,6 +608,7 @@ splat_init(void)
        SPLAT_SUBSYSTEM_INIT(kobj);
        SPLAT_SUBSYSTEM_INIT(atomic);
        SPLAT_SUBSYSTEM_INIT(list);
+       SPLAT_SUBSYSTEM_INIT(generic);
 
        dev = MKDEV(SPLAT_MAJOR, 0);
         if ((rc = register_chrdev_region(dev, SPLAT_MINORS, SPLAT_NAME)))
@@ -654,6 +655,7 @@ splat_fini(void)
         cdev_del(&splat_cdev);
         unregister_chrdev_region(dev, SPLAT_MINORS);
 
+       SPLAT_SUBSYSTEM_FINI(generic);
        SPLAT_SUBSYSTEM_FINI(list);
        SPLAT_SUBSYSTEM_FINI(atomic);
        SPLAT_SUBSYSTEM_FINI(kobj);
diff --git a/modules/splat/splat-generic.c b/modules/splat/splat-generic.c
new file mode 100644 (file)
index 0000000..6da7473
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ *  This file is part of the SPL: Solaris Porting Layer.
+ *
+ *  Copyright (c) 2008 Lawrence Livermore National Security, LLC.
+ *  Produced at Lawrence Livermore National Laboratory
+ *  Written by:
+ *          Brian Behlendorf <behlendorf1@llnl.gov>,
+ *          Herb Wartens <wartens2@llnl.gov>,
+ *          Jim Garlick <garlick@llnl.gov>
+ *  UCRL-CODE-235197
+ *
+ *  This is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ */
+
+#include "splat-internal.h"
+
+#define SPLAT_SUBSYSTEM_GENERIC                0x0d00
+#define SPLAT_GENERIC_NAME             "generic"
+#define SPLAT_GENERIC_DESC             "Kernel Generic Tests"
+
+#define SPLAT_GENERIC_TEST1_ID         0x0d01
+#define SPLAT_GENERIC_TEST1_NAME       "ddi_strtoul"
+#define SPLAT_GENERIC_TEST1_DESC       "ddi_strtoul Test"
+
+#define SPLAT_GENERIC_TEST2_ID         0x0d02
+#define SPLAT_GENERIC_TEST2_NAME       "ddi_strtol"
+#define SPLAT_GENERIC_TEST2_DESC       "ddi_strtol Test"
+
+#define SPLAT_GENERIC_TEST3_ID         0x0d03
+#define SPLAT_GENERIC_TEST3_NAME       "ddi_strtoull"
+#define SPLAT_GENERIC_TEST3_DESC       "ddi_strtoull Test"
+
+#define SPLAT_GENERIC_TEST4_ID         0x0d04
+#define SPLAT_GENERIC_TEST4_NAME       "ddi_strtoll"
+#define SPLAT_GENERIC_TEST4_DESC       "ddi_strtoll Test"
+
+#define STR_POS                                "123456789"
+#define STR_NEG                                "-123456789"
+#define STR_BASE                       "0xabcdef"
+#define STR_RANGE_MAX                  "10000000000000000"
+#define STR_RANGE_MIN                  "-10000000000000000"
+#define STR_INVAL1                     "12345U"
+#define STR_INVAL2                     "invald"
+
+#define VAL_POS                                123456789
+#define VAL_NEG                                -123456789
+#define VAL_BASE                       0xabcdef
+#define VAL_INVAL1                     12345U
+
+#define define_generic_msg_strtox(type, valtype)                       \
+static void                                                            \
+generic_msg_strto##type(struct file *file, char *msg, int rc, int *err, \
+                       const char *s, valtype d, char *endptr)         \
+{                                                                      \
+       splat_vprint(file, SPLAT_GENERIC_TEST1_NAME,                    \
+                    "%s (%d) %s: %s == %lld, 0x%p\n",                  \
+                    rc ? "Fail" : "Pass", *err, msg, s,                \
+                    (unsigned long long)d, endptr);                    \
+       *err = rc;                                                      \
+}
+
+define_generic_msg_strtox(ul, unsigned long);
+define_generic_msg_strtox(l, long);
+define_generic_msg_strtox(ull, unsigned long long);
+define_generic_msg_strtox(ll, long long);
+
+#define define_splat_generic_test_strtox(type, valtype)                        \
+static int                                                             \
+splat_generic_test_strto##type(struct file *file, void *arg)           \
+{                                                                      \
+       int rc, rc1, rc2, rc3, rc4, rc5, rc6, rc7;                      \
+       char str[20], *endptr;                                          \
+       valtype r;                                                      \
+                                                                       \
+       /* Positive value: expect success */                            \
+       r = 0;                                                          \
+       rc = 1;                                                         \
+       endptr = NULL;                                                  \
+       rc1 = ddi_strto##type(STR_POS, &endptr, 10, &r);                \
+       if (rc1 == 0 && r == VAL_POS && endptr && *endptr == '\0')      \
+               rc = 0;                                                 \
+                                                                       \
+       generic_msg_strto##type(file, "positive", rc , &rc1,            \
+                               STR_POS, r, endptr);                    \
+                                                                       \
+       /* Negative value: expect success */                            \
+       r = 0;                                                          \
+       rc = 1;                                                         \
+       endptr = NULL;                                                  \
+       strcpy(str, STR_NEG);                                           \
+       rc2 = ddi_strto##type(str, &endptr, 10, &r);                    \
+       if (#type[0] == 'u') {                                          \
+               if (rc2 == 0 && r == 0 && endptr == str)                \
+                       rc = 0;                                         \
+       } else {                                                        \
+               if (rc2 == 0 && r == VAL_NEG &&                         \
+                   endptr && *endptr == '\0')                          \
+                       rc = 0;                                         \
+       }                                                               \
+                                                                       \
+       generic_msg_strto##type(file, "negative", rc, &rc2,             \
+                               STR_NEG, r, endptr);                    \
+                                                                       \
+       /* Non decimal base: expect sucess */                           \
+       r = 0;                                                          \
+       rc = 1;                                                         \
+       endptr = NULL;                                                  \
+       rc3 = ddi_strto##type(STR_BASE, &endptr, 0, &r);                \
+       if (rc3 == 0 && r == VAL_BASE && endptr && *endptr == '\0')     \
+               rc = 0;                                                 \
+                                                                       \
+       generic_msg_strto##type(file, "base", rc, &rc3,                 \
+                               STR_BASE, r, endptr);                   \
+                                                                       \
+       /* Max out of range: failure expected, r unchanged */           \
+       r = 0;                                                          \
+       rc = 1;                                                         \
+       endptr = NULL;                                                  \
+       rc4 = ddi_strto##type(STR_RANGE_MAX, &endptr, 16, &r);          \
+       if (rc4 == ERANGE && r == 0 && endptr == NULL)                  \
+               rc = 0;                                                 \
+                                                                       \
+       generic_msg_strto##type(file, "max", rc, &rc4,                  \
+                               STR_RANGE_MAX, r, endptr);              \
+                                                                       \
+       /* Min out of range: failure expected, r unchanged */           \
+       r = 0;                                                          \
+       rc = 1;                                                         \
+       endptr = NULL;                                                  \
+       strcpy(str, STR_RANGE_MIN);                                     \
+       rc5 = ddi_strto##type(str, &endptr, 16, &r);                    \
+       if (#type[0] == 'u') {                                          \
+               if (rc5 == 0 && r == 0 && endptr == str)                \
+                       rc = 0;                                         \
+       } else {                                                        \
+               if (rc5 == ERANGE && r == 0 && endptr == NULL)          \
+                       rc = 0;                                         \
+       }                                                               \
+                                                                       \
+       generic_msg_strto##type(file, "min", rc, &rc5,                  \
+                               STR_RANGE_MIN, r, endptr);              \
+                                                                       \
+       /* Invalid string: success expected, endptr == 'U' */           \
+       r = 0;                                                          \
+       rc = 1;                                                         \
+       endptr = NULL;                                                  \
+       rc6 = ddi_strto##type(STR_INVAL1, &endptr, 10, &r);             \
+       if (rc6 == 0 && r == VAL_INVAL1 && endptr && *endptr == 'U')    \
+               rc = 0;                                                 \
+                                                                       \
+       generic_msg_strto##type(file, "invalid", rc, &rc6,              \
+                               STR_INVAL1, r, endptr);                 \
+                                                                       \
+       /* Invalid string: failure expected, endptr == str */           \
+       r = 0;                                                          \
+       rc = 1;                                                         \
+       endptr = NULL;                                                  \
+       strcpy(str, STR_INVAL2);                                        \
+       rc7 = ddi_strto##type(str, &endptr, 10, &r);                    \
+       if (rc7 == 0 && r == 0 && endptr == str)                        \
+               rc = 0;                                                 \
+                                                                       \
+       generic_msg_strto##type(file, "invalid", rc, &rc7,              \
+                               STR_INVAL2, r, endptr);                 \
+                                                                       \
+        return (rc1 || rc2 || rc3 || rc4 || rc5 || rc6 || rc7) ?       \
+               -EINVAL : 0;                                            \
+}
+
+define_splat_generic_test_strtox(ul, unsigned long);
+define_splat_generic_test_strtox(l, long);
+define_splat_generic_test_strtox(ull, unsigned long long);
+define_splat_generic_test_strtox(ll, long long);
+
+splat_subsystem_t *
+splat_generic_init(void)
+{
+        splat_subsystem_t *sub;
+
+        sub = kmalloc(sizeof(*sub), GFP_KERNEL);
+        if (sub == NULL)
+                return NULL;
+
+        memset(sub, 0, sizeof(*sub));
+        strncpy(sub->desc.name, SPLAT_GENERIC_NAME, SPLAT_NAME_SIZE);
+       strncpy(sub->desc.desc, SPLAT_GENERIC_DESC, SPLAT_DESC_SIZE);
+        INIT_LIST_HEAD(&sub->subsystem_list);
+       INIT_LIST_HEAD(&sub->test_list);
+        spin_lock_init(&sub->test_lock);
+        sub->desc.id = SPLAT_SUBSYSTEM_GENERIC;
+
+        SPLAT_TEST_INIT(sub, SPLAT_GENERIC_TEST1_NAME, SPLAT_GENERIC_TEST1_DESC,
+                       SPLAT_GENERIC_TEST1_ID, splat_generic_test_strtoul);
+        SPLAT_TEST_INIT(sub, SPLAT_GENERIC_TEST2_NAME, SPLAT_GENERIC_TEST2_DESC,
+                       SPLAT_GENERIC_TEST2_ID, splat_generic_test_strtol);
+        SPLAT_TEST_INIT(sub, SPLAT_GENERIC_TEST3_NAME, SPLAT_GENERIC_TEST3_DESC,
+                       SPLAT_GENERIC_TEST3_ID, splat_generic_test_strtoull);
+        SPLAT_TEST_INIT(sub, SPLAT_GENERIC_TEST4_NAME, SPLAT_GENERIC_TEST4_DESC,
+                       SPLAT_GENERIC_TEST4_ID, splat_generic_test_strtoll);
+
+        return sub;
+}
+
+void
+splat_generic_fini(splat_subsystem_t *sub)
+{
+        ASSERT(sub);
+
+        SPLAT_TEST_FINI(sub, SPLAT_GENERIC_TEST4_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_GENERIC_TEST3_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_GENERIC_TEST2_ID);
+        SPLAT_TEST_FINI(sub, SPLAT_GENERIC_TEST1_ID);
+
+        kfree(sub);
+}
+
+int
+splat_generic_id(void)
+{
+        return SPLAT_SUBSYSTEM_GENERIC;
+}
index 4a49b4d0153ecc02654a4e9a3285f5acd4c31b0e..87c47b173373719e24f8e9549294b8e5a134e1f9 100644 (file)
@@ -62,6 +62,7 @@
 #include <sys/kobj.h>
 #include <sys/atomic.h>
 #include <sys/list.h>
+#include <sys/sunddi.h>
 #include <linux/cdev.h>
 
 #include "spl-device.h"
@@ -205,6 +206,7 @@ splat_subsystem_t *splat_vnode_init(void);
 splat_subsystem_t *splat_kobj_init(void);
 splat_subsystem_t *splat_atomic_init(void);
 splat_subsystem_t *splat_list_init(void);
+splat_subsystem_t *splat_generic_init(void);
 
 void splat_condvar_fini(splat_subsystem_t *);
 void splat_kmem_fini(splat_subsystem_t *);
@@ -218,6 +220,7 @@ void splat_vnode_fini(splat_subsystem_t *);
 void splat_kobj_fini(splat_subsystem_t *);
 void splat_atomic_fini(splat_subsystem_t *);
 void splat_list_fini(splat_subsystem_t *);
+void splat_generic_fini(splat_subsystem_t *);
 
 int splat_condvar_id(void);
 int splat_kmem_id(void);
@@ -231,5 +234,6 @@ int splat_vnode_id(void);
 int splat_kobj_id(void);
 int splat_atomic_id(void);
 int splat_list_id(void);
+int splat_generic_id(void);
 
 #endif /* _SPLAT_INTERNAL_H */