| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 1 | /* | 
 | 2 |  *  Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com> | 
 | 3 |  * | 
 | 4 |  *  This program is free software; you can redistribute it and/or modify | 
 | 5 |  *  it under the terms of the GNU General Public License as published by | 
 | 6 |  *  the Free Software Foundation; either version 2, or (at your option) | 
 | 7 |  *  any later version. | 
 | 8 |  * | 
 | 9 |  *  This program is distributed in the hope that it will be useful, | 
 | 10 |  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 11 |  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 12 |  *  GNU General Public License for more details. | 
 | 13 |  * | 
 | 14 |  *  You should have received a copy of the GNU General Public License | 
 | 15 |  *  along with this program; see the file COPYING.  If not, write to | 
 | 16 |  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | 
 | 17 |  */ | 
 | 18 |  | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 19 | #include <linux/fs.h> | 
 | 20 | #include <linux/init.h> | 
 | 21 | #include <linux/kernel.h> | 
 | 22 | #include <linux/module.h> | 
 | 23 | #include <linux/mutex.h> | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 24 | #include <linux/spinlock.h> | 
 | 25 |  | 
 | 26 | #include <asm/atomic.h> | 
 | 27 |  | 
 | 28 | #include <linux/fsnotify_backend.h> | 
 | 29 | #include "fsnotify.h" | 
 | 30 |  | 
| Dave Chinner | 55fa609 | 2011-03-22 22:23:40 +1100 | [diff] [blame] | 31 | #include "../internal.h" | 
 | 32 |  | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 33 | /* | 
 | 34 |  * Recalculate the mask of events relevant to a given inode locked. | 
 | 35 |  */ | 
 | 36 | static void fsnotify_recalc_inode_mask_locked(struct inode *inode) | 
 | 37 | { | 
| Eric Paris | 841bdc1 | 2009-12-17 21:24:24 -0500 | [diff] [blame] | 38 | 	struct fsnotify_mark *mark; | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 39 | 	struct hlist_node *pos; | 
 | 40 | 	__u32 new_mask = 0; | 
 | 41 |  | 
 | 42 | 	assert_spin_locked(&inode->i_lock); | 
 | 43 |  | 
| Eric Paris | 841bdc1 | 2009-12-17 21:24:24 -0500 | [diff] [blame] | 44 | 	hlist_for_each_entry(mark, pos, &inode->i_fsnotify_marks, i.i_list) | 
 | 45 | 		new_mask |= mark->mask; | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 46 | 	inode->i_fsnotify_mask = new_mask; | 
 | 47 | } | 
 | 48 |  | 
 | 49 | /* | 
 | 50 |  * Recalculate the inode->i_fsnotify_mask, or the mask of all FS_* event types | 
 | 51 |  * any notifier is interested in hearing for this inode. | 
 | 52 |  */ | 
 | 53 | void fsnotify_recalc_inode_mask(struct inode *inode) | 
 | 54 | { | 
 | 55 | 	spin_lock(&inode->i_lock); | 
 | 56 | 	fsnotify_recalc_inode_mask_locked(inode); | 
 | 57 | 	spin_unlock(&inode->i_lock); | 
| Eric Paris | c28f7e5 | 2009-05-21 17:01:29 -0400 | [diff] [blame] | 58 |  | 
 | 59 | 	__fsnotify_update_child_dentry_flags(inode); | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 60 | } | 
 | 61 |  | 
