Adjust fsnotify_add_[inode|vfsmount]_mark() to new locking order by taking the inode/mount lock before the mark lock is taken. We also set all mark flags (after we took the mark lock) in this function. Signed-off-by: Lino Sanfilippo <LinoSanfilippo@xxxxxx> --- fs/notify/inode_mark.c | 24 +++++++++++++++++++----- fs/notify/vfsmount_mark.c | 19 ++++++++++++++++--- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c index 4c29fcf..8d35a84 100644 --- a/fs/notify/inode_mark.c +++ b/fs/notify/inode_mark.c @@ -188,14 +188,17 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark, struct hlist_node *node, *last = NULL; int ret = 0; - mark->flags |= FSNOTIFY_MARK_FLAG_INODE; - - assert_spin_locked(&mark->lock); - assert_spin_locked(&group->mark_lock); + /* get ref for mark on list */ + fsnotify_get_mark(mark); spin_lock(&inode->i_lock); + spin_lock(&mark->lock); - mark->i.inode = inode; + mark->group = group; + mark->i.inode = igrab(inode); + mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE; + mark->flags |= FSNOTIFY_MARK_FLAG_INODE; + mark->flags |= FSNOTIFY_MARK_FLAG_OBJECT_PINNED; /* is mark the first mark? */ if (hlist_empty(&inode->i_fsnotify_marks)) { @@ -227,9 +230,20 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark, /* mark should be the last entry. last is the current last entry */ hlist_add_after_rcu(last, &mark->i.i_list); out: + spin_unlock(&mark->lock); fsnotify_recalc_inode_mask_locked(inode); spin_unlock(&inode->i_lock); + if (ret) { + mark->flags &= ~FSNOTIFY_MARK_FLAG_OBJECT_PINNED; + mark->flags &= ~FSNOTIFY_MARK_FLAG_INODE; + mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; + iput(mark->i.inode); + mark->group = NULL; + /* unget ref for mark on list */ + fsnotify_put_mark(mark); + } + return ret; } diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c index 85eebff..35dc586 100644 --- a/fs/notify/vfsmount_mark.c +++ b/fs/notify/vfsmount_mark.c @@ -145,14 +145,17 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, struct hlist_node *node, *last = NULL; int ret = 0; - mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT; - assert_spin_locked(&mark->lock); - assert_spin_locked(&group->mark_lock); + /* get ref for mark on list */ + fsnotify_get_mark(mark); spin_lock(&mnt->mnt_root->d_lock); + spin_lock(&mark->lock); + mark->group = group; mark->m.mnt = mnt; + mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE; + mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT; /* is mark the first mark? */ if (hlist_empty(&mnt->mnt_fsnotify_marks)) { @@ -184,8 +187,18 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, /* mark should be the last entry. last is the current last entry */ hlist_add_after_rcu(last, &mark->m.m_list); out: + spin_unlock(&mark->lock); fsnotify_recalc_vfsmount_mask_locked(mnt); spin_unlock(&mnt->mnt_root->d_lock); + if (ret) { + mark->flags &= ~FSNOTIFY_MARK_FLAG_VFSMOUNT; + mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; + mark->m.mnt = NULL; + mark->group = NULL; + /* unget ref for mark on list */ + fsnotify_put_mark(mark); + } + return ret; } -- 1.5.6.5 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html