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