| Eric Paris | 5444e29 | 2009-12-17 21:24:27 -0500 | [diff] [blame] | 62 | void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark) | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 63 | { | 
| Eric Paris | 5444e29 | 2009-12-17 21:24:27 -0500 | [diff] [blame] | 64 | 	struct inode *inode = mark->i.inode; | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 65 |  | 
| Eric Paris | 5444e29 | 2009-12-17 21:24:27 -0500 | [diff] [blame] | 66 | 	assert_spin_locked(&mark->lock); | 
 | 67 | 	assert_spin_locked(&mark->group->mark_lock); | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 68 |  | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 69 | 	spin_lock(&inode->i_lock); | 
 | 70 |  | 
| Eric Paris | a4c6e99 | 2010-07-28 10:18:38 -0400 | [diff] [blame] | 71 | 	hlist_del_init_rcu(&mark->i.i_list); | 
| Eric Paris | 841bdc1 | 2009-12-17 21:24:24 -0500 | [diff] [blame] | 72 | 	mark->i.inode = NULL; | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 73 |  | 
 | 74 | 	/* | 
| Eric Paris | e61ce86 | 2009-12-17 21:24:24 -0500 | [diff] [blame] | 75 | 	 * this mark is now off the inode->i_fsnotify_marks list and we | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 76 | 	 * hold the inode->i_lock, so this is the perfect time to update the | 
 | 77 | 	 * inode->i_fsnotify_mask | 
 | 78 | 	 */ | 
 | 79 | 	fsnotify_recalc_inode_mask_locked(inode); | 
 | 80 |  | 
 | 81 | 	spin_unlock(&inode->i_lock); | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 82 | } | 
 | 83 |  | 
 | 84 | /* | 
 | 85 |  * Given an inode, destroy all of the marks associated with that inode. | 
 | 86 |  */ | 
 | 87 | void fsnotify_clear_marks_by_inode(struct inode *inode) | 
 | 88 | { | 
| Eric Paris | 841bdc1 | 2009-12-17 21:24:24 -0500 | [diff] [blame] | 89 | 	struct fsnotify_mark *mark, *lmark; | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 90 | 	struct hlist_node *pos, *n; | 
 | 91 | 	LIST_HEAD(free_list); | 
 | 92 |  | 
 | 93 | 	spin_lock(&inode->i_lock); | 
| Eric Paris | 841bdc1 | 2009-12-17 21:24:24 -0500 | [diff] [blame] | 94 | 	hlist_for_each_entry_safe(mark, pos, n, &inode->i_fsnotify_marks, i.i_list) { | 
 | 95 | 		list_add(&mark->i.free_i_list, &free_list); | 
| Eric Paris | a4c6e99 | 2010-07-28 10:18:38 -0400 | [diff] [blame] | 96 | 		hlist_del_init_rcu(&mark->i.i_list); | 
| Eric Paris | 841bdc1 | 2009-12-17 21:24:24 -0500 | [diff] [blame] | 97 | 		fsnotify_get_mark(mark); | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 98 | 	} | 
 | 99 | 	spin_unlock(&inode->i_lock); | 
 | 100 |  | 
| Eric Paris | 841bdc1 | 2009-12-17 21:24:24 -0500 | [diff] [blame] | 101 | 	list_for_each_entry_safe(mark, lmark, &free_list, i.free_i_list) { | 
 | 102 | 		fsnotify_destroy_mark(mark); | 
 | 103 | 		fsnotify_put_mark(mark); | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 104 | 	} | 
 | 105 | } | 
 | 106 |  | 
 | 107 | /* | 
| Eric Paris | 4d92604 | 2009-12-17 21:24:34 -0500 | [diff] [blame] | 108 |  * Given a group clear all of the inode marks associated with that group. | 
 | 109 |  */ | 
 | 110 | void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group) | 
 | 111 | { | 
 | 112 | 	fsnotify_clear_marks_by_group_flags(group, FSNOTIFY_MARK_FLAG_INODE); | 
 | 113 | } | 
 | 114 |  | 
 | 115 | /* | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 116 |  * given a group and inode, find the mark associated with that combination. | 
 | 117 |  * if found take a reference to that mark and return it, else return NULL | 
 | 118 |  */ | 
