From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752217AbbAaI1V (ORCPT ); Sat, 31 Jan 2015 03:27:21 -0500 Received: from mailout1.samsung.com ([203.254.224.24]:62056 "EHLO mailout1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751861AbbAaI1R (ORCPT ); Sat, 31 Jan 2015 03:27:17 -0500 X-AuditID: cbfee61b-f79d76d0000024d6-8a-54cc91e2ae13 From: Ganesh Mahendran To: minchan@kernel.org, ngupta@vflare.org, sergey.senozhatsky.work@gmail.com Cc: akpm@linux-foundation.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, Ganesh Mahendran , Sergey Senozhatsky Subject: [PATCH] zram: fix race between reset and mount/mkswap Date: Sat, 31 Jan 2015 16:25:20 +0800 Message-id: <1422692720-19756-1-git-send-email-opensource.ganesh@gmail.com> X-Mailer: git-send-email 1.7.9.5 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmpjluLIzCtJLcpLzFFi42I5/e+xgO6jiWdCDPoOW1nMWb+GzeLyrjls FvfW/Ge1WPb1PbvFhpZZ7Battx6zWDyaMInJYu3nx+wOHB47Z91l99i0qpPNY9OnSeweJ2b8 ZvHY+Wkzq8fnTXIBbFFcNimpOZllqUX6dglcGZcf/GUsmK1Z8XTVL8YGxg2KXYycHBICJhIr e7+zQdhiEhfurQeyuTiEBBYxStyeeJcJwmlnkljR84MFpIoNqOPG6VZ2EFtEwEfi9Zlr7CBF zALbGCUObVsAViQsYCdxvX0fmM0ioCpxv38xK4jNK+At8WbHZ8YuRg6gdQoScybZTGDkXsDI sIpRNLUguaA4KT3XSK84Mbe4NC9dLzk/dxMjOHSeSe9gXNVgcYhRgINRiYe3wvJMiBBrYllx Ze4hRgkOZiUR3hYjoBBvSmJlVWpRfnxRaU5q8SFGaQ4WJXFeJfu2ECGB9MSS1OzU1ILUIpgs EwenVAPjnEnJ677lhWz1T9z1Jk6o+YHkl6tODR/f93dmtvJd3e/8WDfn5ak4/dhzDDJv++Oy LLe+fGX0KXHCmYSvTos67Pd07rgq0rJzVeabWQsnRHKtj3q6kmdHwsTvaRwSPY+eXD8mwrf5 2dI3kUzbSn4zTdig8+XE9t+zAk6+U3Nvm/GH0a/xs/Dmq0osxRmJhlrMRcWJAMX+dwwZAgAA Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Currently there is a racy between reset and mount/mkswap, so that it could make oops when umount a corropted filesystem. This issue can be reproduced by adding delay between bdput() and zram_reset_device reset_store(...) { bdput(bdev); msleep(2000); // test code zram_reset_device(zram, true); } Steps: $ echo 1 > /sys/block/zram0/reset & $ mount /dev/zram0 /mnt/ $ umount /mnt BUG: failure at fs/buffer.c:3006/_submit_bh()! Kernel panic - not syncing: BUG! CPU: 0 PID: 726 Comm: umount Not tainted 3.19.0-rc6+ #32 Hardware name: linux,dummy-virt (DT) Call trace: [] dump_backtrace+0x0/0x124 [] show_stack+0x10/0x1c [] dump_stack+0x80/0xc4 [] panic+0xe0/0x220 [] _submit_bh+0x18c/0x1e0 [] __sync_dirty_buffer+0x6c/0xfc [] sync_dirty_buffer+0xc/0x18 [] ext2_sync_super+0xa8/0xbc [] ext2_sync_fs+0x58/0x70 [] sync_filesystem+0x80/0xb0 [] generic_shutdown_super+0x2c/0xd8 [] kill_block_super+0x1c/0x70 [] deactivate_locked_super+0x54/0x84 [] deactivate_super+0x8c/0x9c [] cleanup_mnt+0x38/0x84 [] __cleanup_mnt+0xc/0x18 [] task_work_run+0x94/0xec [] do_notify_resume+0x54/0x68 ---[ end Kernel panic - not syncing: BUG! The problem is caused by: CPU0 CPU1 t1: bdput t2: mount /dev/zram0 /mnt t3: zram_reset_device At time 3: the mounted filesystem will be corrputed by CPU0, oops will happen when admin umounts /mnt or reset linux system. This patch uses bdev->bd_mutex to prevent concurrent visit of /dev/zram0. Signed-off-by: Ganesh Mahendran Cc: Nitin Gupta Cc: Minchan Kim Cc: Sergey Senozhatsky --- drivers/block/zram/zram_drv.c | 79 ++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index aa5a4c5..2b6b0dc 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -717,17 +717,35 @@ static void zram_bio_discard(struct zram *zram, u32 index, } } -static void zram_reset_device(struct zram *zram, bool reset_capacity) +static int zram_reset_device(struct zram *zram, bool reset_capacity) { - down_write(&zram->init_lock); + int ret; + struct block_device *bdev; - zram->limit_pages = 0; + bdev = bdget_disk(zram->disk, 0); + if (!bdev) + return -ENOMEM; + + mutex_lock(&bdev->bd_mutex); + + /* Do not reset an active device! */ + if (bdev->bd_holders) { + ret = -EBUSY; + goto err; + } + + /* Make sure all pending I/O is finished */ + fsync_bdev(bdev); + + down_write(&zram->init_lock); if (!init_done(zram)) { - up_write(&zram->init_lock); - return; + ret = -EIO; + goto err_init_done; } + zram->limit_pages = 0; + zcomp_destroy(zram->comp); zram->max_comp_streams = 1; zram_meta_free(zram->meta, zram->disksize); @@ -740,6 +758,8 @@ static void zram_reset_device(struct zram *zram, bool reset_capacity) set_capacity(zram->disk, 0); up_write(&zram->init_lock); + mutex_unlock(&bdev->bd_mutex); + bdput(bdev); /* * Revalidate disk out of the init_lock to avoid lockdep splat. @@ -748,6 +768,16 @@ static void zram_reset_device(struct zram *zram, bool reset_capacity) */ if (reset_capacity) revalidate_disk(zram->disk); + + return 0; + +err_init_done: + up_write(&zram->init_lock); +err: + mutex_unlock(&bdev->bd_mutex); + bdput(bdev); + + return ret; } static ssize_t disksize_store(struct device *dev, @@ -811,40 +841,19 @@ static ssize_t reset_store(struct device *dev, { int ret; unsigned short do_reset; - struct zram *zram; - struct block_device *bdev; - - zram = dev_to_zram(dev); - bdev = bdget_disk(zram->disk, 0); - - if (!bdev) - return -ENOMEM; - - /* Do not reset an active device! */ - if (bdev->bd_holders) { - ret = -EBUSY; - goto out; - } ret = kstrtou16(buf, 10, &do_reset); if (ret) - goto out; + return ret; - if (!do_reset) { - ret = -EINVAL; - goto out; - } + if (!do_reset) + return -EINVAL; - /* Make sure all pending I/O is finished */ - fsync_bdev(bdev); - bdput(bdev); + ret = zram_reset_device(dev_to_zram(dev), true); + if (ret) + return ret; - zram_reset_device(zram, true); return len; - -out: - bdput(bdev); - return ret; } static void __zram_make_request(struct zram *zram, struct bio *bio) @@ -1183,12 +1192,8 @@ static void __exit zram_exit(void) for (i = 0; i < num_devices; i++) { zram = &zram_devices[i]; - destroy_device(zram); - /* - * Shouldn't access zram->disk after destroy_device - * because destroy_device already released zram->disk. - */ zram_reset_device(zram, false); + destroy_device(zram); } unregister_blkdev(zram_major, "zram"); -- 1.7.9.5