public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Greg KH <gregkh@linuxfoundation.org>,
	torvalds@linux-foundation.org, akpm@linux-foundation.org,
	alan@lxorguk.ukuu.org.uk, majianpeng <majianpeng@gmail.com>,
	NeilBrown <neilb@suse.de>
Subject: [ 01/23] md: avoid crash when stopping md array races with closing other open fds.
Date: Thu, 26 Jul 2012 14:19:40 -0700	[thread overview]
Message-ID: <20120726211405.959857593@linuxfoundation.org> (raw)
In-Reply-To: <20120726211420.GA7678@kroah.com>

From: Greg KH <gregkh@linuxfoundation.org>

3.4-stable review patch.  If anyone has any objections, please let me know.

------------------

From: NeilBrown <neilb@suse.de>

commit a05b7ea03d72f36edb0cec05e8893803335c61a0 upstream.

md will refuse to stop an array if any other fd (or mounted fs) is
using it.
When any fs is unmounted of when the last open fd is closed all
pending IO will be flushed (e.g. sync_blockdev call in __blkdev_put)
so there will be no pending IO to worry about when the array is
stopped.

However in order to send the STOP_ARRAY ioctl to stop the array one
must first get and open fd on the block device.
If some fd is being used to write to the block device and it is closed
after mdadm open the block device, but before mdadm issues the
STOP_ARRAY ioctl, then there will be no last-close on the md device so
__blkdev_put will not call sync_blockdev.

If this happens, then IO can still be in-flight while md tears down
the array and bad things can happen (use-after-free and subsequent
havoc).

So in the case where do_md_stop is being called from an open file
descriptor, call sync_block after taking the mutex to ensure there
will be no new openers.

This is needed when setting a read-write device to read-only too.

Reported-by: majianpeng <majianpeng@gmail.com>
Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

---
 drivers/md/md.c |   36 +++++++++++++++++++++++-------------
 1 file changed, 23 insertions(+), 13 deletions(-)

--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -3744,8 +3744,8 @@ array_state_show(struct mddev *mddev, ch
 	return sprintf(page, "%s\n", array_states[st]);
 }
 
-static int do_md_stop(struct mddev * mddev, int ro, int is_open);
-static int md_set_readonly(struct mddev * mddev, int is_open);
+static int do_md_stop(struct mddev * mddev, int ro, struct block_device *bdev);
+static int md_set_readonly(struct mddev * mddev, struct block_device *bdev);
 static int do_md_run(struct mddev * mddev);
 static int restart_array(struct mddev *mddev);
 
