Commit 36d6753b authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'block-5.15-2021-09-17' of git://git.kernel.dk/linux-block

Pull block fixes from Jens Axboe:

 - NVMe pull request via Christoph:
       - fix ANA state updates when a namespace is not present (Anton
         Eidelman)
       - nvmet: fix a width vs precision bug in
         nvmet_subsys_attr_serial_show (Dan Carpenter)
       - avoid race in shutdown namespace removal (Daniel Wagner)
       - fix io_work priority inversion in nvme-tcp (Keith Busch)
       - destroy cm id before destroy qp to avoid use after free (Ruozhu
         Li)

 - blk-integrity profile registration fixes (Christoph, Lihong)

 - blk-cgroup UAF fix (Li)

 - blk-mq tag iterator fix (Ming)

 - blkcg memory leak fix (Yanfei)

* tag 'block-5.15-2021-09-17' of git://git.kernel.dk/linux-block:
  blk-cgroup: fix UAF by grabbing blkcg lock before destroying blkg pd
  blkcg: fix memory leak in blk_iolatency_init
  nvme: remove the call to nvme_update_disk_info in nvme_ns_remove
  block: flush the integrity workqueue in blk_integrity_unregister
  block: check if a profile is actually registered in blk_integrity_unregister
  nvme-tcp: fix io_work priority inversion
  nvme-rdma: destroy cm id before destroy qp to avoid use after free
  nvme-multipath: fix ANA state updates when a namespace is not present
  nvme: avoid race in shutdown namespace removal
  nvmet: fix a width vs precision bug in nvmet_subsys_attr_serial_show()
  blk-mq: avoid to iterate over stale request
parents 7f2cd141 858560b2
Loading
Loading
Loading
Loading
+14 −4
Original line number Diff line number Diff line
@@ -1182,10 +1182,6 @@ int blkcg_init_queue(struct request_queue *q)
	if (preloaded)
		radix_tree_preload_end();

	ret = blk_iolatency_init(q);
	if (ret)
		goto err_destroy_all;

	ret = blk_ioprio_init(q);
	if (ret)
		goto err_destroy_all;
@@ -1194,6 +1190,12 @@ int blkcg_init_queue(struct request_queue *q)
	if (ret)
		goto err_destroy_all;

	ret = blk_iolatency_init(q);
	if (ret) {
		blk_throtl_exit(q);
		goto err_destroy_all;
	}

	return 0;

