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#define DEBUG_SUBSYSTEM S_CLASS
39#define D_KUC D_OTHER
40
41#include "../include/obd_support.h"
42#include "../include/lustre_kernelcomm.h"
43
44
45
46
47
48
49
50int libcfs_kkuc_msg_put(struct file *filp, void *payload)
51{
52 struct kuc_hdr *kuch = (struct kuc_hdr *)payload;
53 ssize_t count = kuch->kuc_msglen;
54 loff_t offset = 0;
55 mm_segment_t fs;
56 int rc = -ENXIO;
57
58 if (IS_ERR_OR_NULL(filp))
59 return -EBADF;
60
61 if (kuch->kuc_magic != KUC_MAGIC) {
62 CERROR("KernelComm: bad magic %x\n", kuch->kuc_magic);
63 return rc;
64 }
65
66 fs = get_fs();
67 set_fs(KERNEL_DS);
68 while (count > 0) {
69 rc = vfs_write(filp, (void __force __user *)payload,
70 count, &offset);
71 if (rc < 0)
72 break;
73 count -= rc;
74 payload += rc;
75 rc = 0;
76 }
77 set_fs(fs);
78
79 if (rc < 0)
80 CWARN("message send failed (%d)\n", rc);
81 else
82 CDEBUG(D_KUC, "Sent message rc=%d, fp=%p\n", rc, filp);
83
84 return rc;
85}
86EXPORT_SYMBOL(libcfs_kkuc_msg_put);
87
88
89
90
91
92
93
94struct kkuc_reg {
95 struct list_head kr_chain;
96 int kr_uid;
97 struct file *kr_fp;
98 char kr_data[0];
99};
100
101static struct list_head kkuc_groups[KUC_GRP_MAX + 1] = {};
102
103static DECLARE_RWSEM(kg_sem);
104
105
106
107
108
109
110
111int libcfs_kkuc_group_add(struct file *filp, int uid, unsigned int group,
112 void *data, size_t data_len)
113{
114 struct kkuc_reg *reg;
115
116 if (group > KUC_GRP_MAX) {
117 CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group);
118 return -EINVAL;
119 }
120
121
122 if (!filp)
123 return -EBADF;
124
125
126 reg = kmalloc(sizeof(*reg) + data_len, 0);
127 if (!reg)
128 return -ENOMEM;
129
130 reg->kr_fp = filp;
131 reg->kr_uid = uid;
132 memcpy(reg->kr_data, data, data_len);
133
134 down_write(&kg_sem);
135 if (!kkuc_groups[group].next)
136 INIT_LIST_HEAD(&kkuc_groups[group]);
137 list_add(®->kr_chain, &kkuc_groups[group]);
138 up_write(&kg_sem);
139
140 CDEBUG(D_KUC, "Added uid=%d fp=%p to group %d\n", uid, filp, group);
141
142 return 0;
143}
144EXPORT_SYMBOL(libcfs_kkuc_group_add);
145
146int libcfs_kkuc_group_rem(int uid, unsigned int group)
147{
148 struct kkuc_reg *reg, *next;
149
150 if (!kkuc_groups[group].next)
151 return 0;
152
153 if (!uid) {
154
155 struct kuc_hdr lh;
156
157 lh.kuc_magic = KUC_MAGIC;
158 lh.kuc_transport = KUC_TRANSPORT_GENERIC;
159 lh.kuc_msgtype = KUC_MSG_SHUTDOWN;
160 lh.kuc_msglen = sizeof(lh);
161 libcfs_kkuc_group_put(group, &lh);
162 }
163
164 down_write(&kg_sem);
165 list_for_each_entry_safe(reg, next, &kkuc_groups[group], kr_chain) {
166 if (!uid || (uid == reg->kr_uid)) {
167 list_del(®->kr_chain);
168 CDEBUG(D_KUC, "Removed uid=%d fp=%p from group %d\n",
169 reg->kr_uid, reg->kr_fp, group);
170 if (reg->kr_fp)
171 fput(reg->kr_fp);
172 kfree(reg);
173 }
174 }
175 up_write(&kg_sem);
176
177 return 0;
178}
179EXPORT_SYMBOL(libcfs_kkuc_group_rem);
180
181int libcfs_kkuc_group_put(unsigned int group, void *payload)
182{
183 struct kkuc_reg *reg;
184 int rc = 0;
185 int one_success = 0;
186
187 down_write(&kg_sem);
188 list_for_each_entry(reg, &kkuc_groups[group], kr_chain) {
189 if (reg->kr_fp) {
190 rc = libcfs_kkuc_msg_put(reg->kr_fp, payload);
191 if (!rc) {
192 one_success = 1;
193 } else if (rc == -EPIPE) {
194 fput(reg->kr_fp);
195 reg->kr_fp = NULL;
196 }
197 }
198 }
199 up_write(&kg_sem);
200
201
202
203
204
205 if (one_success)
206 rc = 0;
207
208 return rc;
209}
210EXPORT_SYMBOL(libcfs_kkuc_group_put);
211
212
213
214
215
216
217
218int libcfs_kkuc_group_foreach(unsigned int group, libcfs_kkuc_cb_t cb_func,
219 void *cb_arg)
220{
221 struct kkuc_reg *reg;
222 int rc = 0;
223
224 if (group > KUC_GRP_MAX) {
225 CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group);
226 return -EINVAL;
227 }
228
229
230 if (!kkuc_groups[group].next)
231 return 0;
232
233 down_read(&kg_sem);
234 list_for_each_entry(reg, &kkuc_groups[group], kr_chain) {
235 if (reg->kr_fp)
236 rc = cb_func(reg->kr_data, cb_arg);
237 }
238 up_read(&kg_sem);
239
240 return rc;
241}
242EXPORT_SYMBOL(libcfs_kkuc_group_foreach);
243