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

Commit 2110cf02 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus' of git://git.kernel.dk/linux-block

Pull block layer updates from Jens Axboe:
 "I've got a few bits pending for 3.8 final, that I better get sent out.
  It's all been sitting for a while, I consider it safe.

  It contains:

   - Two bug fixes for mtip32xx, fixing a driver hang and a crash.

   - A few-liner protocol error fix for drbd.

   - A few fixes for the xen block front/back driver, fixing a potential
     data corruption issue.

   - A race fix for disk_clear_events(), causing spurious warnings.  Out
     of the Chrome OS base.

   - A deadlock fix for disk_clear_events(), moving it to the a
     unfreezable workqueue.  Also from the Chrome OS base."

* 'for-linus' of git://git.kernel.dk/linux-block:
  drbd: fix potential protocol error and resulting disconnect/reconnect
  mtip32xx: fix for crash when the device surprise removed during rebuild
  mtip32xx: fix for driver hang after a command timeout
  block: prevent race/cleanup
  block: remove deadlock in disk_clear_events
  xen-blkfront: handle bvecs with partial data
  llist/xen-blkfront: implement safe version of llist_for_each_entry
  xen-blkback: implement safe iterator for the list of persistent grants
parents 1589a3e7 1383923d
Loading
Loading
Loading
Loading
+32 −10
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ static DEFINE_IDR(ext_devt_idr);

static struct device_type disk_type;

static void disk_check_events(struct disk_events *ev,
			      unsigned int *clearing_ptr);
static void disk_alloc_events(struct gendisk *disk);
static void disk_add_events(struct gendisk *disk);
static void disk_del_events(struct gendisk *disk);
@@ -1549,6 +1551,7 @@ unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask)
	const struct block_device_operations *bdops = disk->fops;
	struct disk_events *ev = disk->ev;
	unsigned int pending;
	unsigned int clearing = mask;

	if (!ev) {
		/* for drivers still using the old ->media_changed method */
@@ -1558,34 +1561,53 @@ unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask)
		return 0;
	}

	/* tell the workfn about the events being cleared */
	disk_block_events(disk);

	/*
	 * store the union of mask and ev->clearing on the stack so that the
	 * race with disk_flush_events does not cause ambiguity (ev->clearing
	 * can still be modified even if events are blocked).
	 */
	spin_lock_irq(&ev->lock);
	ev->clearing |= mask;
	clearing |= ev->clearing;
	ev->clearing = 0;
	spin_unlock_irq(&ev->lock);

	/* uncondtionally schedule event check and wait for it to finish */
	disk_block_events(disk);
	queue_delayed_work(system_freezable_wq, &ev->dwork, 0);
	flush_delayed_work(&ev->dwork);
	__disk_unblock_events(disk, false);
	disk_check_events(ev, &clearing);
	/*
	 * if ev->clearing is not 0, the disk_flush_events got called in the
	 * middle of this function, so we want to run the workfn without delay.
	 */
	__disk_unblock_events(disk, ev->clearing ? true : false);

	/* then, fetch and clear pending events */
	spin_lock_irq(&ev->lock);
	WARN_ON_ONCE(ev->clearing & mask);	/* cleared by workfn */
	pending = ev->pending & mask;
	ev->pending &= ~mask;
	spin_unlock_irq(&ev->lock);
	WARN_ON_ONCE(clearing & mask);

	return pending;
}

/*
 * Separate this part out so that a different pointer for clearing_ptr can be
 * passed in for disk_clear_events.
 */
static void disk_events_workfn(struct work_struct *work)
{
	struct delayed_work *dwork = to_delayed_work(work);
	struct disk_events *ev = container_of(dwork, struct disk_events, dwork);

	disk_check_events(ev, &ev->clearing);
}

