kernel_user_comm.c revision 29aaf4962a3bce337d37176858ef1025b9f29cc4
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.sun.com/software/products/lustre/docs/GPLv2.pdf 19 * 20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 21 * CA 95054 USA or visit www.sun.com if you need additional information or 22 * have any questions. 23 * 24 * GPL HEADER END 25 */ 26/* 27 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 28 * Use is subject to license terms. 29 * 30 * Copyright (c) 2012, Intel Corporation. 31 */ 32/* 33 * This file is part of Lustre, http://www.lustre.org/ 34 * Lustre is a trademark of Sun Microsystems, Inc. 35 * 36 * Author: Nathan Rutman <nathan.rutman@sun.com> 37 * 38 * Kernel <-> userspace communication routines. 39 * Using pipes for all arches. 40 */ 41 42#define DEBUG_SUBSYSTEM S_CLASS 43#define D_KUC D_OTHER 44 45#include <linux/libcfs/libcfs.h> 46 47#ifdef LUSTRE_UTILS 48/* This is the userspace side. */ 49 50/** Start the userspace side of a KUC pipe. 51 * @param link Private descriptor for pipe/socket. 52 * @param groups KUC broadcast group to listen to 53 * (can be null for unicast to this pid) 54 */ 55int libcfs_ukuc_start(lustre_kernelcomm *link, int group) 56{ 57 int pfd[2]; 58 59 if (pipe(pfd) < 0) 60 return -errno; 61 62 memset(link, 0, sizeof(*link)); 63 link->lk_rfd = pfd[0]; 64 link->lk_wfd = pfd[1]; 65 link->lk_group = group; 66 link->lk_uid = getpid(); 67 return 0; 68} 69 70int libcfs_ukuc_stop(lustre_kernelcomm *link) 71{ 72 if (link->lk_wfd > 0) 73 close(link->lk_wfd); 74 return close(link->lk_rfd); 75} 76 77#define lhsz sizeof(*kuch) 78 79/** Read a message from the link. 80 * Allocates memory, returns handle 81 * 82 * @param link Private descriptor for pipe/socket. 83 * @param buf Buffer to read into, must include size for kuc_hdr 84 * @param maxsize Maximum message size allowed 85 * @param transport Only listen to messages on this transport 86 * (and the generic transport) 87 */ 88int libcfs_ukuc_msg_get(lustre_kernelcomm *link, char *buf, int maxsize, 89 int transport) 90{ 91 struct kuc_hdr *kuch; 92 int rc = 0; 93 94 memset(buf, 0, maxsize); 95 96 CDEBUG(D_KUC, "Waiting for message from kernel on fd %d\n", 97 link->lk_rfd); 98 99 while (1) { 100 /* Read header first to get message size */ 101 rc = read(link->lk_rfd, buf, lhsz); 102 if (rc <= 0) { 103 rc = -errno; 104 break; 105 } 106 kuch = (struct kuc_hdr *)buf; 107 108 CDEBUG(D_KUC, "Received message mg=%x t=%d m=%d l=%d\n", 109 kuch->kuc_magic, kuch->kuc_transport, kuch->kuc_msgtype, 110 kuch->kuc_msglen); 111 112 if (kuch->kuc_magic != KUC_MAGIC) { 113 CERROR("bad message magic %x != %x\n", 114 kuch->kuc_magic, KUC_MAGIC); 115 rc = -EPROTO; 116 break; 117 } 118 119 if (kuch->kuc_msglen > maxsize) { 120 rc = -EMSGSIZE; 121 break; 122 } 123 124 /* Read payload */ 125 rc = read(link->lk_rfd, buf + lhsz, kuch->kuc_msglen - lhsz); 126 if (rc < 0) { 127 rc = -errno; 128 break; 129 } 130 if (rc < (kuch->kuc_msglen - lhsz)) { 131 CERROR("short read: got %d of %d bytes\n", 132 rc, kuch->kuc_msglen); 133 rc = -EPROTO; 134 break; 135 } 136 137 if (kuch->kuc_transport == transport || 138 kuch->kuc_transport == KUC_TRANSPORT_GENERIC) { 139 return 0; 140 } 141 /* Drop messages for other transports */ 142 } 143 return rc; 144} 145 146#else /* LUSTRE_UTILS */ 147/* This is the kernel side (liblustre as well). */ 148 149/** 150 * libcfs_kkuc_msg_put - send an message from kernel to userspace 151 * @param fp to send the message to 152 * @param payload Payload data. First field of payload is always 153 * struct kuc_hdr 154 */ 155int libcfs_kkuc_msg_put(struct file *filp, void *payload) 156{ 157 struct kuc_hdr *kuch = (struct kuc_hdr *)payload; 158 ssize_t count = kuch->kuc_msglen; 159 loff_t offset = 0; 160 mm_segment_t fs; 161 int rc = -ENOSYS; 162 163 if (filp == NULL || IS_ERR(filp)) 164 return -EBADF; 165 166 if (kuch->kuc_magic != KUC_MAGIC) { 167 CERROR("KernelComm: bad magic %x\n", kuch->kuc_magic); 168 return -ENOSYS; 169 } 170 171 fs = get_fs(); 172 set_fs(KERNEL_DS); 173 while (count > 0) { 174 rc = vfs_write(filp, (void __force __user *)payload, 175 count, &offset); 176 if (rc < 0) 177 break; 178 count -= rc; 179 payload += rc; 180 rc = 0; 181 } 182 set_fs(fs); 183 184 if (rc < 0) 185 CWARN("message send failed (%d)\n", rc); 186 else 187 CDEBUG(D_KUC, "Sent message rc=%d, fp=%p\n", rc, filp); 188 189 return rc; 190} 191EXPORT_SYMBOL(libcfs_kkuc_msg_put); 192 193/* Broadcast groups are global across all mounted filesystems; 194 * i.e. registering for a group on 1 fs will get messages for that 195 * group from any fs */ 196/** A single group reigstration has a uid and a file pointer */ 197struct kkuc_reg { 198 struct list_head kr_chain; 199 int kr_uid; 200 struct file *kr_fp; 201 __u32 kr_data; 202}; 203static struct list_head kkuc_groups[KUC_GRP_MAX+1] = {}; 204/* Protect message sending against remove and adds */ 205static DECLARE_RWSEM(kg_sem); 206 207/** Add a receiver to a broadcast group 208 * @param filp pipe to write into 209 * @param uid identidier for this receiver 210 * @param group group number 211 */ 212int libcfs_kkuc_group_add(struct file *filp, int uid, int group, __u32 data) 213{ 214 struct kkuc_reg *reg; 215 216 if (group > KUC_GRP_MAX) { 217 CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group); 218 return -EINVAL; 219 } 220 221 /* fput in group_rem */ 222 if (filp == NULL) 223 return -EBADF; 224 225 /* freed in group_rem */ 226 reg = kmalloc(sizeof(*reg), 0); 227 if (reg == NULL) 228 return -ENOMEM; 229 230 reg->kr_fp = filp; 231 reg->kr_uid = uid; 232 reg->kr_data = data; 233 234 down_write(&kg_sem); 235 if (kkuc_groups[group].next == NULL) 236 INIT_LIST_HEAD(&kkuc_groups[group]); 237 list_add(®->kr_chain, &kkuc_groups[group]); 238 up_write(&kg_sem); 239 240 CDEBUG(D_KUC, "Added uid=%d fp=%p to group %d\n", uid, filp, group); 241 242 return 0; 243} 244EXPORT_SYMBOL(libcfs_kkuc_group_add); 245 246int libcfs_kkuc_group_rem(int uid, int group) 247{ 248 struct kkuc_reg *reg, *next; 249 250 if (kkuc_groups[group].next == NULL) 251 RETURN(0); 252 253 if (uid == 0) { 254 /* Broadcast a shutdown message */ 255 struct kuc_hdr lh; 256 257 lh.kuc_magic = KUC_MAGIC; 258 lh.kuc_transport = KUC_TRANSPORT_GENERIC; 259 lh.kuc_msgtype = KUC_MSG_SHUTDOWN; 260 lh.kuc_msglen = sizeof(lh); 261 libcfs_kkuc_group_put(group, &lh); 262 } 263 264 down_write(&kg_sem); 265 list_for_each_entry_safe(reg, next, &kkuc_groups[group], kr_chain) { 266 if ((uid == 0) || (uid == reg->kr_uid)) { 267 list_del(®->kr_chain); 268 CDEBUG(D_KUC, "Removed uid=%d fp=%p from group %d\n", 269 reg->kr_uid, reg->kr_fp, group); 270 if (reg->kr_fp != NULL) 271 fput(reg->kr_fp); 272 kfree(reg); 273 } 274 } 275 up_write(&kg_sem); 276 277 RETURN(0); 278} 279EXPORT_SYMBOL(libcfs_kkuc_group_rem); 280 281int libcfs_kkuc_group_put(int group, void *payload) 282{ 283 struct kkuc_reg *reg; 284 int rc = 0; 285 int one_success = 0; 286 287 down_read(&kg_sem); 288 list_for_each_entry(reg, &kkuc_groups[group], kr_chain) { 289 if (reg->kr_fp != NULL) { 290 rc = libcfs_kkuc_msg_put(reg->kr_fp, payload); 291 if (rc == 0) 292 one_success = 1; 293 else if (rc == -EPIPE) { 294 fput(reg->kr_fp); 295 reg->kr_fp = NULL; 296 } 297 } 298 } 299 up_read(&kg_sem); 300 301 /* don't return an error if the message has been delivered 302 * at least to one agent */ 303 if (one_success) 304 rc = 0; 305 306 RETURN(rc); 307} 308EXPORT_SYMBOL(libcfs_kkuc_group_put); 309 310/** 311 * Calls a callback function for each link of the given kuc group. 312 * @param group the group to call the function on. 313 * @param cb_func the function to be called. 314 * @param cb_arg iextra argument to be passed to the callback function. 315 */ 316int libcfs_kkuc_group_foreach(int group, libcfs_kkuc_cb_t cb_func, 317 void *cb_arg) 318{ 319 struct kkuc_reg *reg; 320 int rc = 0; 321 322 if (group > KUC_GRP_MAX) { 323 CDEBUG(D_WARNING, "Kernelcomm: bad group %d\n", group); 324 RETURN(-EINVAL); 325 } 326 327 /* no link for this group */ 328 if (kkuc_groups[group].next == NULL) 329 RETURN(0); 330 331 down_read(&kg_sem); 332 list_for_each_entry(reg, &kkuc_groups[group], kr_chain) { 333 if (reg->kr_fp != NULL) { 334 rc = cb_func(reg->kr_data, cb_arg); 335 } 336 } 337 up_read(&kg_sem); 338 339 RETURN(rc); 340} 341EXPORT_SYMBOL(libcfs_kkuc_group_foreach); 342 343#endif /* LUSTRE_UTILS */ 344