11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/ext2/ioctl.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 1993, 1994, 1995 51da177e4SLinus Torvalds * Remy Card (card@masi.ibp.fr) 61da177e4SLinus Torvalds * Laboratoire MASI - Institut Blaise Pascal 71da177e4SLinus Torvalds * Universite Pierre et Marie Curie (Paris VI) 81da177e4SLinus Torvalds */ 91da177e4SLinus Torvalds 101da177e4SLinus Torvalds #include "ext2.h" 1116f7e0feSRandy Dunlap #include <linux/capability.h> 121da177e4SLinus Torvalds #include <linux/time.h> 131da177e4SLinus Torvalds #include <linux/sched.h> 14e322ff07SDavid Howells #include <linux/compat.h> 1542a74f20SDave Hansen #include <linux/mount.h> 161da177e4SLinus Torvalds #include <asm/current.h> 171da177e4SLinus Torvalds #include <asm/uaccess.h> 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds 2014f9f7b2SAndi Kleen long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 211da177e4SLinus Torvalds { 2214f9f7b2SAndi Kleen struct inode *inode = filp->f_dentry->d_inode; 231da177e4SLinus Torvalds struct ext2_inode_info *ei = EXT2_I(inode); 241da177e4SLinus Torvalds unsigned int flags; 25a686cd89SMartin J. Bligh unsigned short rsv_window_size; 2642a74f20SDave Hansen int ret; 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg); 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds switch (cmd) { 311da177e4SLinus Torvalds case EXT2_IOC_GETFLAGS: 324f99ed67SJan Kara ext2_get_inode_flags(ei); 331da177e4SLinus Torvalds flags = ei->i_flags & EXT2_FL_USER_VISIBLE; 341da177e4SLinus Torvalds return put_user(flags, (int __user *) arg); 351da177e4SLinus Torvalds case EXT2_IOC_SETFLAGS: { 361da177e4SLinus Torvalds unsigned int oldflags; 371da177e4SLinus Torvalds 38a561be71SAl Viro ret = mnt_want_write_file(filp); 3942a74f20SDave Hansen if (ret) 4042a74f20SDave Hansen return ret; 411da177e4SLinus Torvalds 422e149670SSerge E. Hallyn if (!inode_owner_or_capable(inode)) { 4342a74f20SDave Hansen ret = -EACCES; 4442a74f20SDave Hansen goto setflags_out; 4542a74f20SDave Hansen } 461da177e4SLinus Torvalds 4742a74f20SDave Hansen if (get_user(flags, (int __user *) arg)) { 4842a74f20SDave Hansen ret = -EFAULT; 4942a74f20SDave Hansen goto setflags_out; 5042a74f20SDave Hansen } 511da177e4SLinus Torvalds 52ef8b6461SDuane Griffin flags = ext2_mask_flags(inode->i_mode, flags); 531da177e4SLinus Torvalds 5493f210ddSAndrew Morton mutex_lock(&inode->i_mutex); 55e47776a0SJan Kara /* Is it quota file? Do not allow user to mess with it */ 56e47776a0SJan Kara if (IS_NOQUOTA(inode)) { 57e47776a0SJan Kara mutex_unlock(&inode->i_mutex); 5842a74f20SDave Hansen ret = -EPERM; 5942a74f20SDave Hansen goto setflags_out; 60e47776a0SJan Kara } 611da177e4SLinus Torvalds oldflags = ei->i_flags; 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds /* 641da177e4SLinus Torvalds * The IMMUTABLE and APPEND_ONLY flags can only be changed by 651da177e4SLinus Torvalds * the relevant capability. 661da177e4SLinus Torvalds * 671da177e4SLinus Torvalds * This test looks nicer. Thanks to Pauline Middelink 681da177e4SLinus Torvalds */ 691da177e4SLinus Torvalds if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) { 7093f210ddSAndrew Morton if (!capable(CAP_LINUX_IMMUTABLE)) { 7193f210ddSAndrew Morton mutex_unlock(&inode->i_mutex); 7242a74f20SDave Hansen ret = -EPERM; 7342a74f20SDave Hansen goto setflags_out; 741da177e4SLinus Torvalds } 7593f210ddSAndrew Morton } 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds flags = flags & EXT2_FL_USER_MODIFIABLE; 781da177e4SLinus Torvalds flags |= oldflags & ~EXT2_FL_USER_MODIFIABLE; 791da177e4SLinus Torvalds ei->i_flags = flags; 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds ext2_set_inode_flags(inode); 821da177e4SLinus Torvalds inode->i_ctime = CURRENT_TIME_SEC; 8334b07840SDjalal Harouni mutex_unlock(&inode->i_mutex); 8434b07840SDjalal Harouni 851da177e4SLinus Torvalds mark_inode_dirty(inode); 8642a74f20SDave Hansen setflags_out: 872a79f17eSAl Viro mnt_drop_write_file(filp); 8842a74f20SDave Hansen return ret; 891da177e4SLinus Torvalds } 901da177e4SLinus Torvalds case EXT2_IOC_GETVERSION: 911da177e4SLinus Torvalds return put_user(inode->i_generation, (int __user *) arg); 9234b07840SDjalal Harouni case EXT2_IOC_SETVERSION: { 9334b07840SDjalal Harouni __u32 generation; 9434b07840SDjalal Harouni 952e149670SSerge E. Hallyn if (!inode_owner_or_capable(inode)) 961da177e4SLinus Torvalds return -EPERM; 97a561be71SAl Viro ret = mnt_want_write_file(filp); 9842a74f20SDave Hansen if (ret) 9942a74f20SDave Hansen return ret; 10034b07840SDjalal Harouni if (get_user(generation, (int __user *) arg)) { 10142a74f20SDave Hansen ret = -EFAULT; 10234b07840SDjalal Harouni goto setversion_out; 10342a74f20SDave Hansen } 10434b07840SDjalal Harouni 10534b07840SDjalal Harouni mutex_lock(&inode->i_mutex); 10634b07840SDjalal Harouni inode->i_ctime = CURRENT_TIME_SEC; 10734b07840SDjalal Harouni inode->i_generation = generation; 10834b07840SDjalal Harouni mutex_unlock(&inode->i_mutex); 10934b07840SDjalal Harouni 11034b07840SDjalal Harouni mark_inode_dirty(inode); 11134b07840SDjalal Harouni setversion_out: 1122a79f17eSAl Viro mnt_drop_write_file(filp); 11342a74f20SDave Hansen return ret; 11434b07840SDjalal Harouni } 115a686cd89SMartin J. Bligh case EXT2_IOC_GETRSVSZ: 116a686cd89SMartin J. Bligh if (test_opt(inode->i_sb, RESERVATION) 117a686cd89SMartin J. Bligh && S_ISREG(inode->i_mode) 118a686cd89SMartin J. Bligh && ei->i_block_alloc_info) { 119a686cd89SMartin J. Bligh rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size; 120a686cd89SMartin J. Bligh return put_user(rsv_window_size, (int __user *)arg); 121a686cd89SMartin J. Bligh } 122a686cd89SMartin J. Bligh return -ENOTTY; 123a686cd89SMartin J. Bligh case EXT2_IOC_SETRSVSZ: { 124a686cd89SMartin J. Bligh 125a686cd89SMartin J. Bligh if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) 126a686cd89SMartin J. Bligh return -ENOTTY; 127a686cd89SMartin J. Bligh 1282e149670SSerge E. Hallyn if (!inode_owner_or_capable(inode)) 129a686cd89SMartin J. Bligh return -EACCES; 130a686cd89SMartin J. Bligh 131a686cd89SMartin J. Bligh if (get_user(rsv_window_size, (int __user *)arg)) 132a686cd89SMartin J. Bligh return -EFAULT; 133a686cd89SMartin J. Bligh 134a561be71SAl Viro ret = mnt_want_write_file(filp); 13542a74f20SDave Hansen if (ret) 13642a74f20SDave Hansen return ret; 13742a74f20SDave Hansen 138a686cd89SMartin J. Bligh if (rsv_window_size > EXT2_MAX_RESERVE_BLOCKS) 139a686cd89SMartin J. Bligh rsv_window_size = EXT2_MAX_RESERVE_BLOCKS; 140a686cd89SMartin J. Bligh 141a686cd89SMartin J. Bligh /* 142a686cd89SMartin J. Bligh * need to allocate reservation structure for this inode 143a686cd89SMartin J. Bligh * before set the window size 144a686cd89SMartin J. Bligh */ 145a686cd89SMartin J. Bligh /* 146a686cd89SMartin J. Bligh * XXX What lock should protect the rsv_goal_size? 147a686cd89SMartin J. Bligh * Accessed in ext2_get_block only. ext3 uses i_truncate. 148a686cd89SMartin J. Bligh */ 149a686cd89SMartin J. Bligh mutex_lock(&ei->truncate_mutex); 150a686cd89SMartin J. Bligh if (!ei->i_block_alloc_info) 151a686cd89SMartin J. Bligh ext2_init_block_alloc_info(inode); 152a686cd89SMartin J. Bligh 153a686cd89SMartin J. Bligh if (ei->i_block_alloc_info){ 154a686cd89SMartin J. Bligh struct ext2_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node; 155a686cd89SMartin J. Bligh rsv->rsv_goal_size = rsv_window_size; 156a686cd89SMartin J. Bligh } 157a686cd89SMartin J. Bligh mutex_unlock(&ei->truncate_mutex); 1582a79f17eSAl Viro mnt_drop_write_file(filp); 159a686cd89SMartin J. Bligh return 0; 160a686cd89SMartin J. Bligh } 1611da177e4SLinus Torvalds default: 1621da177e4SLinus Torvalds return -ENOTTY; 1631da177e4SLinus Torvalds } 1641da177e4SLinus Torvalds } 165e322ff07SDavid Howells 166e322ff07SDavid Howells #ifdef CONFIG_COMPAT 167e322ff07SDavid Howells long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 168e322ff07SDavid Howells { 169e322ff07SDavid Howells /* These are just misnamed, they actually get/put from/to user an int */ 170e322ff07SDavid Howells switch (cmd) { 171e322ff07SDavid Howells case EXT2_IOC32_GETFLAGS: 172e322ff07SDavid Howells cmd = EXT2_IOC_GETFLAGS; 173e322ff07SDavid Howells break; 174e322ff07SDavid Howells case EXT2_IOC32_SETFLAGS: 175e322ff07SDavid Howells cmd = EXT2_IOC_SETFLAGS; 176e322ff07SDavid Howells break; 177e322ff07SDavid Howells case EXT2_IOC32_GETVERSION: 178e322ff07SDavid Howells cmd = EXT2_IOC_GETVERSION; 179e322ff07SDavid Howells break; 180e322ff07SDavid Howells case EXT2_IOC32_SETVERSION: 181e322ff07SDavid Howells cmd = EXT2_IOC_SETVERSION; 182e322ff07SDavid Howells break; 183e322ff07SDavid Howells default: 184e322ff07SDavid Howells return -ENOIOCTLCMD; 185e322ff07SDavid Howells } 18614f9f7b2SAndi Kleen return ext2_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); 187e322ff07SDavid Howells } 188e322ff07SDavid Howells #endif 189