Whamcloud - gitweb
LU-17662 osd-zfs: Support for ZFS 2.2.3
[fs/lustre-release.git] / libcfs / libcfs / util / l_ioctl.c
1 /*
2  * Copyright (C) 2001, 2002 Cluster File Systems, Inc.
3  *
4  * Copyright (c) 2014, 2017, Intel Corporation.
5  *
6  *   This file is part of Lustre, https://wiki.whamcloud.com/
7  *
8  *   Portals is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Portals is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Portals; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22
23 #define __USE_FILE_OFFSET64
24
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/ioctl.h>
31 #include <sys/mman.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <unistd.h>
35 #include <linux/types.h>
36
37 #include <libcfs/util/ioctl.h>
38 #include <linux/lnet/lnetctl.h>
39
40 struct ioc_dev {
41         const char *dev_name;
42         int dev_fd;
43 };
44
45 static struct ioc_dev ioc_dev_list[10];
46
47 #ifndef ARRAY_SIZE
48 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
49 #endif /* !ARRAY_SIZE */
50
51 static int
52 open_ioc_dev(int dev_id)
53 {
54         const char *dev_name;
55
56         if (dev_id < 0 || dev_id >= ARRAY_SIZE(ioc_dev_list)) {
57                 errno = EINVAL;
58                 return -errno;
59         }
60
61         dev_name = ioc_dev_list[dev_id].dev_name;
62         if (!dev_name) {
63                 fprintf(stderr, "unknown device id: %d\n", dev_id);
64                 errno = EINVAL;
65                 return -errno;
66         }
67
68         if (ioc_dev_list[dev_id].dev_fd < 0) {
69                 int fd = open(dev_name, O_RDWR);
70
71                 if (fd < 0) {
72                         fprintf(stderr, "opening %s failed: %s\n"
73                                 "hint: the kernel modules may not be loaded\n",
74                                 dev_name, strerror(errno));
75                         return -errno;
76                 }
77                 ioc_dev_list[dev_id].dev_fd = fd;
78         }
79
80         return ioc_dev_list[dev_id].dev_fd;
81 }
82
83 int l_ioctl(int dev_id, unsigned int opc, void *buf)
84 {
85         int fd, rc;
86
87         fd = open_ioc_dev(dev_id);
88         if (fd < 0)
89                 return fd;
90
91         rc = ioctl(fd, opc, buf);
92
93         return rc < 0 ? -errno : rc;
94 }
95
96 /* register a device to send ioctls to. */
97 int
98 register_ioc_dev(int dev_id, const char *dev_name)
99 {
100         if (dev_id < 0 ||
101             dev_id >= sizeof(ioc_dev_list) / sizeof(ioc_dev_list[0]))
102                 return -EINVAL;
103
104         unregister_ioc_dev(dev_id);
105
106         ioc_dev_list[dev_id].dev_name = dev_name;
107         ioc_dev_list[dev_id].dev_fd = -1;
108
109         return dev_id;
110 }
111
112 void
113 unregister_ioc_dev(int dev_id)
114 {
115         if (dev_id < 0 ||
116             dev_id >= sizeof(ioc_dev_list) / sizeof(ioc_dev_list[0]))
117                 return;
118
119         if (ioc_dev_list[dev_id].dev_name &&
120             ioc_dev_list[dev_id].dev_fd >= 0)
121                 close(ioc_dev_list[dev_id].dev_fd);
122
123         ioc_dev_list[dev_id].dev_name = NULL;
124         ioc_dev_list[dev_id].dev_fd = -1;
125 }
126
127 static inline size_t libcfs_ioctl_packlen(struct libcfs_ioctl_data *data)
128 {
129         size_t len = sizeof(*data);
130
131         len += (data->ioc_inllen1 + 7) & ~7;
132         len += (data->ioc_inllen2 + 7) & ~7;
133         return len;
134 }
135
136 int libcfs_ioctl_pack(struct libcfs_ioctl_data *data, char **pbuf, int max)
137 {
138         char *ptr;
139         struct libcfs_ioctl_data *overlay;
140
141         data->ioc_hdr.ioc_len = libcfs_ioctl_packlen(data);
142         data->ioc_hdr.ioc_version = LNET_IOCTL_VERSION;
143
144         if (*pbuf && libcfs_ioctl_packlen(data) > max)
145                 return 1;
146         if (!*pbuf)
147                 *pbuf = malloc(data->ioc_hdr.ioc_len);
148         if (!*pbuf)
149                 return 1;
150         overlay = (struct libcfs_ioctl_data *)*pbuf;
151         memcpy(*pbuf, data, sizeof(*data));
152
153         ptr = overlay->ioc_bulk;
154         if (data->ioc_inlbuf1) {
155                 memcpy((char *)ptr, (const char *)data->ioc_inlbuf1,
156                        data->ioc_inllen1);
157                 ptr += ((data->ioc_inllen1 + 7) & ~7);
158         }
159         if (data->ioc_inlbuf2) {
160                 memcpy((char *)ptr, (const char *)data->ioc_inlbuf2,
161                        data->ioc_inllen2);
162                 ptr += ((data->ioc_inllen2 + 7) & ~7);
163         }
164
165         return 0;
166 }
167
168 void
169 libcfs_ioctl_unpack(struct libcfs_ioctl_data *data, char *pbuf)
170 {
171         struct libcfs_ioctl_data *overlay = (struct libcfs_ioctl_data *)pbuf;
172         char *ptr;
173
174         /* Preserve the caller's buffer pointers */
175         overlay->ioc_inlbuf1 = data->ioc_inlbuf1;
176         overlay->ioc_inlbuf2 = data->ioc_inlbuf2;
177
178         memcpy(data, pbuf, sizeof(*data));
179         ptr = &overlay->ioc_bulk[0];
180
181         if (data->ioc_inlbuf1) {
182                 memcpy((char *)data->ioc_inlbuf1, (const char *)ptr,
183                        data->ioc_inllen1);
184                 ptr += ((data->ioc_inllen1 + 7) & ~7);
185         }
186         if (data->ioc_inlbuf2) {
187                 memcpy((char *)data->ioc_inlbuf2, (const char *)ptr,
188                        data->ioc_inllen2);
189                 ptr += ((data->ioc_inllen2 + 7) & ~7);
190         }
191 }