]> err.no Git - linux-2.6/blob - fs/ext4/ioctl.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
[linux-2.6] / fs / ext4 / ioctl.c
1 /*
2  * linux/fs/ext4/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/jbd2.h>
12 #include <linux/capability.h>
13 #include <linux/time.h>
14 #include <linux/compat.h>
15 #include <linux/smp_lock.h>
16 #include <linux/mount.h>
17 #include <asm/uaccess.h>
18 #include "ext4_jbd2.h"
19 #include "ext4.h"
20
21 long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
22 {
23         struct inode *inode = filp->f_dentry->d_inode;
24         struct ext4_inode_info *ei = EXT4_I(inode);
25         unsigned int flags;
26         unsigned short rsv_window_size;
27
28         ext4_debug ("cmd = %u, arg = %lu\n", cmd, arg);
29
30         switch (cmd) {
31         case EXT4_IOC_GETFLAGS:
32                 ext4_get_inode_flags(ei);
33                 flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
34                 return put_user(flags, (int __user *) arg);
35         case EXT4_IOC_SETFLAGS: {
36                 handle_t *handle = NULL;
37                 int err;
38                 struct ext4_iloc iloc;
39                 unsigned int oldflags;
40                 unsigned int jflag;
41
42                 if (!is_owner_or_cap(inode))
43                         return -EACCES;
44
45                 if (get_user(flags, (int __user *) arg))
46                         return -EFAULT;
47
48                 err = mnt_want_write(filp->f_path.mnt);
49                 if (err)
50                         return err;
51
52                 if (!S_ISDIR(inode->i_mode))
53                         flags &= ~EXT4_DIRSYNC_FL;
54
55                 err = -EPERM;
56                 mutex_lock(&inode->i_mutex);
57                 /* Is it quota file? Do not allow user to mess with it */
58                 if (IS_NOQUOTA(inode))
59                         goto flags_out;
60
61                 oldflags = ei->i_flags;
62
63                 /* The JOURNAL_DATA flag is modifiable only by root */
64                 jflag = flags & EXT4_JOURNAL_DATA_FL;
65
66                 /*
67                  * The IMMUTABLE and APPEND_ONLY flags can only be changed by
68                  * the relevant capability.
69                  *
70                  * This test looks nicer. Thanks to Pauline Middelink
71                  */
72                 if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
73                         if (!capable(CAP_LINUX_IMMUTABLE))
74                                 goto flags_out;
75                 }
76
77                 /*
78                  * The JOURNAL_DATA flag can only be changed by
79                  * the relevant capability.
80                  */
81                 if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
82                         if (!capable(CAP_SYS_RESOURCE))
83                                 goto flags_out;
84                 }
85
86                 handle = ext4_journal_start(inode, 1);
87                 if (IS_ERR(handle)) {
88                         err = PTR_ERR(handle);
89                         goto flags_out;
90                 }
91                 if (IS_SYNC(inode))
92                         handle->h_sync = 1;
93                 err = ext4_reserve_inode_write(handle, inode, &iloc);
94                 if (err)
95                         goto flags_err;
96
97                 flags = flags & EXT4_FL_USER_MODIFIABLE;
98                 flags |= oldflags & ~EXT4_FL_USER_MODIFIABLE;
99                 ei->i_flags = flags;
100
101                 ext4_set_inode_flags(inode);
102                 inode->i_ctime = ext4_current_time(inode);
103
104                 err = ext4_mark_iloc_dirty(handle, inode, &iloc);
105 flags_err:
106                 ext4_journal_stop(handle);
107                 if (err)
108                         goto flags_out;
109
110                 if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
111                         err = ext4_change_inode_journal_flag(inode, jflag);
112 flags_out:
113                 mutex_unlock(&inode->i_mutex);
114                 mnt_drop_write(filp->f_path.mnt);
115                 return err;
116         }
117         case EXT4_IOC_GETVERSION:
118         case EXT4_IOC_GETVERSION_OLD:
119                 return put_user(inode->i_generation, (int __user *) arg);
120         case EXT4_IOC_SETVERSION:
121         case EXT4_IOC_SETVERSION_OLD: {
122                 handle_t *handle;
123                 struct ext4_iloc iloc;
124                 __u32 generation;
125                 int err;
126
127                 if (!is_owner_or_cap(inode))
128                         return -EPERM;
129
130                 err = mnt_want_write(filp->f_path.mnt);
131                 if (err)
132                         return err;
133                 if (get_user(generation, (int __user *) arg)) {
134                         err = -EFAULT;
135                         goto setversion_out;
136                 }
137
138                 handle = ext4_journal_start(inode, 1);
139                 if (IS_ERR(handle)) {
140                         err = PTR_ERR(handle);
141                         goto setversion_out;
142                 }
143                 err = ext4_reserve_inode_write(handle, inode, &iloc);
144                 if (err == 0) {
145                         inode->i_ctime = ext4_current_time(inode);
146                         inode->i_generation = generation;
147                         err = ext4_mark_iloc_dirty(handle, inode, &iloc);
148                 }
149                 ext4_journal_stop(handle);
150 setversion_out:
151                 mnt_drop_write(filp->f_path.mnt);
152                 return err;
153         }
154 #ifdef CONFIG_JBD2_DEBUG
155         case EXT4_IOC_WAIT_FOR_READONLY:
156                 /*
157                  * This is racy - by the time we're woken up and running,
158                  * the superblock could be released.  And the module could
159                  * have been unloaded.  So sue me.
160                  *
161                  * Returns 1 if it slept, else zero.
162                  */
163                 {
164                         struct super_block *sb = inode->i_sb;
165                         DECLARE_WAITQUEUE(wait, current);
166                         int ret = 0;
167
168                         set_current_state(TASK_INTERRUPTIBLE);
169                         add_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait);
170                         if (timer_pending(&EXT4_SB(sb)->turn_ro_timer)) {
171                                 schedule();
172                                 ret = 1;
173                         }
174                         remove_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait);
175                         return ret;
176                 }
177 #endif
178         case EXT4_IOC_GETRSVSZ:
179                 if (test_opt(inode->i_sb, RESERVATION)
180                         && S_ISREG(inode->i_mode)
181                         && ei->i_block_alloc_info) {
182                         rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size;
183                         return put_user(rsv_window_size, (int __user *)arg);
184                 }
185                 return -ENOTTY;
186         case EXT4_IOC_SETRSVSZ: {
187                 int err;
188
189                 if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode))
190                         return -ENOTTY;
191
192                 if (!is_owner_or_cap(inode))
193                         return -EACCES;
194
195                 if (get_user(rsv_window_size, (int __user *)arg))
196                         return -EFAULT;
197
198                 err = mnt_want_write(filp->f_path.mnt);
199                 if (err)
200                         return err;
201
202                 if (rsv_window_size > EXT4_MAX_RESERVE_BLOCKS)
203                         rsv_window_size = EXT4_MAX_RESERVE_BLOCKS;
204
205                 /*
206                  * need to allocate reservation structure for this inode
207                  * before set the window size
208                  */
209                 down_write(&ei->i_data_sem);
210                 if (!ei->i_block_alloc_info)
211                         ext4_init_block_alloc_info(inode);
212
213                 if (ei->i_block_alloc_info){
214                         struct ext4_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node;
215                         rsv->rsv_goal_size = rsv_window_size;
216                 }
217                 up_write(&ei->i_data_sem);
218                 mnt_drop_write(filp->f_path.mnt);
219                 return 0;
220         }
221         case EXT4_IOC_GROUP_EXTEND: {
222                 ext4_fsblk_t n_blocks_count;
223                 struct super_block *sb = inode->i_sb;
224                 int err;
225
226                 if (!capable(CAP_SYS_RESOURCE))
227                         return -EPERM;
228
229                 if (get_user(n_blocks_count, (__u32 __user *)arg))
230                         return -EFAULT;
231
232                 err = mnt_want_write(filp->f_path.mnt);
233                 if (err)
234                         return err;
235
236                 err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count);
237                 jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
238                 jbd2_journal_flush(EXT4_SB(sb)->s_journal);
239                 jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
240                 mnt_drop_write(filp->f_path.mnt);
241
242                 return err;
243         }
244         case EXT4_IOC_GROUP_ADD: {
245                 struct ext4_new_group_data input;
246                 struct super_block *sb = inode->i_sb;
247                 int err;
248
249                 if (!capable(CAP_SYS_RESOURCE))
250                         return -EPERM;
251
252                 if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg,
253                                 sizeof(input)))
254                         return -EFAULT;
255
256                 err = mnt_want_write(filp->f_path.mnt);
257                 if (err)
258                         return err;
259
260                 err = ext4_group_add(sb, &input);
261                 jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
262                 jbd2_journal_flush(EXT4_SB(sb)->s_journal);
263                 jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
264                 mnt_drop_write(filp->f_path.mnt);
265
266                 return err;
267         }
268
269         case EXT4_IOC_MIGRATE:
270                 return ext4_ext_migrate(inode, filp, cmd, arg);
271
272         default:
273                 return -ENOTTY;
274         }
275 }
276
277 #ifdef CONFIG_COMPAT
278 long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
279 {
280         /* These are just misnamed, they actually get/put from/to user an int */
281         switch (cmd) {
282         case EXT4_IOC32_GETFLAGS:
283                 cmd = EXT4_IOC_GETFLAGS;
284                 break;
285         case EXT4_IOC32_SETFLAGS:
286                 cmd = EXT4_IOC_SETFLAGS;
287                 break;
288         case EXT4_IOC32_GETVERSION:
289                 cmd = EXT4_IOC_GETVERSION;
290                 break;
291         case EXT4_IOC32_SETVERSION:
292                 cmd = EXT4_IOC_SETVERSION;
293                 break;
294         case EXT4_IOC32_GROUP_EXTEND:
295                 cmd = EXT4_IOC_GROUP_EXTEND;
296                 break;
297         case EXT4_IOC32_GETVERSION_OLD:
298                 cmd = EXT4_IOC_GETVERSION_OLD;
299                 break;
300         case EXT4_IOC32_SETVERSION_OLD:
301                 cmd = EXT4_IOC_SETVERSION_OLD;
302                 break;
303 #ifdef CONFIG_JBD2_DEBUG
304         case EXT4_IOC32_WAIT_FOR_READONLY:
305                 cmd = EXT4_IOC_WAIT_FOR_READONLY;
306                 break;
307 #endif
308         case EXT4_IOC32_GETRSVSZ:
309                 cmd = EXT4_IOC_GETRSVSZ;
310                 break;
311         case EXT4_IOC32_SETRSVSZ:
312                 cmd = EXT4_IOC_SETRSVSZ;
313                 break;
314         case EXT4_IOC_GROUP_ADD:
315                 break;
316         default:
317                 return -ENOIOCTLCMD;
318         }
319         return ext4_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
320 }
321 #endif