From: Andrea Arcangeli <aarca...@redhat.com> If getdents64 is killed or hits on segfault, it'll leave cgroups directories in sysfs pinned leaking memory because the kernfs node won't be freed on rmdir and the parent neither.
Repro: # for i in `seq 1000`; do mkdir $i; done # rmdir * # for i in `seq 1000`; do mkdir $i; done # rmdir * # for i in `seq 1000`; do while :; do ls $i/ >/dev/null; done & done # while :; do killall ls; done kernfs_node_cache in /proc/slabinfo keeps going up as expected. Signed-off-by: Andrea Arcangeli <aarca...@redhat.com> Signed-off-by: Tejun Heo <t...@kernel.org> Cc: sta...@vger.kernel.org # goes way back to original sysfs days --- fs/kernfs/dir.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 1e7a74b8e064..82b6c699fa34 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -1683,11 +1683,14 @@ static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx) kernfs_get(pos); mutex_unlock(&kernfs_mutex); - if (!dir_emit(ctx, name, len, ino, type)) - return 0; + if (unlikely(!dir_emit(ctx, name, len, ino, type))) { + kernfs_put(pos); + goto out; + } mutex_lock(&kernfs_mutex); } mutex_unlock(&kernfs_mutex); +out: file->private_data = NULL; ctx->pos = INT_MAX; return 0;