diff options
author | Slava Pestov <sviatoslavpestov@gmail.com> | 2015-01-27 00:16:11 -0800 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2016-10-07 12:33:06 -0800 |
commit | bcf72741f90b5a40b58e214fdb093d4a8f14162e (patch) | |
tree | a17bec867e05afb912f536582166551dad23fe04 | |
parent | 7e9d45f8d73183b3980f2fe0eca478aedf557f77 (diff) |
bcache: notify user space of state changes using kobject_uevent
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r-- | drivers/md/bcache/Makefile | 4 | ||||
-rw-r--r-- | drivers/md/bcache/bcache.h | 4 | ||||
-rw-r--r-- | drivers/md/bcache/io.c | 5 | ||||
-rw-r--r-- | drivers/md/bcache/notify.c | 124 | ||||
-rw-r--r-- | drivers/md/bcache/notify.h | 21 | ||||
-rw-r--r-- | drivers/md/bcache/super.c | 21 |
6 files changed, 177 insertions, 2 deletions
diff --git a/drivers/md/bcache/Makefile b/drivers/md/bcache/Makefile index 1fc9c32d4d33..769c199337f5 100644 --- a/drivers/md/bcache/Makefile +++ b/drivers/md/bcache/Makefile @@ -3,7 +3,7 @@ obj-$(CONFIG_BCACHE) += bcache.o bcache-y := alloc.o bkey.o bkey_methods.o blockdev.o bset.o\ btree.o buckets.o closure.o debug.o extents.o gc.o inode.o io.o\ - journal.o keybuf.o keylist.o move.o movinggc.o request.o six.o stats.o\ - super.o sysfs.o tier.o trace.o util.o writeback.o + journal.o keybuf.o keylist.o move.o movinggc.o notify.o request.o six.o\ + stats.o super.o sysfs.o tier.o trace.o util.o writeback.o ccflags-y := -Werror diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index 3639964e4aa4..1250669cf37e 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -552,6 +552,10 @@ struct cache_set { struct task_struct *tiering_read; struct bch_pd_controller tiering_pd; + /* NOTIFICATIONS */ + struct mutex uevent_lock; + struct kobj_uevent_env uevent_env; + /* DEBUG JUNK */ struct dentry *debug; #ifdef CONFIG_BCACHE_DEBUG diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c index 285e8f80bc7b..eee3de4882c7 100644 --- a/drivers/md/bcache/io.c +++ b/drivers/md/bcache/io.c @@ -15,6 +15,7 @@ #include "gc.h" #include "io.h" #include "keylist.h" +#include "notify.h" #include "stats.h" #include "super.h" @@ -195,9 +196,13 @@ void bch_count_io_errors(struct cache *ca, int error, const char *m) &ca->io_errors); if (errors < ca->set->error_limit) { + bch_notify_cache_error(ca, false, m); + pr_err("%s: IO error on %s, recovering", bdevname(ca->disk_sb.bdev, buf), m); } else { + bch_notify_cache_error(ca, true, m); + if (bch_cache_remove(ca, true)) pr_err("%s: too many IO errors on %s, removing", bdevname(ca->disk_sb.bdev, buf), m); diff --git a/drivers/md/bcache/notify.c b/drivers/md/bcache/notify.c new file mode 100644 index 000000000000..9d3a8ca78ae2 --- /dev/null +++ b/drivers/md/bcache/notify.c @@ -0,0 +1,124 @@ +/* + * Code for sending uevent notifications to user-space. + * + * Copyright 2015 Datera, Inc. + */ + +#include "bcache.h" + +#include <linux/kobject.h> + +#define notify_var(c, format, ...) \ +({ \ + int ret; \ + lockdep_assert_held(&(c)->uevent_lock); \ + ret = add_uevent_var(&(c)->uevent_env, format, ##__VA_ARGS__); \ + WARN_ON_ONCE(ret); \ +}) + +static void notify_get(struct cache_set *c) +{ + struct kobj_uevent_env *env = &c->uevent_env; + + mutex_lock(&c->uevent_lock); + env->envp_idx = 0; + env->buflen = 0; + + notify_var(c, "SET_UUID=%pU", c->sb.set_uuid.b); +} + +static void notify_get_cache(struct cache *ca) +{ + struct cache_set *c = ca->set; + char buf[BDEVNAME_SIZE]; + + notify_get(c); + notify_var(c, "UUID=%pU", ca->sb.disk_uuid.b); + notify_var(c, "BLOCKDEV=%s", bdevname(ca->disk_sb.bdev, buf)); +} + +static void notify_put(struct cache_set *c) +{ + struct kobj_uevent_env *env = &c->uevent_env; + + env->envp[env->envp_idx] = NULL; + kobject_uevent_env(&c->kobj, KOBJ_CHANGE, env->envp); + mutex_unlock(&c->uevent_lock); +} + +void bch_notify_cache_set_read_write(struct cache_set *c) +{ + notify_get(c); + notify_var(c, "STATE=active"); + notify_put(c); +} + +void bch_notify_cache_set_read_only(struct cache_set *c) +{ + notify_get(c); + notify_var(c, "STATE=readonly"); + notify_put(c); +} + +void bch_notify_cache_set_stopped(struct cache_set *c) +{ + notify_get(c); + notify_var(c, "STATE=stopped"); + notify_put(c); +} + +void bch_notify_cache_read_write(struct cache *ca) +{ + struct cache_set *c = ca->set; + + notify_get_cache(ca); + notify_var(c, "STATE=active"); + notify_put(c); +} + +void bch_notify_cache_read_only(struct cache *ca) +{ + struct cache_set *c = ca->set; + + notify_get_cache(ca); + notify_var(c, "STATE=readonly"); + notify_put(c); +} + +void bch_notify_cache_added(struct cache *ca) +{ + struct cache_set *c = ca->set; + + notify_get_cache(ca); + notify_var(c, "STATE=removing"); + notify_put(c); +} + +void bch_notify_cache_removing(struct cache *ca) +{ + struct cache_set *c = ca->set; + + notify_get_cache(ca); + notify_var(c, "STATE=removing"); + notify_put(c); +} + +void bch_notify_cache_removed(struct cache *ca) +{ + struct cache_set *c = ca->set; + + notify_get_cache(ca); + notify_var(c, "STATE=removed"); + notify_put(c); +} + +void bch_notify_cache_error(struct cache *ca, bool fatal, const char *m) +{ + struct cache_set *c = ca->set; + + notify_get_cache(ca); + notify_var(c, "STATE=error"); + notify_var(c, "FATAL=%d", fatal); + notify_var(c, "MESSAGE=%s", m); + notify_put(c); +} diff --git a/drivers/md/bcache/notify.h b/drivers/md/bcache/notify.h new file mode 100644 index 000000000000..b915feff3c00 --- /dev/null +++ b/drivers/md/bcache/notify.h @@ -0,0 +1,21 @@ +/* + * Code for sending uevent notifications to user-space. + * + * Copyright 2015 Datera, Inc. + */ + +#ifndef _NOTIFY_H +#define _NOTIFY_H + +void bch_notify_cache_set_read_write(struct cache_set *); +void bch_notify_cache_set_read_only(struct cache_set *); +void bch_notify_cache_set_stopped(struct cache_set *); + +void bch_notify_cache_read_write(struct cache *); +void bch_notify_cache_read_only(struct cache *); +void bch_notify_cache_added(struct cache *); +void bch_notify_cache_removing(struct cache *); +void bch_notify_cache_removed(struct cache *); +void bch_notify_cache_error(struct cache *, bool, const char *); + +#endif /* _NOTIFY_H */ diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index b7e9b48616bd..d0dd1231471a 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -18,6 +18,7 @@ #include "keylist.h" #include "move.h" #include "movinggc.h" +#include "notify.h" #include "stats.h" #include "super.h" #include "tier.h" @@ -671,6 +672,8 @@ static void bch_cache_set_read_only(struct cache_set *c) c->journal.work.work.func(&c->journal.work.work); } + bch_notify_cache_set_read_only(c); + trace_bcache_cache_set_read_only_done(c); } @@ -741,6 +744,8 @@ static void cache_set_free(struct closure *cl) list_del(&c->list); mutex_unlock(&bch_register_lock); + bch_notify_cache_set_stopped(c); + pr_info("Cache set %pU unregistered", c->sb.set_uuid.b); closure_debug_destroy(&c->cl); @@ -937,6 +942,8 @@ static const char *bch_cache_set_alloc(struct cache_sb *sb, c->bucket_reserve_percent = 10; c->sector_reserve_percent = 20; + mutex_init(&c->uevent_lock); + c->search = mempool_create_slab_pool(32, bch_search_cache); if (!c->search) goto err; @@ -1161,6 +1168,8 @@ static const char *run_cache_set(struct cache_set *c) closure_put(&c->caching); + bch_notify_cache_set_read_write(c); + return NULL; err: closure_sync(&cl); @@ -1262,6 +1271,9 @@ static void __bch_cache_read_only(struct cache *ca) * This will suspend the running task until outstanding writes complete. */ bch_await_scheduled_data_writes(ca); + + bch_notify_cache_read_only(ca); + /* * Device data write barrier -- no non-meta-data writes should * occur after this point. However, writes to btree buckets, @@ -1386,6 +1398,8 @@ const char *bch_cache_read_write(struct cache *ca) wake_up_process(ca->set->tiering_read); + bch_notify_cache_read_write(ca); + return err; } @@ -1516,6 +1530,8 @@ static void bch_cache_remove_work(struct work_struct *work) char buf[BDEVNAME_SIZE]; bool force = (test_bit(CACHE_DEV_FORCE_REMOVE, &ca->flags)); + bch_notify_cache_removing(ca); + mutex_lock(&bch_register_lock); allmi = cache_member_info_get(c); mi = &allmi->m[ca->sb.nr_this_dev]; @@ -1691,6 +1707,9 @@ static void bch_cache_remove_work(struct work_struct *work) mutex_lock(&bch_register_lock); bch_cache_stop(ca); mutex_unlock(&bch_register_lock); + + bch_notify_cache_removed(ca); + return; } @@ -1997,6 +2016,8 @@ have_slot: if (bch_cache_journal_alloc(ca)) goto err_put; + bch_notify_cache_added(ca); + err = bch_cache_read_write(ca); if (err) goto err_put; |