block: add internal hd part table references
Jens Axboe [Fri, 7 Jan 2011 07:43:37 +0000 (08:43 +0100)]
We can't use krefs since it's apparently restricted to very basic
reference counting.

This reverts commit e4a683c8.

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

block/blk-core.c
block/blk-merge.c
block/genhd.c
fs/partitions/check.c
include/linux/genhd.h
include/linux/kref.h
lib/kref.c

index 500c080..2f4002f 100644 (file)
@@ -70,7 +70,7 @@ static void drive_stat_acct(struct request *rq, int new_io)
                part_stat_inc(cpu, part, merges[rw]);
        } else {
                part = disk_map_sector_rcu(rq->rq_disk, blk_rq_pos(rq));
-               if (!kref_test_and_get(&part->ref)) {
+               if (!hd_struct_try_get(part)) {
                        /*
                         * The partition is already being removed,
                         * the request will be accounted on the disk only
@@ -80,7 +80,7 @@ static void drive_stat_acct(struct request *rq, int new_io)
                         * it as any other partition.
                         */
                        part = &rq->rq_disk->part0;
-                       kref_get(&part->ref);
+                       hd_struct_get(part);
                }
                part_round_stats(cpu, part);
                part_inc_in_flight(part, rw);
@@ -1818,7 +1818,7 @@ static void blk_account_io_done(struct request *req)
                part_round_stats(cpu, part);
                part_dec_in_flight(part, rw);
 
-               kref_put(&part->ref, __delete_partition);
+               hd_struct_put(part);
                part_stat_unlock();
        }
 }
index b06b83b..00b7d31 100644 (file)
@@ -356,7 +356,7 @@ static void blk_account_io_merge(struct request *req)
                part_round_stats(cpu, part);
                part_dec_in_flight(part, rq_data_dir(req));
 
-               kref_put(&part->ref, __delete_partition);
+               hd_struct_put(part);
                part_stat_unlock();
        }
 }
index 85c1505..399d37e 100644 (file)
@@ -1192,7 +1192,8 @@ struct gendisk *alloc_disk_node(int minors, int node_id)
                        return NULL;
                }
                disk->part_tbl->part[0] = &disk->part0;
-               kref_init(&disk->part0.ref);
+
+               hd_ref_init(&disk->part0);
 
                disk->minors = minors;
                rand_initialize_disk(disk);
index 48209f5..011520d 100644 (file)
@@ -381,10 +381,8 @@ static void delete_partition_rcu_cb(struct rcu_head *head)
        put_device(part_to_dev(part));
 }
 
-void __delete_partition(struct kref *ref)
+void __delete_partition(struct hd_struct *part)
 {
-       struct hd_struct *part = container_of(ref, struct hd_struct, ref);
-
        call_rcu(&part->rcu_head, delete_partition_rcu_cb);
 }
 
@@ -406,7 +404,7 @@ void delete_partition(struct gendisk *disk, int partno)
        kobject_put(part->holder_dir);
        device_del(part_to_dev(part));
 
-       kref_put(&part->ref, __delete_partition);
+       hd_struct_put(part);
 }
 
 static ssize_t whole_disk_show(struct device *dev,
@@ -505,7 +503,7 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
        if (!dev_get_uevent_suppress(ddev))
                kobject_uevent(&pdev->kobj, KOBJ_ADD);
 
-       kref_init(&p->ref);
+       hd_ref_init(p);
        return p;
 
 out_free_info:
index 2ba2792..2d04681 100644 (file)
@@ -115,8 +115,8 @@ struct hd_struct {
 #else
        struct disk_stats dkstats;
 #endif
+       atomic_t ref;
        struct rcu_head rcu_head;
-       struct kref ref;
 };
 
 #define GENHD_FL_REMOVABLE                     1
@@ -584,7 +584,7 @@ extern struct hd_struct * __must_check add_partition(struct gendisk *disk,
                                                     sector_t len, int flags,
                                                     struct partition_meta_info
                                                       *info);
-extern void __delete_partition(struct kref *ref);
+extern void __delete_partition(struct hd_struct *);
 extern void delete_partition(struct gendisk *, int);
 extern void printk_all_partitions(void);
 
@@ -613,6 +613,29 @@ extern ssize_t part_fail_store(struct device *dev,
                               const char *buf, size_t count);
 #endif /* CONFIG_FAIL_MAKE_REQUEST */
 
+static inline void hd_ref_init(struct hd_struct *part)
+{
+       atomic_set(&part->ref, 1);
+       smp_mb();
+}
+
+static inline void hd_struct_get(struct hd_struct *part)
+{
+       atomic_inc(&part->ref);
+       smp_mb__after_atomic_inc();
+}
+
+static inline int hd_struct_try_get(struct hd_struct *part)
+{
+       return atomic_inc_not_zero(&part->ref);
+}
+
+static inline void hd_struct_put(struct hd_struct *part)
+{
+       if (atomic_dec_and_test(&part->ref))
+               __delete_partition(part);
+}
+
 #else /* CONFIG_BLOCK */
 
 static inline void printk_all_partitions(void) { }
index 90b9e44..6cc38fc 100644 (file)
@@ -23,7 +23,6 @@ struct kref {
 
 void kref_init(struct kref *kref);
 void kref_get(struct kref *kref);
-int kref_test_and_get(struct kref *kref);
 int kref_put(struct kref *kref, void (*release) (struct kref *kref));
 
 #endif /* _KREF_H_ */
index e7a6e10..d3d227a 100644 (file)
@@ -37,18 +37,6 @@ void kref_get(struct kref *kref)
 }
 
 /**
- * kref_test_and_get - increment refcount for object only if refcount is not
- * zero.
- * @kref: object.
- *
- * Return non-zero if the refcount was incremented, 0 otherwise
- */
-int kref_test_and_get(struct kref *kref)
-{
-       return atomic_inc_not_zero(&kref->refcount);
-}
-
-/**
  * kref_put - decrement refcount for object.
  * @kref: object.
  * @release: pointer to the function that will clean up the object when the