aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2009-12-17 21:24:33 -0500
committerEric Paris <eparis@redhat.com>2010-07-28 09:58:59 -0400
commit90b1e7a57880fb66437ab7db39e1e65ca0372822 (patch)
tree61b7195c84d9dfd057ed3dcb07c5fc831db6a3a9
parent33d3dfff451a2ab6fe2f6aaabed9b24e91aad109 (diff)
fsnotify: allow marks to not pin inodes in core
inotify marks must pin inodes in core. dnotify doesn't technically need to since they are closed when the directory is closed. fanotify also need to pin inodes in core as it works today. But the next step is to introduce the concept of 'ignored masks' which is actually a mask of events for an inode of no interest. I claim that these should be liberally sent to the kernel and should not pin the inode in core. If the inode is brought back in the listener will get an event it may have thought excluded, but this is not a serious situation and one any listener should deal with. This patch lays the ground work for non-pinning inode marks by using lazy inode pinning. We do not pin a mark until it has a non-zero mask entry. If a listener new sets a mask we never pin the inode. Signed-off-by: Eric Paris <eparis@redhat.com>
-rw-r--r--fs/notify/dnotify/dnotify.c2
-rw-r--r--fs/notify/fanotify/fanotify_user.c4
-rw-r--r--fs/notify/fsnotify.h2
-rw-r--r--fs/notify/inode_mark.c35
-rw-r--r--fs/notify/inotify/inotify_user.c12
-rw-r--r--fs/notify/mark.c17
-rw-r--r--include/linux/fsnotify_backend.h7
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 */
21extern void fsnotify_flush_notify(struct fsnotify_group *group); 21extern void fsnotify_flush_notify(struct fsnotify_group *group);
22 22
23extern 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 */
24extern int fsnotify_add_inode_mark(struct fsnotify_mark *mark, 26extern 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 */
147void 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
183void 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
372extern struct fsnotify_mark *fsnotify_find_vfsmount_mark(struct fsnotify_group *group, struct vfsmount *mnt); 373extern 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 */
374extern void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old); 375extern 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 */
377extern 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 */
376extern int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group, 379extern 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);