Blame view

fs/ext4/ioctl.c 7.27 KB
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
1
  /*
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
2
   * linux/fs/ext4/ioctl.c
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
3
4
5
6
7
8
9
10
   *
   * Copyright (C) 1993, 1994, 1995
   * Remy Card (card@masi.ibp.fr)
   * Laboratoire MASI - Institut Blaise Pascal
   * Universite Pierre et Marie Curie (Paris VI)
   */
  
  #include <linux/fs.h>
dab291af8   Mingming Cao   [PATCH] jbd2: ena...
11
  #include <linux/jbd2.h>
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
12
  #include <linux/capability.h>
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
13
  #include <linux/ext4_fs.h>
dab291af8   Mingming Cao   [PATCH] jbd2: ena...
14
  #include <linux/ext4_jbd2.h>
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
15
16
17
18
  #include <linux/time.h>
  #include <linux/compat.h>
  #include <linux/smp_lock.h>
  #include <asm/uaccess.h>
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
19
  int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
20
21
  		unsigned long arg)
  {
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
22
  	struct ext4_inode_info *ei = EXT4_I(inode);
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
23
24
  	unsigned int flags;
  	unsigned short rsv_window_size;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
25
26
  	ext4_debug ("cmd = %u, arg = %lu
  ", cmd, arg);
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
27
28
  
  	switch (cmd) {
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
29
  	case EXT4_IOC_GETFLAGS:
ff9ddf7e8   Jan Kara   ext4: copy i_flag...
30
  		ext4_get_inode_flags(ei);
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
31
  		flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
32
  		return put_user(flags, (int __user *) arg);
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
33
  	case EXT4_IOC_SETFLAGS: {
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
34
35
  		handle_t *handle = NULL;
  		int err;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
36
  		struct ext4_iloc iloc;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
37
38
39
40
41
  		unsigned int oldflags;
  		unsigned int jflag;
  
  		if (IS_RDONLY(inode))
  			return -EROFS;
3bd858ab1   Satyam Sharma   Introduce is_owne...
42
  		if (!is_owner_or_cap(inode))
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
43
44
45
46
47
48
  			return -EACCES;
  
  		if (get_user(flags, (int __user *) arg))
  			return -EFAULT;
  
  		if (!S_ISDIR(inode->i_mode))
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
49
  			flags &= ~EXT4_DIRSYNC_FL;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
50
51
52
53
54
  
  		mutex_lock(&inode->i_mutex);
  		oldflags = ei->i_flags;
  
  		/* The JOURNAL_DATA flag is modifiable only by root */
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
55
  		jflag = flags & EXT4_JOURNAL_DATA_FL;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
56
57
58
59
60
61
62
  
  		/*
  		 * The IMMUTABLE and APPEND_ONLY flags can only be changed by
  		 * the relevant capability.
  		 *
  		 * This test looks nicer. Thanks to Pauline Middelink
  		 */
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
63
  		if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
64
65
66
67
68
69
70
71
72
73
  			if (!capable(CAP_LINUX_IMMUTABLE)) {
  				mutex_unlock(&inode->i_mutex);
  				return -EPERM;
  			}
  		}
  
  		/*
  		 * The JOURNAL_DATA flag can only be changed by
  		 * the relevant capability.
  		 */
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
74
  		if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
75
76
77
78
79
  			if (!capable(CAP_SYS_RESOURCE)) {
  				mutex_unlock(&inode->i_mutex);
  				return -EPERM;
  			}
  		}
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
80
  		handle = ext4_journal_start(inode, 1);
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
81
82
83
84
85
86
  		if (IS_ERR(handle)) {
  			mutex_unlock(&inode->i_mutex);
  			return PTR_ERR(handle);
  		}
  		if (IS_SYNC(inode))
  			handle->h_sync = 1;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
87
  		err = ext4_reserve_inode_write(handle, inode, &iloc);
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
88
89
  		if (err)
  			goto flags_err;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
90
91
  		flags = flags & EXT4_FL_USER_MODIFIABLE;
  		flags |= oldflags & ~EXT4_FL_USER_MODIFIABLE;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
92
  		ei->i_flags = flags;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
93
  		ext4_set_inode_flags(inode);
ef7f38359   Kalpak Shah   ext4: Add nanosec...
94
  		inode->i_ctime = ext4_current_time(inode);
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
95

617ba13b3   Mingming Cao   [PATCH] ext4: ren...
96
  		err = ext4_mark_iloc_dirty(handle, inode, &iloc);
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
97
  flags_err:
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
98
  		ext4_journal_stop(handle);
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
99
100
101
102
  		if (err) {
  			mutex_unlock(&inode->i_mutex);
  			return err;
  		}
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
103
104
  		if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
  			err = ext4_change_inode_journal_flag(inode, jflag);
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
105
106
107
  		mutex_unlock(&inode->i_mutex);
  		return err;
  	}
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
108
109
  	case EXT4_IOC_GETVERSION:
  	case EXT4_IOC_GETVERSION_OLD:
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
110
  		return put_user(inode->i_generation, (int __user *) arg);
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
111
112
  	case EXT4_IOC_SETVERSION:
  	case EXT4_IOC_SETVERSION_OLD: {
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
113
  		handle_t *handle;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
114
  		struct ext4_iloc iloc;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
115
116
  		__u32 generation;
  		int err;
3bd858ab1   Satyam Sharma   Introduce is_owne...
117
  		if (!is_owner_or_cap(inode))
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
118
119
120
121
122
  			return -EPERM;
  		if (IS_RDONLY(inode))
  			return -EROFS;
  		if (get_user(generation, (int __user *) arg))
  			return -EFAULT;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
123
  		handle = ext4_journal_start(inode, 1);
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
124
125
  		if (IS_ERR(handle))
  			return PTR_ERR(handle);
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
126
  		err = ext4_reserve_inode_write(handle, inode, &iloc);
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
127
  		if (err == 0) {
ef7f38359   Kalpak Shah   ext4: Add nanosec...
128
  			inode->i_ctime = ext4_current_time(inode);
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
129
  			inode->i_generation = generation;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
130
  			err = ext4_mark_iloc_dirty(handle, inode, &iloc);
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
131
  		}
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
132
  		ext4_journal_stop(handle);
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
133
134
  		return err;
  	}
e23291b91   Jose R. Santos   jbd2: Fix CONFIG_...
135
  #ifdef CONFIG_JBD2_DEBUG
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
136
  	case EXT4_IOC_WAIT_FOR_READONLY:
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
137
138
139
140
141
142
143
144
145
146
147
148
149
  		/*
  		 * This is racy - by the time we're woken up and running,
  		 * the superblock could be released.  And the module could
  		 * have been unloaded.  So sue me.
  		 *
  		 * Returns 1 if it slept, else zero.
  		 */
  		{
  			struct super_block *sb = inode->i_sb;
  			DECLARE_WAITQUEUE(wait, current);
  			int ret = 0;
  
  			set_current_state(TASK_INTERRUPTIBLE);
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
150
151
  			add_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait);
  			if (timer_pending(&EXT4_SB(sb)->turn_ro_timer)) {
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
152
153
154
  				schedule();
  				ret = 1;
  			}
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
155
  			remove_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait);
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
156
157
158
  			return ret;
  		}
  #endif
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
159
  	case EXT4_IOC_GETRSVSZ:
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
160
161
162
163
164
165
166
  		if (test_opt(inode->i_sb, RESERVATION)
  			&& S_ISREG(inode->i_mode)
  			&& ei->i_block_alloc_info) {
  			rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size;
  			return put_user(rsv_window_size, (int __user *)arg);
  		}
  		return -ENOTTY;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
