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

Generated by: LCOV version 1.9