]> granicus.if.org Git - zfs/commitdiff
Fix zfsdev_ioctl() kmem leak warning
authorBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 17 Apr 2014 17:06:37 +0000 (10:06 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Fri, 18 Apr 2014 20:30:15 +0000 (13:30 -0700)
Due to an asymmetry in the kmem accounting a memory leak was being
reported when it was only an accounting issue.  All memory allocated
with kmem_alloc() must be released with kmem_free() or it will not
be properly accounted for.

In this case the code used strfree() to release the memory allocated
by kmem_alloc().  Presumably this was done because the size of the
memory region wasn't available when the memory needed to be freed.

To resolve this issue the code has been updated to use strdup() instead
of kmem_alloc() to allocate the memory.  Like strfree(), strdup() is
not integrated with the memory accounting.  This means we can use
strfree() to release it like Illumos.

  SPL: kmem leaked 10/4368729 bytes
  address          size  data             func:line
  ffff880067e9aa40 10    ZZZZZZZZZZ       zfsdev_ioctl:5655

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Tim Chase <tim@chase2k.com>
Signed-off-by: Chunwei Chen <tuxoko@gmail.com>
Closes #2262

module/zfs/zfs_ioctl.c

index 0dfda1abf77cc60d97c269ed4934fd4b30d8ce6a..5f97ea45421fb211ce5a81759ee6b3dbe4c753d9 100644 (file)
@@ -5584,7 +5584,7 @@ zfsdev_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
 {
        zfs_cmd_t *zc;
        uint_t vecnum;
-       int error, rc, len = 0, flag = 0;
+       int error, rc, flag = 0;
        const zfs_ioc_vec_t *vec;
        char *saved_poolname = NULL;
        nvlist_t *innvl = NULL;
@@ -5651,9 +5651,13 @@ zfsdev_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
                goto out;
 
        /* legacy ioctls can modify zc_name */
-       len = strcspn(zc->zc_name, "/@#") + 1;
-       saved_poolname = kmem_alloc(len, KM_SLEEP);
-       (void) strlcpy(saved_poolname, zc->zc_name, len);
+       saved_poolname = strdup(zc->zc_name);
+       if (saved_poolname == NULL) {
+               error = SET_ERROR(ENOMEM);
+               goto out;
+       } else {
+               saved_poolname[strcspn(saved_poolname, "/@#")] = '\0';
+       }
 
        if (vec->zvec_func != NULL) {
                nvlist_t *outnvl;
@@ -5721,7 +5725,7 @@ out:
                (void) tsd_set(zfs_allow_log_key, saved_poolname);
        } else {
                if (saved_poolname != NULL)
-                       kmem_free(saved_poolname, len);
+                       strfree(saved_poolname);
        }
 
        kmem_free(zc, sizeof (zfs_cmd_t));