From 8a32c441c1609f80e55df75422324a1151208f40 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 21 Nov 2011 12:32:23 -0800 Subject: freezer: implement and use kthread_freezable_should_stop() Writeback and thinkpad_acpi have been using thaw_process() to prevent deadlock between the freezer and kthread_stop(); unfortunately, this is inherently racy - nothing prevents freezing from happening between thaw_process() and kthread_stop(). This patch implements kthread_freezable_should_stop() which enters refrigerator if necessary but is guaranteed to return if kthread_stop() is invoked. Both thaw_process() users are converted to use the new function. Note that this deadlock condition exists for many of freezable kthreads. They need to be converted to use the new should_stop or freezable workqueue. Tested with synthetic test case. Signed-off-by: Tejun Heo Acked-by: Henrique de Moraes Holschuh Cc: Jens Axboe Cc: Oleg Nesterov --- fs/fs-writeback.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'fs/fs-writeback.c') diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 73c3992b2bb4..271fde50f0ee 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -947,7 +947,7 @@ int bdi_writeback_thread(void *data) trace_writeback_thread_start(bdi); - while (!kthread_should_stop()) { + while (!kthread_freezable_should_stop(NULL)) { /* * Remove own delayed wake-up timer, since we are already awake * and we'll take care of the preriodic write-back. @@ -977,8 +977,6 @@ int bdi_writeback_thread(void *data) */ schedule(); } - - try_to_freeze(); } /* Flush any work that raced with us exiting */ -- cgit v1.2.3 From 786228ab3095fe18dba3bc0d62055a123991d9d9 Mon Sep 17 00:00:00 2001 From: Marcos Paulo de Souza Date: Wed, 23 Nov 2011 20:56:45 +0800 Subject: writeback: Fix issue on make htmldocs Document the @reason parameter to make "make htmldocs" happy. Acked-by: Randy Dunlap Signed-off-by: Marcos Paulo de Souza Signed-off-by: Wu Fengguang --- fs/fs-writeback.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'fs/fs-writeback.c') diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 73c3992b2bb4..ac86f8b3e3cb 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -156,6 +156,7 @@ __bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages, * bdi_start_writeback - start writeback * @bdi: the backing device to write from * @nr_pages: the number of pages to write + * @reason: reason why some writeback work was initiated * * Description: * This does WB_SYNC_NONE opportunistic writeback. The IO is only @@ -1223,6 +1224,7 @@ static void wait_sb_inodes(struct super_block *sb) * writeback_inodes_sb_nr - writeback dirty inodes from given super_block * @sb: the superblock * @nr: the number of pages to write + * @reason: reason why some writeback work initiated * * Start writeback on some inodes on this super_block. No guarantees are made * on how many (if any) will be written, and this function does not wait @@ -1251,6 +1253,7 @@ EXPORT_SYMBOL(writeback_inodes_sb_nr); /** * writeback_inodes_sb - writeback dirty inodes from given super_block * @sb: the superblock + * @reason: reason why some writeback work was initiated * * Start writeback on some inodes on this super_block. No guarantees are made * on how many (if any) will be written, and this function does not wait @@ -1265,6 +1268,7 @@ EXPORT_SYMBOL(writeback_inodes_sb); /** * writeback_inodes_sb_if_idle - start writeback if none underway * @sb: the superblock + * @reason: reason why some writeback work was initiated * * Invoke writeback_inodes_sb if no writeback is currently underway. * Returns 1 if writeback was started, 0 if not. @@ -1285,6 +1289,7 @@ EXPORT_SYMBOL(writeback_inodes_sb_if_idle); * writeback_inodes_sb_if_idle - start writeback if none underway * @sb: the superblock * @nr: the number of pages to write + * @reason: reason why some writeback work was initiated * * Invoke writeback_inodes_sb if no writeback is currently underway. * Returns 1 if writeback was started, 0 if not. -- cgit v1.2.3 From b3bba872ddb0320a7ecb54decae53c13ceb2ed4c Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Thu, 8 Dec 2011 16:53:54 -0600 Subject: writeback: show writeback reason with __print_symbolic This makes the binary trace understandable by trace-cmd. CC: Dave Chinner CC: Curt Wohlgemuth CC: Steven Rostedt Signed-off-by: Wu Fengguang --- fs/fs-writeback.c | 11 ----------- include/trace/events/writeback.h | 15 +++++++++++++-- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'fs/fs-writeback.c') diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index ac86f8b3e3cb..517f211a3bd4 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -47,17 +47,6 @@ struct wb_writeback_work { struct completion *done; /* set if the caller waits */ }; -const char *wb_reason_name[] = { - [WB_REASON_BACKGROUND] = "background", - [WB_REASON_TRY_TO_FREE_PAGES] = "try_to_free_pages", - [WB_REASON_SYNC] = "sync", - [WB_REASON_PERIODIC] = "periodic", - [WB_REASON_LAPTOP_TIMER] = "laptop_timer", - [WB_REASON_FREE_MORE_MEM] = "free_more_memory", - [WB_REASON_FS_FREE_SPACE] = "fs_free_space", - [WB_REASON_FORKER_THREAD] = "forker_thread" -}; - /* * Include the creation of the trace points after defining the * wb_writeback_work structure so that the definition remains local to this diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h index b99caa8b780c..99d1d0decf88 100644 --- a/include/trace/events/writeback.h +++ b/include/trace/events/writeback.h @@ -21,6 +21,16 @@ {I_REFERENCED, "I_REFERENCED"} \ ) +#define WB_WORK_REASON \ + {WB_REASON_BACKGROUND, "background"}, \ + {WB_REASON_TRY_TO_FREE_PAGES, "try_to_free_pages"}, \ + {WB_REASON_SYNC, "sync"}, \ + {WB_REASON_PERIODIC, "periodic"}, \ + {WB_REASON_LAPTOP_TIMER, "laptop_timer"}, \ + {WB_REASON_FREE_MORE_MEM, "free_more_memory"}, \ + {WB_REASON_FS_FREE_SPACE, "fs_free_space"}, \ + {WB_REASON_FORKER_THREAD, "forker_thread"} + struct wb_writeback_work; DECLARE_EVENT_CLASS(writeback_work_class, @@ -55,7 +65,7 @@ DECLARE_EVENT_CLASS(writeback_work_class, __entry->for_kupdate, __entry->range_cyclic, __entry->for_background, - wb_reason_name[__entry->reason] + __print_symbolic(__entry->reason, WB_WORK_REASON) ) ); #define DEFINE_WRITEBACK_WORK_EVENT(name) \ @@ -184,7 +194,8 @@ TRACE_EVENT(writeback_queue_io, __entry->older, /* older_than_this in jiffies */ __entry->age, /* older_than_this in relative milliseconds */ __entry->moved, - wb_reason_name[__entry->reason]) + __print_symbolic(__entry->reason, WB_WORK_REASON) + ) ); TRACE_EVENT(global_dirty_state, -- cgit v1.2.3 From ff01bb4832651c6d25ac509a06a10fcbd75c461c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 16 Sep 2011 02:31:11 -0400 Subject: fs: move code out of buffer.c Move invalidate_bdev, block_sync_page into fs/block_dev.c. Export kill_bdev as well, so brd doesn't have to open code it. Reduce buffer_head.h requirement accordingly. Removed a rather large comment from invalidate_bdev, as it looked a bit obsolete to bother moving. The small comment replacing it says enough. Signed-off-by: Nick Piggin Cc: Al Viro Cc: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Al Viro --- arch/powerpc/sysdev/axonram.c | 1 - block/genhd.c | 1 - block/ioctl.c | 2 +- drivers/block/amiflop.c | 2 +- drivers/block/brd.c | 9 ++++---- drivers/block/floppy.c | 1 - drivers/block/loop.c | 1 - drivers/cdrom/cdrom.c | 1 - drivers/md/dm.c | 1 - drivers/md/md.c | 3 +-- drivers/mtd/devices/block2mtd.c | 1 - drivers/s390/block/dasd.c | 1 - drivers/scsi/scsicam.c | 1 - drivers/tty/sysrq.c | 2 +- fs/block_dev.c | 30 ++++++++++++++++++++++--- fs/buffer.c | 50 ----------------------------------------- fs/cachefiles/interface.c | 1 - fs/cramfs/inode.c | 1 - fs/fs-writeback.c | 1 - fs/libfs.c | 2 +- fs/quota/dquot.c | 1 - fs/quota/quota.c | 1 - fs/splice.c | 1 - fs/sync.c | 1 - include/linux/fs.h | 3 +++ kernel/power/swap.c | 1 - mm/page-writeback.c | 2 +- mm/swap_state.c | 1 - 28 files changed, 40 insertions(+), 83 deletions(-) (limited to 'fs/fs-writeback.c') diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index ba4271919062..1c16141c031c 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -25,7 +25,6 @@ #include #include -#include #include #include #include diff --git a/block/genhd.c b/block/genhd.c index bf443a71b93e..b7d1a0e42686 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/block/ioctl.c b/block/ioctl.c index ca939fc1030f..91e7b19c86f4 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 8eba86bba599..386146d792d1 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -63,7 +63,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/block/brd.c b/drivers/block/brd.c index d22119d49e53..ec246437f5a4 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -17,7 +17,7 @@ #include #include #include -#include /* invalidate_bh_lrus() */ +#include #include #include @@ -402,14 +402,13 @@ static int brd_ioctl(struct block_device *bdev, fmode_t mode, error = -EBUSY; if (bdev->bd_openers <= 1) { /* - * Invalidate the cache first, so it isn't written - * back to the device. + * Kill the cache first, so it isn't written back to the + * device. * * Another thread might instantiate more buffercache here, * but there is not much we can do to close that race. */ - invalidate_bh_lrus(); - truncate_inode_pages(bdev->bd_inode->i_mapping, 0); + kill_bdev(bdev); brd_free_pages(brd); error = 0; } diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 9955a53733b2..510fb10ec45a 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -188,7 +188,6 @@ static int print_unex = 1; #include #include #include -#include /* for invalidate_buffers() */ #include #include #include diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 1e888c9e85b3..f00257782fcc 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -69,7 +69,6 @@ #include #include #include -#include /* for invalidate_bdev() */ #include #include #include diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index f997c27d79e2..2118211aff99 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -267,7 +267,6 @@ #include #include -#include #include #include #include diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 4720f68f817e..b89c548ec3f8 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/md/md.c b/drivers/md/md.c index f47f1f8ac44b..5d1b6762f108 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -36,8 +36,7 @@ #include #include #include -#include -#include /* for invalidate_bdev */ +#include #include #include #include diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index b78f23169d4e..ebeabc727f70 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 65894f05a801..2de5b60ee8c8 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c index 6803b1e26ecc..92d24d6dcb39 100644 --- a/drivers/scsi/scsicam.c +++ b/drivers/scsi/scsicam.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 43db715f1502..7867b7c4538e 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -32,7 +32,6 @@ #include #include #include -#include /* for fsync_bdev() */ #include #include #include @@ -41,6 +40,7 @@ #include #include #include +#include #include #include diff --git a/fs/block_dev.c b/fs/block_dev.c index 7866cdd9fe70..69a5b6fbee2b 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #include "internal.h" @@ -82,13 +84,35 @@ static sector_t max_block(struct block_device *bdev) } /* Kill _all_ buffers and pagecache , dirty or not.. */ -static void kill_bdev(struct block_device *bdev) +void kill_bdev(struct block_device *bdev) { - if (bdev->bd_inode->i_mapping->nrpages == 0) + struct address_space *mapping = bdev->bd_inode->i_mapping; + + if (mapping->nrpages == 0) return; + invalidate_bh_lrus(); - truncate_inode_pages(bdev->bd_inode->i_mapping, 0); + truncate_inode_pages(mapping, 0); } +EXPORT_SYMBOL(kill_bdev); + +/* Invalidate clean unused buffers and pagecache. */ +void invalidate_bdev(struct block_device *bdev) +{ + struct address_space *mapping = bdev->bd_inode->i_mapping; + + if (mapping->nrpages == 0) + return; + + invalidate_bh_lrus(); + lru_add_drain_all(); /* make sure all lru add caches are flushed */ + invalidate_mapping_pages(mapping, 0, -1); + /* 99% of the time, we don't need to flush the cleancache on the bdev. + * But, for the strange corners, lets be cautious + */ + cleancache_flush_inode(mapping); +} +EXPORT_SYMBOL(invalidate_bdev); int set_blocksize(struct block_device *bdev, int size) { diff --git a/fs/buffer.c b/fs/buffer.c index 19d8eb7fdc81..1a30db77af32 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -41,7 +41,6 @@ #include #include #include -#include static int fsync_buffers_list(spinlock_t *lock, struct list_head *list); @@ -231,55 +230,6 @@ out: return ret; } -/* If invalidate_buffers() will trash dirty buffers, it means some kind - of fs corruption is going on. Trashing dirty data always imply losing - information that was supposed to be just stored on the physical layer - by the user. - - Thus invalidate_buffers in general usage is not allwowed to trash - dirty buffers. For example ioctl(FLSBLKBUF) expects dirty data to - be preserved. These buffers are simply skipped. - - We also skip buffers which are still in use. For example this can - happen if a userspace program is reading the block device. - - NOTE: In the case where the user removed a removable-media-disk even if - there's still dirty data not synced on disk (due a bug in the device driver - or due an error of the user), by not destroying the dirty buffers we could - generate corruption also on the next media inserted, thus a parameter is - necessary to handle this case in the most safe way possible (trying - to not corrupt also the new disk inserted with the data belonging to - the old now corrupted disk). Also for the ramdisk the natural thing - to do in order to release the ramdisk memory is to destroy dirty buffers. - - These are two special cases. Normal usage imply the device driver - to issue a sync on the device (without waiting I/O completion) and - then an invalidate_buffers call that doesn't trash dirty buffers. - - For handling cache coherency with the blkdev pagecache the 'update' case - is been introduced. It is needed to re-read from disk any pinned - buffer. NOTE: re-reading from disk is destructive so we can do it only - when we assume nobody is changing the buffercache under our I/O and when - we think the disk contains more recent information than the buffercache. - The update == 1 pass marks the buffers we need to update, the update == 2 - pass does the actual I/O. */ -void invalidate_bdev(struct block_device *bdev) -{ - struct address_space *mapping = bdev->bd_inode->i_mapping; - - if (mapping->nrpages == 0) - return; - - invalidate_bh_lrus(); - lru_add_drain_all(); /* make sure all lru add caches are flushed */ - invalidate_mapping_pages(mapping, 0, -1); - /* 99% of the time, we don't need to flush the cleancache on the bdev. - * But, for the strange corners, lets be cautious - */ - cleancache_flush_inode(mapping); -} -EXPORT_SYMBOL(invalidate_bdev); - /* * Kick the writeback threads then try to free up some ZONE_NORMAL memory. */ diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c index 1064805e653b..67bef6d01484 100644 --- a/fs/cachefiles/interface.c +++ b/fs/cachefiles/interface.c @@ -11,7 +11,6 @@ #include #include -#include #include "internal.h" #define list_to_page(head) (list_entry((head)->prev, struct page, lru)) diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 739fb59bcdc2..c37adb222113 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 517f211a3bd4..80a4574028f1 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include "internal.h" diff --git a/fs/libfs.c b/fs/libfs.c index f6d411eef1e7..5b2dbb3ba4fc 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include /* sync_mapping_buffers */ #include diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 5b572c89e6c4..5d81e92daf83 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -73,7 +73,6 @@ #include #include #include -#include #include #include #include "../internal.h" /* ugh */ diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 35f4b0ecdeb3..7898cd688a00 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/fs/splice.c b/fs/splice.c index fa2defa8afcf..1ec0493266b3 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/fs/sync.c b/fs/sync.c index 101b8ef901d7..f3501ef39235 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "internal.h" diff --git a/include/linux/fs.h b/include/linux/fs.h index cec429d76ab0..e853ba5eddd4 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2092,6 +2092,7 @@ extern void bd_forget(struct inode *inode); extern void bdput(struct block_device *); extern void invalidate_bdev(struct block_device *); extern int sync_blockdev(struct block_device *bdev); +extern void kill_bdev(struct block_device *); extern struct super_block *freeze_bdev(struct block_device *); extern void emergency_thaw_all(void); extern int thaw_bdev(struct block_device *bdev, struct super_block *sb); @@ -2099,6 +2100,7 @@ extern int fsync_bdev(struct block_device *); #else static inline void bd_forget(struct inode *inode) {} static inline int sync_blockdev(struct block_device *bdev) { return 0; } +static inline void kill_bdev(struct block_device *bdev) {} static inline void invalidate_bdev(struct block_device *bdev) {} static inline struct super_block *freeze_bdev(struct block_device *sb) @@ -2415,6 +2417,7 @@ extern ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos); extern int blkdev_fsync(struct file *filp, loff_t start, loff_t end, int datasync); +extern void block_sync_page(struct page *page); /* fs/splice.c */ extern ssize_t generic_file_splice_read(struct file *, loff_t *, diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 11a594c4ba25..3739ecced085 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 50f08241f981..8616ef3025a4 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include /* __set_page_dirty_buffers */ #include #include diff --git a/mm/swap_state.c b/mm/swap_state.c index 78cc4d1f6cce..ea6b32d61873 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3