@@ -3761,14 +3761,14 @@ array_state_store(struct mddev *mddev, c
 		/* stopping an active array */
 		if (atomic_read(&mddev->openers) > 0)
 			return -EBUSY;
-		err = do_md_stop(mddev, 0, 0);
+		err = do_md_stop(mddev, 0, NULL);
 		break;
 	case inactive:
 		/* stopping an active array */
 		if (mddev->pers) {
 			if (atomic_read(&mddev->openers) > 0)
 				return -EBUSY;
-			err = do_md_stop(mddev, 2, 0);
+			err = do_md_stop(mddev, 2, NULL);
 		} else
 			err = 0; /* already inactive */
 		break;
@@ -3776,7 +3776,7 @@ array_state_store(struct mddev *mddev, c
 		break; /* not supported yet */
 	case readonly:
 		if (mddev->pers)
-			err = md_set_readonly(mddev, 0);
+			err = md_set_readonly(mddev, NULL);
 		else {
 			mddev->ro = 1;
 			set_disk_ro(mddev->gendisk, 1);
@@ -3786,7 +3786,7 @@ array_state_store(struct mddev *mddev, c
 	case read_auto:
 		if (mddev->pers) {
 			if (mddev->ro == 0)
-				err = md_set_readonly(mddev, 0);
+				err = md_set_readonly(mddev, NULL);
 			else if (mddev->ro == 1)
 				err = restart_array(mddev);
 			if (err == 0) {
@@ -5124,15 +5124,17 @@ void md_stop(struct mddev *mddev)
 }
 EXPORT_SYMBOL_GPL(md_stop);
 
-static int md_set_readonly(struct mddev *mddev, int is_open)
+static int md_set_readonly(struct mddev *mddev, struct block_device *bdev)
 {
 	int err = 0;
 	mutex_lock(&mddev->open_mutex);
-	if (atomic_read(&mddev->openers) > is_open) {
+	if (atomic_read(&mddev->openers) > !!bdev) {
 		printk("md: %s still in use.\n",mdname(mddev));
 		err = -EBUSY;
 		goto out;
 	}
+	if (bdev)
+		sync_blockdev(bdev);
 	if (mddev->pers) {
 		__md_stop_writes(mddev);
 
@@ -5154,18 +5156,26 @@ out:
  *   0 - completely stop and dis-assemble array
  *   2 - stop but do not disassemble array
  */
-static int do_md_stop(struct mddev * mddev, int mode, int is_open)
+static int do_md_stop(struct mddev * mddev, int mode,
+		      struct block_device *bdev)
 {
 	struct gendisk *disk = mddev->gendisk;
 	struct md_rdev *rdev;
 
 	mutex_lock(&mddev->open_mutex);
-	if (atomic_read(&mddev->openers) > is_open ||
+	if (atomic_read(&mddev->openers) > !!bdev ||
 	    mddev->sysfs_active) {
 		printk("md: %s still in use.\n",mdname(mddev));
 		mutex_unlock(&mddev->open_mutex);
 		return -EBUSY;
 	}
+	if (bdev)
+		/* It is possible IO was issued on some other
+		 * open file which was closed before we took ->open_mutex.
+		 * As that was not the last close __blkdev_put will not
+		 * have called sync_blockdev, so we must.
+		 */
+		sync_blockdev(bdev);
 
 	if (mddev->pers) {
 		if (mddev->ro)
@@ -5239,7 +5249,7 @@ static void autorun_array(struct mddev *
 	err = do_md_run(mddev);
 	if (err) {
 		printk(KERN_WARNING "md: do_md_run() returned %d\n", err);
-		do_md_stop(mddev, 0, 0);
+		do_md_stop(mddev, 0, NULL);
 	}
 }
 
@@ -6237,11 +6247,11 @@ static int md_ioctl(struct block_device
 			goto done_unlock;
 
 		case STOP_ARRAY:
-			err = do_md_stop(mddev, 0, 1);
+			err = do_md_stop(mddev, 0, bdev);
 			goto done_unlock;
 
 		case STOP_ARRAY_RO:
-			err = md_set_readonly(mddev, 1);
+			err = md_set_readonly(mddev, bdev);
 			goto done_unlock;
 
 		case BLKROSET:



  reply	other threads:[~2012-07-26 21:20 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-07-26 21:14 [ 00/23] 3.4.7-stable review Greg KH
2012-07-26 21:19 ` Greg Kroah-Hartman [this message]
2012-07-26 21:19   ` [ 02/23] md/raid1: close some possible races on write errors during resync Greg Kroah-Hartman
2012-07-26 21:19   ` [ 03/23] cifs: always update the inode cache with the results from a FIND_* Greg Kroah-Hartman
2012-07-26 21:19   ` [ 04/23] cifs: on CONFIG_HIGHMEM machines, limit the rsize/wsize to the kmap space Greg Kroah-Hartman
2012-07-26 21:19   ` [ 05/23] target: Clean up returning errors in PR handling code Greg Kroah-Hartman
2012-07-26 21:19   ` [ 06/23] target: Fix range calculation in WRITE SAME emulation when num blocks == 0 Greg Kroah-Hartman
2012-07-26 21:19   ` [ 07/23] ntp: Fix STA_INS/DEL clearing bug Greg Kroah-Hartman
2012-07-26 21:19   ` [ 08/23] tcm_fc: Fix crash seen with aborts and large reads Greg Kroah-Hartman
2012-07-26 21:19   ` [ 09/23] ext4: fix duplicated mnt_drop_write call in EXT4_IOC_MOVE_EXT Greg Kroah-Hartman
2012-07-26 21:19   ` [ 10/23] mm: fix lost kswapd wakeup in kswapd_stop() Greg Kroah-Hartman
2012-07-26 21:19   ` [ 11/23] HID: add battery quirk for Apple Wireless ANSI Greg Kroah-Hartman
2012-07-26 21:19   ` [ 12/23] HID: add Sennheiser BTD500USB device support Greg Kroah-Hartman
2012-07-26 21:19   ` [ 13/23] HID: multitouch: Add support for Baanto touchscreen Greg Kroah-Hartman
2012-07-26 21:19   ` [ 14/23] MIPS: Properly align the .data..init_task section Greg Kroah-Hartman
2012-07-26 21:19   ` [ 15/23] UBIFS: fix a bug in empty space fix-up Greg Kroah-Hartman
2012-07-26 21:19   ` [ 16/23] ore: Fix NFS crash by supporting any unaligned RAID IO Greg Kroah-Hartman
2012-07-26 21:19   ` [ 17/23] ore: Remove support of partial IO request (NFS crash) Greg Kroah-Hartman
2012-07-26 21:19   ` [ 18/23] pnfs-obj: dont leak objio_state if ore_write/read fails Greg Kroah-Hartman
2012-07-26 21:19   ` [ 19/23] dm thin: do not send discards to shared blocks Greg Kroah-Hartman
2012-07-26 21:19   ` [ 20/23] dm raid1: fix crash with mirror recovery and discard Greg Kroah-Hartman
2012-07-26 21:20   ` [ 21/23] dm raid1: set discard_zeroes_data_unsupported Greg Kroah-Hartman
2012-07-26 21:20   ` [ 22/23] ARM: SAMSUNG: Update default rate for xusbxti clock Greg Kroah-Hartman
2012-07-26 21:20   ` [ 23/23] cifs: when CONFIG_HIGHMEM is set, serialize the read/write kmaps Greg Kroah-Hartman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120726211405.959857593@linuxfoundation.org \
    --to=gregkh@linuxfoundation.org \
    --cc=akpm@linux-foundation.org \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=linux-kernel@vger.kernel.org \
    --cc=majianpeng@gmail.com \
    --cc=neilb@suse.de \
    --cc=stable@vger.kernel.org \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox