Jump to content
  • [6.12.10] SSH Sessions creates a new cgroup that is never deleted after connection is closed.


    KnF
    • Minor

    Hi! I'm gonna briefly describe my setup and then my findings.

     

    I have Unraid installed on my desktop PC. It has 64GB of RAM and two 3070s. Mostly for "2 Gamers - 1 PC setup" (I share it with my wife). 

     

    We have 2 windows VMs and 2 Ubuntu VMs, one of each for each person. Each set of VMs (1 win, 1 ubuntu) share the same GPU passthrough, so they can't be on at the same time because of this. We switch between VMs when we want to game or work.

     

    For this, I created a script that is executed for this purpose. The script takes two parameters, the "from" and "to" VMs, then it checks if the "from" VM is ON at the moment, if so it shuts it off, sets USB passthrough config to the "to" VM and then turns it on. 

     

    For example, when I'm done working (Ubuntu VM on) and I want to game (turn on Windows VM) I call the script and it turns off the ubuntu VM, changes the USB devices assignation to the Windows VM and then turns it on.

     

    Said script is actually executed by my HomeAssistant instance (running on another server) and it does so by connecting through ssh and running the script. This way I can ask Alexa to turn on the windows VM and all the magic is going to happen behind without me running any commands. 

     

    Home Assistant uses another set of commands, also through SSH, to pull each VM state just for showing it on the UI. This command is executed periodically (10s) for each VM.

     

    When I was on 6.11.5 everything was working just fine. But when I upgraded to 6.12.4, after a couple hours I couldn't turn on the the VMs. I receive the following error:

     

    Quote

    Failed to create v2 cgroup '/sys/fs/cgroup/machine/qemu-5-<VM-NAME>.libvirt-qemu/': No space left on device

     

    The only way to fix this is to reboot the server. I ignored the problem for a couple weeks and after I got tired of this I updated to 6.12.10 hoping the problem would go away. It didn't.

    After digging a little bit more, I found out that this "not space left on device" was actually a problem with cgroups limit. I was hitting the cap for this (around 65k cgroups). The "no space on the device" it's because the kernel is not deleting the cgroups and thus it starts to error out once you reach the limit.

     

    I embarked on the quest to find out why I'm the only person in the planet that has this problem and I thought it could be my script or the HomeAssistant interaction. So, I disabled all my HA scripts and commands and started checking how many cgroups were being created with that disabled. None was being created. I re-enabled the scripts and each time HA connected through SSH the cgroups increased by 4 (go figure). Turns out each SSH session that is opened creates a cgroup and when the session is closed, the cgroup is not being deleted.

     

    After a couple minutes googling I found this old thread in StackOverflow that described the exact same problem I was having. 

     

    To confirm if this was my problem, while running the following command:

     

    root@Unraid:~# cat /proc/cgroups 
    #subsys_name    hierarchy       num_cgroups     enabled
    cpuset  0       26      1
    cpu     0       26      1
    cpuacct 0       26      1
    blkio   0       26      1
    memory  0       26      1
    devices 0       26      1
    freezer 0       26      1
    net_cls 0       26      1
    perf_event      0       26      1
    net_prio        0       26      1
    hugetlb 0       26      1
    pids    0       26      1

     

    I connected and disconnected several times via SSH to the server. Confirming the increase on "hierarchy" count each time I connected and never decreasing when disconnecting. The combination of this issue and my HA script which connects 4 times each 10s drives this count to the limit in a matter of hours.

     

    Then I found out that the Unraid 6.12 update introduced a new cgroup version and I think this is the culprit. This new version is having this issue. The Stack Overflow post said that the host having the problem had docker installed, which is also true for Unraid, even though I'm not using it and it's disabled. Also, I've seen on the forum some other post related to docker containers that had similar errors.

     

    I think this is something important that needs to be looked into.

     

     

     




    User Feedback

    Recommended Comments

    Here is a script that can be added to User Scripts plugin and run on a schedule, however often is necessary.

     

    It is undoubtedly the wrong way to address this, but it works for now.

     

    #!/bin/bash
    
    #
    # This issue crept up in unraid 6.12.x, presumably with a switch from cgroup v1 to v2.
    #
    # cgroups are used for SSH connections (via elogind) and when the SSH session ends the cgroup is not cleaned up.
    #
    # This results in old cgroups continuing to collect until errors like this start preventing new connections:
    #
    #    unraid2 elogind-daemon[1504]: Failed to create cgroup c65514: No space left on device
    #
    # Here are some mentions on the unraid forums:
    #
    #    https://forums.unraid.net/topic/45586-ssh-and-denyhosts-updated-for-v61/?do=findComment&comment=1398585
    #    https://forums.unraid.net/bug-reports/stable-releases/61210-ssh-sessions-creates-a-new-cgroup-that-is-never-deleted-after-connection-is-closed-r2981/
    #
    # In the first link, the workaround was to comment the line in /etc/pam.d/sshd for pam_elogind.so which works, but 
    # is that the right way to do it?
    #
    # Seems this used to be handled properly up through 6.11.x when cgroups v1 was in use via the release_agent paradigm.
    # Indeed, for cgroup v1 it used to be mounted like this:
    #
    #    cgroup /sys/fs/cgroup/elogind cgroup rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib64/elogind/elogind-cgroups-agent,name=elogind 0 0
    #
    # cgroup v2 has no concept of release_agent and in 6.12.x /lib64/elogind/elogind-cgroups-agent still exists, so it seems it's an incomplete migration from v1 to v2.
    #
    # cgroup v2 has a cgroup.events file under each individual cgroup which contains values that an external process is supposed to use inotify
    # events to monitor and when the populated value goes to zero it can be cleaned up.
    #
    # this process is either part of systemd (which is not complete/fully present in slackware) or it is supposed to be implemented
    # by sshd/elogind and isn't in unraid.
    #
    # in any case, the script below can look for cgroups where populated is zero and assume they can safely be deleted via the cgdelete command.
    #
    # it can be ran however often is necessary to match whatever rate of SSH connections are made/terminated.
    #
    # *This script is undoubtedly also the wrong way to handle this, but it at least leaves elogind in-play and continues
    # to allow cgroups to be used for SSH connections.
    #
    
    CGROUP_BASE_DIR="/sys/fs/cgroup"
    
    for CGRP in $(find ${CGROUP_BASE_DIR} -type d -maxdepth 1 -regextype sed -regex "^.*/c[0-9]\{1,\}$" -printf "%f\n")
    do
      { sed -n '/populated 0/Q 1'; i=$?; } < ${CGROUP_BASE_DIR}/${CGRP}/cgroup.events
      { sed -n '/frozen 0/Q 1'; j=$?; } < ${CGROUP_BASE_DIR}/${CGRP}/cgroup.events
      if [[ $i -eq 1 && $j -eq 1 ]]
      then
        echo "cleaning up old cgroup ::/${CGRP}"
        /usr/bin/cgdelete -r "::/${CGRP}"
      else
        echo "cgroup ::/${CGRP} still active, skipping"
      fi
    done
    

     

    Link to comment

    I'm currently looking into this and also into other issues in regards to cgroup2.

     

    EDIT: @user12345678 is the script actually working for you that you've posted.

     

    EDIT2: @KnF do you have maybe Diagnostics from when that occured, it would be very interesting what happened on your system since I really can't reproduce the "no space left on device" I'm not at around 10000 ssh login/logouts and everything is working over here.

    Link to comment

    @ich777 - Thank you for looking into this.

     

    I did not experience the actual error, I just noticed the same symptoms (cgroups not being cleaned up after SSH sessions are terminated) while setting up an SFTP connection and could clearly see that I would run into it eventually so I did some research (which included finding this forum topic and another, similar one) and came up with this workaround script.

     

    It does indeed work. I just run it about every hour or-so and it will find the abandoned cgroups and delete them.

     

    I think the way it is intended to work in cgroups v2 is there should be a daemon process monitoring inotify events for the cgroup.events file, checking to see if populated and frozen (or at the very least, populated) goes to zero and, if so, clean up the cgroup.

     

    It may be that the daemon is either part of systemd (which I don't think is fully present in slackware so this part may be missing in unraid) or it could be some sort of plugin/add-on to elogind and is missing here, I am not sure on any of that.

     

    Thanks again!

    Link to comment
    7 minutes ago, user12345678 said:

    It may be that the daemon is either part of systemd (which I don't think is fully present in slackware so this part may be missing in unraid) or it could be some sort of plugin/add-on to elogind and is missing here, I am not sure on any of that.

    I already have a solution in mind to solve this issue.

    systemd is a different kind of beast... :D

     

    For systemd it's actually the case that it works in combination with cgroup and does the cleanup of all necessary or better speaking unused cgroups on it's own.

     

    11 minutes ago, user12345678 said:

    It does indeed work. I just run it about every hour or-so and it will find the abandoned cgroups and delete them.

    I tested the script and on my system it does basically nothing, maybe it would be better to look at cgroup.procs since the active PIDs listed in there and if they are empty no processes are running anymore.

    Link to comment
    27 minutes ago, ich777 said:

    I tested the script and on my system it does basically nothing, maybe it would be better to look at cgroup.procs since the active PIDs listed in there and if they are empty no processes are running anymore.

     

    Here is an example of how it works for me:

     

    root@unraid:~# ls -d /sys/fs/cgroup/c*/
    /bin/ls: cannot access '/sys/fs/cgroup/c*/': No such file or directory
    root@unraid:~# ssh -l XXX unraid.localdomain
    ([email protected]) Password: 
    Last login: XXXXXXXXXXXX from XXX.XXX.XXX.XXX
    Linux 6.1.106-Unraid.
    XXX@unraid:~$ ls -d /sys/fs/cgroup/c*/
    /sys/fs/cgroup/c18//
    XXX@unraid:~$ exit
    logout
    Connection to unraid.localdomain closed.
    root@unraid:~# ls -d /sys/fs/cgroup/c*/
    /sys/fs/cgroup/c18//
    root@unraid:~# bash /boot/scripts/cgroup2_cleanup.sh 
    cleaning up old cgroup ::/c18
    root@unraid:~# ls -d /sys/fs/cgroup/c*/
    /bin/ls: cannot access '/sys/fs/cgroup/c*/': No such file or directory
    root@unraid:~#

     

    The documentation for cgroups v2 specifically says to monitor cgroups.events so that's the one I went after, if cgroups.procs is better than so be it, I am not an expert on this :)

     

    https://docs.kernel.org/admin-guide/cgroup-v2.html

     

    cgroup.events
    
        A read-only flat-keyed file which exists on non-root cgroups. The following entries are defined. Unless specified otherwise, a value change in this file generates a file modified event.
    
            populated
    
                1 if the cgroup or its descendants contains any live processes; otherwise, 0.
            frozen
    
                1 if the cgroup is frozen; otherwise, 0.
    
    

     

    https://man7.org/linux/man-pages/man7/cgroups.7.html

     

    Cgroups v2 cgroup.events file
           Each nonroot cgroup in the v2 hierarchy contains a read-only
           file, cgroup.events, whose contents are key-value pairs
           (delimited by newline characters, with the key and value
           separated by spaces) providing state information about the
           cgroup:
    
               $ cat mygrp/cgroup.events
               populated 1
               frozen 0
    
           The following keys may appear in this file:
    
           populated
                  The value of this key is either 1, if this cgroup or any
                  of its descendants has member processes, or otherwise 0.
    
           frozen (since Linux 5.2)
                  The value of this key is 1 if this cgroup is currently
                  frozen, or 0 if it is not.
    
           The cgroup.events file can be monitored, in order to receive
           notification when the value of one of its keys changes.  Such
           monitoring can be done using inotify(7), which notifies changes
           as IN_MODIFY events, or poll(2), which notifies changes by
           returning the POLLPRI and POLLERR bits in the revents field.
    
       Cgroup v2 release notification
           Cgroups v2 provides a new mechanism for obtaining notification
           when a cgroup becomes empty.  The cgroups v1 release_agent and
           notify_on_release files are removed, and replaced by the
           populated key in the cgroup.events file.  This key either has the
           value 0, meaning that the cgroup (and its descendants) contain no
           (nonzombie) member processes, or 1, meaning that the cgroup (or
           one of its descendants) contains member processes.
    
           The cgroups v2 release-notification mechanism offers the
           following advantages over the cgroups v1 release_agent mechanism:
    
           •  It allows for cheaper notification, since a single process can
              monitor multiple cgroup.events files (using the techniques
              described earlier).  By contrast, the cgroups v1 mechanism
              requires the expense of creating a process for each
              notification.
    
           •  Notification for different cgroup subhierarchies can be
              delegated to different processes.  By contrast, the cgroups v1
              mechanism allows only one release agent for an entire
              hierarchy.

     

    Edited by user12345678
    Link to comment
    14 minutes ago, user12345678 said:

    The documentation for cgroups v2 specifically says to monitor cgroups.events so that's the one I went after, if cgroups.procs is better than so be it, I am not an expert on this :)

    Ah, now I get why it is not working for me, you are searching for directories starting with "c" followed by a number here:

    On 9/7/2024 at 4:47 PM, user12345678 said:
    -regex "^.*/c[0-9]\{1,\}$"

     

    I completely overlooked that part, on my systems the ssh sessions don't start with a "c" that's why it fails, however I'm currently working on another solution to empty the cgroups which are currently not in use.

     

     

    14 minutes ago, user12345678 said:

    Thanks, already read that, I think both ways are a valid way of deleting unused cgroups however for ssh sessions it would be better to use pam for that.

    Link to comment
    2 minutes ago, ich777 said:

    ... however I'm currently working on another solution to empty the cgroups which are currently not in use.

     

    I am 100% positive your way will be better than mine :)

     

    Thank you for working on this!!

    • Like 1
    Link to comment

    Hey guys! Thanks for looking into this issue. 

     

    @ich777 I disabled my HomeAssistant scripts so it wouldn't fail anymore, but I'll enable them now so in a couple days the groups will hit the cap. As soon as that happens I will post the Diagnostics like you asked.

     

    For what I get you already have a solution, but I guess this will provide you more information to confirm if your solution works as intended :)

     

    Thank you both for taking time to look into this issue!

    Link to comment
    42 minutes ago, KnF said:

    @ich777 I disabled my HomeAssistant scripts so it wouldn't fail anymore, but I'll enable them now so in a couple days the groups will hit the cap. As soon as that happens I will post the Diagnostics like you asked.

    I don't think that's necessary anymore, the next version from Unraid should have a daemon included which automatically removes unused cgroups.

    • Like 1
    Link to comment


    Join the conversation

    You can post now and register later. If you have an account, sign in now to post with your account.
    Note: Your post will require moderator approval before it will be visible.

    Guest
    Add a comment...

    ×   Pasted as rich text.   Restore formatting

      Only 75 emoji are allowed.

    ×   Your link has been automatically embedded.   Display as a link instead

    ×   Your previous content has been restored.   Clear editor

    ×   You cannot paste images directly. Upload or insert images from URL.


  • Status Definitions

     

    Open = Under consideration.

     

    Solved = The issue has been resolved.

     

    Solved version = The issue has been resolved in the indicated release version.

     

    Closed = Feedback or opinion better posted on our forum for discussion. Also for reports we cannot reproduce or need more information. In this case just add a comment and we will review it again.

     

    Retest = Please retest in latest release.


    Priority Definitions

     

    Minor = Something not working correctly.

     

    Urgent = Server crash, data loss, or other showstopper.

     

    Annoyance = Doesn't affect functionality but should be fixed.

     

    Other = Announcement or other non-issue.

×
×
  • Create New...