• Tejun Heo's avatar
    kernfs: fix get_active failure handling in kernfs_seq_*() · bb305947
    Tejun Heo authored
    When kernfs_seq_start() fails to obtain an active reference, it
    returns ERR_PTR(-ENODEV).  kernfs_seq_stop() is then invoked with the
    error pointer value; however, it still proceeds to invoke
    kernfs_put_active() on the node leading to unbalanced put.
    
    If kernfs_seq_stop() is called even after active ref failure, it
    should skip invocation of @ops->seq_stop() and put_active.
    Unfortunately, this is a bit complicated because active ref failure
    isn't the only thing which may fail with ERR_PTR(-ENODEV).
    @ops->seq_start/next() may also fail with the error value and
    kernfs_seq_stop() doesn't have a way to tell apart those failures.
    
    Work it around by factoring out the active part of kernfs_seq_stop()
    into kernfs_seq_stop_active() and invoking it directly if
    @ops->seq_start/next() fail with ERR_PTR(-ENODEV) and updating
    kernfs_seq_stop() to skip kernfs_seq_stop_active() on
    ERR_PTR(-ENODEV).  This is a bit nasty but ensures that the active put
    is skipped iff get_active failed in kernfs_seq_start().
    
    tj: This was originally committed as d92d2e6b but got reverted by
        683bb276 along with other kernfs self removal patches.
        However, this one is an independent fix and shouldn't have been
        reverted together.  Reinstate the change.  Sorry about the mess.
    Signed-off-by: default avatarTejun Heo <tj@kernel.org>
    Cc: Sasha Levin <sasha.levin@oracle.com>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    bb305947
file.c 21.3 KB