| Eric Paris | 5444e29 | 2009-12-17 21:24:27 -0500 | [diff] [blame] | 119 | struct fsnotify_mark *fsnotify_find_inode_mark_locked(struct fsnotify_group *group, | 
 | 120 | 						      struct inode *inode) | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 121 | { | 
| Eric Paris | 841bdc1 | 2009-12-17 21:24:24 -0500 | [diff] [blame] | 122 | 	struct fsnotify_mark *mark; | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 123 | 	struct hlist_node *pos; | 
 | 124 |  | 
 | 125 | 	assert_spin_locked(&inode->i_lock); | 
 | 126 |  | 
| Eric Paris | 841bdc1 | 2009-12-17 21:24:24 -0500 | [diff] [blame] | 127 | 	hlist_for_each_entry(mark, pos, &inode->i_fsnotify_marks, i.i_list) { | 
 | 128 | 		if (mark->group == group) { | 
 | 129 | 			fsnotify_get_mark(mark); | 
 | 130 | 			return mark; | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 131 | 		} | 
 | 132 | 	} | 
 | 133 | 	return NULL; | 
 | 134 | } | 
 | 135 |  | 
 | 136 | /* | 
| Andreas Gruenbacher | 3556608 | 2009-12-17 21:24:25 -0500 | [diff] [blame] | 137 |  * given a group and inode, find the mark associated with that combination. | 
 | 138 |  * if found take a reference to that mark and return it, else return NULL | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 139 |  */ | 
| Eric Paris | 5444e29 | 2009-12-17 21:24:27 -0500 | [diff] [blame] | 140 | struct fsnotify_mark *fsnotify_find_inode_mark(struct fsnotify_group *group, | 
 | 141 | 					       struct inode *inode) | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 142 | { | 
| Andreas Gruenbacher | 3556608 | 2009-12-17 21:24:25 -0500 | [diff] [blame] | 143 | 	struct fsnotify_mark *mark; | 
 | 144 |  | 
 | 145 | 	spin_lock(&inode->i_lock); | 
| Eric Paris | 5444e29 | 2009-12-17 21:24:27 -0500 | [diff] [blame] | 146 | 	mark = fsnotify_find_inode_mark_locked(group, inode); | 
| Andreas Gruenbacher | 3556608 | 2009-12-17 21:24:25 -0500 | [diff] [blame] | 147 | 	spin_unlock(&inode->i_lock); | 
 | 148 |  | 
 | 149 | 	return mark; | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 150 | } | 
 | 151 |  | 
 | 152 | /* | 
| Eric Paris | 90b1e7a | 2009-12-17 21:24:33 -0500 | [diff] [blame] | 153 |  * If we are setting a mark mask on an inode mark we should pin the inode | 
 | 154 |  * in memory. | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 155 |  */ | 
