diff options
Diffstat (limited to 'fs/buffer.c')
-rw-r--r-- | fs/buffer.c | 201 |
1 files changed, 45 insertions, 156 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index 891e1c78e4f1..f5f8b15a6e40 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -166,151 +166,6 @@ void end_buffer_write_sync(struct buffer_head *bh, int uptodate) | |||
166 | } | 166 | } |
167 | 167 | ||
168 | /* | 168 | /* |
169 | * Write out and wait upon all the dirty data associated with a block | ||
170 | * device via its mapping. Does not take the superblock lock. | ||
171 | */ | ||
172 | int sync_blockdev(struct block_device *bdev) | ||
173 | { | ||
174 | int ret = 0; | ||
175 | |||
176 | if (bdev) | ||
177 | ret = filemap_write_and_wait(bdev->bd_inode->i_mapping); | ||
178 | return ret; | ||
179 | } | ||
180 | EXPORT_SYMBOL(sync_blockdev); | ||
181 | |||
182 | /* | ||
183 | * Write out and wait upon all dirty data associated with this | ||
184 | * device. Filesystem data as well as the underlying block | ||
185 | * device. Takes the superblock lock. | ||
186 | */ | ||
187 | int fsync_bdev(struct block_device *bdev) | ||
188 | { | ||
189 | struct super_block *sb = get_super(bdev); | ||
190 | if (sb) { | ||
191 | int res = fsync_super(sb); | ||
192 | drop_super(sb); | ||
193 | return res; | ||
194 | } | ||
195 | return sync_blockdev(bdev); | ||
196 | } | ||
197 | |||
198 | /** | ||
199 | * freeze_bdev -- lock a filesystem and force it into a consistent state | ||
200 | * @bdev: blockdevice to lock | ||
201 | * | ||
202 | * This takes the block device bd_mount_sem to make sure no new mounts | ||
203 | * happen on bdev until thaw_bdev() is called. | ||
204 | * If a superblock is found on this device, we take the s_umount semaphore | ||
205 | * on it to make sure nobody unmounts until the snapshot creation is done. | ||
206 | * The reference counter (bd_fsfreeze_count) guarantees that only the last | ||
207 | * unfreeze process can unfreeze the frozen filesystem actually when multiple | ||
208 | * freeze requests arrive simultaneously. It counts up in freeze_bdev() and | ||
209 | * count down in thaw_bdev(). When it becomes 0, thaw_bdev() will unfreeze | ||
210 | * actually. | ||
211 | */ | ||
212 | struct super_block *freeze_bdev(struct block_device *bdev) | ||
213 | { | ||
214 | struct super_block *sb; | ||
215 | int error = 0; | ||
216 | |||
217 | mutex_lock(&bdev->bd_fsfreeze_mutex); | ||
218 | if (bdev->bd_fsfreeze_count > 0) { | ||
219 | bdev->bd_fsfreeze_count++; | ||
220 | sb = get_super(bdev); | ||
221 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | ||
222 | return sb; | ||
223 | } | ||
224 | bdev->bd_fsfreeze_count++; | ||
225 | |||
226 | down(&bdev->bd_mount_sem); | ||
227 | sb = get_super(bdev); | ||
228 | if (sb && !(sb->s_flags & MS_RDONLY)) { | ||
229 | sb->s_frozen = SB_FREEZE_WRITE; | ||
230 | smp_wmb(); | ||
231 | |||
232 | __fsync_super(sb); | ||
233 | |||
234 | sb->s_frozen = SB_FREEZE_TRANS; | ||
235 | smp_wmb(); | ||
236 | |||
237 | sync_blockdev(sb->s_bdev); | ||
238 | |||
239 | if (sb->s_op->freeze_fs) { | ||
240 | error = sb->s_op->freeze_fs(sb); | ||
241 | if (error) { | ||
242 | printk(KERN_ERR | ||
243 | "VFS:Filesystem freeze failed\n"); | ||
244 | sb->s_frozen = SB_UNFROZEN; | ||
245 | drop_super(sb); | ||
246 | up(&bdev->bd_mount_sem); | ||
247 | bdev->bd_fsfreeze_count--; | ||
248 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | ||
249 | return ERR_PTR(error); | ||
250 | } | ||
251 | } | ||
252 | } | ||
253 | |||
254 | sync_blockdev(bdev); | ||
255 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | ||
256 | |||
257 | return sb; /* thaw_bdev releases s->s_umount and bd_mount_sem */ | ||
258 | } | ||
259 | EXPORT_SYMBOL(freeze_bdev); | ||
260 | |||
261 | /** | ||
262 | * thaw_bdev -- unlock filesystem | ||
263 | * @bdev: blockdevice to unlock | ||
264 | * @sb: associated superblock | ||
265 | * | ||
266 | * Unlocks the filesystem and marks it writeable again after freeze_bdev(). | ||
267 | */ | ||
268 | int thaw_bdev(struct block_device *bdev, struct super_block *sb) | ||
269 | { | ||
270 | int error = 0; | ||
271 | |||
272 | mutex_lock(&bdev->bd_fsfreeze_mutex); | ||
273 | if (!bdev->bd_fsfreeze_count) { | ||
274 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | ||
275 | return -EINVAL; | ||
276 | } | ||
277 | |||
278 | bdev->bd_fsfreeze_count--; | ||
279 | if (bdev->bd_fsfreeze_count > 0) { | ||
280 | if (sb) | ||
281 | drop_super(sb); | ||
282 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | if (sb) { | ||
287 | BUG_ON(sb->s_bdev != bdev); | ||
288 | if (!(sb->s_flags & MS_RDONLY)) { | ||
289 | if (sb->s_op->unfreeze_fs) { | ||
290 | error = sb->s_op->unfreeze_fs(sb); | ||
291 | if (error) { | ||
292 | printk(KERN_ERR | ||
293 | "VFS:Filesystem thaw failed\n"); | ||
294 | sb->s_frozen = SB_FREEZE_TRANS; | ||
295 | bdev->bd_fsfreeze_count++; | ||
296 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | ||
297 | return error; | ||
298 | } | ||
299 | } | ||
300 | sb->s_frozen = SB_UNFROZEN; | ||
301 | smp_wmb(); | ||
302 | wake_up(&sb->s_wait_unfrozen); | ||
303 | } | ||
304 | drop_super(sb); | ||
305 | } | ||
306 | |||
307 | up(&bdev->bd_mount_sem); | ||
308 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | ||
309 | return 0; | ||
310 | } | ||
311 | EXPORT_SYMBOL(thaw_bdev); | ||
312 | |||
313 | /* | ||
314 | * Various filesystems appear to want __find_get_block to be non-blocking. | 169 | * Various filesystems appear to want __find_get_block to be non-blocking. |
315 | * But it's the page lock which protects the buffers. To get around this, | 170 | * But it's the page lock which protects the buffers. To get around this, |
316 | * we get exclusion from try_to_free_buffers with the blockdev mapping's | 171 | * we get exclusion from try_to_free_buffers with the blockdev mapping's |
@@ -435,7 +290,7 @@ static void free_more_memory(void) | |||
435 | &zone); | 290 | &zone); |
436 | if (zone) | 291 | if (zone) |
437 | try_to_free_pages(node_zonelist(nid, GFP_NOFS), 0, | 292 | try_to_free_pages(node_zonelist(nid, GFP_NOFS), 0, |
438 | GFP_NOFS); | 293 | GFP_NOFS, NULL); |
439 | } | 294 | } |
440 | } | 295 | } |
441 | 296 | ||
@@ -692,6 +547,39 @@ repeat: | |||
692 | return err; | 547 | return err; |
693 | } | 548 | } |
694 | 549 | ||
550 | void do_thaw_all(unsigned long unused) | ||
551 | { | ||
552 | struct super_block *sb; | ||
553 | char b[BDEVNAME_SIZE]; | ||
554 | |||
555 | spin_lock(&sb_lock); | ||
556 | restart: | ||
557 | list_for_each_entry(sb, &super_blocks, s_list) { | ||
558 | sb->s_count++; | ||
559 | spin_unlock(&sb_lock); | ||
560 | down_read(&sb->s_umount); | ||
561 | while (sb->s_bdev && !thaw_bdev(sb->s_bdev, sb)) | ||
562 | printk(KERN_WARNING "Emergency Thaw on %s\n", | ||
563 | bdevname(sb->s_bdev, b)); | ||
564 | up_read(&sb->s_umount); | ||
565 | spin_lock(&sb_lock); | ||
566 | if (__put_super_and_need_restart(sb)) | ||
567 | goto restart; | ||
568 | } | ||
569 | spin_unlock(&sb_lock); | ||
570 | printk(KERN_WARNING "Emergency Thaw complete\n"); | ||
571 | } | ||
572 | |||
573 | /** | ||
574 | * emergency_thaw_all -- forcibly thaw every frozen filesystem | ||
575 | * | ||
576 | * Used for emergency unfreeze of all filesystems via SysRq | ||
577 | */ | ||
578 | void emergency_thaw_all(void) | ||
579 | { | ||
580 | pdflush_operation(do_thaw_all, 0); | ||
581 | } | ||
582 | |||
695 | /** | 583 | /** |
696 | * sync_mapping_buffers - write out & wait upon a mapping's "associated" buffers | 584 | * sync_mapping_buffers - write out & wait upon a mapping's "associated" buffers |
697 | * @mapping: the mapping which wants those buffers written | 585 | * @mapping: the mapping which wants those buffers written |
@@ -766,14 +654,7 @@ static void __set_page_dirty(struct page *page, | |||
766 | spin_lock_irq(&mapping->tree_lock); | 654 | spin_lock_irq(&mapping->tree_lock); |
767 | if (page->mapping) { /* Race with truncate? */ | 655 | if (page->mapping) { /* Race with truncate? */ |
768 | WARN_ON_ONCE(warn && !PageUptodate(page)); | 656 | WARN_ON_ONCE(warn && !PageUptodate(page)); |
769 | 657 | account_page_dirtied(page, mapping); | |
770 | if (mapping_cap_account_dirty(mapping)) { | ||
771 | __inc_zone_page_state(page, NR_FILE_DIRTY); | ||
772 | __inc_bdi_stat(mapping->backing_dev_info, | ||
773 | BDI_RECLAIMABLE); | ||
774 | task_dirty_inc(current); | ||
775 | task_io_account_write(PAGE_CACHE_SIZE); | ||
776 | } | ||
777 | radix_tree_tag_set(&mapping->page_tree, | 658 | radix_tree_tag_set(&mapping->page_tree, |
778 | page_index(page), PAGECACHE_TAG_DIRTY); | 659 | page_index(page), PAGECACHE_TAG_DIRTY); |
779 | } | 660 | } |
@@ -2465,13 +2346,14 @@ int block_commit_write(struct page *page, unsigned from, unsigned to) | |||
2465 | * unlock the page. | 2346 | * unlock the page. |
2466 | */ | 2347 | */ |
2467 | int | 2348 | int |
2468 | block_page_mkwrite(struct vm_area_struct *vma, struct page *page, | 2349 | block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, |
2469 | get_block_t get_block) | 2350 | get_block_t get_block) |
2470 | { | 2351 | { |
2352 | struct page *page = vmf->page; | ||
2471 | struct inode *inode = vma->vm_file->f_path.dentry->d_inode; | 2353 | struct inode *inode = vma->vm_file->f_path.dentry->d_inode; |
2472 | unsigned long end; | 2354 | unsigned long end; |
2473 | loff_t size; | 2355 | loff_t size; |
2474 | int ret = -EINVAL; | 2356 | int ret = VM_FAULT_NOPAGE; /* make the VM retry the fault */ |
2475 | 2357 | ||
2476 | lock_page(page); | 2358 | lock_page(page); |
2477 | size = i_size_read(inode); | 2359 | size = i_size_read(inode); |
@@ -2491,6 +2373,13 @@ block_page_mkwrite(struct vm_area_struct *vma, struct page *page, | |||
2491 | if (!ret) | 2373 | if (!ret) |
2492 | ret = block_commit_write(page, 0, end); | 2374 | ret = block_commit_write(page, 0, end); |
2493 | 2375 | ||
2376 | if (unlikely(ret)) { | ||
2377 | if (ret == -ENOMEM) | ||
2378 | ret = VM_FAULT_OOM; | ||
2379 | else /* -ENOSPC, -EIO, etc */ | ||
2380 | ret = VM_FAULT_SIGBUS; | ||
2381 | } | ||
2382 | |||
2494 | out_unlock: | 2383 | out_unlock: |
2495 | unlock_page(page); | 2384 | unlock_page(page); |
2496 | return ret; | 2385 | return ret; |