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