Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit af209e0a authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus' of git://neil.brown.name/md

* 'for-linus' of git://neil.brown.name/md:
  md: raid5 crash during degradation
  md/raid5: never wait for bad-block acks on failed device.
  md: ensure new badblocks are handled promptly.
  md: bad blocks shouldn't cause a Blocked status on a Faulty device.
  md: take a reference to mddev during sysfs access.
  md: refine interpretation of "hold_active == UNTIL_IOCTL".
  md/lock: ensure updates to page_attrs are properly locked.
parents 53523d52 5d8c71f9
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -1106,10 +1106,12 @@ void bitmap_write_all(struct bitmap *bitmap)
	 */
	 */
	int i;
	int i;


	spin_lock_irq(&bitmap->lock);
	for (i = 0; i < bitmap->file_pages; i++)
	for (i = 0; i < bitmap->file_pages; i++)
		set_page_attr(bitmap, bitmap->filemap[i],
		set_page_attr(bitmap, bitmap->filemap[i],
			      BITMAP_PAGE_NEEDWRITE);
			      BITMAP_PAGE_NEEDWRITE);
	bitmap->allclean = 0;
	bitmap->allclean = 0;
	spin_unlock_irq(&bitmap->lock);
}
}


static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc)
static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc)
@@ -1605,7 +1607,9 @@ void bitmap_dirty_bits(struct bitmap *bitmap, unsigned long s, unsigned long e)
	for (chunk = s; chunk <= e; chunk++) {
	for (chunk = s; chunk <= e; chunk++) {
		sector_t sec = (sector_t)chunk << CHUNK_BLOCK_SHIFT(bitmap);
		sector_t sec = (sector_t)chunk << CHUNK_BLOCK_SHIFT(bitmap);
		bitmap_set_memory_bits(bitmap, sec, 1);
		bitmap_set_memory_bits(bitmap, sec, 1);
		spin_lock_irq(&bitmap->lock);
		bitmap_file_set_bit(bitmap, sec);
		bitmap_file_set_bit(bitmap, sec);
		spin_unlock_irq(&bitmap->lock);
		if (sec < bitmap->mddev->recovery_cp)
		if (sec < bitmap->mddev->recovery_cp)
			/* We are asserting that the array is dirty,
			/* We are asserting that the array is dirty,
			 * so move the recovery_cp address back so
			 * so move the recovery_cp address back so
+23 −4
Original line number Original line Diff line number Diff line
@@ -570,7 +570,7 @@ static void mddev_put(struct mddev *mddev)
	    mddev->ctime == 0 && !mddev->hold_active) {
	    mddev->ctime == 0 && !mddev->hold_active) {
		/* Array is not configured at all, and not held active,
		/* Array is not configured at all, and not held active,
		 * so destroy it */
		 * so destroy it */
		list_del(&mddev->all_mddevs);
		list_del_init(&mddev->all_mddevs);
		bs = mddev->bio_set;
		bs = mddev->bio_set;
		mddev->bio_set = NULL;
		mddev->bio_set = NULL;
		if (mddev->gendisk) {
		if (mddev->gendisk) {
@@ -2546,7 +2546,8 @@ state_show(struct md_rdev *rdev, char *page)
		sep = ",";
		sep = ",";
	}
	}
	if (test_bit(Blocked, &rdev->flags) ||
	if (test_bit(Blocked, &rdev->flags) ||
	    rdev->badblocks.unacked_exist) {
	    (rdev->badblocks.unacked_exist
	     && !test_bit(Faulty, &rdev->flags))) {
		len += sprintf(page+len, "%sblocked", sep);
		len += sprintf(page+len, "%sblocked", sep);
		sep = ",";
		sep = ",";
	}
	}
@@ -3788,6 +3789,8 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
	if (err)
	if (err)
		return err;
		return err;
	else {
	else {
		if (mddev->hold_active == UNTIL_IOCTL)
			mddev->hold_active = 0;
		sysfs_notify_dirent_safe(mddev->sysfs_state);
		sysfs_notify_dirent_safe(mddev->sysfs_state);
		return len;
		return len;
	}
	}
@@ -4487,11 +4490,20 @@ md_attr_show(struct kobject *kobj, struct attribute *attr, char *page)


	if (!entry->show)
	if (!entry->show)
		return -EIO;
		return -EIO;
	spin_lock(&all_mddevs_lock);
	if (list_empty(&mddev->all_mddevs)) {
		spin_unlock(&all_mddevs_lock);
		return -EBUSY;
	}
	mddev_get(mddev);
	spin_unlock(&all_mddevs_lock);

	rv = mddev_lock(mddev);
	rv = mddev_lock(mddev);
	if (!rv) {
	if (!rv) {
		rv = entry->show(mddev, page);
		rv = entry->show(mddev, page);
		mddev_unlock(mddev);
		mddev_unlock(mddev);
	}
	}
	mddev_put(mddev);
	return rv;
	return rv;
}
}


