From f3dd00895b2e1301dcd1a9a7ac8fd142ddb4830a Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Wed, 29 Jun 2022 14:22:28 -0700 Subject: [PATCH 1/4] Don't allocate zero size net info Clients don't use the net conn info and specified that it has 0 size. The net layer would try and allocate a zero size region which returns the magic ZERO_SIZE_PTR, which it would then later try and free. While that works, it's a little goofy. We can avoid the allocation when the size is 0. The pointer will remain null which kfree also accepts. Signed-off-by: Zach Brown --- kmod/src/net.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/kmod/src/net.c b/kmod/src/net.c index 93478a5f..1ef6db35 100644 --- a/kmod/src/net.c +++ b/kmod/src/net.c @@ -1345,10 +1345,12 @@ scoutfs_net_alloc_conn(struct super_block *sb, if (!conn) return NULL; - conn->info = kzalloc(info_size, GFP_NOFS); - if (!conn->info) { - kfree(conn); - return NULL; + if (info_size) { + conn->info = kzalloc(info_size, GFP_NOFS); + if (!conn->info) { + kfree(conn); + return NULL; + } } conn->workq = alloc_workqueue("scoutfs_net_%s", From 51a8236316212f969c38df3cd422a33717e34f36 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Wed, 29 Jun 2022 14:51:29 -0700 Subject: [PATCH 2/4] Fix missed partial fill_super teardown If we return an error from .fill_super without having set sb->s_root then the vfs won't call our put_super. Our fill_super is careful to call put_super so that it can tear down partial state, but we weren't doing this with a few very early errors in fill_super. This tripped leak detection when we weren't freeing the sbi when returning errors from bad option parsing. Signed-off-by: Zach Brown --- kmod/src/super.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kmod/src/super.c b/kmod/src/super.c index 5cac5148..d38fcb65 100644 --- a/kmod/src/super.c +++ b/kmod/src/super.c @@ -496,7 +496,7 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent) ret = assign_random_id(sbi); if (ret < 0) - return ret; + goto out; spin_lock_init(&sbi->next_ino_lock); spin_lock_init(&sbi->data_wait_root.lock); @@ -505,7 +505,7 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent) /* parse options early for use during setup */ ret = scoutfs_options_early_setup(sb, data); if (ret < 0) - return ret; + goto out; scoutfs_options_read(sb, &opts); ret = sb_set_blocksize(sb, SCOUTFS_BLOCK_SM_SIZE); From 310725eb72899a17cea2aa628a1e309d9c7ff670 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Fri, 1 Jul 2022 10:02:35 -0700 Subject: [PATCH 3/4] Free omap rid list as server exits The omap code keeps track of rids that are connected to the server. It only freed the tracked rids as the server told it that rids were being removed. But that removal only happened as clients were evicted. If the server shutdown it'd leave the old rid entries around. They'd be leaked as the mount was unmounted and could linger and crate duplicate entries if the server started back up and the same clients reconnected. The fix is to free the tracking rids as the server shuts down. They'll be rebuilt as clients reconnect if the server restarts. Signed-off-by: Zach Brown --- kmod/src/omap.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/kmod/src/omap.c b/kmod/src/omap.c index 604c397e..c39dbc9c 100644 --- a/kmod/src/omap.c +++ b/kmod/src/omap.c @@ -157,6 +157,15 @@ static int free_rid(struct omap_rid_list *list, struct omap_rid_entry *entry) return nr; } +static void free_rid_list(struct omap_rid_list *list) +{ + struct omap_rid_entry *entry; + struct omap_rid_entry *tmp; + + list_for_each_entry_safe(entry, tmp, &list->head, head) + free_rid(list, entry); +} + static int copy_rids(struct omap_rid_list *to, struct omap_rid_list *from, spinlock_t *from_lock) { struct omap_rid_entry *entry; @@ -804,6 +813,10 @@ void scoutfs_omap_server_shutdown(struct super_block *sb) llist_for_each_entry_safe(req, tmp, requests, llnode) kfree(req); + spin_lock(&ominf->lock); + free_rid_list(&ominf->rids); + spin_unlock(&ominf->lock); + synchronize_rcu(); } @@ -864,6 +877,10 @@ void scoutfs_omap_destroy(struct super_block *sb) rhashtable_walk_stop(&iter); rhashtable_walk_exit(&iter); + spin_lock(&ominf->lock); + free_rid_list(&ominf->rids); + spin_unlock(&ominf->lock); + rhashtable_destroy(&ominf->group_ht); rhashtable_destroy(&ominf->req_ht); kfree(ominf); From ba9a106f720d54ef4f13db72bb4c3b7c741f5a35 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Fri, 1 Jul 2022 10:15:17 -0700 Subject: [PATCH 4/4] Free send attempts to disconnected clients Callers who send to specific client connections can get -ENOTCONN if their client has gone away. We forgot to free the send tracking struct in that case. Signed-off-by: Zach Brown --- kmod/src/net.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kmod/src/net.c b/kmod/src/net.c index 1ef6db35..eab190da 100644 --- a/kmod/src/net.c +++ b/kmod/src/net.c @@ -355,6 +355,7 @@ static int submit_send(struct super_block *sb, } if (rid != 0) { spin_unlock(&conn->lock); + kfree(msend); return -ENOTCONN; } }