X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fext3%2Fioctl.c;h=5f374c33aba3fa91079b94b581ebb01df4e9c02e;hb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;hp=21080fbbb6d222da7ec24bfffcb16de36662ce10;hpb=d46bc780027c5439db9f72d42c0732775b53925a;p=linux-2.6.git diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c index 21080fbbb..5f374c33a 100644 --- a/fs/ext3/ioctl.c +++ b/fs/ext3/ioctl.c @@ -8,7 +8,9 @@ */ #include +#include #include +#include #include #include #include @@ -21,13 +23,14 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, { struct ext3_inode_info *ei = EXT3_I(inode); unsigned int flags; + unsigned short rsv_window_size; ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg); switch (cmd) { case EXT3_IOC_GETFLAGS: flags = ei->i_flags & EXT3_FL_USER_VISIBLE; - return put_user(flags, (int *) arg); + return put_user(flags, (int __user *) arg); case EXT3_IOC_SETFLAGS: { handle_t *handle = NULL; int err; @@ -35,18 +38,20 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, unsigned int oldflags; unsigned int jflag; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) return -EACCES; - if (get_user(flags, (int *) arg)) + if (get_user(flags, (int __user *) arg)) return -EFAULT; if (!S_ISDIR(inode->i_mode)) flags &= ~EXT3_DIRSYNC_FL; + mutex_lock(&inode->i_mutex); oldflags = ei->i_flags; /* The JOURNAL_DATA flag is modifiable only by root */ @@ -59,10 +64,12 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, * This test looks nicer. Thanks to Pauline Middelink */ if ((oldflags & EXT3_IMMUTABLE_FL) || - ((flags ^ oldflags) & - (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL))) { - if (!capable(CAP_LINUX_IMMUTABLE)) + ((flags ^ oldflags) & (EXT3_APPEND_FL | + EXT3_IMMUTABLE_FL | EXT3_IUNLINK_FL))) { + if (!capable(CAP_LINUX_IMMUTABLE)) { + mutex_unlock(&inode->i_mutex); return -EPERM; + } } /* @@ -70,14 +77,18 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, * the relevant capability. */ if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) { - if (!capable(CAP_SYS_RESOURCE)) + if (!capable(CAP_SYS_RESOURCE)) { + mutex_unlock(&inode->i_mutex); return -EPERM; + } } handle = ext3_journal_start(inode, 1); - if (IS_ERR(handle)) + if (IS_ERR(handle)) { + mutex_unlock(&inode->i_mutex); return PTR_ERR(handle); + } if (IS_SYNC(inode)) handle->h_sync = 1; err = ext3_reserve_inode_write(handle, inode, &iloc); @@ -89,21 +100,24 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, ei->i_flags = flags; ext3_set_inode_flags(inode); - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = CURRENT_TIME_SEC; err = ext3_mark_iloc_dirty(handle, inode, &iloc); flags_err: ext3_journal_stop(handle); - if (err) + if (err) { + mutex_unlock(&inode->i_mutex); return err; + } if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) err = ext3_change_inode_journal_flag(inode, jflag); + mutex_unlock(&inode->i_mutex); return err; } case EXT3_IOC_GETVERSION: case EXT3_IOC_GETVERSION_OLD: - return put_user(inode->i_generation, (int *) arg); + return put_user(inode->i_generation, (int __user *) arg); case EXT3_IOC_SETVERSION: case EXT3_IOC_SETVERSION_OLD: { handle_t *handle; @@ -113,9 +127,10 @@ flags_err: if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) return -EPERM; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; - if (get_user(generation, (int *) arg)) + if (get_user(generation, (int __user *) arg)) return -EFAULT; handle = ext3_journal_start(inode, 1); @@ -123,7 +138,7 @@ flags_err: return PTR_ERR(handle); err = ext3_reserve_inode_write(handle, inode, &iloc); if (err == 0) { - inode->i_ctime = CURRENT_TIME; + inode->i_ctime = CURRENT_TIME_SEC; inode->i_generation = generation; err = ext3_mark_iloc_dirty(handle, inode, &iloc); } @@ -154,6 +169,93 @@ flags_err: return ret; } #endif + case EXT3_IOC_GETRSVSZ: + if (test_opt(inode->i_sb, RESERVATION) + && S_ISREG(inode->i_mode) + && ei->i_block_alloc_info) { + rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size; + return put_user(rsv_window_size, (int __user *)arg); + } + return -ENOTTY; + case EXT3_IOC_SETRSVSZ: { + + if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) + return -ENOTTY; + + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) + return -EROFS; + + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EACCES; + + if (get_user(rsv_window_size, (int __user *)arg)) + return -EFAULT; + + if (rsv_window_size > EXT3_MAX_RESERVE_BLOCKS) + rsv_window_size = EXT3_MAX_RESERVE_BLOCKS; + + /* + * need to allocate reservation structure for this inode + * before set the window size + */ + mutex_lock(&ei->truncate_mutex); + if (!ei->i_block_alloc_info) + ext3_init_block_alloc_info(inode); + + if (ei->i_block_alloc_info){ + struct ext3_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node; + rsv->rsv_goal_size = rsv_window_size; + } + mutex_unlock(&ei->truncate_mutex); + return 0; + } + case EXT3_IOC_GROUP_EXTEND: { + ext3_fsblk_t n_blocks_count; + struct super_block *sb = inode->i_sb; + int err; + + if (!capable(CAP_SYS_RESOURCE)) + return -EPERM; + + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) + return -EROFS; + + if (get_user(n_blocks_count, (__u32 __user *)arg)) + return -EFAULT; + + err = ext3_group_extend(sb, EXT3_SB(sb)->s_es, n_blocks_count); + journal_lock_updates(EXT3_SB(sb)->s_journal); + journal_flush(EXT3_SB(sb)->s_journal); + journal_unlock_updates(EXT3_SB(sb)->s_journal); + + return err; + } + case EXT3_IOC_GROUP_ADD: { + struct ext3_new_group_data input; + struct super_block *sb = inode->i_sb; + int err; + + if (!capable(CAP_SYS_RESOURCE)) + return -EPERM; + + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) + return -EROFS; + + if (copy_from_user(&input, (struct ext3_new_group_input __user *)arg, + sizeof(input))) + return -EFAULT; + + err = ext3_group_add(sb, &input); + journal_lock_updates(EXT3_SB(sb)->s_journal); + journal_flush(EXT3_SB(sb)->s_journal); + journal_unlock_updates(EXT3_SB(sb)->s_journal); + + return err; + } + #if defined(CONFIG_VSERVER_LEGACY) && !defined(CONFIG_INOXID_NONE) case EXT3_IOC_SETXID: { handle_t *handle; @@ -168,8 +270,8 @@ flags_err: return -EROFS; if (!(inode->i_sb->s_flags & MS_TAGXID)) return -ENOSYS; - if (get_user(xid, (int *) arg)) - return -EFAULT; + if (get_user(xid, (int __user *) arg)) + return -EFAULT; handle = ext3_journal_start(inode, 1); if (IS_ERR(handle)) @@ -186,6 +288,7 @@ flags_err: return err; } #endif + default: return -ENOTTY; }