aboutsummaryrefslogtreecommitdiffstats
path: root/fs/super.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2010-03-22 15:22:31 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2010-05-21 18:31:14 -0400
commit1712ac8fda7d8bc4dc921f5777b7423aacad7263 (patch)
tree1493bc7166ace04d9ac2f4d5383eaab1d43e17c4 /fs/super.c
parentb20bd1a5e78af267dc4b6e1ffed48d5d776302c5 (diff)
Saner locking around deactivate_super()
Make sure that s_umount is acquired *before* we drop the final active reference; we still have the fast path (atomic_dec_unless) and we have gotten rid of the window between the moment when s_active hits zero and s_umount is acquired. Which simplifies the living hell out of grab_super() and inotify pin_to_kill() stuff. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/super.c')
-rw-r--r--fs/super.c45
1 files changed, 19 insertions, 26 deletions
diff --git a/fs/super.c b/fs/super.c
index bc734f8b3e18..157657b32798 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -178,53 +178,48 @@ void put_super(struct super_block *sb)
178 178
179 179
180/** 180/**
181 * deactivate_super - drop an active reference to superblock 181 * deactivate_locked_super - drop an active reference to superblock
182 * @s: superblock to deactivate 182 * @s: superblock to deactivate
183 * 183 *
184 * Drops an active reference to superblock, acquiring a temprory one if 184 * Drops an active reference to superblock, converting it into a temprory
185 * there is no active references left. In that case we lock superblock, 185 * one if there is no other active references left. In that case we
186 * tell fs driver to shut it down and drop the temporary reference we 186 * tell fs driver to shut it down and drop the temporary reference we
187 * had just acquired. 187 * had just acquired.
188 *
189 * Caller holds exclusive lock on superblock; that lock is released.
188 */ 190 */
189void deactivate_super(struct super_block *s) 191void deactivate_locked_super(struct super_block *s)
190{ 192{
191 struct file_system_type *fs = s->s_type; 193 struct file_system_type *fs = s->s_type;
192 if (atomic_dec_and_test(&s->s_active)) { 194 if (atomic_dec_and_test(&s->s_active)) {
193 vfs_dq_off(s, 0); 195 vfs_dq_off(s, 0);
194 down_write(&s->s_umount);
195 fs->kill_sb(s); 196 fs->kill_sb(s);
196 put_filesystem(fs); 197 put_filesystem(fs);
197 put_super(s); 198 put_super(s);
199 } else {
200 up_write(&s->s_umount);
198 } 201 }
199} 202}
200 203
201EXPORT_SYMBOL(deactivate_super); 204EXPORT_SYMBOL(deactivate_locked_super);
202 205
203/** 206/**
204 * deactivate_locked_super - drop an active reference to superblock 207 * deactivate_super - drop an active reference to superblock
205 * @s: superblock to deactivate 208 * @s: superblock to deactivate
206 * 209 *
207 * Equivalent of up_write(&s->s_umount); deactivate_super(s);, except that 210 * Variant of deactivate_locked_super(), except that superblock is *not*
208 * it does not unlock it until it's all over. As the result, it's safe to 211 * locked by caller. If we are going to drop the final active reference,
209 * use to dispose of new superblock on ->get_sb() failure exits - nobody 212 * lock will be acquired prior to that.
210 * will see the sucker until it's all over. Equivalent using up_write +
211 * deactivate_super is safe for that purpose only if superblock is either
212 * safe to use or has NULL ->s_root when we unlock.
213 */ 213 */
214void deactivate_locked_super(struct super_block *s) 214void deactivate_super(struct super_block *s)
215{ 215{
216 struct file_system_type *fs = s->s_type; 216 if (!atomic_add_unless(&s->s_active, -1, 1)) {
217 if (atomic_dec_and_test(&s->s_active)) { 217 down_write(&s->s_umount);
218 vfs_dq_off(s, 0); 218 deactivate_locked_super(s);
219 fs->kill_sb(s);
220 put_filesystem(fs);
221 put_super(s);
222 } else {
223 up_write(&s->s_umount);
224 } 219 }
225} 220}
226 221
227EXPORT_SYMBOL(deactivate_locked_super); 222EXPORT_SYMBOL(deactivate_super);
228 223
229/** 224/**
230 * grab_super - acquire an active reference 225 * grab_super - acquire an active reference
@@ -247,12 +242,10 @@ static int grab_super(struct super_block *s) __releases(sb_lock)
247 /* it's going away */ 242 /* it's going away */
248 s->s_count++; 243 s->s_count++;
249 spin_unlock(&sb_lock); 244 spin_unlock(&sb_lock);
250 /* usually that'll be enough for it to die... */ 245 /* wait for it to die */
251 down_write(&s->s_umount); 246 down_write(&s->s_umount);
252 up_write(&s->s_umount); 247 up_write(&s->s_umount);
253 put_super(s); 248 put_super(s);
254 /* ... but in case it wasn't, let's at least yield() */
255 yield();
256 return 0; 249 return 0;
257} 250}
258 251