1 /* 2 * linux/fs/ext4/ioctl.c 3 * 4 * Copyright (C) 1993, 1994, 1995 5 * Remy Card (card@masi.ibp.fr) 6 * Laboratoire MASI - Institut Blaise Pascal 7 * Universite Pierre et Marie Curie (Paris VI) 8 */ 9 10 #include <linux/fs.h> 11 #include <linux/jbd2.h> 12 #include <linux/capability.h> 13 #include <linux/time.h> 14 #include <linux/compat.h> 15 #include <linux/mount.h> 16 #include <linux/file.h> 17 #include <asm/uaccess.h> 18 #include "ext4_jbd2.h" 19 #include "ext4.h" 20 21 long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 22 { 23 struct inode *inode = filp->f_dentry->d_inode; 24 struct super_block *sb = inode->i_sb; 25 struct ext4_inode_info *ei = EXT4_I(inode); 26 unsigned int flags; 27 28 ext4_debug("cmd = %u, arg = %lu\n", cmd, arg); 29 30 switch (cmd) { 31 case EXT4_IOC_GETFLAGS: 32 ext4_get_inode_flags(ei); 33 flags = ei->i_flags & EXT4_FL_USER_VISIBLE; 34 return put_user(flags, (int __user *) arg); 35 case EXT4_IOC_SETFLAGS: { 36 handle_t *handle = NULL; 37 int err, migrate = 0; 38 struct ext4_iloc iloc; 39 unsigned int oldflags; 40 unsigned int jflag; 41 42 if (!inode_owner_or_capable(inode)) 43 return -EACCES; 44 45 if (get_user(flags, (int __user *) arg)) 46 return -EFAULT; 47 48 err = mnt_want_write(filp->f_path.mnt); 49 if (err) 50 return err; 51 52 flags = ext4_mask_flags(inode->i_mode, flags); 53 54 err = -EPERM; 55 mutex_lock(&inode->i_mutex); 56 /* Is it quota file? Do not allow user to mess with it */ 57 if (IS_NOQUOTA(inode)) 58 goto flags_out; 59 60 oldflags = ei->i_flags; 61 62 /* The JOURNAL_DATA flag is modifiable only by root */ 63 jflag = flags & EXT4_JOURNAL_DATA_FL; 64 65 /* 66 * The IMMUTABLE and APPEND_ONLY flags can only be changed by 67 * the relevant capability. 68 * 69 * This test looks nicer. Thanks to Pauline Middelink 70 */ 71 if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) { 72 if (!capable(CAP_LINUX_IMMUTABLE)) 73 goto flags_out; 74 } 75 76 /* 77 * The JOURNAL_DATA flag can only be changed by 78 * the relevant capability. 79 */ 80 if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) { 81 if (!capable(CAP_SYS_RESOURCE)) 82 goto flags_out; 83 } 84 if (oldflags & EXT4_EXTENTS_FL) { 85 /* We don't support clearning extent flags */ 86 if (!(flags & EXT4_EXTENTS_FL)) { 87 err = -EOPNOTSUPP; 88 goto flags_out; 89 } 90 } else if (flags & EXT4_EXTENTS_FL) { 91 /* migrate the file */ 92 migrate = 1; 93 flags &= ~EXT4_EXTENTS_FL; 94 } 95 96 if (flags & EXT4_EOFBLOCKS_FL) { 97 /* we don't support adding EOFBLOCKS flag */ 98 if (!(oldflags & EXT4_EOFBLOCKS_FL)) { 99 err = -EOPNOTSUPP; 100 goto flags_out; 101 } 102 } else if (oldflags & EXT4_EOFBLOCKS_FL) 103 ext4_truncate(inode); 104 105 handle = ext4_journal_start(inode, 1); 106 if (IS_ERR(handle)) { 107 err = PTR_ERR(handle); 108 goto flags_out; 109 } 110 if (IS_SYNC(inode)) 111 ext4_handle_sync(handle); 112 err = ext4_reserve_inode_write(handle, inode, &iloc); 113 if (err) 114 goto flags_err; 115 116 flags = flags & EXT4_FL_USER_MODIFIABLE; 117 flags |= oldflags & ~EXT4_FL_USER_MODIFIABLE; 118 ei->i_flags = flags; 119 120 ext4_set_inode_flags(inode); 121 inode->i_ctime = ext4_current_time(inode); 122 123 err = ext4_mark_iloc_dirty(handle, inode, &iloc); 124 flags_err: 125 ext4_journal_stop(handle); 126 if (err) 127 goto flags_out; 128 129 if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) 130 err = ext4_change_inode_journal_flag(inode, jflag); 131 if (err) 132 goto flags_out; 133 if (migrate) 134 err = ext4_ext_migrate(inode); 135 flags_out: 136 mutex_unlock(&inode->i_mutex); 137 mnt_drop_write(filp->f_path.mnt); 138 return err; 139 } 140 case EXT4_IOC_GETVERSION: 141 case EXT4_IOC_GETVERSION_OLD: 142 return put_user(inode->i_generation, (int __user *) arg); 143 case EXT4_IOC_SETVERSION: 144 case EXT4_IOC_SETVERSION_OLD: { 145 handle_t *handle; 146 struct ext4_iloc iloc; 147 __u32 generation; 148 int err; 149 150 if (!inode_owner_or_capable(inode)) 151 return -EPERM; 152 153 err = mnt_want_write(filp->f_path.mnt); 154 if (err) 155 return err; 156 if (get_user(generation, (int __user *) arg)) { 157 err = -EFAULT; 158 goto setversion_out; 159 } 160 161 handle = ext4_journal_start(inode, 1); 162 if (IS_ERR(handle)) { 163 err = PTR_ERR(handle); 164 goto setversion_out; 165 } 166 err = ext4_reserve_inode_write(handle, inode, &iloc); 167 if (err == 0) { 168 inode->i_ctime = ext4_current_time(inode); 169 inode->i_generation = generation; 170 err = ext4_mark_iloc_dirty(handle, inode, &iloc); 171 } 172 ext4_journal_stop(handle); 173 setversion_out: 174 mnt_drop_write(filp->f_path.mnt); 175 return err; 176 } 177 case EXT4_IOC_GROUP_EXTEND: { 178 ext4_fsblk_t n_blocks_count; 179 int err, err2=0; 180 181 err = ext4_resize_begin(sb); 182 if (err) 183 return err; 184 185 if (get_user(n_blocks_count, (__u32 __user *)arg)) 186 return -EFAULT; 187 188 if (EXT4_HAS_RO_COMPAT_FEATURE(sb, 189 EXT4_FEATURE_RO_COMPAT_BIGALLOC)) { 190 ext4_msg(sb, KERN_ERR, 191 "Online resizing not supported with bigalloc"); 192 return -EOPNOTSUPP; 193 } 194 195 err = mnt_want_write(filp->f_path.mnt); 196 if (err) 197 return err; 198 199 err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count); 200 if (EXT4_SB(sb)->s_journal) { 201 jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); 202 err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal); 203 jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); 204 } 205 if (err == 0) 206 err = err2; 207 mnt_drop_write(filp->f_path.mnt); 208 ext4_resize_end(sb); 209 210 return err; 211 } 212 213 case EXT4_IOC_MOVE_EXT: { 214 struct move_extent me; 215 struct file *donor_filp; 216 int err; 217 218 if (!(filp->f_mode & FMODE_READ) || 219 !(filp->f_mode & FMODE_WRITE)) 220 return -EBADF; 221 222 if (copy_from_user(&me, 223 (struct move_extent __user *)arg, sizeof(me))) 224 return -EFAULT; 225 me.moved_len = 0; 226 227 donor_filp = fget(me.donor_fd); 228 if (!donor_filp) 229 return -EBADF; 230 231 if (!(donor_filp->f_mode & FMODE_WRITE)) { 232 err = -EBADF; 233 goto mext_out; 234 } 235 236 if (EXT4_HAS_RO_COMPAT_FEATURE(sb, 237 EXT4_FEATURE_RO_COMPAT_BIGALLOC)) { 238 ext4_msg(sb, KERN_ERR, 239 "Online defrag not supported with bigalloc"); 240 return -EOPNOTSUPP; 241 } 242 243 err = mnt_want_write(filp->f_path.mnt); 244 if (err) 245 goto mext_out; 246 247 err = ext4_move_extents(filp, donor_filp, me.orig_start, 248 me.donor_start, me.len, &me.moved_len); 249 mnt_drop_write(filp->f_path.mnt); 250 if (me.moved_len > 0) 251 file_remove_suid(donor_filp); 252 253 if (copy_to_user((struct move_extent __user *)arg, 254 &me, sizeof(me))) 255 err = -EFAULT; 256 mext_out: 257 fput(donor_filp); 258 return err; 259 } 260 261 case EXT4_IOC_GROUP_ADD: { 262 struct ext4_new_group_data input; 263 int err, err2=0; 264 265 err = ext4_resize_begin(sb); 266 if (err) 267 return err; 268 269 if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg, 270 sizeof(input))) 271 return -EFAULT; 272 273 if (EXT4_HAS_RO_COMPAT_FEATURE(sb, 274 EXT4_FEATURE_RO_COMPAT_BIGALLOC)) { 275 ext4_msg(sb, KERN_ERR, 276 "Online resizing not supported with bigalloc"); 277 return -EOPNOTSUPP; 278 } 279 280 err = mnt_want_write(filp->f_path.mnt); 281 if (err) 282 return err; 283 284 err = ext4_group_add(sb, &input); 285 if (EXT4_SB(sb)->s_journal) { 286 jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); 287 err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal); 288 jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); 289 } 290 if (err == 0) 291 err = err2; 292 mnt_drop_write(filp->f_path.mnt); 293 ext4_resize_end(sb); 294 295 return err; 296 } 297 298 case EXT4_IOC_MIGRATE: 299 { 300 int err; 301 if (!inode_owner_or_capable(inode)) 302 return -EACCES; 303 304 err = mnt_want_write(filp->f_path.mnt); 305 if (err) 306 return err; 307 /* 308 * inode_mutex prevent write and truncate on the file. 309 * Read still goes through. We take i_data_sem in 310 * ext4_ext_swap_inode_data before we switch the 311 * inode format to prevent read. 312 */ 313 mutex_lock(&(inode->i_mutex)); 314 err = ext4_ext_migrate(inode); 315 mutex_unlock(&(inode->i_mutex)); 316 mnt_drop_write(filp->f_path.mnt); 317 return err; 318 } 319 320 case EXT4_IOC_ALLOC_DA_BLKS: 321 { 322 int err; 323 if (!inode_owner_or_capable(inode)) 324 return -EACCES; 325 326 err = mnt_want_write(filp->f_path.mnt); 327 if (err) 328 return err; 329 err = ext4_alloc_da_blocks(inode); 330 mnt_drop_write(filp->f_path.mnt); 331 return err; 332 } 333 334 case FITRIM: 335 { 336 struct request_queue *q = bdev_get_queue(sb->s_bdev); 337 struct fstrim_range range; 338 int ret = 0; 339 340 if (!capable(CAP_SYS_ADMIN)) 341 return -EPERM; 342 343 if (!blk_queue_discard(q)) 344 return -EOPNOTSUPP; 345 346 if (EXT4_HAS_RO_COMPAT_FEATURE(sb, 347 EXT4_FEATURE_RO_COMPAT_BIGALLOC)) { 348 ext4_msg(sb, KERN_ERR, 349 "FITRIM not supported with bigalloc"); 350 return -EOPNOTSUPP; 351 } 352 353 if (copy_from_user(&range, (struct fstrim_range __user *)arg, 354 sizeof(range))) 355 return -EFAULT; 356 357 range.minlen = max((unsigned int)range.minlen, 358 q->limits.discard_granularity); 359 ret = ext4_trim_fs(sb, &range); 360 if (ret < 0) 361 return ret; 362 363 if (copy_to_user((struct fstrim_range __user *)arg, &range, 364 sizeof(range))) 365 return -EFAULT; 366 367 return 0; 368 } 369 370 default: 371 return -ENOTTY; 372 } 373 } 374 375 #ifdef CONFIG_COMPAT 376 long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 377 { 378 /* These are just misnamed, they actually get/put from/to user an int */ 379 switch (cmd) { 380 case EXT4_IOC32_GETFLAGS: 381 cmd = EXT4_IOC_GETFLAGS; 382 break; 383 case EXT4_IOC32_SETFLAGS: 384 cmd = EXT4_IOC_SETFLAGS; 385 break; 386 case EXT4_IOC32_GETVERSION: 387 cmd = EXT4_IOC_GETVERSION; 388 break; 389 case EXT4_IOC32_SETVERSION: 390 cmd = EXT4_IOC_SETVERSION; 391 break; 392 case EXT4_IOC32_GROUP_EXTEND: 393 cmd = EXT4_IOC_GROUP_EXTEND; 394 break; 395 case EXT4_IOC32_GETVERSION_OLD: 396 cmd = EXT4_IOC_GETVERSION_OLD; 397 break; 398 case EXT4_IOC32_SETVERSION_OLD: 399 cmd = EXT4_IOC_SETVERSION_OLD; 400 break; 401 case EXT4_IOC32_GETRSVSZ: 402 cmd = EXT4_IOC_GETRSVSZ; 403 break; 404 case EXT4_IOC32_SETRSVSZ: 405 cmd = EXT4_IOC_SETRSVSZ; 406 break; 407 case EXT4_IOC32_GROUP_ADD: { 408 struct compat_ext4_new_group_input __user *uinput; 409 struct ext4_new_group_input input; 410 mm_segment_t old_fs; 411 int err; 412 413 uinput = compat_ptr(arg); 414 err = get_user(input.group, &uinput->group); 415 err |= get_user(input.block_bitmap, &uinput->block_bitmap); 416 err |= get_user(input.inode_bitmap, &uinput->inode_bitmap); 417 err |= get_user(input.inode_table, &uinput->inode_table); 418 err |= get_user(input.blocks_count, &uinput->blocks_count); 419 err |= get_user(input.reserved_blocks, 420 &uinput->reserved_blocks); 421 if (err) 422 return -EFAULT; 423 old_fs = get_fs(); 424 set_fs(KERNEL_DS); 425 err = ext4_ioctl(file, EXT4_IOC_GROUP_ADD, 426 (unsigned long) &input); 427 set_fs(old_fs); 428 return err; 429 } 430 case EXT4_IOC_MOVE_EXT: 431 case FITRIM: 432 break; 433 default: 434 return -ENOIOCTLCMD; 435 } 436 return ext4_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); 437 } 438 #endif 439