From e61f224150ca322700620c30cb11ae2ef93ff6ad Mon Sep 17 00:00:00 2001 From: Maximilian Attems Date: Tue, 18 May 2010 14:24:31 +0000 Subject: [PATCH] Explicitly pass in whether sb is pinned or not fix famous Kees Cook bug, patches are scheduled for 2.6.35-rc1 and will go into stable. this is the first that fixes original issue. svn path=/dists/trunk/linux-2.6/; revision=15747 --- debian/changelog | 1 + ...-pass-in-whether-sb-is-pinned-or-not.patch | 196 ++++++++++++++++++ debian/patches/series/base | 1 + 3 files changed, 198 insertions(+) create mode 100644 debian/patches/bugfix/all/fs-explicitly-pass-in-whether-sb-is-pinned-or-not.patch diff --git a/debian/changelog b/debian/changelog index 15b001899..00eac6482 100644 --- a/debian/changelog +++ b/debian/changelog @@ -20,6 +20,7 @@ linux-2.6 (2.6.34-1~experimental.1) UNRELEASED; urgency=low * Fix backlight support on some recent Thinkpads. * Enable autosuspend on UVC by default. * acpi: Fall back to manually changing SCI_EN. + * Explicitly pass in whether sb is pinned or not. [ Ben Hutchings ] * Prepare debconf templates for translation (Closes: #576758) diff --git a/debian/patches/bugfix/all/fs-explicitly-pass-in-whether-sb-is-pinned-or-not.patch b/debian/patches/bugfix/all/fs-explicitly-pass-in-whether-sb-is-pinned-or-not.patch new file mode 100644 index 000000000..dc7178674 --- /dev/null +++ b/debian/patches/bugfix/all/fs-explicitly-pass-in-whether-sb-is-pinned-or-not.patch @@ -0,0 +1,196 @@ +From: Jens Axboe +Date: 2010-05-06 07:08:55 +Subject: Explicitly pass in whether sb is pinned or not + + +Revision two of this patch. I got rid of WB_SYNC_NONE_PIN, since we should not +further muddy the sync type and whether or not the sb is pinned. Instead lets +add a specific flag for this. + +BZ: 15906, Launchpad: 543617 + +diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c +index 4b37f7c..c9ac9cb 100644 +--- a/fs/fs-writeback.c ++++ b/fs/fs-writeback.c +@@ -45,6 +45,7 @@ struct wb_writeback_args { + int for_kupdate:1; + int range_cyclic:1; + int for_background:1; ++ int sb_pinned:1; + }; + + /* +@@ -230,6 +231,11 @@ static void bdi_sync_writeback(struct backing_dev_info *bdi, + .sync_mode = WB_SYNC_ALL, + .nr_pages = LONG_MAX, + .range_cyclic = 0, ++ /* ++ * Setting sb_pinned is not necessary for WB_SYNC_ALL, but ++ * lets make it explicitly clear. ++ */ ++ .sb_pinned = 1, + }; + struct bdi_work work; + +@@ -245,21 +251,23 @@ static void bdi_sync_writeback(struct backing_dev_info *bdi, + * @bdi: the backing device to write from + * @sb: write inodes from this super_block + * @nr_pages: the number of pages to write ++ * @sb_locked: caller already holds sb umount sem. + * + * Description: + * This does WB_SYNC_NONE opportunistic writeback. The IO is only + * started when this function returns, we make no guarentees on +- * completion. Caller need not hold sb s_umount semaphore. ++ * completion. Caller specifies whether sb umount sem is held already or not. + * + */ + void bdi_start_writeback(struct backing_dev_info *bdi, struct super_block *sb, +- long nr_pages) ++ long nr_pages, int sb_locked) + { + struct wb_writeback_args args = { + .sb = sb, + .sync_mode = WB_SYNC_NONE, + .nr_pages = nr_pages, + .range_cyclic = 1, ++ .sb_pinned = sb_locked, + }; + + /* +@@ -577,7 +585,7 @@ static enum sb_pin_state pin_sb_for_writeback(struct writeback_control *wbc, + /* + * Caller must already hold the ref for this + */ +- if (wbc->sync_mode == WB_SYNC_ALL) { ++ if (wbc->sync_mode == WB_SYNC_ALL || wbc->sb_pinned) { + WARN_ON(!rwsem_is_locked(&sb->s_umount)); + return SB_NOT_PINNED; + } +@@ -751,6 +759,7 @@ static long wb_writeback(struct bdi_writeback *wb, + .for_kupdate = args->for_kupdate, + .for_background = args->for_background, + .range_cyclic = args->range_cyclic, ++ .sb_pinned = args->sb_pinned, + }; + unsigned long oldest_jif; + long wrote = 0; +@@ -1183,6 +1192,18 @@ static void wait_sb_inodes(struct super_block *sb) + iput(old_inode); + } + ++static void __writeback_inodes_sb(struct super_block *sb, int sb_locked) ++{ ++ unsigned long nr_dirty = global_page_state(NR_FILE_DIRTY); ++ unsigned long nr_unstable = global_page_state(NR_UNSTABLE_NFS); ++ long nr_to_write; ++ ++ nr_to_write = nr_dirty + nr_unstable + ++ (inodes_stat.nr_inodes - inodes_stat.nr_unused); ++ ++ bdi_start_writeback(sb->s_bdi, sb, nr_to_write, sb_locked); ++} ++ + /** + * writeback_inodes_sb - writeback dirty inodes from given super_block + * @sb: the superblock +@@ -1194,18 +1215,23 @@ static void wait_sb_inodes(struct super_block *sb) + */ + void writeback_inodes_sb(struct super_block *sb) + { +- unsigned long nr_dirty = global_page_state(NR_FILE_DIRTY); +- unsigned long nr_unstable = global_page_state(NR_UNSTABLE_NFS); +- long nr_to_write; +- +- nr_to_write = nr_dirty + nr_unstable + +- (inodes_stat.nr_inodes - inodes_stat.nr_unused); +- +- bdi_start_writeback(sb->s_bdi, sb, nr_to_write); ++ __writeback_inodes_sb(sb, 0); + } + EXPORT_SYMBOL(writeback_inodes_sb); + + /** ++ * writeback_inodes_sb_locked - writeback dirty inodes from given super_block ++ * @sb: the superblock ++ * ++ * Like writeback_inodes_sb(), except the caller already holds the ++ * sb umount sem. ++ */ ++void writeback_inodes_sb_locked(struct super_block *sb) ++{ ++ __writeback_inodes_sb(sb, 1); ++} ++ ++/** + * writeback_inodes_sb_if_idle - start writeback if none underway + * @sb: the superblock + * +diff --git a/fs/sync.c b/fs/sync.c +index 92b2281..de6a441 100644 +--- a/fs/sync.c ++++ b/fs/sync.c +@@ -42,7 +42,7 @@ static int __sync_filesystem(struct super_block *sb, int wait) + if (wait) + sync_inodes_sb(sb); + else +- writeback_inodes_sb(sb); ++ writeback_inodes_sb_locked(sb); + + if (sb->s_op->sync_fs) + sb->s_op->sync_fs(sb, wait); +diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h +index bd0e3c6..90e677a 100644 +--- a/include/linux/backing-dev.h ++++ b/include/linux/backing-dev.h +@@ -103,7 +103,7 @@ int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev); + void bdi_unregister(struct backing_dev_info *bdi); + int bdi_setup_and_register(struct backing_dev_info *, char *, unsigned int); + void bdi_start_writeback(struct backing_dev_info *bdi, struct super_block *sb, +- long nr_pages); ++ long nr_pages, int sb_locked); + int bdi_writeback_task(struct bdi_writeback *wb); + int bdi_has_dirty_io(struct backing_dev_info *bdi); + +diff --git a/include/linux/writeback.h b/include/linux/writeback.h +index 36520de..3790165 100644 +--- a/include/linux/writeback.h ++++ b/include/linux/writeback.h +@@ -65,6 +65,15 @@ struct writeback_control { + * so we use a single control to update them + */ + unsigned no_nrwrite_index_update:1; ++ ++ /* ++ * For WB_SYNC_ALL, the sb must always be pinned. For WB_SYNC_NONE, ++ * the writeback code will pin the sb for the caller. However, ++ * for eg umount, the caller does WB_SYNC_NONE but already has ++ * the sb pinned. If the below is set, caller already has the ++ * sb pinned. ++ */ ++ unsigned sb_pinned:1; + }; + + /* +@@ -73,6 +82,7 @@ struct writeback_control { + struct bdi_writeback; + int inode_wait(void *); + void writeback_inodes_sb(struct super_block *); ++void writeback_inodes_sb_locked(struct super_block *); + int writeback_inodes_sb_if_idle(struct super_block *); + void sync_inodes_sb(struct super_block *); + void writeback_inodes_wbc(struct writeback_control *wbc); +diff --git a/mm/page-writeback.c b/mm/page-writeback.c +index 0b19943..49d3508 100644 +--- a/mm/page-writeback.c ++++ b/mm/page-writeback.c +@@ -597,7 +597,7 @@ static void balance_dirty_pages(struct address_space *mapping, + (!laptop_mode && ((global_page_state(NR_FILE_DIRTY) + + global_page_state(NR_UNSTABLE_NFS)) + > background_thresh))) +- bdi_start_writeback(bdi, NULL, 0); ++ bdi_start_writeback(bdi, NULL, 0, 0); + } + + void set_page_dirty_balance(struct page *page, int page_mkwrite) diff --git a/debian/patches/series/base b/debian/patches/series/base index 9d46bc5e0..785804c29 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -68,3 +68,4 @@ + bugfix/all/thinkpad-acpi-fix-backlight.patch + bugfix/all/linux-2.6-usb-uvc-autosuspend.diff + bugfix/all/linux-2.6-acpi-sleep-live-sci-live.patch ++ bugfix/all/fs-explicitly-pass-in-whether-sb-is-pinned-or-not.patch