| Eric Paris | 90b1e7a | 2009-12-17 21:24:33 -0500 | [diff] [blame] | 156 | void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *mark, | 
 | 157 | 					 __u32 mask) | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 158 | { | 
| Eric Paris | 90b1e7a | 2009-12-17 21:24:33 -0500 | [diff] [blame] | 159 | 	struct inode *inode; | 
 | 160 |  | 
 | 161 | 	assert_spin_locked(&mark->lock); | 
 | 162 |  | 
 | 163 | 	if (mask && | 
 | 164 | 	    mark->i.inode && | 
 | 165 | 	    !(mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) { | 
 | 166 | 		mark->flags |= FSNOTIFY_MARK_FLAG_OBJECT_PINNED; | 
 | 167 | 		inode = igrab(mark->i.inode); | 
 | 168 | 		/* | 
 | 169 | 		 * we shouldn't be able to get here if the inode wasn't | 
 | 170 | 		 * already safely held in memory.  But bug in case it | 
 | 171 | 		 * ever is wrong. | 
 | 172 | 		 */ | 
 | 173 | 		BUG_ON(!inode); | 
 | 174 | 	} | 
 | 175 | } | 
 | 176 |  | 
 | 177 | /* | 
| Eric Paris | 0c6532e | 2010-07-28 10:18:38 -0400 | [diff] [blame] | 178 |  * Attach an initialized mark to a given inode. | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 179 |  * These marks may be used for the fsnotify backend to determine which | 
| Eric Paris | 0c6532e | 2010-07-28 10:18:38 -0400 | [diff] [blame] | 180 |  * event types should be delivered to which group and for which inodes.  These | 
| Eric Paris | 6ad2d4e | 2010-10-28 17:21:56 -0400 | [diff] [blame] | 181 |  * marks are ordered according to priority, highest number first, and then by | 
 | 182 |  * the group's location in memory. | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 183 |  */ | 
| Eric Paris | 5444e29 | 2009-12-17 21:24:27 -0500 | [diff] [blame] | 184 | int fsnotify_add_inode_mark(struct fsnotify_mark *mark, | 
 | 185 | 			    struct fsnotify_group *group, struct inode *inode, | 
 | 186 | 			    int allow_dups) | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 187 | { | 
| Eric Paris | 0c6532e | 2010-07-28 10:18:38 -0400 | [diff] [blame] | 188 | 	struct fsnotify_mark *lmark; | 
 | 189 | 	struct hlist_node *node, *last = NULL; | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 190 | 	int ret = 0; | 
 | 191 |  | 
| Eric Paris | 700307a | 2010-07-28 10:18:38 -0400 | [diff] [blame] | 192 | 	mark->flags |= FSNOTIFY_MARK_FLAG_INODE; | 
| Eric Paris | 1ef5f13 | 2009-05-21 17:01:54 -0400 | [diff] [blame] | 193 |  | 
| Eric Paris | 5444e29 | 2009-12-17 21:24:27 -0500 | [diff] [blame] | 194 | 	assert_spin_locked(&mark->lock); | 
 | 195 | 	assert_spin_locked(&group->mark_lock); | 
| Eric Paris | 7131485 | 2009-12-17 21:24:23 -0500 | [diff] [blame] | 196 |  | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 197 | 	spin_lock(&inode->i_lock); | 
 | 198 |  | 
| Eric Paris | 0c6532e | 2010-07-28 10:18:38 -0400 | [diff] [blame] | 199 | 	mark->i.inode = inode; | 
| Eric Paris | 9f0d793 | 2009-09-11 13:03:19 -0400 | [diff] [blame] | 200 |  | 
| Eric Paris | 0c6532e | 2010-07-28 10:18:38 -0400 | [diff] [blame] | 201 | 	/* is mark the first mark? */ | 
 | 202 | 	if (hlist_empty(&inode->i_fsnotify_marks)) { | 
| Eric Paris | a4c6e99 | 2010-07-28 10:18:38 -0400 | [diff] [blame] | 203 | 		hlist_add_head_rcu(&mark->i.i_list, &inode->i_fsnotify_marks); | 
| Eric Paris | 0c6532e | 2010-07-28 10:18:38 -0400 | [diff] [blame] | 204 | 		goto out; | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 205 | 	} | 
 | 206 |  | 
| Eric Paris | 0c6532e | 2010-07-28 10:18:38 -0400 | [diff] [blame] | 207 | 	/* should mark be in the middle of the current list? */ | 
 | 208 | 	hlist_for_each_entry(lmark, node, &inode->i_fsnotify_marks, i.i_list) { | 
 | 209 | 		last = node; | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 210 |  | 
| Eric Paris | 0c6532e | 2010-07-28 10:18:38 -0400 | [diff] [blame] | 211 | 		if ((lmark->group == group) && !allow_dups) { | 
 | 212 | 			ret = -EEXIST; | 
 | 213 | 			goto out; | 
 | 214 | 		} | 
 | 215 |  | 
| Eric Paris | 6ad2d4e | 2010-10-28 17:21:56 -0400 | [diff] [blame] | 216 | 		if (mark->group->priority < lmark->group->priority) | 
 | 217 | 			continue; | 
 | 218 |  | 
 | 219 | 		if ((mark->group->priority == lmark->group->priority) && | 
 | 220 | 		    (mark->group < lmark->group)) | 
| Eric Paris | 0c6532e | 2010-07-28 10:18:38 -0400 | [diff] [blame] | 221 | 			continue; | 
 | 222 |  | 
| Eric Paris | a4c6e99 | 2010-07-28 10:18:38 -0400 | [diff] [blame] | 223 | 		hlist_add_before_rcu(&mark->i.i_list, &lmark->i.i_list); | 
| Eric Paris | 0c6532e | 2010-07-28 10:18:38 -0400 | [diff] [blame] | 224 | 		goto out; | 
 | 225 | 	} | 
 | 226 |  | 
 | 227 | 	BUG_ON(last == NULL); | 
 | 228 | 	/* mark should be the last entry.  last is the current last entry */ | 
| Eric Paris | a4c6e99 | 2010-07-28 10:18:38 -0400 | [diff] [blame] | 229 | 	hlist_add_after_rcu(last, &mark->i.i_list); | 
| Eric Paris | 0c6532e | 2010-07-28 10:18:38 -0400 | [diff] [blame] | 230 | out: | 
 | 231 | 	fsnotify_recalc_inode_mask_locked(inode); | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 232 | 	spin_unlock(&inode->i_lock); | 
| Eric Paris | 3be25f4 | 2009-05-21 17:01:26 -0400 | [diff] [blame] | 233 |  | 
 | 234 | 	return ret; | 
 | 235 | } | 
| Eric Paris | 164bc61 | 2009-05-21 17:01:58 -0400 | [diff] [blame] | 236 |  | 
 | 237 | /** | 
 | 238 |  * fsnotify_unmount_inodes - an sb is unmounting.  handle any watched inodes. | 
 | 239 |  * @list: list of inodes being unmounted (sb->s_inodes) | 
 | 240 |  * | 
| Dave Chinner | 55fa609 | 2011-03-22 22:23:40 +1100 | [diff] [blame] | 241 |  * Called during unmount with no locks held, so needs to be safe against | 
 | 242 |  * concurrent modifiers. We temporarily drop inode_sb_list_lock and CAN block. | 
| Eric Paris | 164bc61 | 2009-05-21 17:01:58 -0400 | [diff] [blame] | 243 |  */ | 
 | 244 | void fsnotify_unmount_inodes(struct list_head *list) | 
 | 245 | { | 
 | 246 | 	struct inode *inode, *next_i, *need_iput = NULL; | 
 | 247 |  | 
| Dave Chinner | 55fa609 | 2011-03-22 22:23:40 +1100 | [diff] [blame] | 248 | 	spin_lock(&inode_sb_list_lock); | 
| Eric Paris | 164bc61 | 2009-05-21 17:01:58 -0400 | [diff] [blame] | 249 | 	list_for_each_entry_safe(inode, next_i, list, i_sb_list) { | 
 | 250 | 		struct inode *need_iput_tmp; | 
 | 251 |  | 
 | 252 | 		/* | 
| Al Viro | a4ffdde | 2010-06-02 17:38:30 -0400 | [diff] [blame] | 253 | 		 * We cannot __iget() an inode in state I_FREEING, | 
| Eric Paris | 164bc61 | 2009-05-21 17:01:58 -0400 | [diff] [blame] | 254 | 		 * I_WILL_FREE, or I_NEW which is fine because by that point | 
 | 255 | 		 * the inode cannot have any associated watches. | 
 | 256 | 		 */ | 
| Dave Chinner | 250df6e | 2011-03-22 22:23:36 +1100 | [diff] [blame] | 257 | 		spin_lock(&inode->i_lock); | 
 | 258 | 		if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) { | 
 | 259 | 			spin_unlock(&inode->i_lock); | 
| Eric Paris | 164bc61 | 2009-05-21 17:01:58 -0400 | [diff] [blame] | 260 | 			continue; | 
| Dave Chinner | 250df6e | 2011-03-22 22:23:36 +1100 | [diff] [blame] | 261 | 		} | 
| Eric Paris | 164bc61 | 2009-05-21 17:01:58 -0400 | [diff] [blame] | 262 |  | 
 | 263 | 		/* | 
 | 264 | 		 * If i_count is zero, the inode cannot have any watches and | 
 | 265 | 		 * doing an __iget/iput with MS_ACTIVE clear would actually | 
 | 266 | 		 * evict all inodes with zero i_count from icache which is | 
 | 267 | 		 * unnecessarily violent and may in fact be illegal to do. | 
 | 268 | 		 */ | 
| Dave Chinner | 250df6e | 2011-03-22 22:23:36 +1100 | [diff] [blame] | 269 | 		if (!atomic_read(&inode->i_count)) { | 
 | 270 | 			spin_unlock(&inode->i_lock); | 
| Eric Paris | 164bc61 | 2009-05-21 17:01:58 -0400 | [diff] [blame] | 271 | 			continue; | 
| Dave Chinner | 250df6e | 2011-03-22 22:23:36 +1100 | [diff] [blame] | 272 | 		} | 
| Eric Paris | 164bc61 | 2009-05-21 17:01:58 -0400 | [diff] [blame] | 273 |  | 
 | 274 | 		need_iput_tmp = need_iput; | 
 | 275 | 		need_iput = NULL; | 
 | 276 |  | 
 | 277 | 		/* In case fsnotify_inode_delete() drops a reference. */ | 
 | 278 | 		if (inode != need_iput_tmp) | 
 | 279 | 			__iget(inode); | 
 | 280 | 		else | 
 | 281 | 			need_iput_tmp = NULL; | 
| Dave Chinner | 250df6e | 2011-03-22 22:23:36 +1100 | [diff] [blame] | 282 | 		spin_unlock(&inode->i_lock); | 
| Eric Paris | 164bc61 | 2009-05-21 17:01:58 -0400 | [diff] [blame] | 283 |  | 
 | 284 | 		/* In case the dropping of a reference would nuke next_i. */ | 
 | 285 | 		if ((&next_i->i_sb_list != list) && | 
| Dave Chinner | 250df6e | 2011-03-22 22:23:36 +1100 | [diff] [blame] | 286 | 		    atomic_read(&next_i->i_count)) { | 
 | 287 | 			spin_lock(&next_i->i_lock); | 
 | 288 | 			if (!(next_i->i_state & (I_FREEING | I_WILL_FREE))) { | 
 | 289 | 				__iget(next_i); | 
 | 290 | 				need_iput = next_i; | 
 | 291 | 			} | 
 | 292 | 			spin_unlock(&next_i->i_lock); | 
| Eric Paris | 164bc61 | 2009-05-21 17:01:58 -0400 | [diff] [blame] | 293 | 		} | 
 | 294 |  | 
 | 295 | 		/* | 
| Dave Chinner | 55fa609 | 2011-03-22 22:23:40 +1100 | [diff] [blame] | 296 | 		 * We can safely drop inode_sb_list_lock here because we hold | 
| Eric Paris | 164bc61 | 2009-05-21 17:01:58 -0400 | [diff] [blame] | 297 | 		 * references on both inode and next_i.  Also no new inodes | 
| Dave Chinner | 55fa609 | 2011-03-22 22:23:40 +1100 | [diff] [blame] | 298 | 		 * will be added since the umount has begun. | 
| Eric Paris | 164bc61 | 2009-05-21 17:01:58 -0400 | [diff] [blame] | 299 | 		 */ | 
| Dave Chinner | 55fa609 | 2011-03-22 22:23:40 +1100 | [diff] [blame] | 300 | 		spin_unlock(&inode_sb_list_lock); | 
| Eric Paris | 164bc61 | 2009-05-21 17:01:58 -0400 | [diff] [blame] | 301 |  | 
 | 302 | 		if (need_iput_tmp) | 
 | 303 | 			iput(need_iput_tmp); | 
 | 304 |  | 
 | 305 | 		/* for each watch, send FS_UNMOUNT and then remove it */ | 
 | 306 | 		fsnotify(inode, FS_UNMOUNT, inode, FSNOTIFY_EVENT_INODE, NULL, 0); | 
 | 307 |  | 
 | 308 | 		fsnotify_inode_delete(inode); | 
 | 309 |  | 
 | 310 | 		iput(inode); | 
 | 311 |  | 
| Dave Chinner | 55fa609 | 2011-03-22 22:23:40 +1100 | [diff] [blame] | 312 | 		spin_lock(&inode_sb_list_lock); | 
| Eric Paris | 164bc61 | 2009-05-21 17:01:58 -0400 | [diff] [blame] | 313 | 	} | 
| Dave Chinner | 55fa609 | 2011-03-22 22:23:40 +1100 | [diff] [blame] | 314 | 	spin_unlock(&inode_sb_list_lock); | 
| Eric Paris | 164bc61 | 2009-05-21 17:01:58 -0400 | [diff] [blame] | 315 | } |