• Tejun Heo's avatar
    kernfs: fix get_active failure handling in kernfs_seq_*() · d92d2e6b
    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().
    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>
    d92d2e6b
file.c 21.3 KB