summaryrefslogtreecommitdiff
path: root/libbcache/notify.c
blob: 00b7999a98bd616371d269c1da26d77df6f6dec9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * Code for sending uevent notifications to user-space.
 *
 * Copyright 2015 Datera, Inc.
 */

#include "bcache.h"
#include "notify.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.user_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->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_fs_read_write(struct cache_set *c)
{
	notify_get(c);
	notify_var(c, "STATE=active");
	notify_put(c);
}

void bch_notify_fs_read_only(struct cache_set *c)
{
	notify_get(c);
	notify_var(c, "STATE=readonly");
	notify_put(c);
}

void bch_notify_fs_stopped(struct cache_set *c)
{
	notify_get(c);
	notify_var(c, "STATE=stopped");
	notify_put(c);
}

void bch_notify_dev_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_dev_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_dev_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_dev_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_dev_remove_failed(struct cache *ca)
{
	struct cache_set *c = ca->set;

	notify_get_cache(ca);
	notify_var(c, "STATE=remove_failed");
	notify_put(c);
}

void bch_notify_dev_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_dev_error(struct cache *ca, bool fatal)
{
	struct cache_set *c = ca->set;

	notify_get_cache(ca);
	notify_var(c, "STATE=error");
	notify_var(c, "FATAL=%d", fatal);
	notify_put(c);
}