static void disk_check_events(struct disk_events *ev,
			      unsigned int *clearing_ptr)
{
	struct gendisk *disk = ev->disk;
	char *envp[ARRAY_SIZE(disk_uevents) + 1] = { };
	unsigned int clearing = ev->clearing;
	unsigned int clearing = *clearing_ptr;
	unsigned int events;
	unsigned long intv;
	int nr_events = 0, i;
@@ -1598,7 +1620,7 @@ static void disk_events_workfn(struct work_struct *work)

	events &= ~ev->pending;
	ev->pending |= events;
	ev->clearing &= ~clearing;
	*clearing_ptr &= ~clearing;

	intv = disk_events_poll_jiffies(disk);
	if (!ev->block && intv)
+1 −1
Original line number Diff line number Diff line
@@ -168,7 +168,7 @@ static void wake_all_senders(struct drbd_tconn *tconn) {
}

/* must hold resource->req_lock */
static void start_new_tl_epoch(struct drbd_tconn *tconn)
void start_new_tl_epoch(struct drbd_tconn *tconn)
{
	/* no point closing an epoch, if it is empty, anyways. */
	if (tconn->current_tle_writes == 0)
+1 −0
Original line number Diff line number Diff line
@@ -267,6 +267,7 @@ struct bio_and_error {
	int error;
};

extern void start_new_tl_epoch(struct drbd_tconn *tconn);
extern void drbd_req_destroy(struct kref *kref);
extern void _req_may_be_done(struct drbd_request *req,
		struct bio_and_error *m);
+7 −0
Original line number Diff line number Diff line
@@ -931,6 +931,7 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
	enum drbd_state_rv rv = SS_SUCCESS;
	enum sanitize_state_warnings ssw;
	struct after_state_chg_work *ascw;
	bool did_remote, should_do_remote;

	os = drbd_read_state(mdev);

@@ -981,11 +982,17 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
	    (os.disk != D_DISKLESS && ns.disk == D_DISKLESS))
		atomic_inc(&mdev->local_cnt);

	did_remote = drbd_should_do_remote(mdev->state);
	mdev->state.i = ns.i;
	should_do_remote = drbd_should_do_remote(mdev->state);
	mdev->tconn->susp = ns.susp;
	mdev->tconn->susp_nod = ns.susp_nod;
	mdev->tconn->susp_fen = ns.susp_fen;

	/* put replicated vs not-replicated requests in seperate epochs */
	if (did_remote != should_do_remote)
		start_new_tl_epoch(mdev->tconn);

	if (os.disk == D_ATTACHING && ns.disk >= D_NEGOTIATING)
		drbd_print_uuids(mdev, "attached to UUIDs");

+18 −6
Original line number Diff line number Diff line
@@ -626,13 +626,14 @@ static void mtip_timeout_function(unsigned long int data)
		}
	}

	if (cmdto_cnt && !test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) {
	if (cmdto_cnt) {
		print_tags(port->dd, "timed out", tagaccum, cmdto_cnt);

		if (!test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) {
			mtip_restart_port(port);
		clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags);
			wake_up_interruptible(&port->svc_wait);
		}
		clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags);
	}

	if (port->ic_pause_timer) {
		to  = port->ic_pause_timer + msecs_to_jiffies(1000);
@@ -3887,7 +3888,12 @@ static int mtip_block_remove(struct driver_data *dd)
	 * Delete our gendisk structure. This also removes the device
	 * from /dev
	 */
	if (dd->disk) {
		if (dd->disk->queue)
			del_gendisk(dd->disk);
		else
			put_disk(dd->disk);
	}

	spin_lock(&rssd_index_lock);
	ida_remove(&rssd_index_ida, dd->index);
@@ -3921,7 +3927,13 @@ static int mtip_block_shutdown(struct driver_data *dd)
		"Shutting down %s ...\n", dd->disk->disk_name);

	/* Delete our gendisk structure, and cleanup the blk queue. */
	if (dd->disk) {
		if (dd->disk->queue)
			del_gendisk(dd->disk);
		else
			put_disk(dd->disk);
	}


	spin_lock(&rssd_index_lock);
	ida_remove(&rssd_index_ida, dd->index);
Loading