Whamcloud - gitweb
LU-13048 mdd: allow release after a non-blocking migrate
[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 <linux/lustre/lustre_ver.h>
44 #include <lustre_ioctl_old.h>
45
46 #include "lustreapi_internal.h"
47
48 int llapi_ioctl_pack(struct obd_ioctl_data *data, char **pbuf, int max_len)
49 {
50         struct obd_ioctl_data *overlay;
51         char *ptr;
52
53         data->ioc_len = obd_ioctl_packlen(data);
54         data->ioc_version = OBD_IOCTL_VERSION;
55
56         if (*pbuf != NULL && data->ioc_len > max_len) {
57                 llapi_error(LLAPI_MSG_ERROR, -EINVAL,
58                             "pbuf = %p, ioc_len = %u, max_len = %d",
59                             *pbuf, data->ioc_len, max_len);
60                 return -EINVAL;
61         }
62
63         if (*pbuf == NULL)
64                 *pbuf = malloc(data->ioc_len);
65
66         if (*pbuf == NULL)
67                 return -ENOMEM;
68
69         overlay = (struct obd_ioctl_data *)*pbuf;
70         memcpy(*pbuf, data, sizeof(*data));
71
72         ptr = overlay->ioc_bulk;
73         if (data->ioc_inlbuf1) {
74                 memcpy(ptr, data->ioc_inlbuf1, data->ioc_inllen1);
75                 ptr += __ALIGN_KERNEL(data->ioc_inllen1, 8);
76         }
77
78         if (data->ioc_inlbuf2) {
79                 memcpy(ptr, data->ioc_inlbuf2, data->ioc_inllen2);
80                 ptr += __ALIGN_KERNEL(data->ioc_inllen2, 8);
81         }
82
83         if (data->ioc_inlbuf3) {
84                 memcpy(ptr, data->ioc_inlbuf3, data->ioc_inllen3);
85                 ptr += __ALIGN_KERNEL(data->ioc_inllen3, 8);
86         }
87
88         if (data->ioc_inlbuf4) {
89                 memcpy(ptr, data->ioc_inlbuf4, data->ioc_inllen4);
90                 ptr += __ALIGN_KERNEL(data->ioc_inllen4, 8);
91         }
92
93         return 0;
94 }
95
96 /**
97  * Remap OBD device ioctl cmd to old one in case running with older modules.
98  * Replaces callers that use "l_ioctl(OBD_DEV_ID, ...)".
99  *
100  * \param dev_id        Lustre device number (from 'lctl dl')
101  * \param cmd           ioctl command
102  * \param buf           ioctl data argument, usually obd_ioctl_data
103  */
104 int llapi_ioctl_dev(int dev_id, unsigned int cmd, void *buf)
105 {
106         unsigned int oldcmd;
107         int rc;
108
109         /* common case, ioctl works as expected */
110         rc = l_ioctl(dev_id, cmd, buf);
111         if (rc >= 0 || errno != ENOTTY)
112                 return rc;
113
114         switch (cmd) {
115         /*
116          * Use #ifdef instead of version check to minimize the places that a
117          * version change might cause a compiler error in the future.
118          *
119          * Version in comment is to allow finding this code for later removal.
120          */
121 #ifdef OBD_IOC_BARRIER          /* < OBD_OCD_VERSION(2, 19, 53, 0) */
122         case OBD_IOC_BARRIER_V2:
123                 oldcmd = OBD_IOC_BARRIER;
124                 break;
125 #endif
126 #ifdef IOC_OSC_SET_ACTIVE       /* < OBD_OCD_VERSION(2, 19, 53, 0) */
127         case OBD_IOC_SET_ACTIVE:
128                 oldcmd = IOC_OSC_SET_ACTIVE;
129                 break;
130 #endif
131         default:
132                 oldcmd = 0;
133                 break;
134         }
135         if (oldcmd)
136                 rc = l_ioctl(dev_id, oldcmd, buf);
137
138         return rc;
139 }
140
141 /**
142  * Remap regular file ioctl cmd to old one in case running with older modules.
143  * Replaces callers that use "ioctl(fd, ...)".
144  *
145  * \param fd            open file descriptor
146  * \param cmd           ioctl command
147  * \param buf           ioctl data argument
148  */
149 int llapi_ioctl(int fd, unsigned int cmd, void *buf)
150 {
151         unsigned int oldcmd;
152         int rc;
153
154         if (fd < 0)
155                 return -EBADF;
156
157         /* common case, ioctl works as expected */
158         rc = ioctl(fd, cmd, buf);
159         if (rc >= 0 || errno != ENOTTY)
160                 return rc;
161
162         switch (cmd) {
163         /*
164          * Use #ifdef instead of version check to minimize the places that a
165          * version change might cause a compiler error in the future.
166          *
167          * Version in comment is to allow finding this code for later removal.
168          */
169 #ifdef OBD_IOC_GETNAME_OLD      /* < OBD_OCD_VERSION(2, 18, 53, 0) */
170         case OBD_IOC_GETDTNAME:
171                 oldcmd = OBD_IOC_GETNAME_OLD;
172                 break;
173 #endif
174         default:
175                 oldcmd = 0;
176                 break;
177         }
178         if (oldcmd)
179                 rc = ioctl(fd, oldcmd, buf);
180
181         return rc;
182 }
183
184 int llapi_ioctl_unpack(struct obd_ioctl_data *data, char *pbuf, int max_len)
185 {
186         struct obd_ioctl_data *overlay;
187         char *ptr;
188
189         if (pbuf == NULL)
190                 return -EINVAL;
191
192         overlay = (struct obd_ioctl_data *)pbuf;
193
194         /* Preserve the caller's buffer pointers */
195         overlay->ioc_inlbuf1 = data->ioc_inlbuf1;
196         overlay->ioc_inlbuf2 = data->ioc_inlbuf2;
197         overlay->ioc_inlbuf3 = data->ioc_inlbuf3;
198         overlay->ioc_inlbuf4 = data->ioc_inlbuf4;
199
200         memcpy(data, pbuf, sizeof(*data));
201
202         ptr = overlay->ioc_bulk;
203         if (data->ioc_inlbuf1) {
204                 memcpy(data->ioc_inlbuf1, ptr, data->ioc_inllen1);
205                 ptr += __ALIGN_KERNEL(data->ioc_inllen1, 8);
206         }
207
208         if (data->ioc_inlbuf2) {
209                 memcpy(data->ioc_inlbuf2, ptr, data->ioc_inllen2);
210                 ptr += __ALIGN_KERNEL(data->ioc_inllen2, 8);
211         }
212
213         if (data->ioc_inlbuf3) {
214                 memcpy(data->ioc_inlbuf3, ptr, data->ioc_inllen3);
215                 ptr += __ALIGN_KERNEL(data->ioc_inllen3, 8);
216         }
217
218         if (data->ioc_inlbuf4) {
219                 memcpy(data->ioc_inlbuf4, ptr, data->ioc_inllen4);
220                 ptr += __ALIGN_KERNEL(data->ioc_inllen4, 8);
221         }
222
223         return 0;
224 }