blkcg: update blkg_lookup_create() to do locking
[sfrench/cifs-2.6.git] / include / linux / blk-cgroup.h
index 1e76ceebeb5dc58c7f98e9f1d18d65fbe62477ef..b3b1a8187d23271da15e3ac8ae22419a3e54e471 100644 (file)
@@ -122,11 +122,8 @@ struct blkcg_gq {
        /* all non-root blkcg_gq's are guaranteed to have access to parent */
        struct blkcg_gq                 *parent;
 
-       /* request allocation list for this blkcg-q pair */
-       struct request_list             rl;
-
        /* reference count */
-       struct percpu_ref               refcnt;
+       atomic_t                        refcnt;
 
        /* is this blkg online? protected by both blkcg and q locks */
        bool                            online;
@@ -249,26 +246,70 @@ static inline struct cgroup_subsys_state *blkcg_css(void)
        return task_css(current, io_cgrp_id);
 }
 
+/**
+ * blkcg_get_css - find and get a reference to the css
+ *
+ * Find the css associated with either the kthread or the current task.
+ * This takes a reference on the blkcg which will need to be managed by the
+ * caller.
+ */
+static inline struct cgroup_subsys_state *blkcg_get_css(void)
+{
+       struct cgroup_subsys_state *css;
+
+       rcu_read_lock();
+
+       css = kthread_blkcg();
+       if (css) {
+               css_get(css);
+       } else {
+               /*
+                * This is a bit complicated.  It is possible task_css() is
+                * seeing an old css pointer here.  This is caused by the
+                * current thread migrating away from this cgroup and this
+                * cgroup dying.  css_tryget() will fail when trying to take a
+                * ref on a cgroup that's ref count has hit 0.
+                *
+                * Therefore, if it does fail, this means current must have
+                * been swapped away already and this is waiting for it to
+                * propagate on the polling cpu.  Hence the use of cpu_relax().
+                */
+               while (true) {
+                       css = task_css(current, io_cgrp_id);
+                       if (likely(css_tryget(css)))
+                               break;
+                       cpu_relax();
+               }
+       }
+
+       rcu_read_unlock();
+
+       return css;
+}
+
 static inline struct blkcg *css_to_blkcg(struct cgroup_subsys_state *css)
 {
        return css ? container_of(css, struct blkcg, css) : NULL;
 }
 
 /**
- * __bio_blkcg - internal version of bio_blkcg for bfq and cfq
+ * __bio_blkcg - internal, inconsistent version to get blkcg
  *
  * DO NOT USE.
- * There is a flaw using this version of the function.  In particular, this was
- * used in a broken paradigm where association was called on the given css.  It
- * is possible though that the returned css from task_css() is in the process
- * of dying due to migration of the current task.  So it is improper to assume
- * *_get() is going to succeed.  Both BFQ and CFQ rely on this logic and will
- * take additional work to handle more gracefully.
+ * This function is inconsistent and consequently is dangerous to use.  The
+ * first part of the function returns a blkcg where a reference is owned by the
+ * bio.  This means it does not need to be rcu protected as it cannot go away
+ * with the bio owning a reference to it.  However, the latter potentially gets
+ * it from task_css().  This can race against task migration and the cgroup
+ * dying.  It is also semantically different as it must be called rcu protected
+ * and is susceptible to failure when trying to get a reference to it.
+ * Therefore, it is not ok to assume that *_get() will always succeed on the
+ * blkcg returned here.
  */
 static inline struct blkcg *__bio_blkcg(struct bio *bio)
 {
-       if (bio && bio->bi_blkg)
-               return bio->bi_blkg->blkcg;
+       if (bio && bio->bi_css)
+               return css_to_blkcg(bio->bi_css);
        return css_to_blkcg(blkcg_css());
 }
 
@@ -276,14 +317,14 @@ static inline struct blkcg *__bio_blkcg(struct bio *bio)
  * bio_blkcg - grab the blkcg associated with a bio
  * @bio: target bio
  *
- * This returns the blkcg associated with a bio, NULL if not associated.
- * Callers are expected to either handle NULL or know association has been
+ * This returns the blkcg associated with a bio, %NULL if not associated.
+ * Callers are expected to either handle %NULL or know association has been
  * done prior to calling this.
  */
 static inline struct blkcg *bio_blkcg(struct bio *bio)
 {
-       if (bio && bio->bi_blkg)
-               return bio->bi_blkg->blkcg;
+       if (bio && bio->bi_css)
+               return css_to_blkcg(bio->bi_css);
        return NULL;
 }
 