@@ -4507,13 +4519,19 @@ md_attr_store(struct kobject *kobj, struct attribute *attr,
		return -EIO;
		return -EIO;
	if (!capable(CAP_SYS_ADMIN))
	if (!capable(CAP_SYS_ADMIN))
		return -EACCES;
		return -EACCES;
	spin_lock(&all_mddevs_lock);
	if (list_empty(&mddev->all_mddevs)) {
		spin_unlock(&all_mddevs_lock);
		return -EBUSY;
	}
	mddev_get(mddev);
	spin_unlock(&all_mddevs_lock);
	rv = mddev_lock(mddev);
	rv = mddev_lock(mddev);
	if (mddev->hold_active == UNTIL_IOCTL)
		mddev->hold_active = 0;
	if (!rv) {
	if (!rv) {
		rv = entry->store(mddev, page, length);
		rv = entry->store(mddev, page, length);
		mddev_unlock(mddev);
		mddev_unlock(mddev);
	}
	}
	mddev_put(mddev);
	return rv;
	return rv;
}
}


@@ -7840,6 +7858,7 @@ int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
				  s + rdev->data_offset, sectors, acknowledged);
				  s + rdev->data_offset, sectors, acknowledged);
	if (rv) {
	if (rv) {
		/* Make sure they get written out promptly */
		/* Make sure they get written out promptly */
		sysfs_notify_dirent_safe(rdev->sysfs_state);
		set_bit(MD_CHANGE_CLEAN, &rdev->mddev->flags);
		set_bit(MD_CHANGE_CLEAN, &rdev->mddev->flags);
		md_wakeup_thread(rdev->mddev->thread);
		md_wakeup_thread(rdev->mddev->thread);
	}
	}
+5 −3
Original line number Original line Diff line number Diff line
@@ -3036,6 +3036,8 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s)
		if (dev->written)
		if (dev->written)
			s->written++;
			s->written++;
		rdev = rcu_dereference(conf->disks[i].rdev);
		rdev = rcu_dereference(conf->disks[i].rdev);
		if (rdev && test_bit(Faulty, &rdev->flags))
			rdev = NULL;
		if (rdev) {
		if (rdev) {
			is_bad = is_badblock(rdev, sh->sector, STRIPE_SECTORS,
			is_bad = is_badblock(rdev, sh->sector, STRIPE_SECTORS,
					     &first_bad, &bad_sectors);
					     &first_bad, &bad_sectors);
@@ -3063,12 +3065,12 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s)
			}
			}
		} else if (test_bit(In_sync, &rdev->flags))
		} else if (test_bit(In_sync, &rdev->flags))
			set_bit(R5_Insync, &dev->flags);
			set_bit(R5_Insync, &dev->flags);
		else if (!test_bit(Faulty, &rdev->flags)) {
		else {
			/* in sync if before recovery_offset */
			/* in sync if before recovery_offset */
			if (sh->sector + STRIPE_SECTORS <= rdev->recovery_offset)
			if (sh->sector + STRIPE_SECTORS <= rdev->recovery_offset)
				set_bit(R5_Insync, &dev->flags);
				set_bit(R5_Insync, &dev->flags);
		}
		}
		if (test_bit(R5_WriteError, &dev->flags)) {
		if (rdev && test_bit(R5_WriteError, &dev->flags)) {
			clear_bit(R5_Insync, &dev->flags);
			clear_bit(R5_Insync, &dev->flags);
			if (!test_bit(Faulty, &rdev->flags)) {
			if (!test_bit(Faulty, &rdev->flags)) {
				s->handle_bad_blocks = 1;
				s->handle_bad_blocks = 1;
@@ -3076,7 +3078,7 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s)
			} else
			} else
				clear_bit(R5_WriteError, &dev->flags);
				clear_bit(R5_WriteError, &dev->flags);
		}
		}
		if (test_bit(R5_MadeGood, &dev->flags)) {
		if (rdev && test_bit(R5_MadeGood, &dev->flags)) {
			if (!test_bit(Faulty, &rdev->flags)) {
			if (!test_bit(Faulty, &rdev->flags)) {
				s->handle_bad_blocks = 1;
				s->handle_bad_blocks = 1;
				atomic_inc(&rdev->nr_pending);
				atomic_inc(&rdev->nr_pending);