Commit 483f4afc authored by Al Viro's avatar Al Viro

[PATCH] fix sysfs interaction and lifetime rules handling for queues

parent 1312f40e
...@@ -1740,16 +1740,11 @@ EXPORT_SYMBOL(blk_run_queue); ...@@ -1740,16 +1740,11 @@ EXPORT_SYMBOL(blk_run_queue);
* Hopefully the low level driver will have finished any * Hopefully the low level driver will have finished any
* outstanding requests first... * outstanding requests first...
**/ **/
void blk_cleanup_queue(request_queue_t * q) static void blk_release_queue(struct kobject *kobj)
{ {
request_queue_t *q = container_of(kobj, struct request_queue, kobj);
struct request_list *rl = &q->rq; struct request_list *rl = &q->rq;
if (!atomic_dec_and_test(&q->refcnt))
return;
if (q->elevator)
elevator_exit(q->elevator);
blk_sync_queue(q); blk_sync_queue(q);
if (rl->rq_pool) if (rl->rq_pool)
...@@ -1761,6 +1756,24 @@ void blk_cleanup_queue(request_queue_t * q) ...@@ -1761,6 +1756,24 @@ void blk_cleanup_queue(request_queue_t * q)
kmem_cache_free(requestq_cachep, q); kmem_cache_free(requestq_cachep, q);
} }
void blk_put_queue(request_queue_t *q)
{
kobject_put(&q->kobj);
}
EXPORT_SYMBOL(blk_put_queue);
void blk_cleanup_queue(request_queue_t * q)
{
mutex_lock(&q->sysfs_lock);
set_bit(QUEUE_FLAG_DEAD, &q->queue_flags);
mutex_unlock(&q->sysfs_lock);
if (q->elevator)
elevator_exit(q->elevator);
blk_put_queue(q);
}
EXPORT_SYMBOL(blk_cleanup_queue); EXPORT_SYMBOL(blk_cleanup_queue);
static int blk_init_free_list(request_queue_t *q) static int blk_init_free_list(request_queue_t *q)
...@@ -1788,6 +1801,8 @@ request_queue_t *blk_alloc_queue(gfp_t gfp_mask) ...@@ -1788,6 +1801,8 @@ request_queue_t *blk_alloc_queue(gfp_t gfp_mask)
} }
EXPORT_SYMBOL(blk_alloc_queue); EXPORT_SYMBOL(blk_alloc_queue);
static struct kobj_type queue_ktype;
request_queue_t *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) request_queue_t *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
{ {
request_queue_t *q; request_queue_t *q;
...@@ -1798,11 +1813,16 @@ request_queue_t *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) ...@@ -1798,11 +1813,16 @@ request_queue_t *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
memset(q, 0, sizeof(*q)); memset(q, 0, sizeof(*q));
init_timer(&q->unplug_timer); init_timer(&q->unplug_timer);
atomic_set(&q->refcnt, 1);
snprintf(q->kobj.name, KOBJ_NAME_LEN, "%s", "queue");
q->kobj.ktype = &queue_ktype;
kobject_init(&q->kobj);
q->backing_dev_info.unplug_io_fn = blk_backing_dev_unplug; q->backing_dev_info.unplug_io_fn = blk_backing_dev_unplug;
q->backing_dev_info.unplug_io_data = q; q->backing_dev_info.unplug_io_data = q;
mutex_init(&q->sysfs_lock);
return q; return q;
} }
EXPORT_SYMBOL(blk_alloc_queue_node); EXPORT_SYMBOL(blk_alloc_queue_node);
...@@ -1901,7 +1921,7 @@ EXPORT_SYMBOL(blk_init_queue_node); ...@@ -1901,7 +1921,7 @@ EXPORT_SYMBOL(blk_init_queue_node);
int blk_get_queue(request_queue_t *q) int blk_get_queue(request_queue_t *q)
{ {
if (likely(!test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) { if (likely(!test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) {
atomic_inc(&q->refcnt); kobject_get(&q->kobj);
return 0; return 0;
} }
...@@ -3764,13 +3784,19 @@ static ssize_t ...@@ -3764,13 +3784,19 @@ static ssize_t
queue_attr_show(struct kobject *kobj, struct attribute *attr, char *page) queue_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
{ {
struct queue_sysfs_entry *entry = to_queue(attr); struct queue_sysfs_entry *entry = to_queue(attr);
struct request_queue *q; request_queue_t *q = container_of(kobj, struct request_queue, kobj);
ssize_t res;
q = container_of(kobj, struct request_queue, kobj);
if (!entry->show) if (!entry->show)
return -EIO; return -EIO;
mutex_lock(&q->sysfs_lock);
return entry->show(q, page); if (test_bit(QUEUE_FLAG_DEAD, &q->queue_flags)) {
mutex_unlock(&q->sysfs_lock);
return -ENOENT;
}
res = entry->show(q, page);
mutex_unlock(&q->sysfs_lock);
return res;
} }
static ssize_t static ssize_t
...@@ -3778,13 +3804,20 @@ queue_attr_store(struct kobject *kobj, struct attribute *attr, ...@@ -3778,13 +3804,20 @@ queue_attr_store(struct kobject *kobj, struct attribute *attr,
const char *page, size_t length) const char *page, size_t length)
{ {
struct queue_sysfs_entry *entry = to_queue(attr); struct queue_sysfs_entry *entry = to_queue(attr);
struct request_queue *q; request_queue_t *q = container_of(kobj, struct request_queue, kobj);
ssize_t res;
q = container_of(kobj, struct request_queue, kobj);
if (!entry->store) if (!entry->store)
return -EIO; return -EIO;
mutex_lock(&q->sysfs_lock);
return entry->store(q, page, length); if (test_bit(QUEUE_FLAG_DEAD, &q->queue_flags)) {
mutex_unlock(&q->sysfs_lock);
return -ENOENT;
}
res = entry->store(q, page, length);
mutex_unlock(&q->sysfs_lock);
return res;
} }
static struct sysfs_ops queue_sysfs_ops = { static struct sysfs_ops queue_sysfs_ops = {
...@@ -3795,6 +3828,7 @@ static struct sysfs_ops queue_sysfs_ops = { ...@@ -3795,6 +3828,7 @@ static struct sysfs_ops queue_sysfs_ops = {
static struct kobj_type queue_ktype = { static struct kobj_type queue_ktype = {
.sysfs_ops = &queue_sysfs_ops, .sysfs_ops = &queue_sysfs_ops,
.default_attrs = default_attrs, .default_attrs = default_attrs,
.release = blk_release_queue,
}; };
int blk_register_queue(struct gendisk *disk) int blk_register_queue(struct gendisk *disk)
...@@ -3807,19 +3841,17 @@ int blk_register_queue(struct gendisk *disk) ...@@ -3807,19 +3841,17 @@ int blk_register_queue(struct gendisk *disk)
return -ENXIO; return -ENXIO;
q->kobj.parent = kobject_get(&disk->kobj); q->kobj.parent = kobject_get(&disk->kobj);
if (!q->kobj.parent)
return -EBUSY;
snprintf(q->kobj.name, KOBJ_NAME_LEN, "%s", "queue"); ret = kobject_add(&q->kobj);
q->kobj.ktype = &queue_ktype;
ret = kobject_register(&q->kobj);
if (ret < 0) if (ret < 0)
return ret; return ret;
kobject_uevent(&q->kobj, KOBJ_ADD);
ret = elv_register_queue(q); ret = elv_register_queue(q);
if (ret) { if (ret) {
kobject_unregister(&q->kobj); kobject_uevent(&q->kobj, KOBJ_REMOVE);
kobject_del(&q->kobj);
return ret; return ret;
} }
...@@ -3833,7 +3865,8 @@ void blk_unregister_queue(struct gendisk *disk) ...@@ -3833,7 +3865,8 @@ void blk_unregister_queue(struct gendisk *disk)
if (q && q->request_fn) { if (q && q->request_fn) {
elv_unregister_queue(q); elv_unregister_queue(q);
kobject_unregister(&q->kobj); kobject_uevent(&q->kobj, KOBJ_REMOVE);
kobject_del(&q->kobj);
kobject_put(&disk->kobj); kobject_put(&disk->kobj);
} }
} }
...@@ -406,8 +406,6 @@ struct request_queue ...@@ -406,8 +406,6 @@ struct request_queue
struct blk_queue_tag *queue_tags; struct blk_queue_tag *queue_tags;
atomic_t refcnt;
unsigned int nr_sorted; unsigned int nr_sorted;
unsigned int in_flight; unsigned int in_flight;
...@@ -426,6 +424,8 @@ struct request_queue ...@@ -426,6 +424,8 @@ struct request_queue
struct request pre_flush_rq, bar_rq, post_flush_rq; struct request pre_flush_rq, bar_rq, post_flush_rq;
struct request *orig_bar_rq; struct request *orig_bar_rq;
unsigned int bi_size; unsigned int bi_size;
struct mutex sysfs_lock;
}; };
#define RQ_INACTIVE (-1) #define RQ_INACTIVE (-1)
...@@ -727,7 +727,7 @@ extern long nr_blockdev_pages(void); ...@@ -727,7 +727,7 @@ extern long nr_blockdev_pages(void);
int blk_get_queue(request_queue_t *); int blk_get_queue(request_queue_t *);
request_queue_t *blk_alloc_queue(gfp_t); request_queue_t *blk_alloc_queue(gfp_t);
request_queue_t *blk_alloc_queue_node(gfp_t, int); request_queue_t *blk_alloc_queue_node(gfp_t, int);
#define blk_put_queue(q) blk_cleanup_queue((q)) extern void blk_put_queue(request_queue_t *);
/* /*
* tag stuff * tag stuff
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment