aboutsummaryrefslogtreecommitdiffstats
path: root/fs/block_dev.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2009-08-03 17:28:35 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2009-09-24 07:47:41 -0400
commit4504230a71566785a05d3e6b53fa1ee071b864eb (patch)
treee73070fcad99b800f0324992c392d44c6dddc97c /fs/block_dev.c
parent4fadd7bb20a1e7c774ed88dc703d8fbcd00ff917 (diff)
freeze_bdev: grab active reference to frozen superblocks
Currently we held s_umount while a filesystem is frozen, despite that we might return to userspace and unlock it from a different process. Instead grab an active reference to keep the file system busy and add an explicit check for frozen filesystems in remount and reject the remount instead of blocking on s_umount. Add a new get_active_super helper to super.c for use by freeze_bdev that grabs an active reference to a superblock from a given block device. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r--fs/block_dev.c132
1 files changed, 72 insertions, 60 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 22506eb4a58..9cf4b926f8e 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -230,43 +230,54 @@ struct super_block *freeze_bdev(struct block_device *bdev)
230 int error = 0; 230 int error = 0;
231 231
232 mutex_lock(&bdev->bd_fsfreeze_mutex); 232 mutex_lock(&bdev->bd_fsfreeze_mutex);
233 if (bdev->bd_fsfreeze_count > 0) { 233 if (++bdev->bd_fsfreeze_count > 1) {
234 bdev->bd_fsfreeze_count++; 234 /*
235 * We don't even need to grab a reference - the first call
236 * to freeze_bdev grab an active reference and only the last
237 * thaw_bdev drops it.
238 */
235 sb = get_super(bdev); 239 sb = get_super(bdev);
240 drop_super(sb);
236 mutex_unlock(&bdev->bd_fsfreeze_mutex); 241 mutex_unlock(&bdev->bd_fsfreeze_mutex);
237 return sb; 242 return sb;
238 } 243 }
239 bdev->bd_fsfreeze_count++; 244
240 245 sb = get_active_super(bdev);
241 sb = get_super(bdev); 246 if (!sb)
242 if (sb && !(sb->s_flags & MS_RDONLY)) { 247 goto out;
243 sb->s_frozen = SB_FREEZE_WRITE; 248 if (sb->s_flags & MS_RDONLY) {
244 smp_wmb(); 249 deactivate_locked_super(sb);
245 250 mutex_unlock(&bdev->bd_fsfreeze_mutex);
246 sync_filesystem(sb); 251 return sb;
247 252 }
248 sb->s_frozen = SB_FREEZE_TRANS; 253
249 smp_wmb(); 254 sb->s_frozen = SB_FREEZE_WRITE;
250 255 smp_wmb();
251 sync_blockdev(sb->s_bdev); 256
252 257 sync_filesystem(sb);
253 if (sb->s_op->freeze_fs) { 258
254 error = sb->s_op->freeze_fs(sb); 259 sb->s_frozen = SB_FREEZE_TRANS;
255 if (error) { 260 smp_wmb();
256 printk(KERN_ERR 261
257 "VFS:Filesystem freeze failed\n"); 262 sync_blockdev(sb->s_bdev);
258 sb->s_frozen = SB_UNFROZEN; 263
259 drop_super(sb); 264 if (sb->s_op->freeze_fs) {
260 bdev->bd_fsfreeze_count--; 265 error = sb->s_op->freeze_fs(sb);
261 mutex_unlock(&bdev->bd_fsfreeze_mutex); 266 if (error) {
262 return ERR_PTR(error); 267 printk(KERN_ERR
263 } 268 "VFS:Filesystem freeze failed\n");
269 sb->s_frozen = SB_UNFROZEN;
270 deactivate_locked_super(sb);
271 bdev->bd_fsfreeze_count--;
272 mutex_unlock(&bdev->bd_fsfreeze_mutex);
273 return ERR_PTR(error);
264 } 274 }
265 } 275 }
276 up_write(&sb->s_umount);
266 277
278 out:
267 sync_blockdev(bdev); 279 sync_blockdev(bdev);
268 mutex_unlock(&bdev->bd_fsfreeze_mutex); 280 mutex_unlock(&bdev->bd_fsfreeze_mutex);
269
270 return sb; /* thaw_bdev releases s->s_umount */ 281 return sb; /* thaw_bdev releases s->s_umount */
271} 282}
272EXPORT_SYMBOL(freeze_bdev); 283EXPORT_SYMBOL(freeze_bdev);
@@ -280,43 +291,44 @@ EXPORT_SYMBOL(freeze_bdev);
280 */ 291 */
281int thaw_bdev(struct block_device *bdev, struct super_block *sb) 292int thaw_bdev(struct block_device *bdev, struct super_block *sb)
282{ 293{
283 int error = 0; 294 int error = -EINVAL;
284 295
285 mutex_lock(&bdev->bd_fsfreeze_mutex); 296 mutex_lock(&bdev->bd_fsfreeze_mutex);
286 if (!bdev->bd_fsfreeze_count) { 297 if (!bdev->bd_fsfreeze_count)
287 mutex_unlock(&bdev->bd_fsfreeze_mutex); 298 goto out_unlock;
288 return -EINVAL; 299
289 } 300 error = 0;
290 301 if (--bdev->bd_fsfreeze_count > 0)
291 bdev->bd_fsfreeze_count--; 302 goto out_unlock;
292 if (bdev->bd_fsfreeze_count > 0) { 303
293 if (sb) 304 if (!sb)
294 drop_super(sb); 305 goto out_unlock;
295 mutex_unlock(&bdev->bd_fsfreeze_mutex); 306
296 return 0; 307 BUG_ON(sb->s_bdev != bdev);
297 } 308 down_write(&sb->s_umount);
298 309 if (sb->s_flags & MS_RDONLY)
299 if (sb) { 310 goto out_deactivate;
300 BUG_ON(sb->s_bdev != bdev); 311
301 if (!(sb->s_flags & MS_RDONLY)) { 312 if (sb->s_op->unfreeze_fs) {
302 if (sb->s_op->unfreeze_fs) { 313 error = sb->s_op->unfreeze_fs(sb);
303 error = sb->s_op->unfreeze_fs(sb); 314 if (error) {
304 if (error) { 315 printk(KERN_ERR
305 printk(KERN_ERR 316 "VFS:Filesystem thaw failed\n");
306 "VFS:Filesystem thaw failed\n"); 317 sb->s_frozen = SB_FREEZE_TRANS;
307 sb->s_frozen = SB_FREEZE_TRANS; 318 bdev->bd_fsfreeze_count++;
308 bdev->bd_fsfreeze_count++; 319 mutex_unlock(&bdev->bd_fsfreeze_mutex);
309 mutex_unlock(&bdev->bd_fsfreeze_mutex); 320 return error;
310 return error;
311 }
312 }
313 sb->s_frozen = SB_UNFROZEN;
314 smp_wmb();
315 wake_up(&sb->s_wait_unfrozen);
316 } 321 }
317 drop_super(sb);
318 } 322 }
319 323
324 sb->s_frozen = SB_UNFROZEN;
325 smp_wmb();
326 wake_up(&sb->s_wait_unfrozen);
327
328out_deactivate:
329 if (sb)
330 deactivate_locked_super(sb);
331out_unlock:
320 mutex_unlock(&bdev->bd_fsfreeze_mutex); 332 mutex_unlock(&bdev->bd_fsfreeze_mutex);
321 return 0; 333 return 0;
322} 334}