aboutsummaryrefslogtreecommitdiffstats
path: root/fs/block_dev.c
diff options
context:
space:
mode:
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 22506eb4a58e..9cf4b926f8e4 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}