lkml.org 
[lkml]   [2017]   [Nov]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.14 080/193] fsnotify: clean up fsnotify_prepare/finish_user_wait()
    Date
    4.14-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Miklos Szeredi <mszeredi@redhat.com>

    commit 24c20305c7fc8959836211cb8c50aab93ae0e54f upstream.

    This patch doesn't actually fix any bug, just paves the way for fixing mark
    and group pinning.

    Reviewed-by: Amir Goldstein <amir73il@gmail.com>
    Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
    Signed-off-by: Jan Kara <jack@suse.cz>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    fs/notify/mark.c | 98 +++++++++++++++++++++++++++----------------------------
    1 file changed, 49 insertions(+), 49 deletions(-)

    --- a/fs/notify/mark.c
    +++ b/fs/notify/mark.c
    @@ -109,16 +109,6 @@ void fsnotify_get_mark(struct fsnotify_m
    atomic_inc(&mark->refcnt);
    }

    -/*
    - * Get mark reference when we found the mark via lockless traversal of object
    - * list. Mark can be already removed from the list by now and on its way to be
    - * destroyed once SRCU period ends.
    - */
    -static bool fsnotify_get_mark_safe(struct fsnotify_mark *mark)
    -{
    - return atomic_inc_not_zero(&mark->refcnt);
    -}
    -
    static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)
    {
    u32 new_mask = 0;
    @@ -256,32 +246,63 @@ void fsnotify_put_mark(struct fsnotify_m
    FSNOTIFY_REAPER_DELAY);
    }

    -bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info)
    +/*
    + * Get mark reference when we found the mark via lockless traversal of object
    + * list. Mark can be already removed from the list by now and on its way to be
    + * destroyed once SRCU period ends.
    + *
    + * Also pin the group so it doesn't disappear under us.
    + */
    +static bool fsnotify_get_mark_safe(struct fsnotify_mark *mark)
    {
    struct fsnotify_group *group;

    - if (WARN_ON_ONCE(!iter_info->inode_mark && !iter_info->vfsmount_mark))
    - return false;
    -
    - if (iter_info->inode_mark)
    - group = iter_info->inode_mark->group;
    - else
    - group = iter_info->vfsmount_mark->group;
    + if (!mark)
    + return true;

    + group = mark->group;
    /*
    * Since acquisition of mark reference is an atomic op as well, we can
    * be sure this inc is seen before any effect of refcount increment.
    */
    atomic_inc(&group->user_waits);
    + if (atomic_inc_not_zero(&mark->refcnt))
    + return true;
    +
    + if (atomic_dec_and_test(&group->user_waits) && group->shutdown)
    + wake_up(&group->notification_waitq);
    +
    + return false;
    +}
    +
    +/*
    + * Puts marks and wakes up group destruction if necessary.
    + *
    + * Pairs with fsnotify_get_mark_safe()
    + */
    +static void fsnotify_put_mark_wake(struct fsnotify_mark *mark)
    +{
    + if (mark) {
    + struct fsnotify_group *group = mark->group;

    - if (iter_info->inode_mark) {
    - /* This can fail if mark is being removed */
    - if (!fsnotify_get_mark_safe(iter_info->inode_mark))
    - goto out_wait;
    - }
    - if (iter_info->vfsmount_mark) {
    - if (!fsnotify_get_mark_safe(iter_info->vfsmount_mark))
    - goto out_inode;
    + fsnotify_put_mark(mark);
    + /*
    + * We abuse notification_waitq on group shutdown for waiting for
    + * all marks pinned when waiting for userspace.
    + */
    + if (atomic_dec_and_test(&group->user_waits) && group->shutdown)
    + wake_up(&group->notification_waitq);
    + }
    +}
    +
    +bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info)
    +{
    + /* This can fail if mark is being removed */
    + if (!fsnotify_get_mark_safe(iter_info->inode_mark))
    + return false;
    + if (!fsnotify_get_mark_safe(iter_info->vfsmount_mark)) {
    + fsnotify_put_mark_wake(iter_info->inode_mark);
    + return false;
    }

    /*
    @@ -292,34 +313,13 @@ bool fsnotify_prepare_user_wait(struct f
    srcu_read_unlock(&fsnotify_mark_srcu, iter_info->srcu_idx);

    return true;
    -out_inode:
    - if (iter_info->inode_mark)
    - fsnotify_put_mark(iter_info->inode_mark);
    -out_wait:
    - if (atomic_dec_and_test(&group->user_waits) && group->shutdown)
    - wake_up(&group->notification_waitq);
    - return false;
    }

    void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info)
    {
    - struct fsnotify_group *group = NULL;
    -
    iter_info->srcu_idx = srcu_read_lock(&fsnotify_mark_srcu);
    - if (iter_info->inode_mark) {
    - group = iter_info->inode_mark->group;
    - fsnotify_put_mark(iter_info->inode_mark);
    - }
    - if (iter_info->vfsmount_mark) {
    - group = iter_info->vfsmount_mark->group;
    - fsnotify_put_mark(iter_info->vfsmount_mark);
    - }
    - /*
    - * We abuse notification_waitq on group shutdown for waiting for all
    - * marks pinned when waiting for userspace.
    - */
    - if (atomic_dec_and_test(&group->user_waits) && group->shutdown)
    - wake_up(&group->notification_waitq);
    + fsnotify_put_mark_wake(iter_info->inode_mark);
    + fsnotify_put_mark_wake(iter_info->vfsmount_mark);
    }

    /*

    \
     
     \ /
      Last update: 2017-11-28 12:20    [W:4.169 / U:0.372 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site