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