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.c147
1 files changed, 147 insertions, 0 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c
index b3c1efff5e1d..f45dbc18dd17 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -18,6 +18,7 @@
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/blkpg.h> 19#include <linux/blkpg.h>
20#include <linux/buffer_head.h> 20#include <linux/buffer_head.h>
21#include <linux/pagevec.h>
21#include <linux/writeback.h> 22#include <linux/writeback.h>
22#include <linux/mpage.h> 23#include <linux/mpage.h>
23#include <linux/mount.h> 24#include <linux/mount.h>
@@ -174,6 +175,152 @@ blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
174 iov, offset, nr_segs, blkdev_get_blocks, NULL); 175 iov, offset, nr_segs, blkdev_get_blocks, NULL);
175} 176}
176 177
178/*
179 * Write out and wait upon all the dirty data associated with a block
180 * device via its mapping. Does not take the superblock lock.
181 */
182int sync_blockdev(struct block_device *bdev)
183{
184 int ret = 0;
185
186 if (bdev)
187 ret = filemap_write_and_wait(bdev->bd_inode->i_mapping);
188 return ret;
189}
190EXPORT_SYMBOL(sync_blockdev);
191
192/*
193 * Write out and wait upon all dirty data associated with this
194 * device. Filesystem data as well as the underlying block
195 * device. Takes the superblock lock.
196 */
197int fsync_bdev(struct block_device *bdev)
198{
199 struct super_block *sb = get_super(bdev);
200 if (sb) {
201 int res = fsync_super(sb);
202 drop_super(sb);
203 return res;
204 }
205 return sync_blockdev(bdev);
206}
207EXPORT_SYMBOL(fsync_bdev);
208
209/**
210 * freeze_bdev -- lock a filesystem and force it into a consistent state
211 * @bdev: blockdevice to lock
212 *
213 * This takes the block device bd_mount_sem to make sure no new mounts
214 * happen on bdev until thaw_bdev() is called.
215 * If a superblock is found on this device, we take the s_umount semaphore
216 * on it to make sure nobody unmounts until the snapshot creation is done.
217 * The reference counter (bd_fsfreeze_count) guarantees that only the last
218 * unfreeze process can unfreeze the frozen filesystem actually when multiple
219 * freeze requests arrive simultaneously. It counts up in freeze_bdev() and
220 * count down in thaw_bdev(). When it becomes 0, thaw_bdev() will unfreeze
221 * actually.
222 */
223struct super_block *freeze_bdev(struct block_device *bdev)
224{
225 struct super_block *sb;
226 int error = 0;
227
228 mutex_lock(&bdev->bd_fsfreeze_mutex);
229 if (bdev->bd_fsfreeze_count > 0) {
230 bdev->bd_fsfreeze_count++;
231 sb = get_super(bdev);
232 mutex_unlock(&bdev->bd_fsfreeze_mutex);
233 return sb;
234 }
235 bdev->bd_fsfreeze_count++;
236
237 down(&bdev->bd_mount_sem);
238 sb = get_super(bdev);
239 if (sb && !(sb->s_flags & MS_RDONLY)) {
240 sb->s_frozen = SB_FREEZE_WRITE;
241 smp_wmb();
242
243 __fsync_super(sb);
244
245 sb->s_frozen = SB_FREEZE_TRANS;
246 smp_wmb();
247
248 sync_blockdev(sb->s_bdev);
249
250 if (sb->s_op->freeze_fs) {
251 error = sb->s_op->freeze_fs(sb);
252 if (error) {
253 printk(KERN_ERR
254 "VFS:Filesystem freeze failed\n");
255 sb->s_frozen = SB_UNFROZEN;
256 drop_super(sb);
257 up(&bdev->bd_mount_sem);
258 bdev->bd_fsfreeze_count--;
259 mutex_unlock(&bdev->bd_fsfreeze_mutex);
260 return ERR_PTR(error);
261 }
262 }
263 }
264
265 sync_blockdev(bdev);
266 mutex_unlock(&bdev->bd_fsfreeze_mutex);
267
268 return sb; /* thaw_bdev releases s->s_umount and bd_mount_sem */
269}
270EXPORT_SYMBOL(freeze_bdev);
271
272/**
273 * thaw_bdev -- unlock filesystem
274 * @bdev: blockdevice to unlock
275 * @sb: associated superblock
276 *
277 * Unlocks the filesystem and marks it writeable again after freeze_bdev().
278 */
279int thaw_bdev(struct block_device *bdev, struct super_block *sb)
280{
281 int error = 0;
282
283 mutex_lock(&bdev->bd_fsfreeze_mutex);
284 if (!bdev->bd_fsfreeze_count) {
285 mutex_unlock(&bdev->bd_fsfreeze_mutex);
286 return -EINVAL;
287 }
288
289 bdev->bd_fsfreeze_count--;
290 if (bdev->bd_fsfreeze_count > 0) {
291 if (sb)
292 drop_super(sb);
293 mutex_unlock(&bdev->bd_fsfreeze_mutex);
294 return 0;
295 }
296
297 if (sb) {
298 BUG_ON(sb->s_bdev != bdev);
299 if (!(sb->s_flags & MS_RDONLY)) {
300 if (sb->s_op->unfreeze_fs) {
301 error = sb->s_op->unfreeze_fs(sb);
302 if (error) {
303 printk(KERN_ERR
304 "VFS:Filesystem thaw failed\n");
305 sb->s_frozen = SB_FREEZE_TRANS;
306 bdev->bd_fsfreeze_count++;
307 mutex_unlock(&bdev->bd_fsfreeze_mutex);
308 return error;
309 }
310 }
311 sb->s_frozen = SB_UNFROZEN;
312 smp_wmb();
313 wake_up(&sb->s_wait_unfrozen);
314 }
315 drop_super(sb);
316 }
317
318 up(&bdev->bd_mount_sem);
319 mutex_unlock(&bdev->bd_fsfreeze_mutex);
320 return 0;
321}
322EXPORT_SYMBOL(thaw_bdev);
323
177static int blkdev_writepage(struct page *page, struct writeback_control *wbc) 324static int blkdev_writepage(struct page *page, struct writeback_control *wbc)
178{ 325{
179 return block_write_full_page(page, blkdev_get_block, wbc); 326 return block_write_full_page(page, blkdev_get_block, wbc);