diff options
Diffstat (limited to 'fs/notify/vfsmount_mark.c')
-rw-r--r-- | fs/notify/vfsmount_mark.c | 40 |
1 files changed, 26 insertions, 14 deletions
diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c index ec580a25d293..c4b3f14d2530 100644 --- a/fs/notify/vfsmount_mark.c +++ b/fs/notify/vfsmount_mark.c | |||
@@ -141,34 +141,46 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, | |||
141 | struct fsnotify_group *group, struct vfsmount *mnt, | 141 | struct fsnotify_group *group, struct vfsmount *mnt, |
142 | int allow_dups) | 142 | int allow_dups) |
143 | { | 143 | { |
144 | struct fsnotify_mark *lmark = NULL; | 144 | struct fsnotify_mark *lmark; |
145 | struct hlist_node *node, *last = NULL; | ||
145 | int ret = 0; | 146 | int ret = 0; |
146 | 147 | ||
147 | mark->flags = FSNOTIFY_MARK_FLAG_VFSMOUNT; | 148 | mark->flags = FSNOTIFY_MARK_FLAG_VFSMOUNT; |
148 | 149 | ||
149 | /* | ||
150 | * LOCKING ORDER!!!! | ||
151 | * mark->lock | ||
152 | * group->mark_lock | ||
153 | * mnt->mnt_root->d_lock | ||
154 | */ | ||
155 | assert_spin_locked(&mark->lock); | 150 | assert_spin_locked(&mark->lock); |
156 | assert_spin_locked(&group->mark_lock); | 151 | assert_spin_locked(&group->mark_lock); |
157 | 152 | ||
158 | spin_lock(&mnt->mnt_root->d_lock); | 153 | spin_lock(&mnt->mnt_root->d_lock); |
159 | 154 | ||
160 | if (!allow_dups) | 155 | mark->m.mnt = mnt; |
161 | lmark = fsnotify_find_vfsmount_mark_locked(group, mnt); | ||
162 | if (!lmark) { | ||
163 | mark->m.mnt = mnt; | ||
164 | 156 | ||
157 | /* is mark the first mark? */ | ||
158 | if (hlist_empty(&mnt->mnt_fsnotify_marks)) { | ||
165 | hlist_add_head(&mark->m.m_list, &mnt->mnt_fsnotify_marks); | 159 | hlist_add_head(&mark->m.m_list, &mnt->mnt_fsnotify_marks); |
160 | goto out; | ||
161 | } | ||
162 | |||
163 | /* should mark be in the middle of the current list? */ | ||
164 | hlist_for_each_entry(lmark, node, &mnt->mnt_fsnotify_marks, m.m_list) { | ||
165 | last = node; | ||
166 | |||
167 | if ((lmark->group == group) && !allow_dups) { | ||
168 | ret = -EEXIST; | ||
169 | goto out; | ||
170 | } | ||
171 | |||
172 | if (mark->group < lmark->group) | ||
173 | continue; | ||
166 | 174 | ||
167 | fsnotify_recalc_vfsmount_mask_locked(mnt); | 175 | hlist_add_before(&mark->m.m_list, &lmark->m.m_list); |
168 | } else { | 176 | goto out; |
169 | ret = -EEXIST; | ||
170 | } | 177 | } |
171 | 178 | ||
179 | BUG_ON(last == NULL); | ||
180 | /* mark should be the last entry. last is the current last entry */ | ||
181 | hlist_add_after(last, &mark->m.m_list); | ||
182 | out: | ||
183 | fsnotify_recalc_vfsmount_mask_locked(mnt); | ||
172 | spin_unlock(&mnt->mnt_root->d_lock); | 184 | spin_unlock(&mnt->mnt_root->d_lock); |
173 | 185 | ||
174 | return ret; | 186 | return ret; |