summaryrefslogtreecommitdiff
path: root/libbcache/notify.c
blob: 1d5f626fcf5d77db1fde0eaa97278d874dd47428 (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
/*
 * 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 bch_fs *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 bch_dev *ca)
{
	struct bch_fs *c = ca->fs;

	notify_get(c);
	notify_var(c, "UUID=%pU", ca->uuid.b);
	notify_var(c, "BLOCKDEV=%s", ca->name);
}

static void notify_put(struct bch_fs *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 bch_fs *c)
{
	notify_get(c);
	notify_var(c, "STATE=active");
	notify_put(c);
}

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

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

void bch_notify_dev_read_write(struct bch_dev *ca)
{
	struct bch_fs *c = ca->fs;

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

void bch_notify_dev_read_only(struct bch_dev *ca)
{
	struct bch_fs *c = ca->fs;

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

void bch_notify_dev_added(struct bch_dev *ca)
{
	struct bch_fs *c = ca->fs;

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

void bch_notify_dev_removing(struct bch_dev *ca)
{
	struct bch_fs *c = ca->fs;

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

void bch_notify_dev_remove_failed(struct bch_dev *ca)
{
	struct bch_fs *c = ca->fs;

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

void bch_notify_dev_removed(struct bch_dev *ca)
{
	struct bch_fs *c = ca->fs;

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

void bch_notify_dev_error(struct bch_dev *ca, bool fatal)
{
	struct bch_fs *c = ca->fs;

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