doc: Update doc about journalling layer
[sfrench/cifs-2.6.git] / fs / ext3 / ioctl.c
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
15 long 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);
99 flags_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);
106 flags_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
146 unlock_out:
147                 mutex_unlock(&inode->i_mutex);
148 setversion_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);
196 setrsvsz_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;
222 group_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;
250 group_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
284 long 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