err_destroy_all:
@@ -1364,10 +1366,14 @@ int blkcg_activate_policy(struct request_queue *q,
	/* alloc failed, nothing's initialized yet, free everything */
	spin_lock_irq(&q->queue_lock);
	list_for_each_entry(blkg, &q->blkg_list, q_node) {
		struct blkcg *blkcg = blkg->blkcg;

		spin_lock(&blkcg->lock);
		if (blkg->pd[pol->plid]) {
			pol->pd_free_fn(blkg->pd[pol->plid]);
			blkg->pd[pol->plid] = NULL;
		}
		spin_unlock(&blkcg->lock);
	}
	spin_unlock_irq(&q->queue_lock);
	ret = -ENOMEM;
@@ -1399,12 +1405,16 @@ void blkcg_deactivate_policy(struct request_queue *q,
	__clear_bit(pol->plid, q->blkcg_pols);

	list_for_each_entry(blkg, &q->blkg_list, q_node) {
		struct blkcg *blkcg = blkg->blkcg;

		spin_lock(&blkcg->lock);
		if (blkg->pd[pol->plid]) {
			if (pol->pd_offline_fn)
				pol->pd_offline_fn(blkg->pd[pol->plid]);
			pol->pd_free_fn(blkg->pd[pol->plid]);
			blkg->pd[pol->plid] = NULL;
		}
		spin_unlock(&blkcg->lock);
	}

	spin_unlock_irq(&q->queue_lock);
+8 −1
Original line number Diff line number Diff line
@@ -426,8 +426,15 @@ EXPORT_SYMBOL(blk_integrity_register);
 */
void blk_integrity_unregister(struct gendisk *disk)
{
	struct blk_integrity *bi = &disk->queue->integrity;

	if (!bi->profile)
		return;

	/* ensure all bios are off the integrity workqueue */
	blk_flush_integrity();
	blk_queue_flag_clear(QUEUE_FLAG_STABLE_WRITES, disk->queue);
	memset(&disk->queue->integrity, 0, sizeof(struct blk_integrity));
	memset(bi, 0, sizeof(*bi));
}
EXPORT_SYMBOL(blk_integrity_unregister);

+1 −1
Original line number Diff line number Diff line
@@ -208,7 +208,7 @@ static struct request *blk_mq_find_and_get_req(struct blk_mq_tags *tags,

	spin_lock_irqsave(&tags->lock, flags);
	rq = tags->rqs[bitnr];
	if (!rq || !refcount_inc_not_zero(&rq->ref))
	if (!rq || rq->tag != bitnr || !refcount_inc_not_zero(&rq->ref))
		rq = NULL;
	spin_unlock_irqrestore(&tags->lock, flags);
	return rq;
+7 −10
Original line number Diff line number Diff line
@@ -3524,7 +3524,9 @@ static struct nvme_ns_head *nvme_find_ns_head(struct nvme_subsystem *subsys,
	lockdep_assert_held(&subsys->lock);

	list_for_each_entry(h, &subsys->nsheads, entry) {
		if (h->ns_id == nsid && nvme_tryget_ns_head(h))
		if (h->ns_id != nsid)
			continue;
		if (!list_empty(&h->list) && nvme_tryget_ns_head(h))
			return h;
	}

@@ -3843,6 +3845,10 @@ static void nvme_ns_remove(struct nvme_ns *ns)

	mutex_lock(&ns->ctrl->subsys->lock);
	list_del_rcu(&ns->siblings);
	if (list_empty(&ns->head->list)) {
		list_del_init(&ns->head->entry);
		last_path = true;
	}
	mutex_unlock(&ns->ctrl->subsys->lock);

	/* guarantee not available in head->list */
@@ -3856,20 +3862,11 @@ static void nvme_ns_remove(struct nvme_ns *ns)
		nvme_cdev_del(&ns->cdev, &ns->cdev_device);
	del_gendisk(ns->disk);
	blk_cleanup_queue(ns->queue);
	if (blk_get_integrity(ns->disk))
		blk_integrity_unregister(ns->disk);

	down_write(&ns->ctrl->namespaces_rwsem);
	list_del_init(&ns->list);
	up_write(&ns->ctrl->namespaces_rwsem);

	/* Synchronize with nvme_init_ns_head() */
	mutex_lock(&ns->head->subsys->lock);
	if (list_empty(&ns->head->list)) {
		list_del_init(&ns->head->entry);
		last_path = true;
	}
	mutex_unlock(&ns->head->subsys->lock);
	if (last_path)
		nvme_mpath_shutdown_disk(ns->head);
	nvme_put_ns(ns);
+5 −2
Original line number Diff line number Diff line
@@ -600,14 +600,17 @@ static int nvme_update_ana_state(struct nvme_ctrl *ctrl,

	down_read(&ctrl->namespaces_rwsem);
	list_for_each_entry(ns, &ctrl->namespaces, list) {
		unsigned nsid = le32_to_cpu(desc->nsids[n]);

		unsigned nsid;
again:
		nsid = le32_to_cpu(desc->nsids[n]);
		if (ns->head->ns_id < nsid)
			continue;
		if (ns->head->ns_id == nsid)
			nvme_update_ns_ana_state(desc, ns);
		if (++n == nr_nsids)
			break;
		if (ns->head->ns_id > nsid)
			goto again;
	}
	up_read(&ctrl->namespaces_rwsem);
	return 0;
Loading