Merge branch 'for-linus' into for-3.1/core
Jens Axboe [Fri, 1 Jul 2011 14:17:13 +0000 (16:17 +0200)]
Conflicts:
block/blk-throttle.c
block/cfq-iosched.c

Signed-off-by: Jens Axboe <jaxboe@fusionio.com>

1  2 
block/blk-ioc.c
block/cfq-iosched.c
block/genhd.c
fs/partitions/check.c
include/linux/blkdev.h

diff --combined block/blk-ioc.c
@@@ -21,7 -21,7 +21,7 @@@ static void cfq_dtor(struct io_context 
        if (!hlist_empty(&ioc->cic_list)) {
                struct cfq_io_context *cic;
  
-               cic = list_entry(ioc->cic_list.first, struct cfq_io_context,
+               cic = hlist_entry(ioc->cic_list.first, struct cfq_io_context,
                                                                cic_list);
                cic->dtor(ioc);
        }
@@@ -57,7 -57,7 +57,7 @@@ static void cfq_exit(struct io_context 
        if (!hlist_empty(&ioc->cic_list)) {
                struct cfq_io_context *cic;
  
-               cic = list_entry(ioc->cic_list.first, struct cfq_io_context,
+               cic = hlist_entry(ioc->cic_list.first, struct cfq_io_context,
                                                                cic_list);
                cic->exit(ioc);
        }
@@@ -82,26 -82,26 +82,26 @@@ void exit_io_context(struct task_struc
  
  struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
  {
 -      struct io_context *ret;
 +      struct io_context *ioc;
  
 -      ret = kmem_cache_alloc_node(iocontext_cachep, gfp_flags, node);
 -      if (ret) {
 -              atomic_long_set(&ret->refcount, 1);
 -              atomic_set(&ret->nr_tasks, 1);
 -              spin_lock_init(&ret->lock);
 -              ret->ioprio_changed = 0;
 -              ret->ioprio = 0;
 -              ret->last_waited = 0; /* doesn't matter... */
 -              ret->nr_batch_requests = 0; /* because this is 0 */
 -              INIT_RADIX_TREE(&ret->radix_root, GFP_ATOMIC | __GFP_HIGH);
 -              INIT_HLIST_HEAD(&ret->cic_list);
 -              ret->ioc_data = NULL;
 +      ioc = kmem_cache_alloc_node(iocontext_cachep, gfp_flags, node);
 +      if (ioc) {
 +              atomic_long_set(&ioc->refcount, 1);
 +              atomic_set(&ioc->nr_tasks, 1);
 +              spin_lock_init(&ioc->lock);
 +              ioc->ioprio_changed = 0;
 +              ioc->ioprio = 0;
 +              ioc->last_waited = 0; /* doesn't matter... */
 +              ioc->nr_batch_requests = 0; /* because this is 0 */
 +              INIT_RADIX_TREE(&ioc->radix_root, GFP_ATOMIC | __GFP_HIGH);
 +              INIT_HLIST_HEAD(&ioc->cic_list);
 +              ioc->ioc_data = NULL;
  #if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_BLK_CGROUP_MODULE)
 -              ret->cgroup_changed = 0;
 +              ioc->cgroup_changed = 0;
  #endif
        }
  
 -      return ret;
 +      return ioc;
  }
  
  /*
@@@ -139,19 -139,19 +139,19 @@@ struct io_context *current_io_context(g
   */
  struct io_context *get_io_context(gfp_t gfp_flags, int node)
  {
 -      struct io_context *ret = NULL;
 +      struct io_context *ioc = NULL;
  
        /*
         * Check for unlikely race with exiting task. ioc ref count is
         * zero when ioc is being detached.
         */
        do {
 -              ret = current_io_context(gfp_flags, node);
 -              if (unlikely(!ret))
 +              ioc = current_io_context(gfp_flags, node);
 +              if (unlikely(!ioc))
                        break;
 -      } while (!atomic_long_inc_not_zero(&ret->refcount));
 +      } while (!atomic_long_inc_not_zero(&ioc->refcount));
  
 -      return ret;
 +      return ioc;
  }
  EXPORT_SYMBOL(get_io_context);
  
diff --combined block/cfq-iosched.c
@@@ -185,7 -185,7 +185,7 @@@ struct cfq_group 
        int nr_cfqq;
  
        /*
-        * Per group busy queus average. Useful for workload slice calc. We
+        * Per group busy queues average. Useful for workload slice calc. We
         * create the array for each prio class but at run time it is used
         * only for RT and BE class and slot for IDLE class remains unused.
         * This is primarily done to avoid confusion and a gcc warning.
@@@ -369,16 -369,16 +369,16 @@@ CFQ_CFQQ_FNS(wait_busy)
  #define cfq_log_cfqq(cfqd, cfqq, fmt, args...)        \
        blk_add_trace_msg((cfqd)->queue, "cfq%d%c %s " fmt, (cfqq)->pid, \
                        cfq_cfqq_sync((cfqq)) ? 'S' : 'A', \
-                       blkg_path(&(cfqq)->cfqg->blkg), ##args);
+                       blkg_path(&(cfqq)->cfqg->blkg), ##args)
  
  #define cfq_log_cfqg(cfqd, cfqg, fmt, args...)                                \
        blk_add_trace_msg((cfqd)->queue, "%s " fmt,                     \
-                               blkg_path(&(cfqg)->blkg), ##args);      \
+                               blkg_path(&(cfqg)->blkg), ##args)       \
  
  #else
  #define cfq_log_cfqq(cfqd, cfqq, fmt, args...)        \
        blk_add_trace_msg((cfqd)->queue, "cfq%d " fmt, (cfqq)->pid, ##args)
- #define cfq_log_cfqg(cfqd, cfqg, fmt, args...)                do {} while (0);
+ #define cfq_log_cfqg(cfqd, cfqg, fmt, args...)                do {} while (0)
  #endif
  #define cfq_log(cfqd, fmt, args...)   \
        blk_add_trace_msg((cfqd)->queue, "cfq " fmt, ##args)
@@@ -1005,8 -1005,8 +1005,8 @@@ static inline struct cfq_group *cfqg_of
        return NULL;
  }
  
 -void cfq_update_blkio_group_weight(void *key, struct blkio_group *blkg,
 -                                      unsigned int weight)
 +static void cfq_update_blkio_group_weight(void *key, struct blkio_group *blkg,
 +                                        unsigned int weight)
  {
        struct cfq_group *cfqg = cfqg_of_blkg(blkg);
        cfqg->new_weight = weight;
@@@ -1235,7 -1235,7 +1235,7 @@@ static void cfq_release_cfq_groups(stru
   * it should not be NULL as even if elevator was exiting, cgroup deltion
   * path got to it first.
   */
 -void cfq_unlink_blkio_group(void *key, struct blkio_group *blkg)
 +static void cfq_unlink_blkio_group(void *key, struct blkio_group *blkg)
  {
        unsigned long  flags;
        struct cfq_data *cfqd = key;
@@@ -1502,11 -1502,16 +1502,11 @@@ static void cfq_add_rq_rb(struct reques
  {
        struct cfq_queue *cfqq = RQ_CFQQ(rq);
        struct cfq_data *cfqd = cfqq->cfqd;
 -      struct request *__alias, *prev;
 +      struct request *prev;
  
        cfqq->queued[rq_is_sync(rq)]++;
  
 -      /*
 -       * looks a little odd, but the first insert might return an alias.
 -       * if that happens, put the alias on the dispatch list
 -       */
 -      while ((__alias = elv_rb_add(&cfqq->sort_list, rq)) != NULL)
 -              cfq_dispatch_insert(cfqd->queue, __alias);
 +      elv_rb_add(&cfqq->sort_list, rq);
  
        if (!cfq_cfqq_on_rr(cfqq))
                cfq_add_cfqq_rr(cfqd, cfqq);
@@@ -2768,11 -2773,14 +2768,14 @@@ static void __cfq_exit_single_io_contex
        smp_wmb();
        cic->key = cfqd_dead_key(cfqd);
  
+       rcu_read_lock();
        if (rcu_dereference(ioc->ioc_data) == cic) {
+               rcu_read_unlock();
                spin_lock(&ioc->lock);
                rcu_assign_pointer(ioc->ioc_data, NULL);
                spin_unlock(&ioc->lock);
-       }
+       } else
+               rcu_read_unlock();
  
        if (cic->cfqq[BLK_RW_ASYNC]) {
                cfq_exit_cfqq(cfqd, cic->cfqq[BLK_RW_ASYNC]);
@@@ -3079,7 -3087,8 +3082,8 @@@ cfq_drop_dead_cic(struct cfq_data *cfqd
  
        spin_lock_irqsave(&ioc->lock, flags);
  
-       BUG_ON(ioc->ioc_data == cic);
+       BUG_ON(rcu_dereference_check(ioc->ioc_data,
+               lockdep_is_held(&ioc->lock)) == cic);
  
        radix_tree_delete(&ioc->radix_root, cfqd->cic_index);
        hlist_del_rcu(&cic->cic_list);
@@@ -3785,9 -3794,6 +3789,6 @@@ new_queue
        return 0;
  
  queue_fail:
-       if (cic)
-               put_io_context(cic->ioc);
        cfq_schedule_dispatch(cfqd);
        spin_unlock_irqrestore(q->queue_lock, flags);
        cfq_log(cfqd, "set_request fail");
diff --combined block/genhd.c
@@@ -602,7 -602,7 +602,7 @@@ void add_disk(struct gendisk *disk
        disk->major = MAJOR(devt);
        disk->first_minor = MINOR(devt);
  
 -      /* Register BDI before referencing it from bdev */ 
 +      /* Register BDI before referencing it from bdev */
        bdi = &disk->queue->backing_dev_info;
        bdi_register_dev(bdi, disk_devt(disk));
  
@@@ -1148,7 -1148,7 +1148,7 @@@ static int diskstats_show(struct seq_fi
                                "wsect wuse running use aveq"
                                "\n\n");
        */
 - 
 +
        disk_part_iter_init(&piter, gp, DISK_PITER_INCL_EMPTY_PART0);
        while ((hd = disk_part_iter_next(&piter))) {
                cpu = part_stat_lock();
                        );
        }
        disk_part_iter_exit(&piter);
 - 
 +
        return 0;
  }
  
@@@ -1371,6 -1371,7 +1371,7 @@@ struct disk_events 
        struct gendisk          *disk;          /* the associated disk */
        spinlock_t              lock;
  
+       struct mutex            block_mutex;    /* protects blocking */
        int                     block;          /* event blocking depth */
        unsigned int            pending;        /* events already sent out */
        unsigned int            clearing;       /* events being cleared */
@@@ -1414,22 -1415,44 +1415,44 @@@ static unsigned long disk_events_poll_j
        return msecs_to_jiffies(intv_msecs);
  }
  
- static void __disk_block_events(struct gendisk *disk, bool sync)
+ /**
+  * disk_block_events - block and flush disk event checking
+  * @disk: disk to block events for
+  *
+  * On return from this function, it is guaranteed that event checking
+  * isn't in progress and won't happen until unblocked by
+  * disk_unblock_events().  Events blocking is counted and the actual
+  * unblocking happens after the matching number of unblocks are done.
+  *
+  * Note that this intentionally does not block event checking from
+  * disk_clear_events().
+  *
+  * CONTEXT:
+  * Might sleep.
+  */
+ void disk_block_events(struct gendisk *disk)
  {
        struct disk_events *ev = disk->ev;
        unsigned long flags;
        bool cancel;
  
+       if (!ev)
+               return;
+       /*
+        * Outer mutex ensures that the first blocker completes canceling
+        * the event work before further blockers are allowed to finish.
+        */
+       mutex_lock(&ev->block_mutex);
        spin_lock_irqsave(&ev->lock, flags);
        cancel = !ev->block++;
        spin_unlock_irqrestore(&ev->lock, flags);
  
-       if (cancel) {
-               if (sync)
-                       cancel_delayed_work_sync(&disk->ev->dwork);
-               else
-                       cancel_delayed_work(&disk->ev->dwork);
-       }
+       if (cancel)
+               cancel_delayed_work_sync(&disk->ev->dwork);
+       mutex_unlock(&ev->block_mutex);
  }
  
  static void __disk_unblock_events(struct gendisk *disk, bool check_now)
@@@ -1461,27 -1484,6 +1484,6 @@@ out_unlock
  }
  
  /**
-  * disk_block_events - block and flush disk event checking
-  * @disk: disk to block events for
-  *
-  * On return from this function, it is guaranteed that event checking
-  * isn't in progress and won't happen until unblocked by
-  * disk_unblock_events().  Events blocking is counted and the actual
-  * unblocking happens after the matching number of unblocks are done.
-  *
-  * Note that this intentionally does not block event checking from
-  * disk_clear_events().
-  *
-  * CONTEXT:
-  * Might sleep.
-  */
- void disk_block_events(struct gendisk *disk)
- {
-       if (disk->ev)
-               __disk_block_events(disk, true);
- }
- /**
   * disk_unblock_events - unblock disk event checking
   * @disk: disk to unblock events for
   *
@@@ -1508,10 -1510,18 +1510,18 @@@ void disk_unblock_events(struct gendis
   */
  void disk_check_events(struct gendisk *disk)
  {
-       if (disk->ev) {
-               __disk_block_events(disk, false);
-               __disk_unblock_events(disk, true);
+       struct disk_events *ev = disk->ev;
+       unsigned long flags;
+       if (!ev)
+               return;
+       spin_lock_irqsave(&ev->lock, flags);
+       if (!ev->block) {
+               cancel_delayed_work(&ev->dwork);
+               queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
        }
+       spin_unlock_irqrestore(&ev->lock, flags);
  }
  EXPORT_SYMBOL_GPL(disk_check_events);
  
@@@ -1546,7 -1556,7 +1556,7 @@@ unsigned int disk_clear_events(struct g
        spin_unlock_irq(&ev->lock);
  
        /* uncondtionally schedule event check and wait for it to finish */
-       __disk_block_events(disk, true);
+       disk_block_events(disk);
        queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
        flush_delayed_work(&ev->dwork);
        __disk_unblock_events(disk, false);
@@@ -1664,7 -1674,7 +1674,7 @@@ static ssize_t disk_events_poll_msecs_s
        if (intv < 0 && intv != -1)
                return -EINVAL;
  
-       __disk_block_events(disk, true);
+       disk_block_events(disk);
        disk->ev->poll_msecs = intv;
        __disk_unblock_events(disk, true);
  
@@@ -1750,6 -1760,7 +1760,7 @@@ static void disk_add_events(struct gend
        INIT_LIST_HEAD(&ev->node);
        ev->disk = disk;
        spin_lock_init(&ev->lock);
+       mutex_init(&ev->block_mutex);
        ev->block = 1;
        ev->poll_msecs = -1;
        INIT_DELAYED_WORK(&ev->dwork, disk_events_workfn);
@@@ -1770,7 -1781,7 +1781,7 @@@ static void disk_del_events(struct gend
        if (!disk->ev)
                return;
  
-       __disk_block_events(disk, true);
+       disk_block_events(disk);
  
        mutex_lock(&disk_events_mutex);
        list_del_init(&disk->ev->node);
diff --combined fs/partitions/check.c
@@@ -237,31 -237,25 +237,25 @@@ ssize_t part_size_show(struct device *d
        return sprintf(buf, "%llu\n",(unsigned long long)p->nr_sects);
  }
  
 -ssize_t part_ro_show(struct device *dev,
 -                     struct device_attribute *attr, char *buf)
 +static ssize_t part_ro_show(struct device *dev,
 +                          struct device_attribute *attr, char *buf)
  {
        struct hd_struct *p = dev_to_part(dev);
        return sprintf(buf, "%d\n", p->policy ? 1 : 0);
  }
  
 -ssize_t part_alignment_offset_show(struct device *dev,
 -                                 struct device_attribute *attr, char *buf)
 +static ssize_t part_alignment_offset_show(struct device *dev,
 +                                        struct device_attribute *attr, char *buf)
  {
        struct hd_struct *p = dev_to_part(dev);
        return sprintf(buf, "%llu\n", (unsigned long long)p->alignment_offset);
  }
  
 -ssize_t part_discard_alignment_show(struct device *dev,
 -                                 struct device_attribute *attr, char *buf)
 +static ssize_t part_discard_alignment_show(struct device *dev,
 +                                         struct device_attribute *attr, char *buf)
  {
        struct hd_struct *p = dev_to_part(dev);
-       struct gendisk *disk = dev_to_disk(dev);
-       unsigned int alignment = 0;
-       if (disk->queue)
-               alignment = queue_limit_discard_alignment(&disk->queue->limits,
-                                                               p->start_sect);
-       return sprintf(buf, "%u\n", alignment);
+       return sprintf(buf, "%u\n", p->discard_alignment);
  }
  
  ssize_t part_stat_show(struct device *dev,
@@@ -455,6 -449,8 +449,8 @@@ struct hd_struct *add_partition(struct 
        p->start_sect = start;
        p->alignment_offset =
                queue_limit_alignment_offset(&disk->queue->limits, start);
+       p->discard_alignment =
+               queue_limit_discard_alignment(&disk->queue->limits, start);
        p->nr_sects = len;
        p->partno = partno;
        p->policy = get_disk_ro(disk);
diff --combined include/linux/blkdev.h
@@@ -73,7 -73,7 +73,7 @@@ enum rq_cmd_type_bits 
  
  /*
   * try to put the fields that are referenced together in the same cacheline.
 - * if you modify this structure, be sure to check block/blk-core.c:rq_init()
 + * if you modify this structure, be sure to check block/blk-core.c:blk_rq_init()
   * as well!
   */
  struct request {
@@@ -1282,8 -1282,8 +1282,8 @@@ queue_max_integrity_segments(struct req
  #define blk_get_integrity(a)                  (0)
  #define blk_integrity_compare(a, b)           (0)
  #define blk_integrity_register(a, b)          (0)
- #define blk_integrity_unregister(a)           do { } while (0);
- #define blk_queue_max_integrity_segments(a, b)        do { } while (0);
+ #define blk_integrity_unregister(a)           do { } while (0)
+ #define blk_queue_max_integrity_segments(a, b)        do { } while (0)
  #define queue_max_integrity_segments(a)               (0)
  #define blk_integrity_merge_rq(a, b, c)               (0)
  #define blk_integrity_merge_bio(a, b, c)      (0)