diff options
Diffstat (limited to 'fs/notify/inode_mark.c')
-rw-r--r-- | fs/notify/inode_mark.c | 40 |
1 files changed, 29 insertions, 11 deletions
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c index 0c0a48b1659f..83ce6db34039 100644 --- a/fs/notify/inode_mark.c +++ b/fs/notify/inode_mark.c | |||
@@ -174,15 +174,17 @@ void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *mark, | |||
174 | } | 174 | } |
175 | 175 | ||
176 | /* | 176 | /* |
177 | * Attach an initialized mark to a given group and inode. | 177 | * Attach an initialized mark to a given inode. |
178 | * These marks may be used for the fsnotify backend to determine which | 178 | * These marks may be used for the fsnotify backend to determine which |
179 | * event types should be delivered to which group and for which inodes. | 179 | * event types should be delivered to which group and for which inodes. These |
180 | * marks are ordered according to the group's location in memory. | ||
180 | */ | 181 | */ |
181 | int fsnotify_add_inode_mark(struct fsnotify_mark *mark, | 182 | int fsnotify_add_inode_mark(struct fsnotify_mark *mark, |
182 | struct fsnotify_group *group, struct inode *inode, | 183 | struct fsnotify_group *group, struct inode *inode, |
183 | int allow_dups) | 184 | int allow_dups) |
184 | { | 185 | { |
185 | struct fsnotify_mark *lmark = NULL; | 186 | struct fsnotify_mark *lmark; |
187 | struct hlist_node *node, *last = NULL; | ||
186 | int ret = 0; | 188 | int ret = 0; |
187 | 189 | ||
188 | mark->flags = FSNOTIFY_MARK_FLAG_INODE; | 190 | mark->flags = FSNOTIFY_MARK_FLAG_INODE; |
@@ -192,21 +194,37 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark, | |||
192 | 194 | ||
193 | spin_lock(&inode->i_lock); | 195 | spin_lock(&inode->i_lock); |
194 | 196 | ||
195 | if (!allow_dups) | 197 | mark->i.inode = inode; |
196 | lmark = fsnotify_find_inode_mark_locked(group, inode); | ||
197 | if (!lmark) { | ||
198 | mark->i.inode = inode; | ||
199 | 198 | ||
199 | /* is mark the first mark? */ | ||
200 | if (hlist_empty(&inode->i_fsnotify_marks)) { | ||
200 | hlist_add_head(&mark->i.i_list, &inode->i_fsnotify_marks); | 201 | hlist_add_head(&mark->i.i_list, &inode->i_fsnotify_marks); |
202 | goto out; | ||
203 | } | ||
204 | |||
205 | /* should mark be in the middle of the current list? */ | ||
206 | hlist_for_each_entry(lmark, node, &inode->i_fsnotify_marks, i.i_list) { | ||
207 | last = node; | ||
208 | |||
209 | if ((lmark->group == group) && !allow_dups) { | ||
210 | ret = -EEXIST; | ||
211 | goto out; | ||
212 | } | ||
201 | 213 | ||
202 | fsnotify_recalc_inode_mask_locked(inode); | 214 | if (mark->group < lmark->group) |
215 | continue; | ||
216 | |||
217 | hlist_add_before(&mark->i.i_list, &lmark->i.i_list); | ||
218 | goto out; | ||
203 | } | 219 | } |
204 | 220 | ||
221 | BUG_ON(last == NULL); | ||
222 | /* mark should be the last entry. last is the current last entry */ | ||
223 | hlist_add_after(last, &mark->i.i_list); | ||
224 | out: | ||
225 | fsnotify_recalc_inode_mask_locked(inode); | ||
205 | spin_unlock(&inode->i_lock); | 226 | spin_unlock(&inode->i_lock); |
206 | 227 | ||
207 | if (lmark) | ||
208 | ret = -EEXIST; | ||
209 | |||
210 | return ret; | 228 | return ret; |
211 | } | 229 | } |
212 | 230 | ||