diff options
author | Brian Behlendorf <[email protected]> | 2018-09-26 09:50:58 -0700 |
---|---|---|
committer | GitHub <[email protected]> | 2018-09-26 09:50:58 -0700 |
commit | 7a23c81342df05ace730bd303b4a73854dba43dd (patch) | |
tree | 39569e47af4b369c9813aca12dd8ff72a3a1e481 | |
parent | b954e36e512171d94637c709023e4d763b655d91 (diff) |
Fix small sysfs leak
When zfs_kobj_init() is called with an attr_cnt of 0 only the
kobj->zko_default_attrs is allocated. It subsequently won't
get freed in zfs_kobj_release since the free is wrapped in
a kobj->zko_attr_count != 0 conditional.
Split the block in zfs_kobj_release() to make sure the
kobj->zko_default_attrs are freed in this case.
Additionally, fix a minor spelling mistake and typo in
zfs_kobj_init() which could also cause a leak but in practice
is almost certain not to fail.
Reviewed-by: Richard Elling <[email protected]>
Reviewed-by: Tim Chase <[email protected]>
Reviewed-by: John Gallagher <[email protected]>
Reviewed-by: Don Brady <[email protected]>
Reviewed-by: George Melikov <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Closes #7957
-rw-r--r-- | module/zfs/zfs_sysfs.c | 25 |
1 files changed, 15 insertions, 10 deletions
diff --git a/module/zfs/zfs_sysfs.c b/module/zfs/zfs_sysfs.c index 42822b2f2..b17c91f65 100644 --- a/module/zfs/zfs_sysfs.c +++ b/module/zfs/zfs_sysfs.c @@ -102,7 +102,7 @@ typedef ssize_t (*sysfs_show_func)(struct kobject *, struct attribute *, static void zfs_kobj_fini(zfs_mod_kobj_t *zkobj) { - /* finialize any child kobjects */ + /* finalize any child kobjects */ if (zkobj->zko_child_count != 0) { ASSERT(zkobj->zko_children); for (int i = 0; i < zkobj->zko_child_count; i++) @@ -119,18 +119,19 @@ zfs_kobj_release(struct kobject *kobj) { zfs_mod_kobj_t *zkobj = container_of(kobj, zfs_mod_kobj_t, zko_kobj); - if (zkobj->zko_attr_count != 0) { - ASSERT(zkobj->zko_attr_list); - ASSERT(zkobj->zko_default_attrs); - + if (zkobj->zko_attr_list != NULL) { + ASSERT3S(zkobj->zko_attr_count, !=, 0); kmem_free(zkobj->zko_attr_list, ATTR_TABLE_SIZE(zkobj->zko_attr_count)); + zkobj->zko_attr_list = NULL; + } + + if (zkobj->zko_default_attrs != NULL) { kmem_free(zkobj->zko_default_attrs, DEFAULT_ATTR_SIZE(zkobj->zko_attr_count)); - zkobj->zko_attr_count = 0; - zkobj->zko_attr_list = NULL; zkobj->zko_default_attrs = NULL; } + if (zkobj->zko_child_count != 0) { ASSERT(zkobj->zko_children); @@ -139,6 +140,8 @@ zfs_kobj_release(struct kobject *kobj) zkobj->zko_child_count = 0; zkobj->zko_children = NULL; } + + zkobj->zko_attr_count = 0; } static void @@ -170,7 +173,7 @@ zfs_kobj_init(zfs_mod_kobj_t *zkobj, int attr_cnt, int child_cnt, zkobj->zko_default_attrs = kmem_zalloc(DEFAULT_ATTR_SIZE(attr_cnt), KM_SLEEP); if (zkobj->zko_default_attrs == NULL) { - if (zkobj->zko_attr_list) { + if (zkobj->zko_attr_list != NULL) { kmem_free(zkobj->zko_attr_list, ATTR_TABLE_SIZE(attr_cnt)); } @@ -183,9 +186,11 @@ zfs_kobj_init(zfs_mod_kobj_t *zkobj, int attr_cnt, int child_cnt, zkobj->zko_children = kmem_zalloc(CHILD_TABLE_SIZE(child_cnt), KM_SLEEP); if (zkobj->zko_children == NULL) { - if (attr_cnt > 0) { - kmem_free(zkobj->zko_attr_list, + if (zkobj->zko_default_attrs != NULL) { + kmem_free(zkobj->zko_default_attrs, DEFAULT_ATTR_SIZE(attr_cnt)); + } + if (zkobj->zko_attr_list != NULL) { kmem_free(zkobj->zko_attr_list, ATTR_TABLE_SIZE(attr_cnt)); } |