Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at c9a28fa7b9ac19b676deefa0a171ce7df8755c08 485 lines 15 kB view raw
1/* 2 * Copyright (c) 2004-2005 Silicon Graphics, Inc. 3 * All Rights Reserved. 4 * 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. 8 * 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. 13 * 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 17 */ 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> 23#include <linux/fs.h> 24#include <asm/uaccess.h> 25#include "xfs.h" 26#include "xfs_fs.h" 27#include "xfs_bit.h" 28#include "xfs_log.h" 29#include "xfs_inum.h" 30#include "xfs_trans.h" 31#include "xfs_sb.h" 32#include "xfs_ag.h" 33#include "xfs_dir2.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_vfs.h" 40#include "xfs_vnode.h" 41#include "xfs_dinode.h" 42#include "xfs_inode.h" 43#include "xfs_itable.h" 44#include "xfs_error.h" 45#include "xfs_dfrag.h" 46#include "xfs_vnodeops.h" 47 48#define _NATIVE_IOC(cmd, type) \ 49 _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(type)) 50 51#if defined(CONFIG_IA64) || defined(CONFIG_X86_64) 52#define BROKEN_X86_ALIGNMENT 53#define _PACKED __attribute__((packed)) 54/* on ia32 l_start is on a 32-bit boundary */ 55typedef struct xfs_flock64_32 { 56 __s16 l_type; 57 __s16 l_whence; 58 __s64 l_start __attribute__((packed)); 59 /* len == 0 means until end of file */ 60 __s64 l_len __attribute__((packed)); 61 __s32 l_sysid; 62 __u32 l_pid; 63 __s32 l_pad[4]; /* reserve area */ 64} xfs_flock64_32_t; 65 66#define XFS_IOC_ALLOCSP_32 _IOW ('X', 10, struct xfs_flock64_32) 67#define XFS_IOC_FREESP_32 _IOW ('X', 11, struct xfs_flock64_32) 68#define XFS_IOC_ALLOCSP64_32 _IOW ('X', 36, struct xfs_flock64_32) 69#define XFS_IOC_FREESP64_32 _IOW ('X', 37, struct xfs_flock64_32) 70#define XFS_IOC_RESVSP_32 _IOW ('X', 40, struct xfs_flock64_32) 71#define XFS_IOC_UNRESVSP_32 _IOW ('X', 41, struct xfs_flock64_32) 72#define XFS_IOC_RESVSP64_32 _IOW ('X', 42, struct xfs_flock64_32) 73#define XFS_IOC_UNRESVSP64_32 _IOW ('X', 43, struct xfs_flock64_32) 74 75/* just account for different alignment */ 76STATIC unsigned long 77xfs_ioctl32_flock( 78 unsigned long arg) 79{ 80 xfs_flock64_32_t __user *p32 = (void __user *)arg; 81 xfs_flock64_t __user *p = compat_alloc_user_space(sizeof(*p)); 82 83 if (copy_in_user(&p->l_type, &p32->l_type, sizeof(s16)) || 84 copy_in_user(&p->l_whence, &p32->l_whence, sizeof(s16)) || 85 copy_in_user(&p->l_start, &p32->l_start, sizeof(s64)) || 86 copy_in_user(&p->l_len, &p32->l_len, sizeof(s64)) || 87 copy_in_user(&p->l_sysid, &p32->l_sysid, sizeof(s32)) || 88 copy_in_user(&p->l_pid, &p32->l_pid, sizeof(u32)) || 89 copy_in_user(&p->l_pad, &p32->l_pad, 4*sizeof(u32))) 90 return -EFAULT; 91 92 return (unsigned long)p; 93} 94 95typedef struct compat_xfs_fsop_geom_v1 { 96 __u32 blocksize; /* filesystem (data) block size */ 97 __u32 rtextsize; /* realtime extent size */ 98 __u32 agblocks; /* fsblocks in an AG */ 99 __u32 agcount; /* number of allocation groups */ 100 __u32 logblocks; /* fsblocks in the log */ 101 __u32 sectsize; /* (data) sector size, bytes */ 102 __u32 inodesize; /* inode size in bytes */ 103 __u32 imaxpct; /* max allowed inode space(%) */ 104 __u64 datablocks; /* fsblocks in data subvolume */ 105 __u64 rtblocks; /* fsblocks in realtime subvol */ 106 __u64 rtextents; /* rt extents in realtime subvol*/ 107 __u64 logstart; /* starting fsblock of the log */ 108 unsigned char uuid[16]; /* unique id of the filesystem */ 109 __u32 sunit; /* stripe unit, fsblocks */ 110 __u32 swidth; /* stripe width, fsblocks */ 111 __s32 version; /* structure version */ 112 __u32 flags; /* superblock version flags */ 113 __u32 logsectsize; /* log sector size, bytes */ 114 __u32 rtsectsize; /* realtime sector size, bytes */ 115 __u32 dirblocksize; /* directory block size, bytes */ 116} __attribute__((packed)) compat_xfs_fsop_geom_v1_t; 117 118#define XFS_IOC_FSGEOMETRY_V1_32 \ 119 _IOR ('X', 100, struct compat_xfs_fsop_geom_v1) 120 121STATIC unsigned long xfs_ioctl32_geom_v1(unsigned long arg) 122{ 123 compat_xfs_fsop_geom_v1_t __user *p32 = (void __user *)arg; 124 xfs_fsop_geom_v1_t __user *p = compat_alloc_user_space(sizeof(*p)); 125 126 if (copy_in_user(p, p32, sizeof(*p32))) 127 return -EFAULT; 128 return (unsigned long)p; 129} 130 131typedef struct compat_xfs_inogrp { 132 __u64 xi_startino; /* starting inode number */ 133 __s32 xi_alloccount; /* # bits set in allocmask */ 134 __u64 xi_allocmask; /* mask of allocated inodes */ 135} __attribute__((packed)) compat_xfs_inogrp_t; 136 137STATIC int xfs_inumbers_fmt_compat( 138 void __user *ubuffer, 139 const xfs_inogrp_t *buffer, 140 long count, 141 long *written) 142{ 143 compat_xfs_inogrp_t __user *p32 = ubuffer; 144 long i; 145 146 for (i = 0; i < count; i++) { 147 if (put_user(buffer[i].xi_startino, &p32[i].xi_startino) || 148 put_user(buffer[i].xi_alloccount, &p32[i].xi_alloccount) || 149 put_user(buffer[i].xi_allocmask, &p32[i].xi_allocmask)) 150 return -EFAULT; 151 } 152 *written = count * sizeof(*p32); 153 return 0; 154} 155 156#else 157 158#define xfs_inumbers_fmt_compat xfs_inumbers_fmt 159#define _PACKED 160 161#endif 162 163/* XFS_IOC_FSBULKSTAT and friends */ 164 165typedef struct compat_xfs_bstime { 166 __s32 tv_sec; /* seconds */ 167 __s32 tv_nsec; /* and nanoseconds */ 168} compat_xfs_bstime_t; 169 170STATIC int xfs_bstime_store_compat( 171 compat_xfs_bstime_t __user *p32, 172 const xfs_bstime_t *p) 173{ 174 __s32 sec32; 175 176 sec32 = p->tv_sec; 177 if (put_user(sec32, &p32->tv_sec) || 178 put_user(p->tv_nsec, &p32->tv_nsec)) 179 return -EFAULT; 180 return 0; 181} 182 183typedef struct compat_xfs_bstat { 184 __u64 bs_ino; /* inode number */ 185 __u16 bs_mode; /* type and mode */ 186 __u16 bs_nlink; /* number of links */ 187 __u32 bs_uid; /* user id */ 188 __u32 bs_gid; /* group id */ 189 __u32 bs_rdev; /* device value */ 190 __s32 bs_blksize; /* block size */ 191 __s64 bs_size; /* file size */ 192 compat_xfs_bstime_t bs_atime; /* access time */ 193 compat_xfs_bstime_t bs_mtime; /* modify time */ 194 compat_xfs_bstime_t bs_ctime; /* inode change time */ 195 int64_t bs_blocks; /* number of blocks */ 196 __u32 bs_xflags; /* extended flags */ 197 __s32 bs_extsize; /* extent size */ 198 __s32 bs_extents; /* number of extents */ 199 __u32 bs_gen; /* generation count */ 200 __u16 bs_projid; /* project id */ 201 unsigned char bs_pad[14]; /* pad space, unused */ 202 __u32 bs_dmevmask; /* DMIG event mask */ 203 __u16 bs_dmstate; /* DMIG state info */ 204 __u16 bs_aextents; /* attribute number of extents */ 205} _PACKED compat_xfs_bstat_t; 206 207STATIC int xfs_bulkstat_one_fmt_compat( 208 void __user *ubuffer, 209 const xfs_bstat_t *buffer) 210{ 211 compat_xfs_bstat_t __user *p32 = ubuffer; 212 213 if (put_user(buffer->bs_ino, &p32->bs_ino) || 214 put_user(buffer->bs_mode, &p32->bs_mode) || 215 put_user(buffer->bs_nlink, &p32->bs_nlink) || 216 put_user(buffer->bs_uid, &p32->bs_uid) || 217 put_user(buffer->bs_gid, &p32->bs_gid) || 218 put_user(buffer->bs_rdev, &p32->bs_rdev) || 219 put_user(buffer->bs_blksize, &p32->bs_blksize) || 220 put_user(buffer->bs_size, &p32->bs_size) || 221 xfs_bstime_store_compat(&p32->bs_atime, &buffer->bs_atime) || 222 xfs_bstime_store_compat(&p32->bs_mtime, &buffer->bs_mtime) || 223 xfs_bstime_store_compat(&p32->bs_ctime, &buffer->bs_ctime) || 224 put_user(buffer->bs_blocks, &p32->bs_blocks) || 225 put_user(buffer->bs_xflags, &p32->bs_xflags) || 226 put_user(buffer->bs_extsize, &p32->bs_extsize) || 227 put_user(buffer->bs_extents, &p32->bs_extents) || 228 put_user(buffer->bs_gen, &p32->bs_gen) || 229 put_user(buffer->bs_projid, &p32->bs_projid) || 230 put_user(buffer->bs_dmevmask, &p32->bs_dmevmask) || 231 put_user(buffer->bs_dmstate, &p32->bs_dmstate) || 232 put_user(buffer->bs_aextents, &p32->bs_aextents)) 233 return -EFAULT; 234 return sizeof(*p32); 235} 236 237 238 239typedef struct compat_xfs_fsop_bulkreq { 240 compat_uptr_t lastip; /* last inode # pointer */ 241 __s32 icount; /* count of entries in buffer */ 242 compat_uptr_t ubuffer; /* user buffer for inode desc. */ 243 compat_uptr_t ocount; /* output count pointer */ 244} compat_xfs_fsop_bulkreq_t; 245 246#define XFS_IOC_FSBULKSTAT_32 \ 247 _IOWR('X', 101, struct compat_xfs_fsop_bulkreq) 248#define XFS_IOC_FSBULKSTAT_SINGLE_32 \ 249 _IOWR('X', 102, struct compat_xfs_fsop_bulkreq) 250#define XFS_IOC_FSINUMBERS_32 \ 251 _IOWR('X', 103, struct compat_xfs_fsop_bulkreq) 252 253/* copied from xfs_ioctl.c */ 254STATIC int 255xfs_ioc_bulkstat_compat( 256 xfs_mount_t *mp, 257 unsigned int cmd, 258 void __user *arg) 259{ 260 compat_xfs_fsop_bulkreq_t __user *p32 = (void __user *)arg; 261 u32 addr; 262 xfs_fsop_bulkreq_t bulkreq; 263 int count; /* # of records returned */ 264 xfs_ino_t inlast; /* last inode number */ 265 int done; 266 int error; 267 268 /* done = 1 if there are more stats to get and if bulkstat */ 269 /* should be called again (unused here, but used in dmapi) */ 270 271 if (!capable(CAP_SYS_ADMIN)) 272 return -EPERM; 273 274 if (XFS_FORCED_SHUTDOWN(mp)) 275 return -XFS_ERROR(EIO); 276 277 if (get_user(addr, &p32->lastip)) 278 return -EFAULT; 279 bulkreq.lastip = compat_ptr(addr); 280 if (get_user(bulkreq.icount, &p32->icount) || 281 get_user(addr, &p32->ubuffer)) 282 return -EFAULT; 283 bulkreq.ubuffer = compat_ptr(addr); 284 if (get_user(addr, &p32->ocount)) 285 return -EFAULT; 286 bulkreq.ocount = compat_ptr(addr); 287 288 if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64))) 289 return -XFS_ERROR(EFAULT); 290 291 if ((count = bulkreq.icount) <= 0) 292 return -XFS_ERROR(EINVAL); 293 294 if (bulkreq.ubuffer == NULL) 295 return -XFS_ERROR(EINVAL); 296 297 if (cmd == XFS_IOC_FSINUMBERS) 298 error = xfs_inumbers(mp, &inlast, &count, 299 bulkreq.ubuffer, xfs_inumbers_fmt_compat); 300 else { 301 /* declare a var to get a warning in case the type changes */ 302 bulkstat_one_fmt_pf formatter = xfs_bulkstat_one_fmt_compat; 303 error = xfs_bulkstat(mp, &inlast, &count, 304 xfs_bulkstat_one, formatter, 305 sizeof(compat_xfs_bstat_t), bulkreq.ubuffer, 306 BULKSTAT_FG_QUICK, &done); 307 } 308 if (error) 309 return -error; 310 311 if (bulkreq.ocount != NULL) { 312 if (copy_to_user(bulkreq.lastip, &inlast, 313 sizeof(xfs_ino_t))) 314 return -XFS_ERROR(EFAULT); 315 316 if (copy_to_user(bulkreq.ocount, &count, sizeof(count))) 317 return -XFS_ERROR(EFAULT); 318 } 319 320 return 0; 321} 322 323 324 325typedef struct compat_xfs_fsop_handlereq { 326 __u32 fd; /* fd for FD_TO_HANDLE */ 327 compat_uptr_t path; /* user pathname */ 328 __u32 oflags; /* open flags */ 329 compat_uptr_t ihandle; /* user supplied handle */ 330 __u32 ihandlen; /* user supplied length */ 331 compat_uptr_t ohandle; /* user buffer for handle */ 332 compat_uptr_t ohandlen; /* user buffer length */ 333} compat_xfs_fsop_handlereq_t; 334 335#define XFS_IOC_PATH_TO_FSHANDLE_32 \ 336 _IOWR('X', 104, struct compat_xfs_fsop_handlereq) 337#define XFS_IOC_PATH_TO_HANDLE_32 \ 338 _IOWR('X', 105, struct compat_xfs_fsop_handlereq) 339#define XFS_IOC_FD_TO_HANDLE_32 \ 340 _IOWR('X', 106, struct compat_xfs_fsop_handlereq) 341#define XFS_IOC_OPEN_BY_HANDLE_32 \ 342 _IOWR('X', 107, struct compat_xfs_fsop_handlereq) 343#define XFS_IOC_READLINK_BY_HANDLE_32 \ 344 _IOWR('X', 108, struct compat_xfs_fsop_handlereq) 345 346STATIC unsigned long xfs_ioctl32_fshandle(unsigned long arg) 347{ 348 compat_xfs_fsop_handlereq_t __user *p32 = (void __user *)arg; 349 xfs_fsop_handlereq_t __user *p = compat_alloc_user_space(sizeof(*p)); 350 u32 addr; 351 352 if (copy_in_user(&p->fd, &p32->fd, sizeof(__u32)) || 353 get_user(addr, &p32->path) || 354 put_user(compat_ptr(addr), &p->path) || 355 copy_in_user(&p->oflags, &p32->oflags, sizeof(__u32)) || 356 get_user(addr, &p32->ihandle) || 357 put_user(compat_ptr(addr), &p->ihandle) || 358 copy_in_user(&p->ihandlen, &p32->ihandlen, sizeof(__u32)) || 359 get_user(addr, &p32->ohandle) || 360 put_user(compat_ptr(addr), &p->ohandle) || 361 get_user(addr, &p32->ohandlen) || 362 put_user(compat_ptr(addr), &p->ohandlen)) 363 return -EFAULT; 364 365 return (unsigned long)p; 366} 367 368 369STATIC long 370xfs_compat_ioctl( 371 int mode, 372 struct file *file, 373 unsigned cmd, 374 unsigned long arg) 375{ 376 struct inode *inode = file->f_path.dentry->d_inode; 377 int error; 378 379 switch (cmd) { 380 case XFS_IOC_DIOINFO: 381 case XFS_IOC_FSGEOMETRY: 382 case XFS_IOC_GETVERSION: 383 case XFS_IOC_GETXFLAGS: 384 case XFS_IOC_SETXFLAGS: 385 case XFS_IOC_FSGETXATTR: 386 case XFS_IOC_FSSETXATTR: 387 case XFS_IOC_FSGETXATTRA: 388 case XFS_IOC_FSSETDM: 389 case XFS_IOC_GETBMAP: 390 case XFS_IOC_GETBMAPA: 391 case XFS_IOC_GETBMAPX: 392/* not handled 393 case XFS_IOC_FSSETDM_BY_HANDLE: 394 case XFS_IOC_ATTRLIST_BY_HANDLE: 395 case XFS_IOC_ATTRMULTI_BY_HANDLE: 396*/ 397 case XFS_IOC_FSCOUNTS: 398 case XFS_IOC_SET_RESBLKS: 399 case XFS_IOC_GET_RESBLKS: 400 case XFS_IOC_FSGROWFSDATA: 401 case XFS_IOC_FSGROWFSLOG: 402 case XFS_IOC_FSGROWFSRT: 403 case XFS_IOC_FREEZE: 404 case XFS_IOC_THAW: 405 case XFS_IOC_GOINGDOWN: 406 case XFS_IOC_ERROR_INJECTION: 407 case XFS_IOC_ERROR_CLEARALL: 408 break; 409 410#ifdef BROKEN_X86_ALIGNMENT 411 /* xfs_flock_t has wrong u32 vs u64 alignment */ 412 case XFS_IOC_ALLOCSP_32: 413 case XFS_IOC_FREESP_32: 414 case XFS_IOC_ALLOCSP64_32: 415 case XFS_IOC_FREESP64_32: 416 case XFS_IOC_RESVSP_32: 417 case XFS_IOC_UNRESVSP_32: 418 case XFS_IOC_RESVSP64_32: 419 case XFS_IOC_UNRESVSP64_32: 420 arg = xfs_ioctl32_flock(arg); 421 cmd = _NATIVE_IOC(cmd, struct xfs_flock64); 422 break; 423 case XFS_IOC_FSGEOMETRY_V1_32: 424 arg = xfs_ioctl32_geom_v1(arg); 425 cmd = _NATIVE_IOC(cmd, struct xfs_fsop_geom_v1); 426 break; 427 428#else /* These are handled fine if no alignment issues */ 429 case XFS_IOC_ALLOCSP: 430 case XFS_IOC_FREESP: 431 case XFS_IOC_RESVSP: 432 case XFS_IOC_UNRESVSP: 433 case XFS_IOC_ALLOCSP64: 434 case XFS_IOC_FREESP64: 435 case XFS_IOC_RESVSP64: 436 case XFS_IOC_UNRESVSP64: 437 case XFS_IOC_FSGEOMETRY_V1: 438 break; 439 440 /* xfs_bstat_t still has wrong u32 vs u64 alignment */ 441 case XFS_IOC_SWAPEXT: 442 break; 443 444#endif 445 case XFS_IOC_FSBULKSTAT_32: 446 case XFS_IOC_FSBULKSTAT_SINGLE_32: 447 case XFS_IOC_FSINUMBERS_32: 448 cmd = _NATIVE_IOC(cmd, struct xfs_fsop_bulkreq); 449 return xfs_ioc_bulkstat_compat(XFS_I(inode)->i_mount, 450 cmd, (void __user*)arg); 451 case XFS_IOC_FD_TO_HANDLE_32: 452 case XFS_IOC_PATH_TO_HANDLE_32: 453 case XFS_IOC_PATH_TO_FSHANDLE_32: 454 case XFS_IOC_OPEN_BY_HANDLE_32: 455 case XFS_IOC_READLINK_BY_HANDLE_32: 456 arg = xfs_ioctl32_fshandle(arg); 457 cmd = _NATIVE_IOC(cmd, struct xfs_fsop_handlereq); 458 break; 459 default: 460 return -ENOIOCTLCMD; 461 } 462 463 error = xfs_ioctl(XFS_I(inode), file, mode, cmd, (void __user *)arg); 464 xfs_iflags_set(XFS_I(inode), XFS_IMODIFIED); 465 466 return error; 467} 468 469long 470xfs_file_compat_ioctl( 471 struct file *file, 472 unsigned cmd, 473 unsigned long arg) 474{ 475 return xfs_compat_ioctl(0, file, cmd, arg); 476} 477 478long 479xfs_file_compat_invis_ioctl( 480 struct file *file, 481 unsigned cmd, 482 unsigned long arg) 483{ 484 return xfs_compat_ioctl(IO_INVIS, file, cmd, arg); 485}