@@ -367,16 +408,12 @@ static inline struct blkcg_gq *__blkg_lookup(struct blkcg *blkcg,
  * @q: request_queue of interest
  *
  * Lookup blkg for the @blkcg - @q pair.  This function should be called
- * under RCU read lock and is guaranteed to return %NULL if @q is bypassing
- * - see blk_queue_bypass_start() for details.
+ * under RCU read loc.
  */
 static inline struct blkcg_gq *blkg_lookup(struct blkcg *blkcg,
                                           struct request_queue *q)
 {
        WARN_ON_ONCE(!rcu_read_lock_held());
-
-       if (unlikely(blk_queue_bypass(q)))
-               return NULL;
        return __blkg_lookup(blkcg, q, false);
 }
 
@@ -490,35 +527,26 @@ static inline int blkg_path(struct blkcg_gq *blkg, char *buf, int buflen)
  */
 static inline void blkg_get(struct blkcg_gq *blkg)
 {
-       percpu_ref_get(&blkg->refcnt);
+       WARN_ON_ONCE(atomic_read(&blkg->refcnt) <= 0);
+       atomic_inc(&blkg->refcnt);
 }
 
 /**
- * blkg_tryget - try and get a blkg reference
+ * blkg_try_get - try and get a blkg reference
  * @blkg: blkg to get
  *
  * This is for use when doing an RCU lookup of the blkg.  We may be in the midst
  * of freeing this blkg, so we can only use it if the refcnt is not zero.
  */
-static inline bool blkg_tryget(struct blkcg_gq *blkg)
+static inline struct blkcg_gq *blkg_try_get(struct blkcg_gq *blkg)
 {
-       return percpu_ref_tryget(&blkg->refcnt);
+       if (atomic_inc_not_zero(&blkg->refcnt))
+               return blkg;
+       return NULL;
 }
 
-/**
- * blkg_tryget_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_tryget_closest(struct blkcg_gq *blkg)
-{
-       while (!percpu_ref_tryget(&blkg->refcnt))
-               blkg = blkg->parent;
 
-       return blkg;
-}
+void __blkg_release_rcu(struct rcu_head *rcu);
 
 /**
  * blkg_put - put a blkg reference
@@ -526,7 +554,9 @@ static inline struct blkcg_gq *blkg_tryget_closest(struct blkcg_gq *blkg)
  */
 static inline void blkg_put(struct blkcg_gq *blkg)
 {
-       percpu_ref_put(&blkg->refcnt);
+       WARN_ON_ONCE(atomic_read(&blkg->refcnt) <= 0);
+       if (atomic_dec_and_test(&blkg->refcnt))
+               call_rcu(&blkg->rcu_head, __blkg_release_rcu);
 }
 
 /**
@@ -561,105 +591,6 @@ static inline void blkg_put(struct blkcg_gq *blkg)
                if (((d_blkg) = __blkg_lookup(css_to_blkcg(pos_css),    \
                                              (p_blkg)->q, false)))
 
-/**
- * blk_get_rl - get request_list to use
- * @q: request_queue of interest
- * @bio: bio which will be attached to the allocated request (may be %NULL)
- *
- * The caller wants to allocate a request from @q to use for @bio.  Find
- * the request_list to use and obtain a reference on it.  Should be called
- * under queue_lock.  This function is guaranteed to return non-%NULL
- * request_list.
- */
-static inline struct request_list *blk_get_rl(struct request_queue *q,
-                                             struct bio *bio)
-{
-       struct blkcg *blkcg;
-       struct blkcg_gq *blkg;
-
-       rcu_read_lock();
-
-       if (bio && bio->bi_blkg) {
-               blkcg = bio->bi_blkg->blkcg;
-               if (blkcg == &blkcg_root)
-                       goto rl_use_root;
-
-               blkg_get(bio->bi_blkg);
-               rcu_read_unlock();
-               return &bio->bi_blkg->rl;
-       }
-
-       blkcg = css_to_blkcg(blkcg_css());
-       if (blkcg == &blkcg_root)
-               goto rl_use_root;
-
-       blkg = blkg_lookup(blkcg, q);
-       if (unlikely(!blkg))
-               blkg = __blkg_lookup_create(blkcg, q);
-
-       if (blkg->blkcg == &blkcg_root || !blkg_tryget(blkg))
-               goto rl_use_root;
-
-       rcu_read_unlock();
-       return &blkg->rl;
-
-       /*
-        * Each blkg has its own request_list, however, the root blkcg
-        * uses the request_queue's root_rl.  This is to avoid most
-        * overhead for the root blkcg.
-        */
-rl_use_root:
-       rcu_read_unlock();
-       return &q->root_rl;
-}
-
-/**
- * blk_put_rl - put request_list
- * @rl: request_list to put
- *
- * Put the reference acquired by blk_get_rl().  Should be called under
- * queue_lock.
- */
-static inline void blk_put_rl(struct request_list *rl)
-{
-       if (rl->blkg->blkcg != &blkcg_root)
-               blkg_put(rl->blkg);
-}
-
-/**
- * blk_rq_set_rl - associate a request with a request_list
- * @rq: request of interest
- * @rl: target request_list
- *
- * Associate @rq with @rl so that accounting and freeing can know the
- * request_list @rq came from.
- */
-static inline void blk_rq_set_rl(struct request *rq, struct request_list *rl)
-{
-       rq->rl = rl;
-}
-
-/**
- * blk_rq_rl - return the request_list a request came from
- * @rq: request of interest
- *
- * Return the request_list @rq is allocated from.
- */
-static inline struct request_list *blk_rq_rl(struct request *rq)
-{
-       return rq->rl;
-}
-
-struct request_list *__blk_queue_next_rl(struct request_list *rl,
-                                        struct request_queue *q);
-/**
- * blk_queue_for_each_rl - iterate through all request_lists of a request_queue
- *
- * Should be used under queue_lock.
- */
-#define blk_queue_for_each_rl(rl, q)   \
-       for ((rl) = &(q)->root_rl; (rl); (rl) = __blk_queue_next_rl((rl), (q)))
-
 static inline int blkg_stat_init(struct blkg_stat *stat, gfp_t gfp)
 {
        int ret;
@@ -854,26 +785,32 @@ static inline bool blk_throtl_bio(struct request_queue *q, struct blkcg_gq *blkg
                                  struct bio *bio) { return false; }
 #endif
 
-
-static inline void blkcg_bio_issue_init(struct bio *bio)
-{
-       bio_issue_init(&bio->bi_issue, bio_sectors(bio));
-}
-
 static inline bool blkcg_bio_issue_check(struct request_queue *q,
                                         struct bio *bio)
 {
+       struct blkcg *blkcg;
        struct blkcg_gq *blkg;
        bool throtl = false;
 
        rcu_read_lock();
 
-       bio_associate_create_blkg(q, bio);
-       blkg = bio->bi_blkg;
+       /* associate blkcg if bio hasn't attached one */
+       bio_associate_blkcg(bio, NULL);
+       blkcg = bio_blkcg(bio);
+
+       blkg = blkg_lookup(blkcg, q);
+       if (unlikely(!blkg)) {
+               spin_lock_irq(&q->queue_lock);
+               blkg = __blkg_lookup_create(blkcg, q);
+               if (IS_ERR(blkg))
+                       blkg = NULL;
+               spin_unlock_irq(&q->queue_lock);
+       }
 
        throtl = blk_throtl_bio(q, blkg, bio);
 
        if (!throtl) {
+               blkg = blkg ?: q->root_blkg;
                /*
                 * If the bio is flagged with BIO_QUEUE_ENTERED it means this
                 * is a split bio and we would have already accounted for the
@@ -885,8 +822,6 @@ static inline bool blkcg_bio_issue_check(struct request_queue *q,
                blkg_rwstat_add(&blkg->stat_ios, bio->bi_opf, 1);
        }
 
-       blkcg_bio_issue_init(bio);
-
        rcu_read_unlock();
        return !throtl;
 }
@@ -993,13 +928,6 @@ static inline char *blkg_path(struct blkcg_gq *blkg) { return NULL; }
 static inline void blkg_get(struct blkcg_gq *blkg) { }
 static inline void blkg_put(struct blkcg_gq *blkg) { }
 
-static inline struct request_list *blk_get_rl(struct request_queue *q,
-                                             struct bio *bio) { return &q->root_rl; }
-static inline void blk_put_rl(struct request_list *rl) { }
-static inline void blk_rq_set_rl(struct request *rq, struct request_list *rl) { }
-static inline struct request_list *blk_rq_rl(struct request *rq) { return &rq->q->root_rl; }
-
-static inline void blkcg_bio_issue_init(struct bio *bio) { }
 static inline bool blkcg_bio_issue_check(struct request_queue *q,
                                         struct bio *bio) { return true; }