Whamcloud - gitweb
LU-6142 lustre: fix minor typos in comments
[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                 nla_for_each_attr(dev, params, msg_len, rem) {
125                         struct nlattr *prop;
126                         int rem2;
127
128                         nla_for_each_nested(prop, dev, rem2) {
129                                 char name[MAX_OBD_NAME];
130                                 struct obd_device *obd;
131
132                                 if (nla_type(prop) != LN_SCALAR_ATTR_VALUE ||
133                                     nla_strcmp(prop, "name") != 0)
134                                         continue;
135
136                                 prop = nla_next(prop, &rem2);
137                                 if (nla_type(prop) != LN_SCALAR_ATTR_VALUE)
138                                         GOTO(report_err, rc = -EINVAL);
139
140                                 rc = nla_strscpy(name, prop, sizeof(name));
141                                 if (rc < 0)
142                                         GOTO(report_err, rc);
143                                 rc = 0;
144
145                                 obd = class_name2obd(name);
146                                 if (obd)
147                                         glist->gdl_target = obd;
148                         }
149                 }
150                 if (!glist->gdl_target) {
151                         NL_SET_ERR_MSG(extack, "No devices found");
152                         rc = -ENOENT;
153                 }
154         }
155 report_err:
156         if (rc < 0) {
157                 OBD_FREE(glist, sizeof(*glist));
158                 cb->args[0] = 0;
159         }
160         return rc;
161 }
162
163 static int lustre_device_list_dump(struct sk_buff *msg,
164                                    struct netlink_callback *cb)
165 {
166         struct genl_dev_list *glist = device_dump_ctx(cb);
167         struct obd_device *filter = glist->gdl_target;
168 #ifdef HAVE_NL_PARSE_WITH_EXT_ACK
169         struct netlink_ext_ack *extack = NULL;
170 #endif
171         int portid = NETLINK_CB(cb->skb).portid;
172         int seq = cb->nlh->nlmsg_seq;
173         int idx, rc = 0;
174
175 #ifdef HAVE_NL_DUMP_WITH_EXT_ACK
176         extack = cb->extack;
177 #endif
178         if (glist->gdl_start == 0) {
179                 const struct ln_key_list *all[] = {
180                         &device_list, NULL
181                 };
182
183                 rc = lnet_genl_send_scalar_list(msg, portid, seq,
184                                                 &lustre_family,
185                                                 NLM_F_CREATE | NLM_F_MULTI,
186                                                 LUSTRE_CMD_DEVICES, all);
187                 if (rc < 0) {
188                         NL_SET_ERR_MSG(extack, "failed to send key table");
189                         return rc;
190                 }
191         }
192
193         for (idx = glist->gdl_start; idx < class_devno_max(); idx++) {
194                 struct obd_device *obd;
195                 const char *status;
196                 void *hdr;
197
198                 obd = class_num2obd(idx);
199                 if (!obd)
200                         continue;
201
202                 if (filter && filter != obd)
203                         continue;
204
205                 hdr = genlmsg_put(msg, portid, seq, &lustre_family,
206                                   NLM_F_MULTI, LUSTRE_CMD_DEVICES);
207                 if (!hdr) {
208                         NL_SET_ERR_MSG(extack, "failed to send values");
209                         genlmsg_cancel(msg, hdr);
210                         rc = -EMSGSIZE;
211                         break;
212                 }
213
214                 if (idx == 0)
215                         nla_put_string(msg, LUSTRE_DEVICE_ATTR_HDR, "");
216
217                 nla_put_u16(msg, LUSTRE_DEVICE_ATTR_INDEX, obd->obd_minor);
218
219                 /* Collect only the index value for a single obd */
220                 if (filter) {
221                         genlmsg_end(msg, hdr);
222                         idx++;
223                         break;
224                 }
225
226                 if (obd->obd_stopping)
227                         status = "ST";
228                 else if (obd->obd_inactive)
229                         status = "IN";
230                 else if (obd->obd_set_up)
231                         status = "UP";
232                 else if (obd->obd_attached)
233                         status = "AT";
234                 else
235                         status = "--";
236
237                 nla_put_string(msg, LUSTRE_DEVICE_ATTR_STATUS, status);
238
239                 nla_put_string(msg, LUSTRE_DEVICE_ATTR_CLASS,
240                                obd->obd_type->typ_name);
241
242                 nla_put_string(msg, LUSTRE_DEVICE_ATTR_NAME,
243                                obd->obd_name);
244
245                 nla_put_string(msg, LUSTRE_DEVICE_ATTR_UUID,
246                                obd->obd_uuid.uuid);
247
248                 nla_put_u32(msg, LUSTRE_DEVICE_ATTR_REFCOUNT,
249                             atomic_read(&obd->obd_refcount));
250
251                 genlmsg_end(msg, hdr);
252         }
253
254         glist->gdl_start = idx;
255         rc = lnet_nl_send_error(cb->skb, portid, seq, rc);
256         return rc < 0 ? rc : msg->len;
257 }
258
259 #ifndef HAVE_NETLINK_CALLBACK_START
260 int lustre_old_device_list_dump(struct sk_buff *msg,
261                                 struct netlink_callback *cb)
262 {
263         if (!cb->args[0]) {
264                 int rc = lustre_device_list_start(cb);
265
266                 if (rc < 0)
267                         return rc;
268         }
269
270         return lustre_device_list_dump(msg, cb);
271 }
272 #endif
273
274 int lustre_device_done(struct netlink_callback *cb)
275 {
276         struct genl_dev_list *glist;
277
278         glist = device_dump_ctx(cb);
279         if (glist) {
280                 OBD_FREE(glist, sizeof(*glist));
281                 cb->args[0] = 0;
282         }
283
284         return 0;
285 }
286
287 static const struct genl_multicast_group lustre_mcast_grps[] = {
288         { .name         = "devices",            },
289 };
290
291 static const struct genl_ops lustre_genl_ops[] = {
292         {
293                 .cmd            = LUSTRE_CMD_DEVICES,
294 #ifdef HAVE_NETLINK_CALLBACK_START
295                 .start          = lustre_device_list_start,
296                 .dumpit         = lustre_device_list_dump,
297 #else
298                 .dumpit         = lustre_old_device_list_dump,
299 #endif
300                 .done           = lustre_device_done,
301         },
302 };
303
304 static struct genl_family lustre_family = {
305         .name           = LUSTRE_GENL_NAME,
306         .version        = LUSTRE_GENL_VERSION,
307         .module         = THIS_MODULE,
308         .ops            = lustre_genl_ops,
309         .n_ops          = ARRAY_SIZE(lustre_genl_ops),
310         .mcgrps         = lustre_mcast_grps,
311         .n_mcgrps       = ARRAY_SIZE(lustre_mcast_grps),
312 };
313
314 /**
315  * libcfs_kkuc_msg_put - send an message from kernel to userspace
316  * @param fp to send the message to
317  * @param payload Payload data.  First field of payload is always
318  *   struct kuc_hdr
319  */
320 int libcfs_kkuc_msg_put(struct file *filp, void *payload)
321 {
322         struct kuc_hdr *kuch = (struct kuc_hdr *)payload;
323         ssize_t count = kuch->kuc_msglen;
324         loff_t offset = 0;
325         int rc = 0;
326
327         if (IS_ERR_OR_NULL(filp))
328                 return -EBADF;
329
330         if (kuch->kuc_magic != KUC_MAGIC) {
331                 CERROR("KernelComm: bad magic %x\n", kuch->kuc_magic);
332                 return -ENOSYS;
333         }
334
335         while (count > 0) {
336                 rc = cfs_kernel_write(filp, payload, count, &offset);
337                 if (rc < 0)
338                         break;
339                 count -= rc;
340                 payload += rc;
341                 rc = 0;
342         }
343
344         if (rc < 0)
345                 CWARN("message send failed (%d)\n", rc);
346         else
347                 CDEBUG(D_HSM, "Sent message rc=%d, fp=%p\n", rc, filp);
348
349         return rc;
350 }
351 EXPORT_SYMBOL(libcfs_kkuc_msg_put);
352
353 /* Broadcast groups are global across all mounted filesystems;
354  * i.e. registering for a group on 1 fs will get messages for that
355  * group from any fs */
356 /** A single group registration has a uid and a file pointer */
357 struct kkuc_reg {
358         struct list_head kr_chain;
359         struct obd_uuid  kr_uuid;
360         int              kr_uid;
361         struct file     *kr_fp;
362         char             kr_data[0];
363 };
364
365 static struct list_head kkuc_groups[KUC_GRP_MAX + 1];
366 /* Protect message sending against remove and adds */
367 static DECLARE_RWSEM(kg_sem);
368
369 static inline bool libcfs_kkuc_group_is_valid(int group)
370 {
371         return 0 <= group && group < ARRAY_SIZE(kkuc_groups);
372 }
373
374 int libcfs_kkuc_init(void)
375 {
376         int group;
377
378         for (group = 0; group < ARRAY_SIZE(kkuc_groups); group++)
379                 INIT_LIST_HEAD(&kkuc_groups[group]);
380
381         return genl_register_family(&lustre_family);
382 }
383
384 void libcfs_kkuc_fini(void)
385 {
386         genl_unregister_family(&lustre_family);
387 }
388
389 /** Add a receiver to a broadcast group
390  * @param filp pipe to write into
391  * @param uid identifier for this receiver
392  * @param group group number
393  * @param data user data
394  */
395 int libcfs_kkuc_group_add(struct file *filp, const struct obd_uuid *uuid,
396                           int uid, int group, void *data, size_t data_len)
397 {
398         struct kkuc_reg *reg;
399
400         if (!libcfs_kkuc_group_is_valid(group)) {
401                 CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group);
402                 return -EINVAL;
403         }
404
405         /* fput in group_rem */
406         if (filp == NULL)
407                 return -EBADF;
408
409         /* freed in group_rem */
410         reg = kzalloc(sizeof(*reg) + data_len, 0);
411         if (reg == NULL)
412                 return -ENOMEM;
413
414         reg->kr_uuid = *uuid;
415         reg->kr_fp = filp;
416         reg->kr_uid = uid;
417         memcpy(reg->kr_data, data, data_len);
418
419         down_write(&kg_sem);
420         list_add(&reg->kr_chain, &kkuc_groups[group]);
421         up_write(&kg_sem);
422
423         CDEBUG(D_HSM, "Added uid=%d fp=%p to group %d\n", uid, filp, group);
424
425         return 0;
426 }
427 EXPORT_SYMBOL(libcfs_kkuc_group_add);
428
429 int libcfs_kkuc_group_rem(const struct obd_uuid *uuid, int uid, int group)
430 {
431         struct kkuc_reg *reg, *next;
432         ENTRY;
433
434         if (!libcfs_kkuc_group_is_valid(group)) {
435                 CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group);
436                 return -EINVAL;
437         }
438
439         if (uid == 0) {
440                 /* Broadcast a shutdown message */
441                 struct kuc_hdr lh;
442
443                 lh.kuc_magic = KUC_MAGIC;
444                 lh.kuc_transport = KUC_TRANSPORT_GENERIC;
445                 lh.kuc_msgtype = KUC_MSG_SHUTDOWN;
446                 lh.kuc_msglen = sizeof(lh);
447                 libcfs_kkuc_group_put(uuid, group, &lh);
448         }
449
450         down_write(&kg_sem);
451         list_for_each_entry_safe(reg, next, &kkuc_groups[group], kr_chain) {
452                 if (obd_uuid_equals(uuid, &reg->kr_uuid) &&
453                     (uid == 0 || uid == reg->kr_uid)) {
454                         list_del(&reg->kr_chain);
455                         CDEBUG(D_HSM, "Removed uid=%d fp=%p from group %d\n",
456                                 reg->kr_uid, reg->kr_fp, group);
457                         if (reg->kr_fp != NULL)
458                                 fput(reg->kr_fp);
459                         kfree(reg);
460                 }
461         }
462         up_write(&kg_sem);
463
464         RETURN(0);
465 }
466 EXPORT_SYMBOL(libcfs_kkuc_group_rem);
467
468 int libcfs_kkuc_group_put(const struct obd_uuid *uuid, int group, void *payload)
469 {
470         struct kkuc_reg *reg;
471         int              rc = 0;
472         int one_success = 0;
473         ENTRY;
474
475         if (!libcfs_kkuc_group_is_valid(group)) {
476                 CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group);
477                 return -EINVAL;
478         }
479
480         down_write(&kg_sem);
481
482         if (unlikely(list_empty(&kkuc_groups[group])) ||
483             unlikely(OBD_FAIL_CHECK(OBD_FAIL_MDS_HSM_CT_REGISTER_NET))) {
484                 /* no agent have fully registered, CDT will retry */
485                 up_write(&kg_sem);
486                 RETURN(-EAGAIN);
487         }
488
489         list_for_each_entry(reg, &kkuc_groups[group], kr_chain) {
490                 if (obd_uuid_equals(uuid, &reg->kr_uuid) &&
491                     reg->kr_fp != NULL) {
492                         rc = libcfs_kkuc_msg_put(reg->kr_fp, payload);
493                         if (rc == 0)
494                                 one_success = 1;
495                         else if (rc == -EPIPE) {
496                                 fput(reg->kr_fp);
497                                 reg->kr_fp = NULL;
498                         }
499                 }
500         }
501         up_write(&kg_sem);
502
503         /* don't return an error if the message has been delivered
504          * at least to one agent */
505         if (one_success)
506                 rc = 0;
507
508         RETURN(rc);
509 }
510 EXPORT_SYMBOL(libcfs_kkuc_group_put);
511
512 /**
513  * Calls a callback function for each link of the given kuc group.
514  * @param group the group to call the function on.
515  * @param cb_func the function to be called.
516  * @param cb_arg extra argument to be passed to the callback function.
517  */
518 int libcfs_kkuc_group_foreach(const struct obd_uuid *uuid, int group,
519                               libcfs_kkuc_cb_t cb_func, void *cb_arg)
520 {
521         struct kkuc_reg *reg;
522         int              rc = 0;
523         ENTRY;
524
525         if (!libcfs_kkuc_group_is_valid(group)) {
526                 CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group);
527                 RETURN(-EINVAL);
528         }
529
530         down_read(&kg_sem);
531         list_for_each_entry(reg, &kkuc_groups[group], kr_chain) {
532                 if (obd_uuid_equals(uuid, &reg->kr_uuid) && reg->kr_fp != NULL)
533                         rc = cb_func(reg->kr_data, cb_arg);
534         }
535         up_read(&kg_sem);
536
537         RETURN(rc);
538 }
539 EXPORT_SYMBOL(libcfs_kkuc_group_foreach);