From bd5504b1edb5ee39d166b2f1cfcd3cd2c82fbb5c Mon Sep 17 00:00:00 2001 From: Federico Vaga <federico.vaga@gmail.com> Date: Sun, 15 Jan 2012 19:49:52 +0100 Subject: [PATCH] core: enable/disable zio objects A zio object can be enabled or disabled Signed-off-by: Federico Vaga <federico.vaga@gmail.com> Acked-by: Alessandro Rubini <rubini@gnudd.com> --- buffers/zio-buf-kmalloc.c | 9 ++- include/linux/zio-trigger.h | 5 ++ include/linux/zio.h | 4 +- triggers/zio-trig-timer.c | 30 ++++++-- zio-sys.c | 148 +++++++++++++++++++++++++++++++++++- 5 files changed, 185 insertions(+), 11 deletions(-) diff --git a/buffers/zio-buf-kmalloc.c b/buffers/zio-buf-kmalloc.c index 703385d..3c3bd9b 100644 --- a/buffers/zio-buf-kmalloc.c +++ b/buffers/zio-buf-kmalloc.c @@ -103,6 +103,9 @@ static void zbk_free_block(struct zio_bi *bi, struct zio_block *block) static inline int __try_push(struct zio_ti *ti, struct zio_channel *chan, struct zio_block *block) { + /* chek if trigger is disabled */ + if (unlikely((ti->flags & ZIO_STATUS) == ZIO_DISABLED)) + return 0; if (ti->t_op->push_block(ti, chan, block) < 0) return 0; return 1; @@ -183,8 +186,12 @@ out_unlock: spin_unlock(&zbki->lock); /* There is no data in buffer, and we may pull to have data soon */ ti = bi->cset->ti; - if ((bi->flags & ZIO_DIR) == ZIO_DIR_INPUT && ti->t_op->pull_block) + if ((bi->flags & ZIO_DIR) == ZIO_DIR_INPUT && ti->t_op->pull_block){ + /* chek if trigger is disabled */ + if (unlikely((ti->flags & ZIO_STATUS) == ZIO_DISABLED)) + return NULL; ti->t_op->pull_block(ti, bi->chan); + } pr_debug("%s:%d (%p, %p)\n", __func__, __LINE__, bi, NULL); return NULL; } diff --git a/include/linux/zio-trigger.h b/include/linux/zio-trigger.h index 5fb291d..0f48a8d 100644 --- a/include/linux/zio-trigger.h +++ b/include/linux/zio-trigger.h @@ -84,6 +84,8 @@ void zio_fire_trigger(struct zio_ti *ti); * the conf_set callback runs and the instance is notified) or by writing * a whole control to the control device. In this case the config method * is called by the write method. + * + * FIXME describe well abort and change_status */ struct zio_trigger_operations { int (*push_block)(struct zio_ti *ti, @@ -102,6 +104,9 @@ struct zio_trigger_operations { struct zio_control *ctrl, fmode_t flags); void (*destroy)(struct zio_ti *ti); + void (*change_status)(struct zio_ti *ti, + unsigned int status); + void (*abort)(struct zio_cset *cset); }; void zio_generic_data_done(struct zio_cset *cest); diff --git a/include/linux/zio.h b/include/linux/zio.h index 47f5313..0e0ae81 100644 --- a/include/linux/zio.h +++ b/include/linux/zio.h @@ -68,7 +68,9 @@ static inline enum zio_object_type __zio_get_object_type(struct kobject *kobj) /* Bits 0..3 are reserved for use in all objects. By now only bit 1 is used */ enum zobj_flags { - ZIO_DISABLED = 0x1, /* 0 (default) is enabled */ + ZIO_STATUS = 0x1, /* 0 (default) is enabled */ + ZIO_ENABLED = 0x0, + ZIO_DISABLED = 0x1, ZIO_DIR = 0x2, /* 0 is input - 1 is output*/ ZIO_DIR_INPUT = 0x0, ZIO_DIR_OUTPUT = 0x2, diff --git a/triggers/zio-trig-timer.c b/triggers/zio-trig-timer.c index f1345d6..0155a73 100644 --- a/triggers/zio-trig-timer.c +++ b/triggers/zio-trig-timer.c @@ -112,14 +112,18 @@ static int ztt_config(struct zio_ti *ti, struct zio_control *ctrl) pr_debug("%s:%d\n", __func__, __LINE__); return 0; } - +static void ztt_start_timer(struct ztt_instance *ztt_instance, uint32_t ms) +{ + ztt_instance->next_run = jiffies + HZ; + ztt_instance->period = msecs_to_jiffies(ms); + mod_timer(&ztt_instance->timer, ztt_instance->next_run); +} static struct zio_ti *ztt_create(struct zio_trigger_type *trig, struct zio_cset *cset, struct zio_control *ctrl, fmode_t flags) { struct ztt_instance *ztt_instance; struct zio_ti *ti; - uint32_t ms; pr_debug("%s:%d\n", __func__, __LINE__); @@ -135,12 +139,7 @@ static struct zio_ti *ztt_create(struct zio_trigger_type *trig, /* Fill own fields */ setup_timer(&ztt_instance->timer, ztt_fn, (unsigned long)(&ztt_instance->ti)); - ztt_instance->next_run = jiffies + HZ; - ms = ztt_ext_attr[0].value; - ztt_instance->period = msecs_to_jiffies(ms); /* module param */ - - /* Start the timer (dangerous: ti is not filled) */ - mod_timer(&ztt_instance->timer, ztt_instance->next_run); + ztt_start_timer(ztt_instance, ztt_ext_attr[0].value); return ti; } @@ -155,6 +154,20 @@ static void ztt_destroy(struct zio_ti *ti) kfree(ti); } +static void ztt_change_status(struct zio_ti *ti, unsigned int status) +{ + struct ztt_instance *ztt_instance; + + pr_debug("%s:%d status=%d\n", __func__, __LINE__, status); + ztt_instance = to_ztt_instance(ti); + + if (!status) { /* enable */ + ztt_start_timer(ztt_instance, ztt_instance->period); + } else { /* disable */ + /* FIXME kernel/timer.c don't use this is lock*/ + del_timer_sync(&ztt_instance->timer); + } +} static const struct zio_trigger_operations ztt_trigger_ops = { .push_block = ztt_push_block, .pull_block = NULL, @@ -162,6 +175,7 @@ static const struct zio_trigger_operations ztt_trigger_ops = { .config = ztt_config, .create = ztt_create, .destroy = ztt_destroy, + .change_status = ztt_change_status, }; static struct zio_trigger_type ztt_trigger = { diff --git a/zio-sys.c b/zio-sys.c index ea7db9d..ec1a91c 100644 --- a/zio-sys.c +++ b/zio-sys.c @@ -17,6 +17,7 @@ #include <linux/zio-trigger.h> #define ZOBJ_SYSFS_NAME "name" +#define ZOBJ_SYSFS_ENABLE "enable" #define CSET_SYSFS_BUFFER "current_buffer" #define CSET_SYSFS_TRIGGER "current_trigger" @@ -224,6 +225,9 @@ void zio_fire_trigger(struct zio_ti *ti) /* If the trigger runs too early, ti->cset is still NULL */ if (!ti->cset) return; + /* chek if trigger is disabled */ + if (unlikely((ti->flags & ZIO_STATUS) == ZIO_DISABLED)) + return; /* check if previouvs fire is still running*/ if ((ti->flags & ZTI_STATUS) == ZTI_STATUS_ON) return; @@ -435,6 +439,39 @@ static struct zio_attribute_set *__get_zattr_set(struct zio_obj_head *head) } return zattr_set; } +/* Retrieve flag from an object head */ +static unsigned long *__get_flag(struct zio_obj_head *head) +{ + unsigned long *flags; + + switch (head->zobj_type) { + case ZDEV: + flags = &to_zio_dev(&head->kobj)->flags; + break; + case ZCSET: + flags = &to_zio_cset(&head->kobj)->flags; + break; + case ZCHAN: + flags = &to_zio_chan(&head->kobj)->flags; + break; + case ZTRIG: + flags = &to_zio_chan(&head->kobj)->flags; + break; + case ZBUF: + flags = &to_zio_chan(&head->kobj)->flags; + break; + case ZTI: + flags = &to_zio_ti(&head->kobj)->flags; + break; + case ZBI: + flags = &to_zio_bi(&head->kobj)->flags; + break; + default: + WARN(1, "ZIO: unknown zio object %i\n", head->zobj_type); + return NULL; + } + return flags; +} static int zio_change_current_trigger(struct zio_cset *cset, char *name) { @@ -630,7 +667,10 @@ static ssize_t zattr_show(struct kobject *kobj, struct attribute *attr, /* print current buffer name */ if (unlikely(strcmp(attr->name, CSET_SYSFS_BUFFER) == 0)) return sprintf(buf, "%s\n", to_zio_cset(kobj)->zbuf->head.name); - + /* print current enable status */ + if (unlikely(strcmp(attr->name, ZOBJ_SYSFS_ENABLE) == 0)) + return sprintf(buf, "%d\n", + !((*__get_flag(to_zio_head(kobj))) & ZIO_DISABLED)); if (zattr->s_op->info_get) { lock = __get_spinlock(to_zio_head(kobj)); @@ -643,6 +683,91 @@ static ssize_t zattr_show(struct kobject *kobj, struct attribute *attr, len = sprintf(buf, "%i\n", zattr->value); return len; } + +/* enable/disable a zio object*/ +static void __zobj_enable(struct kobject *kobj, unsigned int enable, + unsigned int need_lock) +{ + unsigned long *flags; + int i, status; + struct zio_obj_head *head; + struct zio_device *zdev; + struct zio_cset *cset; + struct zio_ti *ti; + spinlock_t *lock; + + pr_debug("%s\n", __func__); + head = to_zio_head(kobj); + + /* lock object if needed */ + lock = __get_spinlock(head); + if (need_lock) + spin_lock(lock); + + flags = __get_flag(to_zio_head(kobj)); + status = !((*flags) & ZIO_STATUS); + /* if the status is not changing */ + if (!(enable ^ status)) { + goto out; + } + /* change status */ + *flags = (*flags | ZIO_STATUS) & status; + switch (head->zobj_type) { + case ZDEV: + pr_debug("%s: zdev\n", __func__); + + zdev = to_zio_dev(kobj); + /* enable/disable all cset */ + for (i = 0; i < zdev->n_cset; ++i) { + __zobj_enable(&zdev->cset[i].head.kobj, enable, 0); + } + /* device callback */ + break; + case ZCSET: + pr_debug("%s: zcset\n", __func__); + + cset = to_zio_cset(kobj); + /* enable/disable trigger instance */ + __zobj_enable(&cset->ti->head.kobj, enable, 1); + /* enable/disable all channel*/ + for (i = 0; i < cset->n_chan; ++i) { + __zobj_enable(&cset->chan[i].head.kobj, enable, 0); + } + /* cset callback */ + break; + case ZCHAN: + pr_debug("%s: zchan\n", __func__); + /* channel callback */ + break; + case ZTI: + pr_debug("%s: zti\n", __func__); + + ti = to_zio_ti(kobj); + /* if trigger is running, abort it*/ + if ((*flags & ZTI_STATUS) == ZTI_STATUS_ON) + if(ti->t_op->abort) + ti->t_op->abort(ti->cset); + /* trigger instance callback */ + if (ti->t_op->change_status) { + pr_debug("%s:%d\n", __func__, __LINE__); + ti->t_op->change_status(ti, status); + } + break; + /* following objects can't be enabled/disabled */ + case ZBUF: + case ZTRIG: + case ZBI: + pr_debug("%s: others\n", __func__); + /* buffer instance callback */ + break; + default: + WARN(1, "ZIO: unknown zio object %i\n", head->zobj_type); + } +out: + if (need_lock) + spin_unlock(lock); +} + static ssize_t zattr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t size) { @@ -668,9 +793,19 @@ static ssize_t zattr_store(struct kobject *kobj, struct attribute *attr, err = zio_change_current_buffer(to_zio_cset(kobj), buf_tmp); return err == 0 ? size : err; } + err = strict_strtol(buf, 0, &val); if (err) return -EINVAL; + + /* change enable status */ + if (unlikely(strcmp(attr->name, ZOBJ_SYSFS_ENABLE) == 0 && + (val == 0 || val == 1))) { + __zobj_enable(kobj, val, 1); + return size; + } + + /* device attributes */ if (zattr->s_op->conf_set) { lock = __get_spinlock(to_zio_head(kobj)); spin_lock(lock); @@ -695,6 +830,11 @@ static struct attribute default_cset_attrs[] = { .name = ZOBJ_SYSFS_NAME, .mode = 0444, /* read only */ }, + { + /* enable/disable object */ + .name = ZOBJ_SYSFS_ENABLE, + .mode = 0666, /* read write */ + }, { /* get/set trigger */ .name = CSET_SYSFS_TRIGGER, .mode = 0666, /* read write */ @@ -708,6 +848,7 @@ static struct attribute *def_cset_attr_ptr[] = { &default_cset_attrs[0], &default_cset_attrs[1], &default_cset_attrs[2], + &default_cset_attrs[3], NULL, }; static struct kobj_type zdkctype = { /* only for cset */ @@ -720,9 +861,14 @@ static struct attribute default_attrs[] = { .name = ZOBJ_SYSFS_NAME, .mode = 0444, /* read only */ }, + { /* enable/disable object */ + .name = ZOBJ_SYSFS_ENABLE, + .mode = 0666, /* read write */ + }, }; static struct attribute *def_attr_ptr[] = { &default_attrs[0], + &default_attrs[1], NULL, }; -- GitLab