LTP GCOV extension - code coverage report
Current view: directory - fs/ext3 - ioctl.c
Test: kernel.info
Date: 2008-12-15 Instrumented lines: 144
Code covered: 27.8 % Executed lines: 40

       1                 : /*
       2                 :  * linux/fs/ext3/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/jbd.h>
      12                 : #include <linux/capability.h>
      13                 : #include <linux/ext3_fs.h>
      14                 : #include <linux/ext3_jbd.h>
      15                 : #include <linux/mount.h>
      16                 : #include <linux/time.h>
      17                 : #include <linux/compat.h>
      18                 : #include <linux/smp_lock.h>
      19                 : #include <asm/uaccess.h>
      20                 : 
      21                 : int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
      22                 :                 unsigned long arg)
      23           39617 : {
      24           39617 :         struct ext3_inode_info *ei = EXT3_I(inode);
      25                 :         unsigned int flags;
      26                 :         unsigned short rsv_window_size;
      27                 : 
      28                 :         ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg);
      29                 : 
      30           39617 :         switch (cmd) {
      31                 :         case EXT3_IOC_GETFLAGS:
      32             240 :                 ext3_get_inode_flags(ei);
      33             240 :                 flags = ei->i_flags & EXT3_FL_USER_VISIBLE;
      34             240 :                 return put_user(flags, (int __user *) arg);
      35                 :         case EXT3_IOC_SETFLAGS: {
      36             141 :                 handle_t *handle = NULL;
      37                 :                 int err;
      38                 :                 struct ext3_iloc iloc;
      39                 :                 unsigned int oldflags;
      40                 :                 unsigned int jflag;
      41                 : 
      42             141 :                 err = mnt_want_write(filp->f_path.mnt);
      43             141 :                 if (err)
      44               0 :                         return err;
      45                 : 
      46             141 :                 if (!is_owner_or_cap(inode)) {
      47               0 :                         err = -EACCES;
      48               0 :                         goto flags_out;
      49                 :                 }
      50                 : 
      51             141 :                 if (get_user(flags, (int __user *) arg)) {
      52               0 :                         err = -EFAULT;
      53               0 :                         goto flags_out;
      54                 :                 }
      55                 : 
      56             141 :                 if (!S_ISDIR(inode->i_mode))
      57             141 :                         flags &= ~EXT3_DIRSYNC_FL;
      58                 : 
      59             141 :                 mutex_lock(&inode->i_mutex);
      60                 :                 /* Is it quota file? Do not allow user to mess with it */
      61             141 :                 if (IS_NOQUOTA(inode)) {
      62               0 :                         mutex_unlock(&inode->i_mutex);
      63               0 :                         err = -EPERM;
      64               0 :                         goto flags_out;
      65                 :                 }
      66             141 :                 oldflags = ei->i_flags;
      67                 : 
      68                 :                 /* The JOURNAL_DATA flag is modifiable only by root */
      69             141 :                 jflag = flags & EXT3_JOURNAL_DATA_FL;
      70                 : 
      71                 :                 /*
      72                 :                  * The IMMUTABLE and APPEND_ONLY flags can only be changed by
      73                 :                  * the relevant capability.
      74                 :                  *
      75                 :                  * This test looks nicer. Thanks to Pauline Middelink
      76                 :                  */
      77             141 :                 if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) {
      78              84 :                         if (!capable(CAP_LINUX_IMMUTABLE)) {
      79               0 :                                 mutex_unlock(&inode->i_mutex);
      80               0 :                                 err = -EPERM;
      81               0 :                                 goto flags_out;
      82                 :                         }
      83                 :                 }
      84                 : 
      85                 :                 /*
      86                 :                  * The JOURNAL_DATA flag can only be changed by
      87                 :                  * the relevant capability.
      88                 :                  */
      89             141 :                 if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) {
      90               0 :                         if (!capable(CAP_SYS_RESOURCE)) {
      91               0 :                                 mutex_unlock(&inode->i_mutex);
      92               0 :                                 err = -EPERM;
      93               0 :                                 goto flags_out;
      94                 :                         }
      95                 :                 }
      96                 : 
      97                 : 
      98             141 :                 handle = ext3_journal_start(inode, 1);
      99             141 :                 if (IS_ERR(handle)) {
     100               0 :                         mutex_unlock(&inode->i_mutex);
     101               0 :                         err = PTR_ERR(handle);
     102               0 :                         goto flags_out;
     103                 :                 }
     104             141 :                 if (IS_SYNC(inode))
     105               0 :                         handle->h_sync = 1;
     106             141 :                 err = ext3_reserve_inode_write(handle, inode, &iloc);
     107             141 :                 if (err)
     108               0 :                         goto flags_err;
     109                 : 
     110             141 :                 flags = flags & EXT3_FL_USER_MODIFIABLE;
     111             141 :                 flags |= oldflags & ~EXT3_FL_USER_MODIFIABLE;
     112             141 :                 ei->i_flags = flags;
     113                 : 
     114             141 :                 ext3_set_inode_flags(inode);
     115             141 :                 inode->i_ctime = CURRENT_TIME_SEC;
     116                 : 
     117             141 :                 err = ext3_mark_iloc_dirty(handle, inode, &iloc);
     118             141 : flags_err:
     119             141 :                 ext3_journal_stop(handle);
     120             141 :                 if (err) {
     121               0 :                         mutex_unlock(&inode->i_mutex);
     122               0 :                         return err;
     123                 :                 }
     124                 : 
     125             141 :                 if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL))
     126               0 :                         err = ext3_change_inode_journal_flag(inode, jflag);
     127             141 :                 mutex_unlock(&inode->i_mutex);
     128             141 : flags_out:
     129             141 :                 mnt_drop_write(filp->f_path.mnt);
     130             141 :                 return err;
     131                 :         }
     132                 :         case EXT3_IOC_GETVERSION:
     133                 :         case EXT3_IOC_GETVERSION_OLD:
     134               0 :                 return put_user(inode->i_generation, (int __user *) arg);
     135                 :         case EXT3_IOC_SETVERSION:
     136                 :         case EXT3_IOC_SETVERSION_OLD: {
     137                 :                 handle_t *handle;
     138                 :                 struct ext3_iloc iloc;
     139                 :                 __u32 generation;
     140                 :                 int err;
     141                 : 
     142               0 :                 if (!is_owner_or_cap(inode))
     143               0 :                         return -EPERM;
     144               0 :                 err = mnt_want_write(filp->f_path.mnt);
     145               0 :                 if (err)
     146               0 :                         return err;
     147               0 :                 if (get_user(generation, (int __user *) arg)) {
     148               0 :                         err = -EFAULT;
     149               0 :                         goto setversion_out;
     150                 :                 }
     151               0 :                 handle = ext3_journal_start(inode, 1);
     152               0 :                 if (IS_ERR(handle)) {
     153               0 :                         err = PTR_ERR(handle);
     154               0 :                         goto setversion_out;
     155                 :                 }
     156               0 :                 err = ext3_reserve_inode_write(handle, inode, &iloc);
     157               0 :                 if (err == 0) {
     158               0 :                         inode->i_ctime = CURRENT_TIME_SEC;
     159               0 :                         inode->i_generation = generation;
     160               0 :                         err = ext3_mark_iloc_dirty(handle, inode, &iloc);
     161                 :                 }
     162               0 :                 ext3_journal_stop(handle);
     163               0 : setversion_out:
     164               0 :                 mnt_drop_write(filp->f_path.mnt);
     165               0 :                 return err;
     166                 :         }
     167                 : #ifdef CONFIG_JBD_DEBUG
     168                 :         case EXT3_IOC_WAIT_FOR_READONLY:
     169                 :                 /*
     170                 :                  * This is racy - by the time we're woken up and running,
     171                 :                  * the superblock could be released.  And the module could
     172                 :                  * have been unloaded.  So sue me.
     173                 :                  *
     174                 :                  * Returns 1 if it slept, else zero.
     175                 :                  */
     176                 :                 {
     177                 :                         struct super_block *sb = inode->i_sb;
     178                 :                         DECLARE_WAITQUEUE(wait, current);
     179                 :                         int ret = 0;
     180                 : 
     181                 :                         set_current_state(TASK_INTERRUPTIBLE);
     182                 :                         add_wait_queue(&EXT3_SB(sb)->ro_wait_queue, &wait);
     183                 :                         if (timer_pending(&EXT3_SB(sb)->turn_ro_timer)) {
     184                 :                                 schedule();
     185                 :                                 ret = 1;
     186                 :                         }
     187                 :                         remove_wait_queue(&EXT3_SB(sb)->ro_wait_queue, &wait);
     188                 :                         return ret;
     189                 :                 }
     190                 : #endif
     191                 :         case EXT3_IOC_GETRSVSZ:
     192               0 :                 if (test_opt(inode->i_sb, RESERVATION)
     193                 :                         && S_ISREG(inode->i_mode)
     194                 :                         && ei->i_block_alloc_info) {
     195               0 :                         rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size;
     196               0 :                         return put_user(rsv_window_size, (int __user *)arg);
     197                 :                 }
     198               0 :                 return -ENOTTY;
     199                 :         case EXT3_IOC_SETRSVSZ: {
     200                 :                 int err;
     201                 : 
     202               0 :                 if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode))
     203               0 :                         return -ENOTTY;
     204                 : 
     205               0 :                 err = mnt_want_write(filp->f_path.mnt);
     206               0 :                 if (err)
     207               0 :                         return err;
     208                 : 
     209               0 :                 if (!is_owner_or_cap(inode)) {
     210               0 :                         err = -EACCES;
     211               0 :                         goto setrsvsz_out;
     212                 :                 }
     213                 : 
     214               0 :                 if (get_user(rsv_window_size, (int __user *)arg)) {
     215               0 :                         err = -EFAULT;
     216               0 :                         goto setrsvsz_out;
     217                 :                 }
     218                 : 
     219               0 :                 if (rsv_window_size > EXT3_MAX_RESERVE_BLOCKS)
     220               0 :                         rsv_window_size = EXT3_MAX_RESERVE_BLOCKS;
     221                 : 
     222                 :                 /*
     223                 :                  * need to allocate reservation structure for this inode
     224                 :                  * before set the window size
     225                 :                  */
     226               0 :                 mutex_lock(&ei->truncate_mutex);
     227               0 :                 if (!ei->i_block_alloc_info)
     228               0 :                         ext3_init_block_alloc_info(inode);
     229                 : 
     230               0 :                 if (ei->i_block_alloc_info){
     231               0 :                         struct ext3_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node;
     232               0 :                         rsv->rsv_goal_size = rsv_window_size;
     233                 :                 }
     234               0 :                 mutex_unlock(&ei->truncate_mutex);
     235               0 : setrsvsz_out:
     236               0 :                 mnt_drop_write(filp->f_path.mnt);
     237               0 :                 return err;
     238                 :         }
     239                 :         case EXT3_IOC_GROUP_EXTEND: {
     240                 :                 ext3_fsblk_t n_blocks_count;
     241               0 :                 struct super_block *sb = inode->i_sb;
     242                 :                 int err;
     243                 : 
     244               0 :                 if (!capable(CAP_SYS_RESOURCE))
     245               0 :                         return -EPERM;
     246                 : 
     247               0 :                 err = mnt_want_write(filp->f_path.mnt);
     248               0 :                 if (err)
     249               0 :                         return err;
     250                 : 
     251               0 :                 if (get_user(n_blocks_count, (__u32 __user *)arg)) {
     252               0 :                         err = -EFAULT;
     253               0 :                         goto group_extend_out;
     254                 :                 }
     255               0 :                 err = ext3_group_extend(sb, EXT3_SB(sb)->s_es, n_blocks_count);
     256               0 :                 journal_lock_updates(EXT3_SB(sb)->s_journal);
     257               0 :                 journal_flush(EXT3_SB(sb)->s_journal);
     258               0 :                 journal_unlock_updates(EXT3_SB(sb)->s_journal);
     259               0 : group_extend_out:
     260               0 :                 mnt_drop_write(filp->f_path.mnt);
     261               0 :                 return err;
     262                 :         }
     263                 :         case EXT3_IOC_GROUP_ADD: {
     264                 :                 struct ext3_new_group_data input;
     265               0 :                 struct super_block *sb = inode->i_sb;
     266                 :                 int err;
     267                 : 
     268               0 :                 if (!capable(CAP_SYS_RESOURCE))
     269               0 :                         return -EPERM;
     270                 : 
     271               0 :                 err = mnt_want_write(filp->f_path.mnt);
     272               0 :                 if (err)
     273               0 :                         return err;
     274                 : 
     275               0 :                 if (copy_from_user(&input, (struct ext3_new_group_input __user *)arg,
     276                 :                                 sizeof(input))) {
     277               0 :                         err = -EFAULT;
     278               0 :                         goto group_add_out;
     279                 :                 }
     280                 : 
     281               0 :                 err = ext3_group_add(sb, &input);
     282               0 :                 journal_lock_updates(EXT3_SB(sb)->s_journal);
     283               0 :                 journal_flush(EXT3_SB(sb)->s_journal);
     284               0 :                 journal_unlock_updates(EXT3_SB(sb)->s_journal);
     285               0 : group_add_out:
     286               0 :                 mnt_drop_write(filp->f_path.mnt);
     287               0 :                 return err;
     288                 :         }
     289                 : 
     290                 : 
     291                 :         default:
     292           39236 :                 return -ENOTTY;
     293                 :         }
     294                 : }
     295                 : 
     296                 : #ifdef CONFIG_COMPAT
     297                 : long ext3_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
     298                 : {
     299                 :         struct inode *inode = file->f_path.dentry->d_inode;
     300                 :         int ret;
     301                 : 
     302                 :         /* These are just misnamed, they actually get/put from/to user an int */
     303                 :         switch (cmd) {
     304                 :         case EXT3_IOC32_GETFLAGS:
     305                 :                 cmd = EXT3_IOC_GETFLAGS;
     306                 :                 break;
     307                 :         case EXT3_IOC32_SETFLAGS:
     308                 :                 cmd = EXT3_IOC_SETFLAGS;
     309                 :                 break;
     310                 :         case EXT3_IOC32_GETVERSION:
     311                 :                 cmd = EXT3_IOC_GETVERSION;
     312                 :                 break;
     313                 :         case EXT3_IOC32_SETVERSION:
     314                 :                 cmd = EXT3_IOC_SETVERSION;
     315                 :                 break;
     316                 :         case EXT3_IOC32_GROUP_EXTEND:
     317                 :                 cmd = EXT3_IOC_GROUP_EXTEND;
     318                 :                 break;
     319                 :         case EXT3_IOC32_GETVERSION_OLD:
     320                 :                 cmd = EXT3_IOC_GETVERSION_OLD;
     321                 :                 break;
     322                 :         case EXT3_IOC32_SETVERSION_OLD:
     323                 :                 cmd = EXT3_IOC_SETVERSION_OLD;
     324                 :                 break;
     325                 : #ifdef CONFIG_JBD_DEBUG
     326                 :         case EXT3_IOC32_WAIT_FOR_READONLY:
     327                 :                 cmd = EXT3_IOC_WAIT_FOR_READONLY;
     328                 :                 break;
     329                 : #endif
     330                 :         case EXT3_IOC32_GETRSVSZ:
     331                 :                 cmd = EXT3_IOC_GETRSVSZ;
     332                 :                 break;
     333                 :         case EXT3_IOC32_SETRSVSZ:
     334                 :                 cmd = EXT3_IOC_SETRSVSZ;
     335                 :                 break;
     336                 :         case EXT3_IOC_GROUP_ADD:
     337                 :                 break;
     338                 :         default:
     339                 :                 return -ENOIOCTLCMD;
     340                 :         }
     341                 :         lock_kernel();
     342                 :         ret = ext3_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
     343                 :         unlock_kernel();
     344                 :         return ret;
     345                 : }
     346                 : #endif

Generated by: LTP GCOV extension version 1.6