Hello, Overall, the approach looks good to me but please see below. On Mon, Feb 27, 2017 at 06:49:57PM -0800, Tahsin Erdogan wrote: > @@ -806,44 +807,99 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol, > if (!disk) > return -ENODEV; > if (part) { > - owner = disk->fops->owner; > - put_disk(disk); > - module_put(owner); > - return -ENODEV; > + ret = -ENODEV; > + goto fail; > + } > + > + q = disk->queue; > + > + if (!blkcg_policy_enabled(q, pol)) { > + ret = -EOPNOTSUPP; > + goto fail; Pulling this out of the queue_lock doesn't seem safe to me. This function may end up calling into callbacks of disabled policies this way. > + /* > + * Create blkgs walking down from blkcg_root to @blkcg, so that all > + * non-root blkgs have access to their parents. > + */ > + while (true) { > + struct blkcg *pos = blkcg; > + struct blkcg *parent; > + struct blkcg_gq *new_blkg; > + > + parent = blkcg_parent(blkcg); > + while (parent && !__blkg_lookup(parent, q, false)) { > + pos = parent; > + parent = blkcg_parent(parent); > + } Hmm... how about adding @new_blkg to blkg_lookup_create() and calling it with non-NULL @new_blkg until it succeeds? Wouldn't that be simpler? > + > + new_blkg = blkg_alloc(pos, q, GFP_KERNEL); > + if (unlikely(!new_blkg)) { > + ret = -ENOMEM; > + goto fail; > + } > + > + rcu_read_lock(); > + spin_lock_irq(q->queue_lock); > + > + /* Lookup again since we dropped the lock for blkg_alloc(). */ > + blkg = __blkg_lookup(pos, q, false); > + if (blkg) { > + blkg_free(new_blkg); > + } else { > + blkg = blkg_create(pos, q, new_blkg); > + if (unlikely(IS_ERR(blkg))) { > + ret = PTR_ERR(blkg); > + goto fail_unlock; > + } than duplicating the same logic here? Thanks. -- tejun