167
  	case EXT4_IOC_SETRSVSZ: {
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
168
169
170
171
172
173
  
  		if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode))
  			return -ENOTTY;
  
  		if (IS_RDONLY(inode))
  			return -EROFS;
3bd858ab1   Satyam Sharma   Introduce is_owne...
174
  		if (!is_owner_or_cap(inode))
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
175
176
177
178
  			return -EACCES;
  
  		if (get_user(rsv_window_size, (int __user *)arg))
  			return -EFAULT;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
179
180
  		if (rsv_window_size > EXT4_MAX_RESERVE_BLOCKS)
  			rsv_window_size = EXT4_MAX_RESERVE_BLOCKS;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
181
182
183
184
185
186
187
  
  		/*
  		 * need to allocate reservation structure for this inode
  		 * before set the window size
  		 */
  		mutex_lock(&ei->truncate_mutex);
  		if (!ei->i_block_alloc_info)
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
188
  			ext4_init_block_alloc_info(inode);
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
189
190
  
  		if (ei->i_block_alloc_info){
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
191
  			struct ext4_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
192
193
194
195
196
  			rsv->rsv_goal_size = rsv_window_size;
  		}
  		mutex_unlock(&ei->truncate_mutex);
  		return 0;
  	}
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
197
198
  	case EXT4_IOC_GROUP_EXTEND: {
  		ext4_fsblk_t n_blocks_count;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
199
200
201
202
203
204
205
206
207
208
209
  		struct super_block *sb = inode->i_sb;
  		int err;
  
  		if (!capable(CAP_SYS_RESOURCE))
  			return -EPERM;
  
  		if (IS_RDONLY(inode))
  			return -EROFS;
  
  		if (get_user(n_blocks_count, (__u32 __user *)arg))
  			return -EFAULT;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
210
  		err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count);
