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/ext3_fs.h> 13#include <linux/ext3_jbd.h> 14#include <linux/sched.h> 15#include <asm/uaccess.h> 16 17 18int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, 19 unsigned long arg) 20{ 21 unsigned int flags; 22 23 ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg); 24 25 switch (cmd) { 26 case EXT3_IOC_GETFLAGS: 27 flags = inode->u.ext3_i.i_flags & EXT3_FL_USER_VISIBLE; 28 return put_user(flags, (int *) 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 (IS_RDONLY(inode)) 37 return -EROFS; 38 39 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 40 return -EACCES; 41 42 if (get_user(flags, (int *) arg)) 43 return -EFAULT; 44 45 oldflags = inode->u.ext3_i.i_flags; 46 47 /* The JOURNAL_DATA flag is modifiable only by root */ 48 jflag = flags & EXT3_JOURNAL_DATA_FL; 49 50 /* 51 * The IMMUTABLE and APPEND_ONLY flags can only be changed by 52 * the relevant capability. 53 * 54 * This test looks nicer. Thanks to Pauline Middelink 55 */ 56 if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) { 57 if (!capable(CAP_LINUX_IMMUTABLE)) 58 return -EPERM; 59 } 60 61 /* 62 * The JOURNAL_DATA flag can only be changed by 63 * the relevant capability. 64 */ 65 if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) { 66 if (!capable(CAP_SYS_RESOURCE)) 67 return -EPERM; 68 } 69 70 71 handle = ext3_journal_start(inode, 1); 72 if (IS_ERR(handle)) 73 return PTR_ERR(handle); 74 if (IS_SYNC(inode)) 75 handle->h_sync = 1; 76 err = ext3_reserve_inode_write(handle, inode, &iloc); 77 if (err) 78 goto flags_err; 79 80 flags = flags & EXT3_FL_USER_MODIFIABLE; 81 flags |= oldflags & ~EXT3_FL_USER_MODIFIABLE; 82 inode->u.ext3_i.i_flags = flags; 83 84 if (flags & EXT3_SYNC_FL) 85 inode->i_flags |= S_SYNC; 86 else 87 inode->i_flags &= ~S_SYNC; 88 if (flags & EXT3_APPEND_FL) 89 inode->i_flags |= S_APPEND; 90 else 91 inode->i_flags &= ~S_APPEND; 92 if (flags & EXT3_IMMUTABLE_FL) 93 inode->i_flags |= S_IMMUTABLE; 94 else 95 inode->i_flags &= ~S_IMMUTABLE; 96 if (flags & EXT3_NOATIME_FL) 97 inode->i_flags |= S_NOATIME; 98 else 99 inode->i_flags &= ~S_NOATIME; 100 inode->i_ctime = CURRENT_TIME; 101 102 err = ext3_mark_iloc_dirty(handle, inode, &iloc); 103flags_err: 104 ext3_journal_stop(handle, inode); 105 if (err) 106 return err; 107 108 if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) 109 err = ext3_change_inode_journal_flag(inode, jflag); 110 return err; 111 } 112 case EXT3_IOC_GETVERSION: 113 case EXT3_IOC_GETVERSION_OLD: 114 return put_user(inode->i_generation, (int *) arg); 115 case EXT3_IOC_SETVERSION: 116 case EXT3_IOC_SETVERSION_OLD: { 117 handle_t *handle; 118 struct ext3_iloc iloc; 119 __u32 generation; 120 int err; 121 122 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 123 return -EPERM; 124 if (IS_RDONLY(inode)) 125 return -EROFS; 126 if (get_user(generation, (int *) arg)) 127 return -EFAULT; 128 129 handle = ext3_journal_start(inode, 1); 130 if (IS_ERR(handle)) 131 return PTR_ERR(handle); 132 err = ext3_reserve_inode_write(handle, inode, &iloc); 133 if (err) 134 return err; 135 136 inode->i_ctime = CURRENT_TIME; 137 inode->i_generation = generation; 138 139 err = ext3_mark_iloc_dirty(handle, inode, &iloc); 140 ext3_journal_stop(handle, inode); 141 return err; 142 } 143#ifdef CONFIG_JBD_DEBUG 144 case EXT3_IOC_WAIT_FOR_READONLY: 145 /* 146 * This is racy - by the time we're woken up and running, 147 * the superblock could be released. And the module could 148 * have been unloaded. So sue me. 149 * 150 * Returns 1 if it slept, else zero. 151 */ 152 { 153 struct super_block *sb = inode->i_sb; 154 DECLARE_WAITQUEUE(wait, current); 155 int ret = 0; 156 157 set_current_state(TASK_INTERRUPTIBLE); 158 add_wait_queue(&sb->u.ext3_sb.ro_wait_queue, &wait); 159 if (timer_pending(&sb->u.ext3_sb.turn_ro_timer)) { 160 schedule(); 161 ret = 1; 162 } 163 remove_wait_queue(&sb->u.ext3_sb.ro_wait_queue, &wait); 164 return ret; 165 } 166#endif 167 default: 168 return -ENOTTY; 169 } 170} 171