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

Commit 07b05bcc authored by Dennis Zhou (Facebook)'s avatar Dennis Zhou (Facebook) Committed by Jens Axboe
Browse files

blkcg: convert blkg_lookup_create to find closest blkg



There are several scenarios where blkg_lookup_create can fail. Examples
include the blkcg dying, request_queue is dying, or simply being OOM. At
the end of the day, most handle this by simply falling back to the
q->root_blkg and calling it a day.

This patch implements the notion of closest blkg. During
blkg_lookup_create, if it fails to create, return the closest blkg
found or the q->root_blkg. blkg_try_get_closest is introduced and used
during association so a bio is always attached to a blkg.

Acked-by: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarDennis Zhou <dennisszhou@gmail.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 49f4c2dc
Loading
Loading
Loading
Loading
+10 −7
Original line number Diff line number Diff line
@@ -2007,21 +2007,24 @@ int bio_associate_blkcg(struct bio *bio, struct cgroup_subsys_state *blkcg_css)
EXPORT_SYMBOL_GPL(bio_associate_blkcg);

/**
 * bio_associate_blkg - associate a bio with the specified blkg
 * bio_associate_blkg - associate a bio with the a blkg
 * @bio: target bio
 * @blkg: the blkg to associate
 *
 * Associate @bio with the blkg specified by @blkg.  This is the queue specific
 * blkcg information associated with the @bio, a reference will be taken on the
 * @blkg and will be freed when the bio is freed.
 * This tries to associate @bio with the specified blkg.  Association failure
 * is handled by walking up the blkg tree.  Therefore, the blkg associated can
 * be anything between @blkg and the root_blkg.  This situation only happens
 * when a cgroup is dying and then the remaining bios will spill to the closest
 * alive blkg.
 *
 * A reference will be taken on the @blkg and will be released when @bio is
 * freed.
 */
int bio_associate_blkg(struct bio *bio, struct blkcg_gq *blkg)
{
	if (unlikely(bio->bi_blkg))
		return -EBUSY;
	if (!blkg_try_get(blkg))
		return -ENODEV;
	bio->bi_blkg = blkg;
	bio->bi_blkg = blkg_try_get_closest(blkg);
	return 0;
}

+17 −8
Original line number Diff line number Diff line
@@ -268,9 +268,8 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg,
 * that all non-root blkg's have access to the parent blkg.  This function
 * should be called under RCU read lock and @q->queue_lock.
 *
 * Returns pointer to the looked up or created blkg on success, ERR_PTR()
 * value on error.  If @q is dead, returns ERR_PTR(-EINVAL).  If @q is not
 * dead and bypassing, returns ERR_PTR(-EBUSY).
 * Returns the blkg or the closest blkg if blkg_create fails as it walks
 * down from root.
 */
struct blkcg_gq *__blkg_lookup_create(struct blkcg *blkcg,
				      struct request_queue *q)
@@ -285,7 +284,7 @@ struct blkcg_gq *__blkg_lookup_create(struct blkcg *blkcg,
	 * we shouldn't allow anything to go through for a bypassing queue.
	 */
	if (unlikely(blk_queue_bypass(q)))
		return ERR_PTR(blk_queue_dying(q) ? -ENODEV : -EBUSY);
		return q->root_blkg;

	blkg = __blkg_lookup(blkcg, q, true);
	if (blkg)
@@ -293,19 +292,29 @@ struct blkcg_gq *__blkg_lookup_create(struct blkcg *blkcg,

	/*
	 * Create blkgs walking down from blkcg_root to @blkcg, so that all
	 * non-root blkgs have access to their parents.
	 * non-root blkgs have access to their parents.  Returns the closest
	 * blkg to the intended blkg should blkg_create() fail.
	 */
	while (true) {
		struct blkcg *pos = blkcg;
		struct blkcg *parent = blkcg_parent(blkcg);
		struct blkcg_gq *ret_blkg = q->root_blkg;

		while (parent && !__blkg_lookup(parent, q, false)) {
		while (parent) {
			blkg = __blkg_lookup(parent, q, false);
			if (blkg) {
				/* remember closest blkg */
				ret_blkg = blkg;
				break;
			}
			pos = parent;
			parent = blkcg_parent(parent);
		}

		blkg = blkg_create(pos, q, NULL);
		if (pos == blkcg || IS_ERR(blkg))
		if (IS_ERR(blkg))
			return ret_blkg;
		if (pos == blkcg)
			return blkg;
	}
}
+14 −0
Original line number Diff line number Diff line
@@ -549,6 +549,20 @@ static inline struct blkcg_gq *blkg_try_get(struct blkcg_gq *blkg)
	return NULL;
}

/**
 * blkg_try_get_closest - try and get a blkg ref on the closet blkg
 * @blkg: blkg to get
 *
 * This walks up the blkg tree to find the closest non-dying blkg and returns
 * the blkg that it did association with as it may not be the passed in blkg.
 */
static inline struct blkcg_gq *blkg_try_get_closest(struct blkcg_gq *blkg)
{
	while (!atomic_inc_not_zero(&blkg->refcnt))
		blkg = blkg->parent;

	return blkg;
}

void __blkg_release_rcu(struct rcu_head *rcu);