Whamcloud - gitweb
LU-5149 utils: Create debug upcall to dump ldlm namespaces
[fs/lustre-release.git] / lustre / utils / liblustreapi_kernelconn.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) 2012, 2013, 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 #include <unistd.h>
38 #include <fcntl.h>
39 #include <string.h>
40 #include <errno.h>
41
42 #include <lustre/lustreapi.h>
43
44 #include "lustreapi_internal.h"
45
46 /** Start the userspace side of a KUC pipe.
47  * @param link Private descriptor for pipe/socket.
48  * @param groups KUC broadcast group to listen to
49  *          (can be null for unicast to this pid)
50  * @param rfd_flags flags for read side of pipe (e.g. O_NONBLOCK)
51  */
52 int libcfs_ukuc_start(struct lustre_kernelcomm *link,
53                       int group, int rfd_flags)
54 {
55         int pfd[2];
56         int rc;
57
58         link->lk_rfd = link->lk_wfd = LK_NOFD;
59
60         if (pipe(pfd) < 0)
61                 return -errno;
62
63         if (fcntl(pfd[0], F_SETFL, rfd_flags) < 0) {
64                 rc = -errno;
65                 close(pfd[0]);
66                 close(pfd[1]);
67                 return rc;
68         }
69
70         memset(link, 0, sizeof(*link));
71         link->lk_rfd = pfd[0];
72         link->lk_wfd = pfd[1];
73         link->lk_group = group;
74         link->lk_uid = getpid();
75         return 0;
76 }
77
78 int libcfs_ukuc_stop(struct lustre_kernelcomm *link)
79 {
80         int rc;
81
82         if (link->lk_wfd != LK_NOFD)
83                 close(link->lk_wfd);
84         rc = close(link->lk_rfd);
85         link->lk_rfd = link->lk_wfd = LK_NOFD;
86         return rc;
87 }
88
89 /** Returns the file descriptor for the read side of the pipe,
90  *  to be used with poll/select.
91  * @param link Private descriptor for pipe/socket.
92  */
93 int libcfs_ukuc_get_rfd(struct lustre_kernelcomm *link)
94 {
95         return link->lk_rfd;
96 }
97
98 #define lhsz sizeof(*kuch)
99
100 /** Read a message from the link.
101  * Allocates memory, returns handle
102  *
103  * @param link Private descriptor for pipe/socket.
104  * @param buf Buffer to read into, must include size for kuc_hdr
105  * @param maxsize Maximum message size allowed
106  * @param transport Only listen to messages on this transport
107  *      (and the generic transport)
108  */
109 int libcfs_ukuc_msg_get(struct lustre_kernelcomm *link, char *buf, int maxsize,
110                         int transport)
111 {
112         struct kuc_hdr *kuch;
113         int rc = 0;
114
115         memset(buf, 0, maxsize);
116
117         while (1) {
118                 /* Read header first to get message size */
119                 rc = read(link->lk_rfd, buf, lhsz);
120                 if (rc <= 0) {
121                         rc = -errno;
122                         break;
123                 }
124                 kuch = (struct kuc_hdr *)buf;
125
126                 if (kuch->kuc_magic != KUC_MAGIC) {
127                         llapi_err_noerrno(LLAPI_MSG_ERROR,
128                                           "bad message magic %x != %x\n",
129                                           kuch->kuc_magic, KUC_MAGIC);
130                         rc = -EPROTO;
131                         break;
132                 }
133
134                 if (kuch->kuc_msglen > maxsize) {
135                         rc = -EMSGSIZE;
136                         break;
137                 }
138
139                 /* Read payload */
140                 rc = read(link->lk_rfd, buf + lhsz, kuch->kuc_msglen - lhsz);
141                 if (rc < 0) {
142                         rc = -errno;
143                         break;
144                 }
145                 if (rc < (kuch->kuc_msglen - lhsz)) {
146                         llapi_err_noerrno(LLAPI_MSG_ERROR,
147                                           "short read: got %d of %d bytes\n",
148                                           rc, kuch->kuc_msglen);
149                         rc = -EPROTO;
150                         break;
151                 }
152
153                 if (kuch->kuc_transport == transport ||
154                     kuch->kuc_transport == KUC_TRANSPORT_GENERIC) {
155                         return 0;
156                 }
157                 /* Drop messages for other transports */
158         }
159         return rc;
160 }
161