Whamcloud - gitweb
LU-13308 mdc: support additional flags for OBD_IOC_CHLG_POLL ioctl
[fs/lustre-release.git] / lustre / utils / liblustreapi_ioctl.c
1 /*
2  * LGPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the GNU Lesser General Public License
8  * (LGPL) version 2.1 or (at your discretion) any later version.
9  * (LGPL) version 2.1 accompanies this distribution, and is available at
10  * http://www.gnu.org/licenses/lgpl-2.1.html
11  *
12  * This library 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 GNU
15  * Lesser General Public License for more details.
16  *
17  * LGPL HEADER END
18  */
19 /*
20  * This file is part of Lustre, http://www.lustre.org/
21  *
22  * lustre/utils/liblustreapi_ioctl.c
23  *
24  * lustreapi library for packing/unpacking obd_ioctl_data structure to
25  * send commands to different OBD devices.  Mostly for internal use.
26  *
27  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2017, Intel Corporation.
31  *
32  * Copyright (c) 2023, DataDirect Networks Storage.
33  */
34
35 #include <string.h>
36 #include <stddef.h>
37 #include <sys/ioctl.h>
38 #include <errno.h>
39
40 #include <lustre/lustreapi.h>
41 #include <libcfs/util/ioctl.h>
42 #include <linux/lustre/lustre_ioctl.h>
43 #include <lustre_ioctl_old.h>
44 #include <linux/lustre/lustre_ver.h>
45
46 int llapi_ioctl_pack(struct obd_ioctl_data *data, char **pbuf, int max_len)
47 {
48         struct obd_ioctl_data *overlay;
49         char *ptr;
50
51         data->ioc_len = obd_ioctl_packlen(data);
52         data->ioc_version = OBD_IOCTL_VERSION;
53
54         if (*pbuf != NULL && data->ioc_len > max_len) {
55                 llapi_error(LLAPI_MSG_ERROR, -EINVAL,
56                             "pbuf = %p, ioc_len = %u, max_len = %d",
57                             *pbuf, data->ioc_len, max_len);
58                 return -EINVAL;
59         }
60
61         if (*pbuf == NULL)
62                 *pbuf = malloc(data->ioc_len);
63
64         if (*pbuf == NULL)
65                 return -ENOMEM;
66
67         overlay = (struct obd_ioctl_data *)*pbuf;
68         memcpy(*pbuf, data, sizeof(*data));
69
70         ptr = overlay->ioc_bulk;
71         if (data->ioc_inlbuf1) {
72                 memcpy(ptr, data->ioc_inlbuf1, data->ioc_inllen1);
73                 ptr += __ALIGN_KERNEL(data->ioc_inllen1, 8);
74         }
75
76         if (data->ioc_inlbuf2) {
77                 memcpy(ptr, data->ioc_inlbuf2, data->ioc_inllen2);
78                 ptr += __ALIGN_KERNEL(data->ioc_inllen2, 8);
79         }
80
81         if (data->ioc_inlbuf3) {
82                 memcpy(ptr, data->ioc_inlbuf3, data->ioc_inllen3);
83                 ptr += __ALIGN_KERNEL(data->ioc_inllen3, 8);
84         }
85
86         if (data->ioc_inlbuf4) {
87                 memcpy(ptr, data->ioc_inlbuf4, data->ioc_inllen4);
88                 ptr += __ALIGN_KERNEL(data->ioc_inllen4, 8);
89         }
90
91         return 0;
92 }
93
94 /**
95  * Remap OBD device ioctl cmd to old one in case running with older modules.
96  * Replaces callers that use "l_ioctl(OBD_DEV_ID, ...)".
97  *
98  * \param dev_id        Lustre device number (from 'lctl dl')
99  * \param cmd           ioctl command
100  * \param buf           ioctl data argument, usually obd_ioctl_data
101  */
102 int llapi_ioctl_dev(unsigned int dev_id, unsigned int cmd, void *buf)
103 {
104         unsigned int oldcmd;
105         int rc;
106
107         /* common case, ioctl works as expected */
108         rc = l_ioctl(dev_id, cmd, buf);
109         if (rc >= 0 || errno != ENOTTY)
110                 return rc;
111
112         switch (cmd) {
113         /*
114          * Use #ifdef instead of version check to minimize the places that a
115          * version change might cause a compiler error in the future.
116          *
117          * Version in comment is to allow finding this code for later removal.
118          */
119 #ifdef OBD_IOC_BARRIER          /* < OBD_OCD_VERSION(2, 19, 53, 0) */
120         case OBD_IOC_BARRIER_V2:
121                 oldcmd = OBD_IOC_BARRIER;
122                 break;
123 #endif
124 #ifdef IOC_OSC_SET_ACTIVE       /* < OBD_OCD_VERSION(2, 19, 53, 0) */
125         case OBD_IOC_SET_ACTIVE:
126                 oldcmd = IOC_OSC_SET_ACTIVE;
127                 break;
128 #endif
129         default:
130                 oldcmd = 0;
131                 break;
132         }
133         if (oldcmd)
134                 rc = l_ioctl(dev_id, oldcmd, buf);
135
136         return rc;
137 }
138
139 /**
140  * Remap regular file ioctl cmd to old one in case running with older modules.
141  * Replaces callers that use "ioctl(fd, ...)".
142  *
143  * \param fd            open file descriptor
144  * \param cmd           ioctl command
145  * \param buf           ioctl data argument
146  */
147 int llapi_ioctl(int fd, unsigned int cmd, void *buf)
148 {
149         unsigned int oldcmd;
150         int rc;
151
152         if (fd < 0)
153                 return -EBADF;
154
155         /* common case, ioctl works as expected */
156         rc = ioctl(fd, cmd, buf);
157         if (rc >= 0 || errno != ENOTTY)
158                 return rc;
159
160         switch (cmd) {
161         /*
162          * Use #ifdef instead of version check to minimize the places that a
163          * version change might cause a compiler error in the future.
164          *
165          * Version in comment is to allow finding this code for later removal.
166          */
167 #ifdef OBD_IOC_GETNAME_OLD      /* < OBD_OCD_VERSION(2, 18, 53, 0) */
168         case OBD_IOC_GETMDNAME:
169                 oldcmd = OBD_IOC_GETNAME_OLD;
170                 break;
171 #endif
172         default:
173                 oldcmd = 0;
174                 break;
175         }
176         if (oldcmd)
177                 rc = ioctl(fd, oldcmd, buf);
178
179         return rc;
180 }
181
182 int llapi_ioctl_unpack(struct obd_ioctl_data *data, char *pbuf, int max_len)
183 {
184         struct obd_ioctl_data *overlay;
185         char *ptr;
186
187         if (pbuf == NULL)
188                 return -EINVAL;
189
190         overlay = (struct obd_ioctl_data *)pbuf;
191
192         /* Preserve the caller's buffer pointers */
193         overlay->ioc_inlbuf1 = data->ioc_inlbuf1;
194         overlay->ioc_inlbuf2 = data->ioc_inlbuf2;
195         overlay->ioc_inlbuf3 = data->ioc_inlbuf3;
196         overlay->ioc_inlbuf4 = data->ioc_inlbuf4;
197
198         memcpy(data, pbuf, sizeof(*data));
199
200         ptr = overlay->ioc_bulk;
201         if (data->ioc_inlbuf1) {
202                 memcpy(data->ioc_inlbuf1, ptr, data->ioc_inllen1);
203                 ptr += __ALIGN_KERNEL(data->ioc_inllen1, 8);
204         }
205
206         if (data->ioc_inlbuf2) {
207                 memcpy(data->ioc_inlbuf2, ptr, data->ioc_inllen2);
208                 ptr += __ALIGN_KERNEL(data->ioc_inllen2, 8);
209         }
210
211         if (data->ioc_inlbuf3) {
212                 memcpy(data->ioc_inlbuf3, ptr, data->ioc_inllen3);
213                 ptr += __ALIGN_KERNEL(data->ioc_inllen3, 8);
214         }
215
216         if (data->ioc_inlbuf4) {
217                 memcpy(data->ioc_inlbuf4, ptr, data->ioc_inllen4);
218                 ptr += __ALIGN_KERNEL(data->ioc_inllen4, 8);
219         }
220
221         return 0;
222 }