2 * Copyright (c) 2004-2005 Silicon Graphics, Inc.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 #include <linux/compat.h>
19 #include <linux/init.h>
20 #include <linux/ioctl.h>
21 #include <linux/syscalls.h>
22 #include <linux/types.h>
24 #include <asm/uaccess.h>
30 #include "xfs_trans.h"
34 #include "xfs_dmapi.h"
35 #include "xfs_mount.h"
36 #include "xfs_bmap_btree.h"
37 #include "xfs_attr_sf.h"
38 #include "xfs_dir2_sf.h"
39 #include "xfs_vnode.h"
40 #include "xfs_dinode.h"
41 #include "xfs_inode.h"
42 #include "xfs_itable.h"
43 #include "xfs_error.h"
44 #include "xfs_dfrag.h"
45 #include "xfs_vnodeops.h"
46 #include "xfs_fsops.h"
47 #include "xfs_ioctl.h"
48 #include "xfs_ioctl32.h"
50 #define _NATIVE_IOC(cmd, type) \
51 _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(type))
53 #ifdef BROKEN_X86_ALIGNMENT
55 xfs_compat_flock64_copyin(
57 compat_xfs_flock64_t __user
*arg32
)
59 if (get_user(bf
->l_type
, &arg32
->l_type
) ||
60 get_user(bf
->l_whence
, &arg32
->l_whence
) ||
61 get_user(bf
->l_start
, &arg32
->l_start
) ||
62 get_user(bf
->l_len
, &arg32
->l_len
) ||
63 get_user(bf
->l_sysid
, &arg32
->l_sysid
) ||
64 get_user(bf
->l_pid
, &arg32
->l_pid
) ||
65 copy_from_user(bf
->l_pad
, &arg32
->l_pad
, 4*sizeof(u32
)))
66 return -XFS_ERROR(EFAULT
);
71 xfs_compat_ioc_fsgeometry_v1(
73 compat_xfs_fsop_geom_v1_t __user
*arg32
)
75 xfs_fsop_geom_t fsgeo
;
78 error
= xfs_fs_geometry(mp
, &fsgeo
, 3);
81 /* The 32-bit variant simply has some padding at the end */
82 if (copy_to_user(arg32
, &fsgeo
, sizeof(struct compat_xfs_fsop_geom_v1
)))
83 return -XFS_ERROR(EFAULT
);
88 xfs_inumbers_fmt_compat(
90 const xfs_inogrp_t
*buffer
,
94 compat_xfs_inogrp_t __user
*p32
= ubuffer
;
97 for (i
= 0; i
< count
; i
++) {
98 if (put_user(buffer
[i
].xi_startino
, &p32
[i
].xi_startino
) ||
99 put_user(buffer
[i
].xi_alloccount
, &p32
[i
].xi_alloccount
) ||
100 put_user(buffer
[i
].xi_allocmask
, &p32
[i
].xi_allocmask
))
101 return -XFS_ERROR(EFAULT
);
103 *written
= count
* sizeof(*p32
);
108 #define xfs_inumbers_fmt_compat xfs_inumbers_fmt
111 /* XFS_IOC_FSBULKSTAT and friends */
114 xfs_bstime_store_compat(
115 compat_xfs_bstime_t __user
*p32
,
116 const xfs_bstime_t
*p
)
121 if (put_user(sec32
, &p32
->tv_sec
) ||
122 put_user(p
->tv_nsec
, &p32
->tv_nsec
))
123 return -XFS_ERROR(EFAULT
);
128 xfs_bulkstat_one_fmt_compat(
129 void __user
*ubuffer
,
130 const xfs_bstat_t
*buffer
)
132 compat_xfs_bstat_t __user
*p32
= ubuffer
;
134 if (put_user(buffer
->bs_ino
, &p32
->bs_ino
) ||
135 put_user(buffer
->bs_mode
, &p32
->bs_mode
) ||
136 put_user(buffer
->bs_nlink
, &p32
->bs_nlink
) ||
137 put_user(buffer
->bs_uid
, &p32
->bs_uid
) ||
138 put_user(buffer
->bs_gid
, &p32
->bs_gid
) ||
139 put_user(buffer
->bs_rdev
, &p32
->bs_rdev
) ||
140 put_user(buffer
->bs_blksize
, &p32
->bs_blksize
) ||
141 put_user(buffer
->bs_size
, &p32
->bs_size
) ||
142 xfs_bstime_store_compat(&p32
->bs_atime
, &buffer
->bs_atime
) ||
143 xfs_bstime_store_compat(&p32
->bs_mtime
, &buffer
->bs_mtime
) ||
144 xfs_bstime_store_compat(&p32
->bs_ctime
, &buffer
->bs_ctime
) ||
145 put_user(buffer
->bs_blocks
, &p32
->bs_blocks
) ||
146 put_user(buffer
->bs_xflags
, &p32
->bs_xflags
) ||
147 put_user(buffer
->bs_extsize
, &p32
->bs_extsize
) ||
148 put_user(buffer
->bs_extents
, &p32
->bs_extents
) ||
149 put_user(buffer
->bs_gen
, &p32
->bs_gen
) ||
150 put_user(buffer
->bs_projid
, &p32
->bs_projid
) ||
151 put_user(buffer
->bs_dmevmask
, &p32
->bs_dmevmask
) ||
152 put_user(buffer
->bs_dmstate
, &p32
->bs_dmstate
) ||
153 put_user(buffer
->bs_aextents
, &p32
->bs_aextents
))
154 return -XFS_ERROR(EFAULT
);
158 /* copied from xfs_ioctl.c */
160 xfs_ioc_bulkstat_compat(
165 compat_xfs_fsop_bulkreq_t __user
*p32
= (void __user
*)arg
;
167 xfs_fsop_bulkreq_t bulkreq
;
168 int count
; /* # of records returned */
169 xfs_ino_t inlast
; /* last inode number */
173 /* done = 1 if there are more stats to get and if bulkstat */
174 /* should be called again (unused here, but used in dmapi) */
176 if (!capable(CAP_SYS_ADMIN
))
177 return -XFS_ERROR(EPERM
);
179 if (XFS_FORCED_SHUTDOWN(mp
))
180 return -XFS_ERROR(EIO
);
182 if (get_user(addr
, &p32
->lastip
))
183 return -XFS_ERROR(EFAULT
);
184 bulkreq
.lastip
= compat_ptr(addr
);
185 if (get_user(bulkreq
.icount
, &p32
->icount
) ||
186 get_user(addr
, &p32
->ubuffer
))
187 return -XFS_ERROR(EFAULT
);
188 bulkreq
.ubuffer
= compat_ptr(addr
);
189 if (get_user(addr
, &p32
->ocount
))
190 return -XFS_ERROR(EFAULT
);
191 bulkreq
.ocount
= compat_ptr(addr
);
193 if (copy_from_user(&inlast
, bulkreq
.lastip
, sizeof(__s64
)))
194 return -XFS_ERROR(EFAULT
);
196 if ((count
= bulkreq
.icount
) <= 0)
197 return -XFS_ERROR(EINVAL
);
199 if (bulkreq
.ubuffer
== NULL
)
200 return -XFS_ERROR(EINVAL
);
202 if (cmd
== XFS_IOC_FSINUMBERS
)
203 error
= xfs_inumbers(mp
, &inlast
, &count
,
204 bulkreq
.ubuffer
, xfs_inumbers_fmt_compat
);
206 /* declare a var to get a warning in case the type changes */
207 bulkstat_one_fmt_pf formatter
= xfs_bulkstat_one_fmt_compat
;
208 error
= xfs_bulkstat(mp
, &inlast
, &count
,
209 xfs_bulkstat_one
, formatter
,
210 sizeof(compat_xfs_bstat_t
), bulkreq
.ubuffer
,
211 BULKSTAT_FG_QUICK
, &done
);
216 if (bulkreq
.ocount
!= NULL
) {
217 if (copy_to_user(bulkreq
.lastip
, &inlast
,
219 return -XFS_ERROR(EFAULT
);
221 if (copy_to_user(bulkreq
.ocount
, &count
, sizeof(count
)))
222 return -XFS_ERROR(EFAULT
);
229 xfs_compat_handlereq_copyin(
230 xfs_fsop_handlereq_t
*hreq
,
231 compat_xfs_fsop_handlereq_t __user
*arg32
)
233 compat_xfs_fsop_handlereq_t hreq32
;
235 if (copy_from_user(&hreq32
, arg32
, sizeof(compat_xfs_fsop_handlereq_t
)))
236 return -XFS_ERROR(EFAULT
);
238 hreq
->fd
= hreq32
.fd
;
239 hreq
->path
= compat_ptr(hreq32
.path
);
240 hreq
->oflags
= hreq32
.oflags
;
241 hreq
->ihandle
= compat_ptr(hreq32
.ihandle
);
242 hreq
->ihandlen
= hreq32
.ihandlen
;
243 hreq
->ohandle
= compat_ptr(hreq32
.ohandle
);
244 hreq
->ohandlen
= compat_ptr(hreq32
.ohandlen
);
257 struct inode
*inode
= filp
->f_path
.dentry
->d_inode
;
258 xfs_mount_t
*mp
= ip
->i_mount
;
261 xfs_itrace_entry(XFS_I(inode
));
263 case XFS_IOC_DIOINFO
:
264 case XFS_IOC_FSGEOMETRY
:
265 case XFS_IOC_FSGETXATTR
:
266 case XFS_IOC_FSSETXATTR
:
267 case XFS_IOC_FSGETXATTRA
:
268 case XFS_IOC_FSSETDM
:
269 case XFS_IOC_GETBMAP
:
270 case XFS_IOC_GETBMAPA
:
271 case XFS_IOC_GETBMAPX
:
273 case XFS_IOC_FSSETDM_BY_HANDLE:
274 case XFS_IOC_ATTRLIST_BY_HANDLE:
275 case XFS_IOC_ATTRMULTI_BY_HANDLE:
277 case XFS_IOC_FSCOUNTS
:
278 case XFS_IOC_SET_RESBLKS
:
279 case XFS_IOC_GET_RESBLKS
:
280 case XFS_IOC_FSGROWFSDATA
:
281 case XFS_IOC_FSGROWFSLOG
:
282 case XFS_IOC_FSGROWFSRT
:
285 case XFS_IOC_GOINGDOWN
:
286 case XFS_IOC_ERROR_INJECTION
:
287 case XFS_IOC_ERROR_CLEARALL
:
290 case XFS_IOC_GETXFLAGS_32
:
291 case XFS_IOC_SETXFLAGS_32
:
292 case XFS_IOC_GETVERSION_32
:
293 cmd
= _NATIVE_IOC(cmd
, long);
295 #ifdef BROKEN_X86_ALIGNMENT
296 /* xfs_flock_t has wrong u32 vs u64 alignment */
297 case XFS_IOC_ALLOCSP_32
:
298 case XFS_IOC_FREESP_32
:
299 case XFS_IOC_ALLOCSP64_32
:
300 case XFS_IOC_FREESP64_32
:
301 case XFS_IOC_RESVSP_32
:
302 case XFS_IOC_UNRESVSP_32
:
303 case XFS_IOC_RESVSP64_32
:
304 case XFS_IOC_UNRESVSP64_32
: {
305 struct xfs_flock64 bf
;
307 if (xfs_compat_flock64_copyin(&bf
, arg
))
308 return -XFS_ERROR(EFAULT
);
309 cmd
= _NATIVE_IOC(cmd
, struct xfs_flock64
);
310 return xfs_ioc_space(ip
, inode
, filp
, ioflags
, cmd
, &bf
);
312 case XFS_IOC_FSGEOMETRY_V1_32
:
313 return xfs_compat_ioc_fsgeometry_v1(mp
, arg
);
314 #else /* These are handled fine if no alignment issues */
315 case XFS_IOC_ALLOCSP
:
318 case XFS_IOC_UNRESVSP
:
319 case XFS_IOC_ALLOCSP64
:
320 case XFS_IOC_FREESP64
:
321 case XFS_IOC_RESVSP64
:
322 case XFS_IOC_UNRESVSP64
:
323 case XFS_IOC_FSGEOMETRY_V1
:
326 /* xfs_bstat_t still has wrong u32 vs u64 alignment */
327 case XFS_IOC_SWAPEXT
:
331 case XFS_IOC_FSBULKSTAT_32
:
332 case XFS_IOC_FSBULKSTAT_SINGLE_32
:
333 case XFS_IOC_FSINUMBERS_32
:
334 cmd
= _NATIVE_IOC(cmd
, struct xfs_fsop_bulkreq
);
335 return xfs_ioc_bulkstat_compat(XFS_I(inode
)->i_mount
,
336 cmd
, (void __user
*)arg
);
337 case XFS_IOC_FD_TO_HANDLE_32
:
338 case XFS_IOC_PATH_TO_HANDLE_32
:
339 case XFS_IOC_PATH_TO_FSHANDLE_32
: {
340 struct xfs_fsop_handlereq hreq
;
342 if (xfs_compat_handlereq_copyin(&hreq
, arg
))
343 return -XFS_ERROR(EFAULT
);
344 cmd
= _NATIVE_IOC(cmd
, struct xfs_fsop_handlereq
);
345 return xfs_find_handle(cmd
, &hreq
);
347 case XFS_IOC_OPEN_BY_HANDLE_32
: {
348 struct xfs_fsop_handlereq hreq
;
350 if (xfs_compat_handlereq_copyin(&hreq
, arg
))
351 return -XFS_ERROR(EFAULT
);
352 return xfs_open_by_handle(mp
, &hreq
, filp
, inode
);
354 case XFS_IOC_READLINK_BY_HANDLE_32
: {
355 struct xfs_fsop_handlereq hreq
;
357 if (xfs_compat_handlereq_copyin(&hreq
, arg
))
358 return -XFS_ERROR(EFAULT
);
359 return xfs_readlink_by_handle(mp
, &hreq
, inode
);
362 return -XFS_ERROR(ENOIOCTLCMD
);
365 error
= xfs_ioctl(ip
, filp
, ioflags
, cmd
, arg
);
370 xfs_file_compat_ioctl(
375 struct inode
*inode
= filp
->f_path
.dentry
->d_inode
;
377 return xfs_compat_ioctl(XFS_I(inode
), filp
, 0, cmd
, (void __user
*)p
);
381 xfs_file_compat_invis_ioctl(
386 struct inode
*inode
= filp
->f_path
.dentry
->d_inode
;
388 return xfs_compat_ioctl(XFS_I(inode
), filp
, IO_INVIS
, cmd
,