dab291af8   Mingming Cao   [PATCH] jbd2: ena...
211
212
213
  		jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
  		jbd2_journal_flush(EXT4_SB(sb)->s_journal);
  		jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
214
215
216
  
  		return err;
  	}
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
217
218
  	case EXT4_IOC_GROUP_ADD: {
  		struct ext4_new_group_data input;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
219
220
221
222
223
224
225
226
  		struct super_block *sb = inode->i_sb;
  		int err;
  
  		if (!capable(CAP_SYS_RESOURCE))
  			return -EPERM;
  
  		if (IS_RDONLY(inode))
  			return -EROFS;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
227
  		if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg,
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
228
229
  				sizeof(input)))
  			return -EFAULT;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
230
  		err = ext4_group_add(sb, &input);
dab291af8   Mingming Cao   [PATCH] jbd2: ena...
231
232
233
  		jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
  		jbd2_journal_flush(EXT4_SB(sb)->s_journal);
  		jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
234
235
236
  
  		return err;
  	}
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
237
238
239
240
241
242
  	default:
  		return -ENOTTY;
  	}
  }
  
  #ifdef CONFIG_COMPAT
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
243
  long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
244
  {
9d549890e   Josef "Jeff" Sipek   [PATCH] ext4: cha...
245
  	struct inode *inode = file->f_path.dentry->d_inode;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
246
247
248
249
  	int ret;
  
  	/* These are just misnamed, they actually get/put from/to user an int */
  	switch (cmd) {
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
250
251
  	case EXT4_IOC32_GETFLAGS:
  		cmd = EXT4_IOC_GETFLAGS;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
252
  		break;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
253
254
  	case EXT4_IOC32_SETFLAGS:
  		cmd = EXT4_IOC_SETFLAGS;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
255
  		break;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
256
257
  	case EXT4_IOC32_GETVERSION:
  		cmd = EXT4_IOC_GETVERSION;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
258
  		break;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
259
260
  	case EXT4_IOC32_SETVERSION:
  		cmd = EXT4_IOC_SETVERSION;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
261
  		break;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
262
263
  	case EXT4_IOC32_GROUP_EXTEND:
  		cmd = EXT4_IOC_GROUP_EXTEND;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
264
  		break;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
265
266
  	case EXT4_IOC32_GETVERSION_OLD:
  		cmd = EXT4_IOC_GETVERSION_OLD;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
267
  		break;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
268
269
  	case EXT4_IOC32_SETVERSION_OLD:
  		cmd = EXT4_IOC_SETVERSION_OLD;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
270
  		break;
e23291b91   Jose R. Santos   jbd2: Fix CONFIG_...
271
  #ifdef CONFIG_JBD2_DEBUG
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
272
273
  	case EXT4_IOC32_WAIT_FOR_READONLY:
  		cmd = EXT4_IOC_WAIT_FOR_READONLY;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
274
275
  		break;
  #endif
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
276
277
  	case EXT4_IOC32_GETRSVSZ:
  		cmd = EXT4_IOC_GETRSVSZ;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
278
  		break;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
279
280
  	case EXT4_IOC32_SETRSVSZ:
  		cmd = EXT4_IOC_SETRSVSZ;
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
281
  		break;
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
282
  	case EXT4_IOC_GROUP_ADD:
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
283
284
285
286
287
  		break;
  	default:
  		return -ENOIOCTLCMD;
  	}
  	lock_kernel();
617ba13b3   Mingming Cao   [PATCH] ext4: ren...
288
  	ret = ext4_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
ac27a0ec1   Dave Kleikamp   [PATCH] ext4: ini...
289
290
291
292
  	unlock_kernel();
  	return ret;
  }
  #endif