Whamcloud - gitweb
LU-17705 ptlrpc: replace synchronize_rcu() with rcu_barrier()
[fs/lustre-release.git] / lustre / obdclass / kernelcomm.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2015, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  *
31  * Author: Nathan Rutman <nathan.rutman@sun.com>
32  *
33  * Kernel <-> userspace communication routines.
34  * Using pipes for all arches.
35  */
36
37 #define DEBUG_SUBSYSTEM S_CLASS
38
39 #include <linux/file.h>
40 #include <linux/glob.h>
41 #include <net/genetlink.h>
42 #include <net/sock.h>
43
44 #include <libcfs/linux/linux-net.h>
45 #include <obd_class.h>
46 #include <obd_support.h>
47 #include <lustre_kernelcomm.h>
48
49 static struct genl_family lustre_family;
50
51 static struct ln_key_list device_list = {
52         .lkl_maxattr                    = LUSTRE_DEVICE_ATTR_MAX,
53         .lkl_list                       = {
54                 [LUSTRE_DEVICE_ATTR_HDR]        = {
55                         .lkp_value              = "devices",
56                         .lkp_key_format         = LNKF_SEQUENCE | LNKF_MAPPING,
57                         .lkp_data_type          = NLA_NUL_STRING,
58                 },
59                 [LUSTRE_DEVICE_ATTR_INDEX]      = {
60                         .lkp_value              = "index",
61                         .lkp_data_type          = NLA_U16
62                 },
63                 [LUSTRE_DEVICE_ATTR_STATUS]     = {
64                         .lkp_value              = "status",
65                         .lkp_data_type          = NLA_STRING
66                 },
67                 [LUSTRE_DEVICE_ATTR_CLASS]      = {
68                         .lkp_value              = "type",
69                         .lkp_data_type          = NLA_STRING
70                 },
71                 [LUSTRE_DEVICE_ATTR_NAME]       = {
72                         .lkp_value              = "name",
73                         .lkp_data_type          = NLA_STRING
74                 },
75                 [LUSTRE_DEVICE_ATTR_UUID]       = {
76                         .lkp_value              = "uuid",
77                         .lkp_data_type          = NLA_STRING
78                 },
79                 [LUSTRE_DEVICE_ATTR_REFCOUNT]   = {
80                         .lkp_value              = "refcount",
81                         .lkp_data_type          = NLA_U32
82                 },
83         },
84 };
85
86 struct genl_dev_list {
87         struct obd_device       *gdl_target;
88         unsigned int            gdl_start;
89 };
90
91 static inline struct genl_dev_list *
92 device_dump_ctx(struct netlink_callback *cb)
93 {
94         return (struct genl_dev_list *)cb->args[0];
95 }
96
97 /* generic ->start() handler for GET requests */
98 static int lustre_device_list_start(struct netlink_callback *cb)
99 {
100         struct genlmsghdr *gnlh = nlmsg_data(cb->nlh);
101 #ifdef HAVE_NL_PARSE_WITH_EXT_ACK
102         struct netlink_ext_ack *extack = NULL;
103 #endif
104         struct genl_dev_list *glist;
105         int msg_len, rc = 0;
106
107 #ifdef HAVE_NL_DUMP_WITH_EXT_ACK
108         extack = cb->extack;
109 #endif
110         OBD_ALLOC(glist, sizeof(*glist));
111         if (!glist)
112                 return -ENOMEM;
113
114         cb->args[0] = (long)glist;
115         glist->gdl_target = NULL;
116         glist->gdl_start = 0;
117
118         msg_len = genlmsg_len(gnlh);
119         if (msg_len > 0) {
120                 struct nlattr *params = genlmsg_data(gnlh);
121                 struct nlattr *dev;
122                 int rem;
123
124                 if (!(nla_type(params) & LN_SCALAR_ATTR_LIST)) {
125                         NL_SET_ERR_MSG(extack, "no configuration");
126                         GOTO(report_err, rc);
127                 }
128
129                 nla_for_each_nested(dev, params, rem) {
130                         struct nlattr *prop;
131                         int rem2;
132
133                         nla_for_each_nested(prop, dev, rem2) {
134                                 char name[MAX_OBD_NAME];
135                                 struct obd_device *obd;
136
137                                 if (nla_type(prop) != LN_SCALAR_ATTR_VALUE ||
138                                     nla_strcmp(prop, "name") != 0)
139                                         continue;
140
141                                 prop = nla_next(prop, &rem2);
142                                 if (nla_type(prop) != LN_SCALAR_ATTR_VALUE)
143                                         GOTO(report_err, rc = -EINVAL);
144
145                                 rc = nla_strscpy(name, prop, sizeof(name));
146                                 if (rc < 0)
147                                         GOTO(report_err, rc);
148                                 rc = 0;
149
150                                 obd = class_name2obd(name);
151                                 if (obd)
152                                         glist->gdl_target = obd;
153                         }
154                 }
155                 if (!glist->gdl_target) {
156                         NL_SET_ERR_MSG(extack, "No devices found");
157                         rc = -ENOENT;
158                 }
159         }
160 report_err:
161         if (rc < 0) {
162                 OBD_FREE(glist, sizeof(*glist));
163                 cb->args[0] = 0;
164         }
165         return rc;
166 }
167
168 static int lustre_device_list_dump(struct sk_buff *msg,
169                                    struct netlink_callback *cb)
170 {
171         struct genl_dev_list *glist = device_dump_ctx(cb);
172         struct obd_device *filter = glist->gdl_target;
173         struct obd_device *obd = NULL;
174 #ifdef HAVE_NL_PARSE_WITH_EXT_ACK
175         struct netlink_ext_ack *extack = NULL;
176 #endif
177         int portid = NETLINK_CB(cb->skb).portid;
178         int seq = cb->nlh->nlmsg_seq;
179         unsigned long idx = 0;
180         int rc = 0;
181
182 #ifdef HAVE_NL_DUMP_WITH_EXT_ACK
183         extack = cb->extack;
184 #endif
185         if (glist->gdl_start == 0) {
186                 const struct ln_key_list *all[] = {
187                         &device_list, NULL
188                 };
189
190                 rc = lnet_genl_send_scalar_list(msg, portid, seq,
191                                                 &lustre_family,
192                                                 NLM_F_CREATE | NLM_F_MULTI,
193                                                 LUSTRE_CMD_DEVICES, all);
194                 if (rc < 0) {
195                         NL_SET_ERR_MSG(extack, "failed to send key table");
196                         return rc;
197                 }
198         }
199
200         obd_device_lock();
201         obd_device_for_each_start(idx, obd, glist->gdl_start) {
202                 const char *status;
203                 void *hdr;
204
205                 if (filter && filter != obd)
206                         continue;
207
208                 hdr = genlmsg_put(msg, portid, seq, &lustre_family,
209                                   NLM_F_MULTI, LUSTRE_CMD_DEVICES);
210                 if (!hdr) {
211                         NL_SET_ERR_MSG(extack, "failed to send values");
212                         genlmsg_cancel(msg, hdr);
213                         rc = -EMSGSIZE;
214                         break;
215                 }
216
217                 if (idx == 0)
218                         nla_put_string(msg, LUSTRE_DEVICE_ATTR_HDR, "");
219
220                 nla_put_u16(msg, LUSTRE_DEVICE_ATTR_INDEX, obd->obd_minor);
221
222                 /* Collect only the index value for a single obd */
223                 if (filter) {
224                         genlmsg_end(msg, hdr);
225                         idx++;
226                         break;
227                 }
228
229                 if (obd->obd_stopping)
230                         status = "ST";
231                 else if (obd->obd_inactive)
232                         status = "IN";
233                 else if (obd->obd_set_up)
234                         status = "UP";
235                 else if (obd->obd_attached)
236                         status = "AT";
237                 else
238                         status = "--";
239
240                 nla_put_string(msg, LUSTRE_DEVICE_ATTR_STATUS, status);
241
242                 nla_put_string(msg, LUSTRE_DEVICE_ATTR_CLASS,
243                                obd->obd_type->typ_name);
244
245                 nla_put_string(msg, LUSTRE_DEVICE_ATTR_NAME,
246                                obd->obd_name);
247
248                 nla_put_string(msg, LUSTRE_DEVICE_ATTR_UUID,
249                                obd->obd_uuid.uuid);
250
251                 nla_put_u32(msg, LUSTRE_DEVICE_ATTR_REFCOUNT,
252                             kref_read(&obd->obd_refcount));
253
254                 genlmsg_end(msg, hdr);
255         }
256         obd_device_unlock();
257
258         glist->gdl_start = idx + 1;
259         rc = lnet_nl_send_error(cb->skb, portid, seq, rc);
260
261         return rc < 0 ? rc : msg->len;
262 }
263
264 #ifndef HAVE_NETLINK_CALLBACK_START
265 int lustre_old_device_list_dump(struct sk_buff *msg,
266                                 struct netlink_callback *cb)
267 {
268         if (!cb->args[0]) {
269                 int rc = lustre_device_list_start(cb);
270
271                 if (rc < 0)
272                         return rc;
273         }
274
275         return lustre_device_list_dump(msg, cb);
276 }
277 #endif
278
279 static int lustre_device_done(struct netlink_callback *cb)
280 {
281         struct genl_dev_list *glist;
282
283         glist = device_dump_ctx(cb);
284         if (glist) {
285                 OBD_FREE(glist, sizeof(*glist));
286                 cb->args[0] = 0;
287         }
288
289         return 0;
290 }
291
292 static const struct genl_multicast_group lustre_mcast_grps[] = {
293         { .name         = "devices",            },
294 };
295
296 static const struct genl_ops lustre_genl_ops[] = {
297         {
298                 .cmd            = LUSTRE_CMD_DEVICES,
299 #ifdef HAVE_NETLINK_CALLBACK_START
300                 .start          = lustre_device_list_start,
301                 .dumpit         = lustre_device_list_dump,
302 #else
303                 .dumpit         = lustre_old_device_list_dump,
304 #endif
305                 .done           = lustre_device_done,
306         },
307 };
308
309 static struct genl_family lustre_family = {
310         .name           = LUSTRE_GENL_NAME,
311         .version        = LUSTRE_GENL_VERSION,
312         .module         = THIS_MODULE,
313         .ops            = lustre_genl_ops,
314         .n_ops          = ARRAY_SIZE(lustre_genl_ops),
315         .mcgrps         = lustre_mcast_grps,
316         .n_mcgrps       = ARRAY_SIZE(lustre_mcast_grps),
317 #ifdef GENL_FAMILY_HAS_RESV_START_OP
318         .resv_start_op  = __LUSTRE_CMD_MAX_PLUS_ONE,
319 #endif
320 };
321
322 /**
323  * libcfs_kkuc_msg_put - send an message from kernel to userspace
324  * @param fp to send the message to
325  * @param payload Payload data.  First field of payload is always
326  *   struct kuc_hdr
327  */
328 int libcfs_kkuc_msg_put(struct file *filp, void *payload)
329 {
330         struct kuc_hdr *kuch = (struct kuc_hdr *)payload;
331         ssize_t count = kuch->kuc_msglen;
332         loff_t offset = 0;
333         int rc = 0;
334
335         if (IS_ERR_OR_NULL(filp))
336                 return -EBADF;
337
338         if (kuch->kuc_magic != KUC_MAGIC) {
339                 CERROR("KernelComm: bad magic %x\n", kuch->kuc_magic);
340                 return -ENOSYS;
341         }
342
343         while (count > 0) {
344                 rc = cfs_kernel_write(filp, payload, count, &offset);
345                 if (rc < 0)
346                         break;
347                 count -= rc;
348                 payload += rc;
349                 rc = 0;
350         }
351
352         if (rc < 0)
353                 CWARN("message send failed (%d)\n", rc);
354         else
355                 CDEBUG(D_HSM, "Sent message rc=%d, fp=%p\n", rc, filp);
356
357         return rc;
358 }
359 EXPORT_SYMBOL(libcfs_kkuc_msg_put);
360
361 /* Broadcast groups are global across all mounted filesystems;
362  * i.e. registering for a group on 1 fs will get messages for that
363  * group from any fs */
364 /** A single group registration has a uid and a file pointer */
365 struct kkuc_reg {
366         struct list_head kr_chain;
367         struct obd_uuid  kr_uuid;
368         int              kr_uid;
369         struct file     *kr_fp;
370         char             kr_data[0];
371 };
372
373 static struct list_head kkuc_groups[KUC_GRP_MAX + 1];
374 /* Protect message sending against remove and adds */
375 static DECLARE_RWSEM(kg_sem);
376
377 static inline bool libcfs_kkuc_group_is_valid(int group)
378 {
379         return 0 <= group && group < ARRAY_SIZE(kkuc_groups);
380 }
381
382 int libcfs_kkuc_init(void)
383 {
384         int group;
385
386         for (group = 0; group < ARRAY_SIZE(kkuc_groups); group++)
387                 INIT_LIST_HEAD(&kkuc_groups[group]);
388
389         return genl_register_family(&lustre_family);
390 }
391
392 void libcfs_kkuc_fini(void)
393 {
394         genl_unregister_family(&lustre_family);
395 }
396
397 /** Add a receiver to a broadcast group
398  * @param filp pipe to write into
399  * @param uid identifier for this receiver
400  * @param group group number
401  * @param data user data
402  */
403 int libcfs_kkuc_group_add(struct file *filp, const struct obd_uuid *uuid,
404                           int uid, int group, void *data, size_t data_len)
405 {
406         struct kkuc_reg *reg;
407
408         if (!libcfs_kkuc_group_is_valid(group)) {
409                 CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group);
410                 return -EINVAL;
411         }
412
413         /* fput in group_rem */
414         if (filp == NULL)
415                 return -EBADF;
416
417         /* freed in group_rem */
418         reg = kzalloc(sizeof(*reg) + data_len, 0);
419         if (reg == NULL)
420                 return -ENOMEM;
421
422         reg->kr_uuid = *uuid;
423         reg->kr_fp = filp;
424         reg->kr_uid = uid;
425         memcpy(reg->kr_data, data, data_len);
426
427         down_write(&kg_sem);
428         list_add(&reg->kr_chain, &kkuc_groups[group]);
429         up_write(&kg_sem);
430
431         CDEBUG(D_HSM, "Added uid=%d fp=%p to group %d\n", uid, filp, group);
432
433         return 0;
434 }
435 EXPORT_SYMBOL(libcfs_kkuc_group_add);
436
437 int libcfs_kkuc_group_rem(const struct obd_uuid *uuid, int uid, int group)
438 {
439         struct kkuc_reg *reg, *next;
440         ENTRY;
441
442         if (!libcfs_kkuc_group_is_valid(group)) {
443                 CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group);
444                 return -EINVAL;
445         }
446
447         if (uid == 0) {
448                 /* Broadcast a shutdown message */
449                 struct kuc_hdr lh;
450
451                 lh.kuc_magic = KUC_MAGIC;
452                 lh.kuc_transport = KUC_TRANSPORT_GENERIC;
453                 lh.kuc_msgtype = KUC_MSG_SHUTDOWN;
454                 lh.kuc_msglen = sizeof(lh);
455                 libcfs_kkuc_group_put(uuid, group, &lh);
456         }
457
458         down_write(&kg_sem);
459         list_for_each_entry_safe(reg, next, &kkuc_groups[group], kr_chain) {
460                 if (obd_uuid_equals(uuid, &reg->kr_uuid) &&
461                     (uid == 0 || uid == reg->kr_uid)) {
462                         list_del(&reg->kr_chain);
463                         CDEBUG(D_HSM, "Removed uid=%d fp=%p from group %d\n",
464                                 reg->kr_uid, reg->kr_fp, group);
465                         if (reg->kr_fp != NULL)
466                                 fput(reg->kr_fp);
467                         kfree(reg);
468                 }
469         }
470         up_write(&kg_sem);
471
472         RETURN(0);
473 }
474 EXPORT_SYMBOL(libcfs_kkuc_group_rem);
475
476 int libcfs_kkuc_group_put(const struct obd_uuid *uuid, int group, void *payload)
477 {
478         struct kkuc_reg *reg;
479         int              rc = 0;
480         int one_success = 0;
481         ENTRY;
482
483         if (!libcfs_kkuc_group_is_valid(group)) {
484                 CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group);
485                 return -EINVAL;
486         }
487
488         down_write(&kg_sem);
489
490         if (unlikely(list_empty(&kkuc_groups[group])) ||
491             unlikely(CFS_FAIL_CHECK(OBD_FAIL_MDS_HSM_CT_REGISTER_NET))) {
492                 /* no agent have fully registered, CDT will retry */
493                 up_write(&kg_sem);
494                 RETURN(-EAGAIN);
495         }
496
497         list_for_each_entry(reg, &kkuc_groups[group], kr_chain) {
498                 if (obd_uuid_equals(uuid, &reg->kr_uuid) &&
499                     reg->kr_fp != NULL) {
500                         rc = libcfs_kkuc_msg_put(reg->kr_fp, payload);
501                         if (rc == 0)
502                                 one_success = 1;
503                         else if (rc == -EPIPE) {
504                                 fput(reg->kr_fp);
505                                 reg->kr_fp = NULL;
506                         }
507                 }
508         }
509         up_write(&kg_sem);
510
511         /* don't return an error if the message has been delivered
512          * at least to one agent */
513         if (one_success)
514                 rc = 0;
515
516         RETURN(rc);
517 }
518 EXPORT_SYMBOL(libcfs_kkuc_group_put);
519
520 /**
521  * Calls a callback function for each link of the given kuc group.
522  * @param group the group to call the function on.
523  * @param cb_func the function to be called.
524  * @param cb_arg extra argument to be passed to the callback function.
525  */
526 int libcfs_kkuc_group_foreach(const struct obd_uuid *uuid, int group,
527                               libcfs_kkuc_cb_t cb_func, void *cb_arg)
528 {
529         struct kkuc_reg *reg;
530         int              rc = 0;
531         ENTRY;
532
533         if (!libcfs_kkuc_group_is_valid(group)) {
534                 CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group);
535                 RETURN(-EINVAL);
536         }
537
538         down_read(&kg_sem);
539         list_for_each_entry(reg, &kkuc_groups[group], kr_chain) {
540                 if (obd_uuid_equals(uuid, &reg->kr_uuid) && reg->kr_fp != NULL)
541                         rc = cb_func(reg->kr_data, cb_arg);
542         }
543         up_read(&kg_sem);
544
545         RETURN(rc);
546 }
547 EXPORT_SYMBOL(libcfs_kkuc_group_foreach);