diff options
-rw-r--r-- | fs/notify/dnotify/dnotify.c | 2 | ||||
-rw-r--r-- | fs/notify/fanotify/fanotify_user.c | 4 | ||||
-rw-r--r-- | fs/notify/fsnotify.h | 2 | ||||
-rw-r--r-- | fs/notify/inode_mark.c | 35 | ||||
-rw-r--r-- | fs/notify/inotify/inotify_user.c | 12 | ||||
-rw-r--r-- | fs/notify/mark.c | 17 | ||||
-rw-r--r-- | include/linux/fsnotify_backend.h | 7 |
7 files changed, 58 insertions, 21 deletions
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c index 69f42df9ba45..6624c2ee8786 100644 --- a/fs/notify/dnotify/dnotify.c +++ b/fs/notify/dnotify/dnotify.c | |||
@@ -65,7 +65,7 @@ static void dnotify_recalc_inode_mask(struct fsnotify_mark *fsn_mark) | |||
65 | new_mask = 0; | 65 | new_mask = 0; |
66 | for (dn = dn_mark->dn; dn != NULL; dn = dn->dn_next) | 66 | for (dn = dn_mark->dn; dn != NULL; dn = dn->dn_next) |
67 | new_mask |= (dn->dn_mask & ~FS_DN_MULTISHOT); | 67 | new_mask |= (dn->dn_mask & ~FS_DN_MULTISHOT); |
68 | fsn_mark->mask = new_mask; | 68 | fsnotify_set_mark_mask_locked(fsn_mark, new_mask); |
69 | 69 | ||
70 | if (old_mask == new_mask) | 70 | if (old_mask == new_mask) |
71 | return; | 71 | return; |
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 84155841a025..3320f0c57e31 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c | |||
@@ -302,7 +302,7 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, __u3 | |||
302 | 302 | ||
303 | spin_lock(&fsn_mark->lock); | 303 | spin_lock(&fsn_mark->lock); |
304 | oldmask = fsn_mark->mask; | 304 | oldmask = fsn_mark->mask; |
305 | fsn_mark->mask = oldmask & ~mask; | 305 | fsnotify_set_mark_mask_locked(fsn_mark, (oldmask & ~mask)); |
306 | spin_unlock(&fsn_mark->lock); | 306 | spin_unlock(&fsn_mark->lock); |
307 | 307 | ||
308 | if (!(oldmask & ~mask)) | 308 | if (!(oldmask & ~mask)) |
@@ -359,7 +359,7 @@ static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark, __u32 mas | |||
359 | 359 | ||
360 | spin_lock(&fsn_mark->lock); | 360 | spin_lock(&fsn_mark->lock); |
361 | oldmask = fsn_mark->mask; | 361 | oldmask = fsn_mark->mask; |
362 | fsn_mark->mask = oldmask | mask; | 362 | fsnotify_set_mark_mask_locked(fsn_mark, (oldmask | mask)); |
363 | spin_unlock(&fsn_mark->lock); | 363 | spin_unlock(&fsn_mark->lock); |
364 | 364 | ||
365 | return mask & ~oldmask; | 365 | return mask & ~oldmask; |
diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h index 204353c0f663..1be54f6f9e7d 100644 --- a/fs/notify/fsnotify.h +++ b/fs/notify/fsnotify.h | |||
@@ -20,6 +20,8 @@ extern __u32 fsnotify_vfsmount_mask; | |||
20 | /* destroy all events sitting in this groups notification queue */ | 20 | /* destroy all events sitting in this groups notification queue */ |
21 | extern void fsnotify_flush_notify(struct fsnotify_group *group); | 21 | extern void fsnotify_flush_notify(struct fsnotify_group *group); |
22 | 22 | ||
23 | extern void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *fsn_mark, | ||
24 | __u32 mask); | ||
23 | /* add a mark to an inode */ | 25 | /* add a mark to an inode */ |
24 | extern int fsnotify_add_inode_mark(struct fsnotify_mark *mark, | 26 | extern int fsnotify_add_inode_mark(struct fsnotify_mark *mark, |
25 | struct fsnotify_group *group, struct inode *inode, | 27 | struct fsnotify_group *group, struct inode *inode, |
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c index c925579ba011..4292f9e23ae8 100644 --- a/fs/notify/inode_mark.c +++ b/fs/notify/inode_mark.c | |||
@@ -141,7 +141,32 @@ struct fsnotify_mark *fsnotify_find_inode_mark(struct fsnotify_group *group, | |||
141 | } | 141 | } |
142 | 142 | ||
143 | /* | 143 | /* |
144 | * Attach an initialized mark mark to a given group and inode. | 144 | * If we are setting a mark mask on an inode mark we should pin the inode |
145 | * in memory. | ||
146 | */ | ||
147 | void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *mark, | ||
148 | __u32 mask) | ||
149 | { | ||
150 | struct inode *inode; | ||
151 | |||
152 | assert_spin_locked(&mark->lock); | ||
153 | |||
154 | if (mask && | ||
155 | mark->i.inode && | ||
156 | !(mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) { | ||
157 | mark->flags |= FSNOTIFY_MARK_FLAG_OBJECT_PINNED; | ||
158 | inode = igrab(mark->i.inode); | ||
159 | /* | ||
160 | * we shouldn't be able to get here if the inode wasn't | ||
161 | * already safely held in memory. But bug in case it | ||
162 | * ever is wrong. | ||
163 | */ | ||
164 | BUG_ON(!inode); | ||
165 | } | ||
166 | } | ||
167 | |||
168 | /* | ||
169 | * Attach an initialized mark to a given group and inode. | ||
145 | * These marks may be used for the fsnotify backend to determine which | 170 | * These marks may be used for the fsnotify backend to determine which |
146 | * event types should be delivered to which group and for which inodes. | 171 | * event types should be delivered to which group and for which inodes. |
147 | */ | 172 | */ |
@@ -152,10 +177,6 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark, | |||
152 | struct fsnotify_mark *lmark = NULL; | 177 | struct fsnotify_mark *lmark = NULL; |
153 | int ret = 0; | 178 | int ret = 0; |
154 | 179 | ||
155 | inode = igrab(inode); | ||
156 | if (unlikely(!inode)) | ||
157 | return -EINVAL; | ||
158 | |||
159 | mark->flags = FSNOTIFY_MARK_FLAG_INODE; | 180 | mark->flags = FSNOTIFY_MARK_FLAG_INODE; |
160 | 181 | ||
161 | assert_spin_locked(&mark->lock); | 182 | assert_spin_locked(&mark->lock); |
@@ -175,10 +196,8 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark, | |||
175 | 196 | ||
176 | spin_unlock(&inode->i_lock); | 197 | spin_unlock(&inode->i_lock); |
177 | 198 | ||
178 | if (lmark) { | 199 | if (lmark) |
179 | ret = -EEXIST; | 200 | ret = -EEXIST; |
180 | iput(inode); | ||
181 | } | ||
182 | 201 | ||
183 | return ret; | 202 | return ret; |
184 | } | 203 | } |
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index a12315a7553d..19d274057bfa 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c | |||
@@ -575,13 +575,11 @@ static int inotify_update_existing_watch(struct fsnotify_group *group, | |||
575 | spin_lock(&fsn_mark->lock); | 575 | spin_lock(&fsn_mark->lock); |
576 | 576 | ||
577 | old_mask = fsn_mark->mask; | 577 | old_mask = fsn_mark->mask; |
578 | if (add) { | 578 | if (add) |
579 | fsn_mark->mask |= mask; | 579 | fsnotify_set_mark_mask_locked(fsn_mark, (fsn_mark->mask | mask)); |
580 | new_mask = fsn_mark->mask; | 580 | else |
581 | } else { | 581 | fsnotify_set_mark_mask_locked(fsn_mark, mask); |
582 | fsn_mark->mask = mask; | 582 | new_mask = fsn_mark->mask; |
583 | new_mask = fsn_mark->mask; | ||
584 | } | ||
585 | 583 | ||
586 | spin_unlock(&fsn_mark->lock); | 584 | spin_unlock(&fsn_mark->lock); |
587 | 585 | ||
diff --git a/fs/notify/mark.c b/fs/notify/mark.c index d296ec9ffb2a..0ebc3fd7089b 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c | |||
@@ -168,7 +168,7 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) | |||
168 | * is just a lazy update (and could be a perf win...) | 168 | * is just a lazy update (and could be a perf win...) |
169 | */ | 169 | */ |
170 | 170 | ||
171 | if (inode) | 171 | if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) |
172 | iput(inode); | 172 | iput(inode); |
173 | 173 | ||
174 | /* | 174 | /* |
@@ -180,6 +180,17 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) | |||
180 | fsnotify_final_destroy_group(group); | 180 | fsnotify_final_destroy_group(group); |
181 | } | 181 | } |
182 | 182 | ||
183 | void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask) | ||
184 | { | ||
185 | assert_spin_locked(&mark->lock); | ||
186 | |||
187 | mark->mask = mask; | ||
188 | |||
189 | if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) | ||
190 | fsnotify_set_inode_mark_mask_locked(mark, mask); | ||
191 | } | ||
192 | |||
193 | |||
183 | /* | 194 | /* |
184 | * Attach an initialized mark to a given group and fs object. | 195 | * Attach an initialized mark to a given group and fs object. |
185 | * These marks may be used for the fsnotify backend to determine which | 196 | * These marks may be used for the fsnotify backend to determine which |
@@ -230,6 +241,10 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, | |||
230 | } | 241 | } |
231 | 242 | ||
232 | spin_unlock(&group->mark_lock); | 243 | spin_unlock(&group->mark_lock); |
244 | |||
245 | /* this will pin the object if appropriate */ | ||
246 | fsnotify_set_mark_mask_locked(mark, mark->mask); | ||
247 | |||
233 | spin_unlock(&mark->lock); | 248 | spin_unlock(&mark->lock); |
234 | 249 | ||
235 | if (inode) | 250 | if (inode) |
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 2d2f015fb700..489c881ed4ec 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h | |||
@@ -267,8 +267,9 @@ struct fsnotify_mark { | |||
267 | struct fsnotify_vfsmount_mark m; | 267 | struct fsnotify_vfsmount_mark m; |
268 | }; | 268 | }; |
269 | struct list_head free_g_list; /* tmp list used when freeing this mark */ | 269 | struct list_head free_g_list; /* tmp list used when freeing this mark */ |
270 | #define FSNOTIFY_MARK_FLAG_INODE 0x01 | 270 | #define FSNOTIFY_MARK_FLAG_INODE 0x01 |
271 | #define FSNOTIFY_MARK_FLAG_VFSMOUNT 0x02 | 271 | #define FSNOTIFY_MARK_FLAG_VFSMOUNT 0x02 |
272 | #define FSNOTIFY_MARK_FLAG_OBJECT_PINNED 0x04 | ||
272 | unsigned int flags; /* vfsmount or inode mark? */ | 273 | unsigned int flags; /* vfsmount or inode mark? */ |
273 | void (*free_mark)(struct fsnotify_mark *mark); /* called on final put+free */ | 274 | void (*free_mark)(struct fsnotify_mark *mark); /* called on final put+free */ |
274 | }; | 275 | }; |
@@ -372,6 +373,8 @@ extern struct fsnotify_mark *fsnotify_find_inode_mark(struct fsnotify_group *gro | |||
372 | extern struct fsnotify_mark *fsnotify_find_vfsmount_mark(struct fsnotify_group *group, struct vfsmount *mnt); | 373 | extern struct fsnotify_mark *fsnotify_find_vfsmount_mark(struct fsnotify_group *group, struct vfsmount *mnt); |
373 | /* copy the values from old into new */ | 374 | /* copy the values from old into new */ |
374 | extern void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old); | 375 | extern void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old); |
376 | /* set the mask of a mark (might pin the object into memory */ | ||
377 | extern void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask); | ||
375 | /* attach the mark to both the group and the inode */ | 378 | /* attach the mark to both the group and the inode */ |
376 | extern int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group, | 379 | extern int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group, |
377 | struct inode *inode, struct vfsmount *mnt, int allow_dups); | 380 | struct inode *inode, struct vfsmount *mnt, int allow_dups); |