LCOV - code coverage report
Current view: top level - fs/ext4 - ioctl.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 43 238 18.1 %
Date: 2014-02-18 Functions: 1 3 33.3 %
Branches: 28 196 14.3 %

           Branch data     Line data    Source code
       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                 :            : #define MAX_32_NUM ((((unsigned long long) 1) << 32) - 1)
      22                 :            : 
      23                 :            : /**
      24                 :            :  * Swap memory between @a and @b for @len bytes.
      25                 :            :  *
      26                 :            :  * @a:          pointer to first memory area
      27                 :            :  * @b:          pointer to second memory area
      28                 :            :  * @len:        number of bytes to swap
      29                 :            :  *
      30                 :            :  */
      31                 :            : static void memswap(void *a, void *b, size_t len)
      32                 :            : {
      33                 :            :         unsigned char *ap, *bp;
      34                 :            :         unsigned char tmp;
      35                 :            : 
      36                 :            :         ap = (unsigned char *)a;
      37                 :            :         bp = (unsigned char *)b;
      38 [ #  # ][ #  # ]:          0 :         while (len-- > 0) {
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      39                 :          0 :                 tmp = *ap;
      40                 :          0 :                 *ap = *bp;
      41                 :          0 :                 *bp = tmp;
      42                 :          0 :                 ap++;
      43                 :          0 :                 bp++;
      44                 :            :         }
      45                 :            : }
      46                 :            : 
      47                 :            : /**
      48                 :            :  * Swap i_data and associated attributes between @inode1 and @inode2.
      49                 :            :  * This function is used for the primary swap between inode1 and inode2
      50                 :            :  * and also to revert this primary swap in case of errors.
      51                 :            :  *
      52                 :            :  * Therefore you have to make sure, that calling this method twice
      53                 :            :  * will revert all changes.
      54                 :            :  *
      55                 :            :  * @inode1:     pointer to first inode
      56                 :            :  * @inode2:     pointer to second inode
      57                 :            :  */
      58                 :          0 : static void swap_inode_data(struct inode *inode1, struct inode *inode2)
      59                 :            : {
      60                 :            :         loff_t isize;
      61                 :            :         struct ext4_inode_info *ei1;
      62                 :            :         struct ext4_inode_info *ei2;
      63                 :            : 
      64                 :            :         ei1 = EXT4_I(inode1);
      65                 :            :         ei2 = EXT4_I(inode2);
      66                 :            : 
      67                 :          0 :         memswap(&inode1->i_flags, &inode2->i_flags, sizeof(inode1->i_flags));
      68                 :          0 :         memswap(&inode1->i_version, &inode2->i_version,
      69                 :            :                   sizeof(inode1->i_version));
      70                 :          0 :         memswap(&inode1->i_blocks, &inode2->i_blocks,
      71                 :            :                   sizeof(inode1->i_blocks));
      72                 :          0 :         memswap(&inode1->i_bytes, &inode2->i_bytes, sizeof(inode1->i_bytes));
      73                 :          0 :         memswap(&inode1->i_atime, &inode2->i_atime, sizeof(inode1->i_atime));
      74                 :          0 :         memswap(&inode1->i_mtime, &inode2->i_mtime, sizeof(inode1->i_mtime));
      75                 :            : 
      76                 :          0 :         memswap(ei1->i_data, ei2->i_data, sizeof(ei1->i_data));
      77                 :          0 :         memswap(&ei1->i_flags, &ei2->i_flags, sizeof(ei1->i_flags));
      78                 :          0 :         memswap(&ei1->i_disksize, &ei2->i_disksize, sizeof(ei1->i_disksize));
      79                 :          0 :         ext4_es_remove_extent(inode1, 0, EXT_MAX_BLOCKS);
      80                 :          0 :         ext4_es_remove_extent(inode2, 0, EXT_MAX_BLOCKS);
      81                 :          0 :         ext4_es_lru_del(inode1);
      82                 :          0 :         ext4_es_lru_del(inode2);
      83                 :            : 
      84                 :            :         isize = i_size_read(inode1);
      85                 :            :         i_size_write(inode1, i_size_read(inode2));
      86                 :            :         i_size_write(inode2, isize);
      87                 :          0 : }
      88                 :            : 
      89                 :            : /**
      90                 :            :  * Swap the information from the given @inode and the inode
      91                 :            :  * EXT4_BOOT_LOADER_INO. It will basically swap i_data and all other
      92                 :            :  * important fields of the inodes.
      93                 :            :  *
      94                 :            :  * @sb:         the super block of the filesystem
      95                 :            :  * @inode:      the inode to swap with EXT4_BOOT_LOADER_INO
      96                 :            :  *
      97                 :            :  */
      98                 :          0 : static long swap_inode_boot_loader(struct super_block *sb,
      99                 :          0 :                                 struct inode *inode)
     100                 :            : {
     101                 :            :         handle_t *handle;
     102                 :            :         int err;
     103                 :          0 :         struct inode *inode_bl;
     104                 :            :         struct ext4_inode_info *ei;
     105                 :            :         struct ext4_inode_info *ei_bl;
     106                 :            :         struct ext4_sb_info *sbi;
     107                 :            : 
     108 [ #  # ][ #  # ]:          0 :         if (inode->i_nlink != 1 || !S_ISREG(inode->i_mode)) {
     109                 :            :                 err = -EINVAL;
     110                 :            :                 goto swap_boot_out;
     111                 :            :         }
     112                 :            : 
     113 [ #  # ][ #  # ]:          0 :         if (!inode_owner_or_capable(inode) || !capable(CAP_SYS_ADMIN)) {
     114                 :            :                 err = -EPERM;
     115                 :            :                 goto swap_boot_out;
     116                 :            :         }
     117                 :            : 
     118                 :            :         sbi = EXT4_SB(sb);
     119                 :            :         ei = EXT4_I(inode);
     120                 :            : 
     121                 :          0 :         inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO);
     122         [ #  # ]:          0 :         if (IS_ERR(inode_bl)) {
     123                 :            :                 err = PTR_ERR(inode_bl);
     124                 :          0 :                 goto swap_boot_out;
     125                 :            :         }
     126                 :            :         ei_bl = EXT4_I(inode_bl);
     127                 :            : 
     128                 :          0 :         filemap_flush(inode->i_mapping);
     129                 :          0 :         filemap_flush(inode_bl->i_mapping);
     130                 :            : 
     131                 :            :         /* Protect orig inodes against a truncate and make sure,
     132                 :            :          * that only 1 swap_inode_boot_loader is running. */
     133                 :          0 :         lock_two_nondirectories(inode, inode_bl);
     134                 :            : 
     135                 :          0 :         truncate_inode_pages(&inode->i_data, 0);
     136                 :          0 :         truncate_inode_pages(&inode_bl->i_data, 0);
     137                 :            : 
     138                 :            :         /* Wait for all existing dio workers */
     139                 :            :         ext4_inode_block_unlocked_dio(inode);
     140                 :            :         ext4_inode_block_unlocked_dio(inode_bl);
     141                 :          0 :         inode_dio_wait(inode);
     142                 :          0 :         inode_dio_wait(inode_bl);
     143                 :            : 
     144                 :            :         handle = ext4_journal_start(inode_bl, EXT4_HT_MOVE_EXTENTS, 2);
     145         [ #  # ]:          0 :         if (IS_ERR(handle)) {
     146                 :            :                 err = -EINVAL;
     147                 :            :                 goto swap_boot_out;
     148                 :            :         }
     149                 :            : 
     150                 :            :         /* Protect extent tree against block allocations via delalloc */
     151                 :          0 :         ext4_double_down_write_data_sem(inode, inode_bl);
     152                 :            : 
     153         [ #  # ]:          0 :         if (inode_bl->i_nlink == 0) {
     154                 :            :                 /* this inode has never been used as a BOOT_LOADER */
     155                 :          0 :                 set_nlink(inode_bl, 1);
     156                 :            :                 i_uid_write(inode_bl, 0);
     157                 :            :                 i_gid_write(inode_bl, 0);
     158                 :          0 :                 inode_bl->i_flags = 0;
     159                 :          0 :                 ei_bl->i_flags = 0;
     160                 :          0 :                 inode_bl->i_version = 1;
     161                 :            :                 i_size_write(inode_bl, 0);
     162                 :          0 :                 inode_bl->i_mode = S_IFREG;
     163         [ #  # ]:          0 :                 if (EXT4_HAS_INCOMPAT_FEATURE(sb,
     164                 :            :                                               EXT4_FEATURE_INCOMPAT_EXTENTS)) {
     165                 :            :                         ext4_set_inode_flag(inode_bl, EXT4_INODE_EXTENTS);
     166                 :          0 :                         ext4_ext_tree_init(handle, inode_bl);
     167                 :            :                 } else
     168                 :          0 :                         memset(ei_bl->i_data, 0, sizeof(ei_bl->i_data));
     169                 :            :         }
     170                 :            : 
     171                 :          0 :         swap_inode_data(inode, inode_bl);
     172                 :            : 
     173                 :          0 :         inode->i_ctime = inode_bl->i_ctime = ext4_current_time(inode);
     174                 :            : 
     175                 :            :         spin_lock(&sbi->s_next_gen_lock);
     176                 :          0 :         inode->i_generation = sbi->s_next_generation++;
     177                 :          0 :         inode_bl->i_generation = sbi->s_next_generation++;
     178                 :            :         spin_unlock(&sbi->s_next_gen_lock);
     179                 :            : 
     180                 :          0 :         ext4_discard_preallocations(inode);
     181                 :            : 
     182                 :          0 :         err = ext4_mark_inode_dirty(handle, inode);
     183         [ #  # ]:          0 :         if (err < 0) {
     184                 :          0 :                 ext4_warning(inode->i_sb,
     185                 :            :                         "couldn't mark inode #%lu dirty (err %d)",
     186                 :            :                         inode->i_ino, err);
     187                 :            :                 /* Revert all changes: */
     188                 :          0 :                 swap_inode_data(inode, inode_bl);
     189                 :            :         } else {
     190                 :          0 :                 err = ext4_mark_inode_dirty(handle, inode_bl);
     191         [ #  # ]:          0 :                 if (err < 0) {
     192                 :          0 :                         ext4_warning(inode_bl->i_sb,
     193                 :            :                                 "couldn't mark inode #%lu dirty (err %d)",
     194                 :            :                                 inode_bl->i_ino, err);
     195                 :            :                         /* Revert all changes: */
     196                 :          0 :                         swap_inode_data(inode, inode_bl);
     197                 :          0 :                         ext4_mark_inode_dirty(handle, inode);
     198                 :            :                 }
     199                 :            :         }
     200                 :            : 
     201                 :          0 :         ext4_journal_stop(handle);
     202                 :            : 
     203                 :          0 :         ext4_double_up_write_data_sem(inode, inode_bl);
     204                 :            : 
     205                 :            :         ext4_inode_resume_unlocked_dio(inode);
     206                 :            :         ext4_inode_resume_unlocked_dio(inode_bl);
     207                 :            : 
     208                 :          0 :         unlock_two_nondirectories(inode, inode_bl);
     209                 :            : 
     210                 :          0 :         iput(inode_bl);
     211                 :            : 
     212                 :            : swap_boot_out:
     213                 :          0 :         return err;
     214                 :            : }
     215                 :            : 
     216                 :          0 : long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
     217                 :            : {
     218                 :        246 :         struct inode *inode = file_inode(filp);
     219                 :      76043 :         struct super_block *sb = inode->i_sb;
     220                 :      76043 :         struct ext4_inode_info *ei = EXT4_I(inode);
     221                 :            :         unsigned int flags;
     222                 :            : 
     223                 :            :         ext4_debug("cmd = %u, arg = %lu\n", cmd, arg);
     224                 :            : 
     225   [ +  +  -  -  :      76043 :         switch (cmd) {
          -  -  -  -  -  
             -  -  -  -  
                      + ]
     226                 :            :         case EXT4_IOC_GETFLAGS:
     227                 :        204 :                 ext4_get_inode_flags(ei);
     228                 :        204 :                 flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
     229                 :        204 :                 return put_user(flags, (int __user *) arg);
     230                 :            :         case EXT4_IOC_SETFLAGS: {
     231                 :            :                 handle_t *handle = NULL;
     232                 :            :                 int err, migrate = 0;
     233                 :            :                 struct ext4_iloc iloc;
     234                 :            :                 unsigned int oldflags, mask, i;
     235                 :            :                 unsigned int jflag;
     236                 :            : 
     237         [ +  - ]:        123 :                 if (!inode_owner_or_capable(inode))
     238                 :            :                         return -EACCES;
     239                 :            : 
     240         [ +  - ]:        123 :                 if (get_user(flags, (int __user *) arg))
     241                 :            :                         return -EFAULT;
     242                 :            : 
     243                 :        123 :                 err = mnt_want_write_file(filp);
     244         [ +  - ]:        123 :                 if (err)
     245                 :            :                         return err;
     246                 :            : 
     247                 :        123 :                 flags = ext4_mask_flags(inode->i_mode, flags);
     248                 :            : 
     249                 :            :                 err = -EPERM;
     250                 :        123 :                 mutex_lock(&inode->i_mutex);
     251                 :            :                 /* Is it quota file? Do not allow user to mess with it */
     252         [ +  - ]:        123 :                 if (IS_NOQUOTA(inode))
     253                 :            :                         goto flags_out;
     254                 :            : 
     255                 :        123 :                 oldflags = ei->i_flags;
     256                 :            : 
     257                 :            :                 /* The JOURNAL_DATA flag is modifiable only by root */
     258                 :        123 :                 jflag = flags & EXT4_JOURNAL_DATA_FL;
     259                 :            : 
     260                 :            :                 /*
     261                 :            :                  * The IMMUTABLE and APPEND_ONLY flags can only be changed by
     262                 :            :                  * the relevant capability.
     263                 :            :                  *
     264                 :            :                  * This test looks nicer. Thanks to Pauline Middelink
     265                 :            :                  */
     266         [ +  + ]:        123 :                 if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
     267         [ +  - ]:         84 :                         if (!capable(CAP_LINUX_IMMUTABLE))
     268                 :            :                                 goto flags_out;
     269                 :            :                 }
     270                 :            : 
     271                 :            :                 /*
     272                 :            :                  * The JOURNAL_DATA flag can only be changed by
     273                 :            :                  * the relevant capability.
     274                 :            :                  */
     275         [ -  + ]:        123 :                 if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
     276         [ #  # ]:          0 :                         if (!capable(CAP_SYS_RESOURCE))
     277                 :            :                                 goto flags_out;
     278                 :            :                 }
     279         [ -  + ]:        123 :                 if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
     280                 :            :                         migrate = 1;
     281                 :            : 
     282         [ -  + ]:        123 :                 if (flags & EXT4_EOFBLOCKS_FL) {
     283                 :            :                         /* we don't support adding EOFBLOCKS flag */
     284         [ #  # ]:          0 :                         if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
     285                 :            :                                 err = -EOPNOTSUPP;
     286                 :            :                                 goto flags_out;
     287                 :            :                         }
     288         [ -  + ]:        123 :                 } else if (oldflags & EXT4_EOFBLOCKS_FL)
     289                 :          0 :                         ext4_truncate(inode);
     290                 :            : 
     291                 :            :                 handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
     292         [ -  + ]:        123 :                 if (IS_ERR(handle)) {
     293                 :            :                         err = PTR_ERR(handle);
     294                 :          0 :                         goto flags_out;
     295                 :            :                 }
     296 [ +  - ][ -  + ]:        123 :                 if (IS_SYNC(inode))
     297                 :            :                         ext4_handle_sync(handle);
     298                 :        123 :                 err = ext4_reserve_inode_write(handle, inode, &iloc);
     299         [ +  - ]:        123 :                 if (err)
     300                 :            :                         goto flags_err;
     301                 :            : 
     302         [ +  + ]:       4059 :                 for (i = 0, mask = 1; i < 32; i++, mask <<= 1) {
     303         [ +  + ]:       3936 :                         if (!(mask & EXT4_FL_USER_MODIFIABLE))
     304                 :       2460 :                                 continue;
     305         [ +  + ]:       1476 :                         if (mask & flags)
     306                 :         54 :                                 ext4_set_inode_flag(inode, i);
     307                 :            :                         else
     308                 :       1422 :                                 ext4_clear_inode_flag(inode, i);
     309                 :            :                 }
     310                 :            : 
     311                 :        123 :                 ext4_set_inode_flags(inode);
     312                 :        123 :                 inode->i_ctime = ext4_current_time(inode);
     313                 :            : 
     314                 :        123 :                 err = ext4_mark_iloc_dirty(handle, inode, &iloc);
     315                 :            : flags_err:
     316                 :        123 :                 ext4_journal_stop(handle);
     317         [ +  - ]:        123 :                 if (err)
     318                 :            :                         goto flags_out;
     319                 :            : 
     320         [ -  + ]:        123 :                 if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
     321                 :          0 :                         err = ext4_change_inode_journal_flag(inode, jflag);
     322         [ +  - ]:        123 :                 if (err)
     323                 :            :                         goto flags_out;
     324         [ -  + ]:        123 :                 if (migrate) {
     325         [ #  # ]:          0 :                         if (flags & EXT4_EXTENTS_FL)
     326                 :          0 :                                 err = ext4_ext_migrate(inode);
     327                 :            :                         else
     328                 :          0 :                                 err = ext4_ind_migrate(inode);
     329                 :            :                 }
     330                 :            : 
     331                 :            : flags_out:
     332                 :        123 :                 mutex_unlock(&inode->i_mutex);
     333                 :        123 :                 mnt_drop_write_file(filp);
     334                 :        123 :                 return err;
     335                 :            :         }
     336                 :            :         case EXT4_IOC_GETVERSION:
     337                 :            :         case EXT4_IOC_GETVERSION_OLD:
     338                 :          0 :                 return put_user(inode->i_generation, (int __user *) arg);
     339                 :            :         case EXT4_IOC_SETVERSION:
     340                 :            :         case EXT4_IOC_SETVERSION_OLD: {
     341                 :            :                 handle_t *handle;
     342                 :            :                 struct ext4_iloc iloc;
     343                 :            :                 __u32 generation;
     344                 :            :                 int err;
     345                 :            : 
     346         [ #  # ]:          0 :                 if (!inode_owner_or_capable(inode))
     347                 :            :                         return -EPERM;
     348                 :            : 
     349         [ #  # ]:          0 :                 if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
     350                 :            :                                 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
     351                 :          0 :                         ext4_warning(sb, "Setting inode version is not "
     352                 :            :                                      "supported with metadata_csum enabled.");
     353                 :          0 :                         return -ENOTTY;
     354                 :            :                 }
     355                 :            : 
     356                 :          0 :                 err = mnt_want_write_file(filp);
     357         [ #  # ]:          0 :                 if (err)
     358                 :            :                         return err;
     359         [ #  # ]:          0 :                 if (get_user(generation, (int __user *) arg)) {
     360                 :            :                         err = -EFAULT;
     361                 :            :                         goto setversion_out;
     362                 :            :                 }
     363                 :            : 
     364                 :          0 :                 mutex_lock(&inode->i_mutex);
     365                 :            :                 handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
     366         [ #  # ]:          0 :                 if (IS_ERR(handle)) {
     367                 :            :                         err = PTR_ERR(handle);
     368                 :          0 :                         goto unlock_out;
     369                 :            :                 }
     370                 :          0 :                 err = ext4_reserve_inode_write(handle, inode, &iloc);
     371         [ #  # ]:          0 :                 if (err == 0) {
     372                 :          0 :                         inode->i_ctime = ext4_current_time(inode);
     373                 :          0 :                         inode->i_generation = generation;
     374                 :          0 :                         err = ext4_mark_iloc_dirty(handle, inode, &iloc);
     375                 :            :                 }
     376                 :          0 :                 ext4_journal_stop(handle);
     377                 :            : 
     378                 :            : unlock_out:
     379                 :          0 :                 mutex_unlock(&inode->i_mutex);
     380                 :            : setversion_out:
     381                 :          0 :                 mnt_drop_write_file(filp);
     382                 :          0 :                 return err;
     383                 :            :         }
     384                 :            :         case EXT4_IOC_GROUP_EXTEND: {
     385                 :            :                 ext4_fsblk_t n_blocks_count;
     386                 :            :                 int err, err2=0;
     387                 :            : 
     388                 :          0 :                 err = ext4_resize_begin(sb);
     389         [ #  # ]:          0 :                 if (err)
     390                 :            :                         return err;
     391                 :            : 
     392         [ #  # ]:          0 :                 if (get_user(n_blocks_count, (__u32 __user *)arg)) {
     393                 :            :                         err = -EFAULT;
     394                 :            :                         goto group_extend_out;
     395                 :            :                 }
     396                 :            : 
     397         [ #  # ]:          0 :                 if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
     398                 :            :                                EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
     399                 :          0 :                         ext4_msg(sb, KERN_ERR,
     400                 :            :                                  "Online resizing not supported with bigalloc");
     401                 :            :                         err = -EOPNOTSUPP;
     402                 :          0 :                         goto group_extend_out;
     403                 :            :                 }
     404                 :            : 
     405                 :          0 :                 err = mnt_want_write_file(filp);
     406         [ #  # ]:          0 :                 if (err)
     407                 :            :                         goto group_extend_out;
     408                 :            : 
     409                 :          0 :                 err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count);
     410         [ #  # ]:          0 :                 if (EXT4_SB(sb)->s_journal) {
     411                 :          0 :                         jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
     412                 :          0 :                         err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
     413                 :          0 :                         jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
     414                 :            :                 }
     415         [ #  # ]:          0 :                 if (err == 0)
     416                 :            :                         err = err2;
     417                 :          0 :                 mnt_drop_write_file(filp);
     418                 :            : group_extend_out:
     419                 :          0 :                 ext4_resize_end(sb);
     420                 :          0 :                 return err;
     421                 :            :         }
     422                 :            : 
     423                 :            :         case EXT4_IOC_MOVE_EXT: {
     424                 :            :                 struct move_extent me;
     425                 :            :                 struct fd donor;
     426                 :            :                 int err;
     427                 :            : 
     428         [ #  # ]:          0 :                 if (!(filp->f_mode & FMODE_READ) ||
     429                 :            :                     !(filp->f_mode & FMODE_WRITE))
     430                 :            :                         return -EBADF;
     431                 :            : 
     432         [ #  # ]:          0 :                 if (copy_from_user(&me,
     433                 :            :                         (struct move_extent __user *)arg, sizeof(me)))
     434                 :            :                         return -EFAULT;
     435                 :          0 :                 me.moved_len = 0;
     436                 :            : 
     437                 :          0 :                 donor = fdget(me.donor_fd);
     438         [ #  # ]:          0 :                 if (!donor.file)
     439                 :            :                         return -EBADF;
     440                 :            : 
     441         [ #  # ]:          0 :                 if (!(donor.file->f_mode & FMODE_WRITE)) {
     442                 :            :                         err = -EBADF;
     443                 :            :                         goto mext_out;
     444                 :            :                 }
     445                 :            : 
     446         [ #  # ]:          0 :                 if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
     447                 :            :                                EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
     448                 :          0 :                         ext4_msg(sb, KERN_ERR,
     449                 :            :                                  "Online defrag not supported with bigalloc");
     450                 :            :                         err = -EOPNOTSUPP;
     451                 :          0 :                         goto mext_out;
     452                 :            :                 }
     453                 :            : 
     454                 :          0 :                 err = mnt_want_write_file(filp);
     455         [ #  # ]:          0 :                 if (err)
     456                 :            :                         goto mext_out;
     457                 :            : 
     458                 :          0 :                 err = ext4_move_extents(filp, donor.file, me.orig_start,
     459                 :            :                                         me.donor_start, me.len, &me.moved_len);
     460                 :          0 :                 mnt_drop_write_file(filp);
     461                 :            : 
     462         [ #  # ]:          0 :                 if (copy_to_user((struct move_extent __user *)arg,
     463                 :            :                                  &me, sizeof(me)))
     464                 :            :                         err = -EFAULT;
     465                 :            : mext_out:
     466                 :            :                 fdput(donor);
     467                 :          0 :                 return err;
     468                 :            :         }
     469                 :            : 
     470                 :            :         case EXT4_IOC_GROUP_ADD: {
     471                 :            :                 struct ext4_new_group_data input;
     472                 :            :                 int err, err2=0;
     473                 :            : 
     474                 :          0 :                 err = ext4_resize_begin(sb);
     475         [ #  # ]:          0 :                 if (err)
     476                 :            :                         return err;
     477                 :            : 
     478         [ #  # ]:          0 :                 if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg,
     479                 :            :                                 sizeof(input))) {
     480                 :            :                         err = -EFAULT;
     481                 :            :                         goto group_add_out;
     482                 :            :                 }
     483                 :            : 
     484         [ #  # ]:          0 :                 if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
     485                 :            :                                EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
     486                 :          0 :                         ext4_msg(sb, KERN_ERR,
     487                 :            :                                  "Online resizing not supported with bigalloc");
     488                 :            :                         err = -EOPNOTSUPP;
     489                 :          0 :                         goto group_add_out;
     490                 :            :                 }
     491                 :            : 
     492                 :          0 :                 err = mnt_want_write_file(filp);
     493         [ #  # ]:          0 :                 if (err)
     494                 :            :                         goto group_add_out;
     495                 :            : 
     496                 :          0 :                 err = ext4_group_add(sb, &input);
     497         [ #  # ]:          0 :                 if (EXT4_SB(sb)->s_journal) {
     498                 :          0 :                         jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
     499                 :          0 :                         err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
     500                 :          0 :                         jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
     501                 :            :                 }
     502         [ #  # ]:          0 :                 if (err == 0)
     503                 :            :                         err = err2;
     504                 :          0 :                 mnt_drop_write_file(filp);
     505 [ #  # ][ #  # ]:          0 :                 if (!err && ext4_has_group_desc_csum(sb) &&
                 [ #  # ]
     506                 :          0 :                     test_opt(sb, INIT_INODE_TABLE))
     507                 :          0 :                         err = ext4_register_li_request(sb, input.group);
     508                 :            : group_add_out:
     509                 :          0 :                 ext4_resize_end(sb);
     510                 :          0 :                 return err;
     511                 :            :         }
     512                 :            : 
     513                 :            :         case EXT4_IOC_MIGRATE:
     514                 :            :         {
     515                 :            :                 int err;
     516         [ #  # ]:          0 :                 if (!inode_owner_or_capable(inode))
     517                 :            :                         return -EACCES;
     518                 :            : 
     519                 :          0 :                 err = mnt_want_write_file(filp);
     520         [ #  # ]:          0 :                 if (err)
     521                 :            :                         return err;
     522                 :            :                 /*
     523                 :            :                  * inode_mutex prevent write and truncate on the file.
     524                 :            :                  * Read still goes through. We take i_data_sem in
     525                 :            :                  * ext4_ext_swap_inode_data before we switch the
     526                 :            :                  * inode format to prevent read.
     527                 :            :                  */
     528                 :          0 :                 mutex_lock(&(inode->i_mutex));
     529                 :          0 :                 err = ext4_ext_migrate(inode);
     530                 :          0 :                 mutex_unlock(&(inode->i_mutex));
     531                 :          0 :                 mnt_drop_write_file(filp);
     532                 :          0 :                 return err;
     533                 :            :         }
     534                 :            : 
     535                 :            :         case EXT4_IOC_ALLOC_DA_BLKS:
     536                 :            :         {
     537                 :            :                 int err;
     538         [ #  # ]:          0 :                 if (!inode_owner_or_capable(inode))
     539                 :            :                         return -EACCES;
     540                 :            : 
     541                 :          0 :                 err = mnt_want_write_file(filp);
     542         [ #  # ]:          0 :                 if (err)
     543                 :            :                         return err;
     544                 :          0 :                 err = ext4_alloc_da_blocks(inode);
     545                 :          0 :                 mnt_drop_write_file(filp);
     546                 :          0 :                 return err;
     547                 :            :         }
     548                 :            : 
     549                 :            :         case EXT4_IOC_SWAP_BOOT:
     550         [ #  # ]:          0 :                 if (!(filp->f_mode & FMODE_WRITE))
     551                 :            :                         return -EBADF;
     552                 :          0 :                 return swap_inode_boot_loader(sb, inode);
     553                 :            : 
     554                 :            :         case EXT4_IOC_RESIZE_FS: {
     555                 :            :                 ext4_fsblk_t n_blocks_count;
     556                 :            :                 int err = 0, err2 = 0;
     557                 :          0 :                 ext4_group_t o_group = EXT4_SB(sb)->s_groups_count;
     558                 :            : 
     559         [ #  # ]:          0 :                 if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
     560                 :            :                                EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
     561                 :          0 :                         ext4_msg(sb, KERN_ERR,
     562                 :            :                                  "Online resizing not (yet) supported with bigalloc");
     563                 :          0 :                         return -EOPNOTSUPP;
     564                 :            :                 }
     565                 :            : 
     566         [ #  # ]:          0 :                 if (copy_from_user(&n_blocks_count, (__u64 __user *)arg,
     567                 :            :                                    sizeof(__u64))) {
     568                 :            :                         return -EFAULT;
     569                 :            :                 }
     570                 :            : 
     571                 :          0 :                 err = ext4_resize_begin(sb);
     572         [ #  # ]:          0 :                 if (err)
     573                 :            :                         return err;
     574                 :            : 
     575                 :          0 :                 err = mnt_want_write_file(filp);
     576         [ #  # ]:          0 :                 if (err)
     577                 :            :                         goto resizefs_out;
     578                 :            : 
     579                 :          0 :                 err = ext4_resize_fs(sb, n_blocks_count);
     580         [ #  # ]:          0 :                 if (EXT4_SB(sb)->s_journal) {
     581                 :          0 :                         jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
     582                 :          0 :                         err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal);
     583                 :          0 :                         jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
     584                 :            :                 }
     585         [ #  # ]:          0 :                 if (err == 0)
     586                 :            :                         err = err2;
     587                 :          0 :                 mnt_drop_write_file(filp);
     588 [ #  # ][ #  # ]:          0 :                 if (!err && (o_group > EXT4_SB(sb)->s_groups_count) &&
                 [ #  # ]
     589         [ #  # ]:          0 :                     ext4_has_group_desc_csum(sb) &&
     590                 :          0 :                     test_opt(sb, INIT_INODE_TABLE))
     591                 :          0 :                         err = ext4_register_li_request(sb, o_group);
     592                 :            : 
     593                 :            : resizefs_out:
     594                 :          0 :                 ext4_resize_end(sb);
     595                 :          0 :                 return err;
     596                 :            :         }
     597                 :            : 
     598                 :            :         case FITRIM:
     599                 :            :         {
     600                 :          0 :                 struct request_queue *q = bdev_get_queue(sb->s_bdev);
     601                 :            :                 struct fstrim_range range;
     602                 :            :                 int ret = 0;
     603                 :            : 
     604         [ #  # ]:          0 :                 if (!capable(CAP_SYS_ADMIN))
     605                 :            :                         return -EPERM;
     606                 :            : 
     607         [ #  # ]:          0 :                 if (!blk_queue_discard(q))
     608                 :            :                         return -EOPNOTSUPP;
     609                 :            : 
     610         [ #  # ]:          0 :                 if (copy_from_user(&range, (struct fstrim_range __user *)arg,
     611                 :            :                     sizeof(range)))
     612                 :            :                         return -EFAULT;
     613                 :            : 
     614                 :          0 :                 range.minlen = max((unsigned int)range.minlen,
     615                 :            :                                    q->limits.discard_granularity);
     616                 :          0 :                 ret = ext4_trim_fs(sb, &range);
     617         [ #  # ]:          0 :                 if (ret < 0)
     618                 :            :                         return ret;
     619                 :            : 
     620         [ #  # ]:          0 :                 if (copy_to_user((struct fstrim_range __user *)arg, &range,
     621                 :            :                     sizeof(range)))
     622                 :            :                         return -EFAULT;
     623                 :            : 
     624                 :          0 :                 return 0;
     625                 :            :         }
     626                 :            :         case EXT4_IOC_PRECACHE_EXTENTS:
     627                 :          0 :                 return ext4_ext_precache(inode);
     628                 :            : 
     629                 :            :         default:
     630                 :            :                 return -ENOTTY;
     631                 :            :         }
     632                 :            : }
     633                 :            : 
     634                 :            : #ifdef CONFIG_COMPAT
     635                 :            : long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
     636                 :            : {
     637                 :            :         /* These are just misnamed, they actually get/put from/to user an int */
     638                 :            :         switch (cmd) {
     639                 :            :         case EXT4_IOC32_GETFLAGS:
     640                 :            :                 cmd = EXT4_IOC_GETFLAGS;
     641                 :            :                 break;
     642                 :            :         case EXT4_IOC32_SETFLAGS:
     643                 :            :                 cmd = EXT4_IOC_SETFLAGS;
     644                 :            :                 break;
     645                 :            :         case EXT4_IOC32_GETVERSION:
     646                 :            :                 cmd = EXT4_IOC_GETVERSION;
     647                 :            :                 break;
     648                 :            :         case EXT4_IOC32_SETVERSION:
     649                 :            :                 cmd = EXT4_IOC_SETVERSION;
     650                 :            :                 break;
     651                 :            :         case EXT4_IOC32_GROUP_EXTEND:
     652                 :            :                 cmd = EXT4_IOC_GROUP_EXTEND;
     653                 :            :                 break;
     654                 :            :         case EXT4_IOC32_GETVERSION_OLD:
     655                 :            :                 cmd = EXT4_IOC_GETVERSION_OLD;
     656                 :            :                 break;
     657                 :            :         case EXT4_IOC32_SETVERSION_OLD:
     658                 :            :                 cmd = EXT4_IOC_SETVERSION_OLD;
     659                 :            :                 break;
     660                 :            :         case EXT4_IOC32_GETRSVSZ:
     661                 :            :                 cmd = EXT4_IOC_GETRSVSZ;
     662                 :            :                 break;
     663                 :            :         case EXT4_IOC32_SETRSVSZ:
     664                 :            :                 cmd = EXT4_IOC_SETRSVSZ;
     665                 :            :                 break;
     666                 :            :         case EXT4_IOC32_GROUP_ADD: {
     667                 :            :                 struct compat_ext4_new_group_input __user *uinput;
     668                 :            :                 struct ext4_new_group_input input;
     669                 :            :                 mm_segment_t old_fs;
     670                 :            :                 int err;
     671                 :            : 
     672                 :            :                 uinput = compat_ptr(arg);
     673                 :            :                 err = get_user(input.group, &uinput->group);
     674                 :            :                 err |= get_user(input.block_bitmap, &uinput->block_bitmap);
     675                 :            :                 err |= get_user(input.inode_bitmap, &uinput->inode_bitmap);
     676                 :            :                 err |= get_user(input.inode_table, &uinput->inode_table);
     677                 :            :                 err |= get_user(input.blocks_count, &uinput->blocks_count);
     678                 :            :                 err |= get_user(input.reserved_blocks,
     679                 :            :                                 &uinput->reserved_blocks);
     680                 :            :                 if (err)
     681                 :            :                         return -EFAULT;
     682                 :            :                 old_fs = get_fs();
     683                 :            :                 set_fs(KERNEL_DS);
     684                 :            :                 err = ext4_ioctl(file, EXT4_IOC_GROUP_ADD,
     685                 :            :                                  (unsigned long) &input);
     686                 :            :                 set_fs(old_fs);
     687                 :            :                 return err;
     688                 :            :         }
     689                 :            :         case EXT4_IOC_MOVE_EXT:
     690                 :            :         case FITRIM:
     691                 :            :         case EXT4_IOC_RESIZE_FS:
     692                 :            :         case EXT4_IOC_PRECACHE_EXTENTS:
     693                 :            :                 break;
     694                 :            :         default:
     695                 :            :                 return -ENOIOCTLCMD;
     696                 :            :         }
     697                 :            :         return ext4_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
     698                 :            : }
     699                 :            : #endif

Generated by: LCOV version 1.9