Blame view

drivers/mtd/ubi/cdev.c 24.6 KB
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  /*
   * Copyright (c) International Business Machines Corp., 2006
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
   * the GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   *
   * Author: Artem Bityutskiy (Битюцкий Артём)
   */
  
  /*
   * This file includes implementation of UBI character device operations.
   *
   * There are two kinds of character devices in UBI: UBI character devices and
   * UBI volume character devices. UBI character devices allow users to
   * manipulate whole volumes: create, remove, and re-size them. Volume character
   * devices provide volume I/O capabilities.
   *
   * Major and minor numbers are assigned dynamically to both UBI and volume
   * character devices.
9f961b575   Artem Bityutskiy   UBI: add UBI cont...
31
32
33
34
35
   *
   * Well, there is the third kind of character devices - the UBI control
   * character device, which allows to manipulate by UBI devices - create and
   * delete them. In other words, it is used for attaching and detaching MTD
   * devices.
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
36
37
38
39
   */
  
  #include <linux/module.h>
  #include <linux/stat.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
40
  #include <linux/slab.h>
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
41
42
  #include <linux/ioctl.h>
  #include <linux/capability.h>
9c9ec1477   Artem Bityutskiy   UBI: fix checkpat...
43
  #include <linux/uaccess.h>
f429b2ea8   Artem Bityutskiy   UBI: add ioctl co...
44
  #include <linux/compat.h>
3013ee31b   Artem Bityutskiy   UBI: use nicer 64...
45
  #include <linux/math64.h>
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
46
  #include <mtd/ubi-user.h>
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
47
  #include "ubi.h"
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
48
  /**
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
   * get_exclusive - get exclusive access to an UBI volume.
   * @desc: volume descriptor
   *
   * This function changes UBI volume open mode to "exclusive". Returns previous
   * mode value (positive integer) in case of success and a negative error code
   * in case of failure.
   */
  static int get_exclusive(struct ubi_volume_desc *desc)
  {
  	int users, err;
  	struct ubi_volume *vol = desc->vol;
  
  	spin_lock(&vol->ubi->volumes_lock);
  	users = vol->readers + vol->writers + vol->exclusive;
  	ubi_assert(users > 0);
  	if (users > 1) {
e2986827d   Artem Bityutskiy   UBI: get rid of d...
65
  		ubi_err("%d users for volume %d", users, vol->vol_id);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
  		err = -EBUSY;
  	} else {
  		vol->readers = vol->writers = 0;
  		vol->exclusive = 1;
  		err = desc->mode;
  		desc->mode = UBI_EXCLUSIVE;
  	}
  	spin_unlock(&vol->ubi->volumes_lock);
  
  	return err;
  }
  
  /**
   * revoke_exclusive - revoke exclusive mode.
   * @desc: volume descriptor
   * @mode: new mode to switch to
   */
  static void revoke_exclusive(struct ubi_volume_desc *desc, int mode)
  {
  	struct ubi_volume *vol = desc->vol;
  
  	spin_lock(&vol->ubi->volumes_lock);
  	ubi_assert(vol->readers == 0 && vol->writers == 0);
  	ubi_assert(vol->exclusive == 1 && desc->mode == UBI_EXCLUSIVE);
  	vol->exclusive = 0;
  	if (mode == UBI_READONLY)
  		vol->readers = 1;
  	else if (mode == UBI_READWRITE)
  		vol->writers = 1;
  	else
  		vol->exclusive = 1;
  	spin_unlock(&vol->ubi->volumes_lock);
  
  	desc->mode = mode;
  }
  
  static int vol_cdev_open(struct inode *inode, struct file *file)
  {
  	struct ubi_volume_desc *desc;
e73f4459d   Artem Bityutskiy   UBI: add UBI devi...
105
106
107
  	int vol_id = iminor(inode) - 1, mode, ubi_num;
  
  	ubi_num = ubi_major2num(imajor(inode));
7d200e88c   Artem Bityutskiy   UBI: remove BKL
108
  	if (ubi_num < 0)
e73f4459d   Artem Bityutskiy   UBI: add UBI devi...
109
  		return ubi_num;
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
110
111
112
113
114
  
  	if (file->f_mode & FMODE_WRITE)
  		mode = UBI_READWRITE;
  	else
  		mode = UBI_READONLY;
e1cf7e6dd   Artem Bityutskiy   UBI: improve debu...
115
  	dbg_gen("open device %d, volume %d, mode %d",
feddbb34e   Artem Bityutskiy   UBI: fix minor st...
116
  		ubi_num, vol_id, mode);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
117

e73f4459d   Artem Bityutskiy   UBI: add UBI devi...
118
  	desc = ubi_open_volume(ubi_num, vol_id, mode);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
119
120
121
122
123
124
125
126
127
128
129
  	if (IS_ERR(desc))
  		return PTR_ERR(desc);
  
  	file->private_data = desc;
  	return 0;
  }
  
  static int vol_cdev_release(struct inode *inode, struct file *file)
  {
  	struct ubi_volume_desc *desc = file->private_data;
  	struct ubi_volume *vol = desc->vol;
e1cf7e6dd   Artem Bityutskiy   UBI: improve debu...
130
131
  	dbg_gen("release device %d, volume %d, mode %d",
  		vol->ubi->ubi_num, vol->vol_id, desc->mode);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
132
133
134
135
  
  	if (vol->updating) {
  		ubi_warn("update of volume %d not finished, volume is damaged",
  			 vol->vol_id);
e653879c2   Artem Bityutskiy   UBI: implement at...
136
  		ubi_assert(!vol->changing_leb);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
137
  		vol->updating = 0;
92ad8f375   Artem Bityutskiy   UBI: use vmalloc ...
138
  		vfree(vol->upd_buf);
e653879c2   Artem Bityutskiy   UBI: implement at...
139
  	} else if (vol->changing_leb) {
049333cec   Artem Bityutskiy   UBI: comply with ...
140
141
142
  		dbg_gen("only %lld of %lld bytes received for atomic LEB change for volume %d:%d, cancel",
  			vol->upd_received, vol->upd_bytes, vol->ubi->ubi_num,
  			vol->vol_id);
e653879c2   Artem Bityutskiy   UBI: implement at...
143
144
  		vol->changing_leb = 0;
  		vfree(vol->upd_buf);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
145
146
147
148
149
150
151
152
153
154
  	}
  
  	ubi_close_volume(desc);
  	return 0;
  }
  
  static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
  {
  	struct ubi_volume_desc *desc = file->private_data;
  	struct ubi_volume *vol = desc->vol;
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
155
156
  
  	if (vol->updating) {
feddbb34e   Artem Bityutskiy   UBI: fix minor st...
157
  		/* Update is in progress, seeking is prohibited */
e2986827d   Artem Bityutskiy   UBI: get rid of d...
158
  		ubi_err("updating");
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
159
160
  		return -EBUSY;
  	}
4a1f2f386   Al Viro   ubi/cdev: switch ...
161
  	return fixed_size_llseek(file, offset, origin, vol->used_bytes);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
162
  }
049333cec   Artem Bityutskiy   UBI: comply with ...
163
164
  static int vol_cdev_fsync(struct file *file, loff_t start, loff_t end,
  			  int datasync)
1b24bc3aa   Corentin Chary   UBI: add fsync ca...
165
166
167
  {
  	struct ubi_volume_desc *desc = file->private_data;
  	struct ubi_device *ubi = desc->vol->ubi;
496ad9aa8   Al Viro   new helper: file_...
168
  	struct inode *inode = file_inode(file);
02c24a821   Josef Bacik   fs: push i_mutex ...
169
170
171
172
173
  	int err;
  	mutex_lock(&inode->i_mutex);
  	err = ubi_sync(ubi->ubi_num);
  	mutex_unlock(&inode->i_mutex);
  	return err;
1b24bc3aa   Corentin Chary   UBI: add fsync ca...
174
  }
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
175
176
177
178
179
180
  static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
  			     loff_t *offp)
  {
  	struct ubi_volume_desc *desc = file->private_data;
  	struct ubi_volume *vol = desc->vol;
  	struct ubi_device *ubi = vol->ubi;
ae616e1be   Artem Bityutskiy   UBI: fix warnings
181
  	int err, lnum, off, len,  tbuf_size;
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
182
183
  	size_t count_save = count;
  	void *tbuf;
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
184

c8566350a   Artem Bityutskiy   UBI: fix and re-w...
185
  	dbg_gen("read %zd bytes from offset %lld of volume %d",
ae616e1be   Artem Bityutskiy   UBI: fix warnings
186
  		count, *offp, vol->vol_id);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
187
188
  
  	if (vol->updating) {
e2986827d   Artem Bityutskiy   UBI: get rid of d...
189
  		ubi_err("updating");
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
190
191
192
  		return -EBUSY;
  	}
  	if (vol->upd_marker) {
e2986827d   Artem Bityutskiy   UBI: get rid of d...
193
  		ubi_err("damaged volume, update marker is set");
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
194
195
196
197
198
199
  		return -EBADF;
  	}
  	if (*offp == vol->used_bytes || count == 0)
  		return 0;
  
  	if (vol->corrupted)
c8566350a   Artem Bityutskiy   UBI: fix and re-w...
200
  		dbg_gen("read from corrupted volume %d", vol->vol_id);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
201
202
203
204
205
206
207
  
  	if (*offp + count > vol->used_bytes)
  		count_save = count = vol->used_bytes - *offp;
  
  	tbuf_size = vol->usable_leb_size;
  	if (count < tbuf_size)
  		tbuf_size = ALIGN(count, ubi->min_io_size);
92ad8f375   Artem Bityutskiy   UBI: use vmalloc ...
208
  	tbuf = vmalloc(tbuf_size);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
209
210
211
212
  	if (!tbuf)
  		return -ENOMEM;
  
  	len = count > tbuf_size ? tbuf_size : count;
3013ee31b   Artem Bityutskiy   UBI: use nicer 64...
213
  	lnum = div_u64_rem(*offp, vol->usable_leb_size, &off);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
214
215
216
217
218
219
  
  	do {
  		cond_resched();
  
  		if (off + len >= vol->usable_leb_size)
  			len = vol->usable_leb_size - off;
89b96b692   Artem Bityutskiy   UBI: improve inte...
220
  		err = ubi_eba_read_leb(ubi, vol, lnum, tbuf, off, len, 0);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
  		if (err)
  			break;
  
  		off += len;
  		if (off == vol->usable_leb_size) {
  			lnum += 1;
  			off -= vol->usable_leb_size;
  		}
  
  		count -= len;
  		*offp += len;
  
  		err = copy_to_user(buf, tbuf, len);
  		if (err) {
  			err = -EFAULT;
  			break;
  		}
  
  		buf += len;
  		len = count > tbuf_size ? tbuf_size : count;
  	} while (count);
92ad8f375   Artem Bityutskiy   UBI: use vmalloc ...
242
  	vfree(tbuf);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
243
244
  	return err ? err : count_save - count;
  }
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
245
246
  /*
   * This function allows to directly write to dynamic UBI volumes, without
766fb95ba   Sidney Amani   UBI: allow direct...
247
   * issuing the volume update operation.
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
248
249
250
251
252
253
254
   */
  static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
  				     size_t count, loff_t *offp)
  {
  	struct ubi_volume_desc *desc = file->private_data;
  	struct ubi_volume *vol = desc->vol;
  	struct ubi_device *ubi = vol->ubi;
ae616e1be   Artem Bityutskiy   UBI: fix warnings
255
  	int lnum, off, len, tbuf_size, err = 0;
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
256
257
  	size_t count_save = count;
  	char *tbuf;
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
258

766fb95ba   Sidney Amani   UBI: allow direct...
259
260
  	if (!vol->direct_writes)
  		return -EPERM;
c8566350a   Artem Bityutskiy   UBI: fix and re-w...
261
  	dbg_gen("requested: write %zd bytes to offset %lld of volume %u",
ae616e1be   Artem Bityutskiy   UBI: fix warnings
262
  		count, *offp, vol->vol_id);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
263
264
265
  
  	if (vol->vol_type == UBI_STATIC_VOLUME)
  		return -EROFS;
3013ee31b   Artem Bityutskiy   UBI: use nicer 64...
266
  	lnum = div_u64_rem(*offp, vol->usable_leb_size, &off);
cadb40ccc   Kyungmin Park   UBI: avoid unnece...
267
  	if (off & (ubi->min_io_size - 1)) {
e2986827d   Artem Bityutskiy   UBI: get rid of d...
268
  		ubi_err("unaligned position");
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
269
270
271
272
273
274
275
  		return -EINVAL;
  	}
  
  	if (*offp + count > vol->used_bytes)
  		count_save = count = vol->used_bytes - *offp;
  
  	/* We can write only in fractions of the minimum I/O unit */
cadb40ccc   Kyungmin Park   UBI: avoid unnece...
276
  	if (count & (ubi->min_io_size - 1)) {
e2986827d   Artem Bityutskiy   UBI: get rid of d...
277
  		ubi_err("unaligned write length");
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
278
279
280
281
282
283
  		return -EINVAL;
  	}
  
  	tbuf_size = vol->usable_leb_size;
  	if (count < tbuf_size)
  		tbuf_size = ALIGN(count, ubi->min_io_size);
92ad8f375   Artem Bityutskiy   UBI: use vmalloc ...
284
  	tbuf = vmalloc(tbuf_size);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
  	if (!tbuf)
  		return -ENOMEM;
  
  	len = count > tbuf_size ? tbuf_size : count;
  
  	while (count) {
  		cond_resched();
  
  		if (off + len >= vol->usable_leb_size)
  			len = vol->usable_leb_size - off;
  
  		err = copy_from_user(tbuf, buf, len);
  		if (err) {
  			err = -EFAULT;
  			break;
  		}
b36a261e8   Richard Weinberger   UBI: Kill data ty...
301
  		err = ubi_eba_write_leb(ubi, vol, lnum, tbuf, off, len);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
302
303
304
305
306
307
308
309
310
311
312
313
314
315
  		if (err)
  			break;
  
  		off += len;
  		if (off == vol->usable_leb_size) {
  			lnum += 1;
  			off -= vol->usable_leb_size;
  		}
  
  		count -= len;
  		*offp += len;
  		buf += len;
  		len = count > tbuf_size ? tbuf_size : count;
  	}
92ad8f375   Artem Bityutskiy   UBI: use vmalloc ...
316
  	vfree(tbuf);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
317
318
  	return err ? err : count_save - count;
  }
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
319
320
321
322
323
324
325
  static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
  			      size_t count, loff_t *offp)
  {
  	int err = 0;
  	struct ubi_volume_desc *desc = file->private_data;
  	struct ubi_volume *vol = desc->vol;
  	struct ubi_device *ubi = vol->ubi;
e653879c2   Artem Bityutskiy   UBI: implement at...
326
  	if (!vol->updating && !vol->changing_leb)
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
327
  		return vol_cdev_direct_write(file, buf, count, offp);
e653879c2   Artem Bityutskiy   UBI: implement at...
328
329
330
331
  	if (vol->updating)
  		err = ubi_more_update_data(ubi, vol, buf, count);
  	else
  		err = ubi_more_leb_change_data(ubi, vol, buf, count);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
332
  	if (err < 0) {
e653879c2   Artem Bityutskiy   UBI: implement at...
333
  		ubi_err("cannot accept more %zd bytes of data, error %d",
01f7b309e   Artem Bityutskiy   UBI: improve erro...
334
  			count, err);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
335
336
337
338
339
  		return err;
  	}
  
  	if (err) {
  		/*
e653879c2   Artem Bityutskiy   UBI: implement at...
340
341
  		 * The operation is finished, @err contains number of actually
  		 * written bytes.
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
342
343
  		 */
  		count = err;
e653879c2   Artem Bityutskiy   UBI: implement at...
344
345
346
347
  		if (vol->changing_leb) {
  			revoke_exclusive(desc, UBI_READWRITE);
  			return count;
  		}
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
348
349
350
351
352
353
354
355
356
357
  		err = ubi_check_volume(ubi, vol->vol_id);
  		if (err < 0)
  			return err;
  
  		if (err) {
  			ubi_warn("volume %d on UBI device %d is corrupted",
  				 vol->vol_id, ubi->ubi_num);
  			vol->corrupted = 1;
  		}
  		vol->checked = 1;
0e0ee1cc3   Dmitry Pervushin   UBI: add notifica...
358
  		ubi_volume_notify(ubi, vol, UBI_VOLUME_UPDATED);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
359
360
  		revoke_exclusive(desc, UBI_READWRITE);
  	}
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
361
362
  	return count;
  }
f429b2ea8   Artem Bityutskiy   UBI: add ioctl co...
363
364
  static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
  			   unsigned long arg)
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
365
366
367
368
369
370
  {
  	int err = 0;
  	struct ubi_volume_desc *desc = file->private_data;
  	struct ubi_volume *vol = desc->vol;
  	struct ubi_device *ubi = vol->ubi;
  	void __user *argp = (void __user *)arg;
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
371
  	switch (cmd) {
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
  	/* Volume update command */
  	case UBI_IOCVOLUP:
  	{
  		int64_t bytes, rsvd_bytes;
  
  		if (!capable(CAP_SYS_RESOURCE)) {
  			err = -EPERM;
  			break;
  		}
  
  		err = copy_from_user(&bytes, argp, sizeof(int64_t));
  		if (err) {
  			err = -EFAULT;
  			break;
  		}
  
  		if (desc->mode == UBI_READONLY) {
  			err = -EROFS;
  			break;
  		}
73789a3d9   Bruce Leonard   UBI: fix 64-bit c...
392
393
  		rsvd_bytes = (long long)vol->reserved_pebs *
  					ubi->leb_size-vol->data_pad;
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
394
395
396
397
398
399
400
401
  		if (bytes < 0 || bytes > rsvd_bytes) {
  			err = -EINVAL;
  			break;
  		}
  
  		err = get_exclusive(desc);
  		if (err < 0)
  			break;
1b68d0eea   Artem Bityutskiy   UBI: simplify int...
402
  		err = ubi_start_update(ubi, vol, bytes);
fda322a1b   Ezequiel Garcia   UBI: Dispatch upd...
403
404
  		if (bytes == 0) {
  			ubi_volume_notify(ubi, vol, UBI_VOLUME_UPDATED);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
405
  			revoke_exclusive(desc, UBI_READWRITE);
fda322a1b   Ezequiel Garcia   UBI: Dispatch upd...
406
  		}
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
407
408
  		break;
  	}
e653879c2   Artem Bityutskiy   UBI: implement at...
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
  	/* Atomic logical eraseblock change command */
  	case UBI_IOCEBCH:
  	{
  		struct ubi_leb_change_req req;
  
  		err = copy_from_user(&req, argp,
  				     sizeof(struct ubi_leb_change_req));
  		if (err) {
  			err = -EFAULT;
  			break;
  		}
  
  		if (desc->mode == UBI_READONLY ||
  		    vol->vol_type == UBI_STATIC_VOLUME) {
  			err = -EROFS;
  			break;
  		}
  
  		/* Validate the request */
  		err = -EINVAL;
  		if (req.lnum < 0 || req.lnum >= vol->reserved_pebs ||
  		    req.bytes < 0 || req.lnum >= vol->usable_leb_size)
  			break;
e653879c2   Artem Bityutskiy   UBI: implement at...
432
433
434
435
436
437
438
439
440
441
  
  		err = get_exclusive(desc);
  		if (err < 0)
  			break;
  
  		err = ubi_start_leb_change(ubi, vol, &req);
  		if (req.bytes == 0)
  			revoke_exclusive(desc, UBI_READWRITE);
  		break;
  	}
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
442
443
444
445
  	/* Logical eraseblock erasure command */
  	case UBI_IOCEBER:
  	{
  		int32_t lnum;
bf07803a6   Christoph Hellwig   UBI: cleanup ioct...
446
  		err = get_user(lnum, (__user int32_t *)argp);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
447
448
449
450
  		if (err) {
  			err = -EFAULT;
  			break;
  		}
e653879c2   Artem Bityutskiy   UBI: implement at...
451
452
  		if (desc->mode == UBI_READONLY ||
  		    vol->vol_type == UBI_STATIC_VOLUME) {
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
453
454
455
456
457
458
459
460
  			err = -EROFS;
  			break;
  		}
  
  		if (lnum < 0 || lnum >= vol->reserved_pebs) {
  			err = -EINVAL;
  			break;
  		}
c8566350a   Artem Bityutskiy   UBI: fix and re-w...
461
  		dbg_gen("erase LEB %d:%d", vol->vol_id, lnum);
89b96b692   Artem Bityutskiy   UBI: improve inte...
462
  		err = ubi_eba_unmap_leb(ubi, vol, lnum);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
463
464
  		if (err)
  			break;
62f384552   Joel Reardon   UBI: modify ubi_w...
465
  		err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
466
467
  		break;
  	}
141e6ebd1   Corentin Chary   UBI: add ioctl fo...
468
469
470
471
472
473
474
475
476
477
478
  
  	/* Logical eraseblock map command */
  	case UBI_IOCEBMAP:
  	{
  		struct ubi_map_req req;
  
  		err = copy_from_user(&req, argp, sizeof(struct ubi_map_req));
  		if (err) {
  			err = -EFAULT;
  			break;
  		}
b36a261e8   Richard Weinberger   UBI: Kill data ty...
479
  		err = ubi_leb_map(desc, req.lnum);
141e6ebd1   Corentin Chary   UBI: add ioctl fo...
480
481
  		break;
  	}
c3da23be1   Corentin Chary   UBI: add ioctl fo...
482
483
484
485
486
487
488
489
490
491
492
493
494
495
  
  	/* Logical eraseblock un-map command */
  	case UBI_IOCEBUNMAP:
  	{
  		int32_t lnum;
  
  		err = get_user(lnum, (__user int32_t *)argp);
  		if (err) {
  			err = -EFAULT;
  			break;
  		}
  		err = ubi_leb_unmap(desc, lnum);
  		break;
  	}
a27ce8f55   Corentin Chary   UBI: add ioctl fo...
496
497
498
499
500
501
502
503
504
505
506
507
508
509
  
  	/* Check if logical eraseblock is mapped command */
  	case UBI_IOCEBISMAP:
  	{
  		int32_t lnum;
  
  		err = get_user(lnum, (__user int32_t *)argp);
  		if (err) {
  			err = -EFAULT;
  			break;
  		}
  		err = ubi_is_mapped(desc, lnum);
  		break;
  	}
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
510

f089c0b28   Artem Bityutskiy   UBI: re-name volu...
511
  	/* Set volume property command */
6748482f4   Artem Bityutskiy   UBI: re-name set ...
512
  	case UBI_IOCSETVOLPROP:
766fb95ba   Sidney Amani   UBI: allow direct...
513
  	{
6748482f4   Artem Bityutskiy   UBI: re-name set ...
514
  		struct ubi_set_vol_prop_req req;
766fb95ba   Sidney Amani   UBI: allow direct...
515
516
  
  		err = copy_from_user(&req, argp,
6748482f4   Artem Bityutskiy   UBI: re-name set ...
517
  				     sizeof(struct ubi_set_vol_prop_req));
766fb95ba   Sidney Amani   UBI: allow direct...
518
519
520
521
522
  		if (err) {
  			err = -EFAULT;
  			break;
  		}
  		switch (req.property) {
6748482f4   Artem Bityutskiy   UBI: re-name set ...
523
  		case UBI_VOL_PROP_DIRECT_WRITE:
f089c0b28   Artem Bityutskiy   UBI: re-name volu...
524
  			mutex_lock(&ubi->device_mutex);
766fb95ba   Sidney Amani   UBI: allow direct...
525
  			desc->vol->direct_writes = !!req.value;
f089c0b28   Artem Bityutskiy   UBI: re-name volu...
526
  			mutex_unlock(&ubi->device_mutex);
766fb95ba   Sidney Amani   UBI: allow direct...
527
528
529
530
531
532
533
  			break;
  		default:
  			err = -EINVAL;
  			break;
  		}
  		break;
  	}
8af871887   Artem Bityutskiy   UBI: rename block...
534
535
  	/* Create a R/O block device on top of the UBI volume */
  	case UBI_IOCVOLCRBLK:
9d54c8a33   Ezequiel Garcia   UBI: R/O block dr...
536
537
538
539
  	{
  		struct ubi_volume_info vi;
  
  		ubi_get_volume_info(desc, &vi);
4d283ee25   Artem Bityutskiy   UBI: block: do no...
540
  		err = ubiblock_create(&vi);
9d54c8a33   Ezequiel Garcia   UBI: R/O block dr...
541
542
  		break;
  	}
8af871887   Artem Bityutskiy   UBI: rename block...
543
544
  	/* Remove the R/O block device */
  	case UBI_IOCVOLRMBLK:
9d54c8a33   Ezequiel Garcia   UBI: R/O block dr...
545
546
547
548
  	{
  		struct ubi_volume_info vi;
  
  		ubi_get_volume_info(desc, &vi);
4d283ee25   Artem Bityutskiy   UBI: block: do no...
549
  		err = ubiblock_remove(&vi);
9d54c8a33   Ezequiel Garcia   UBI: R/O block dr...
550
551
  		break;
  	}
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
552
553
554
555
  	default:
  		err = -ENOTTY;
  		break;
  	}
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
  	return err;
  }
  
  /**
   * verify_mkvol_req - verify volume creation request.
   * @ubi: UBI device description object
   * @req: the request to check
   *
   * This function zero if the request is correct, and %-EINVAL if not.
   */
  static int verify_mkvol_req(const struct ubi_device *ubi,
  			    const struct ubi_mkvol_req *req)
  {
  	int n, err = -EINVAL;
  
  	if (req->bytes < 0 || req->alignment < 0 || req->vol_type < 0 ||
  	    req->name_len < 0)
  		goto bad;
  
  	if ((req->vol_id < 0 || req->vol_id >= ubi->vtbl_slots) &&
  	    req->vol_id != UBI_VOL_NUM_AUTO)
  		goto bad;
  
  	if (req->alignment == 0)
  		goto bad;
  
  	if (req->bytes == 0)
  		goto bad;
  
  	if (req->vol_type != UBI_DYNAMIC_VOLUME &&
  	    req->vol_type != UBI_STATIC_VOLUME)
  		goto bad;
  
  	if (req->alignment > ubi->leb_size)
  		goto bad;
cadb40ccc   Kyungmin Park   UBI: avoid unnece...
591
  	n = req->alignment & (ubi->min_io_size - 1);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
592
593
  	if (req->alignment != 1 && n)
  		goto bad;
4a59c797a   Richard Weinberger   UBI: fix nameless...
594
595
  	if (!req->name[0] || !req->name_len)
  		goto bad;
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
596
597
598
599
  	if (req->name_len > UBI_VOL_NAME_MAX) {
  		err = -ENAMETOOLONG;
  		goto bad;
  	}
a6ea44076   Artem Bityutskiy   UBI: improve mkvo...
600
601
602
  	n = strnlen(req->name, req->name_len + 1);
  	if (n != req->name_len)
  		goto bad;
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
603
604
605
  	return 0;
  
  bad:
e2986827d   Artem Bityutskiy   UBI: get rid of d...
606
  	ubi_err("bad volume creation request");
718c00bb8   Artem Bityutskiy   UBI: rename ubi_d...
607
  	ubi_dump_mkvol_req(req);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
  	return err;
  }
  
  /**
   * verify_rsvol_req - verify volume re-size request.
   * @ubi: UBI device description object
   * @req: the request to check
   *
   * This function returns zero if the request is correct, and %-EINVAL if not.
   */
  static int verify_rsvol_req(const struct ubi_device *ubi,
  			    const struct ubi_rsvol_req *req)
  {
  	if (req->bytes <= 0)
  		return -EINVAL;
  
  	if (req->vol_id < 0 || req->vol_id >= ubi->vtbl_slots)
  		return -EINVAL;
  
  	return 0;
  }
f40ac9cdf   Artem Bityutskiy   UBI: implement mu...
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
  /**
   * rename_volumes - rename UBI volumes.
   * @ubi: UBI device description object
   * @req: volumes re-name request
   *
   * This is a helper function for the volume re-name IOCTL which validates the
   * the request, opens the volume and calls corresponding volumes management
   * function. Returns zero in case of success and a negative error code in case
   * of failure.
   */
  static int rename_volumes(struct ubi_device *ubi,
  			  struct ubi_rnvol_req *req)
  {
  	int i, n, err;
  	struct list_head rename_list;
  	struct ubi_rename_entry *re, *re1;
  
  	if (req->count < 0 || req->count > UBI_MAX_RNVOL)
  		return -EINVAL;
  
  	if (req->count == 0)
  		return 0;
  
  	/* Validate volume IDs and names in the request */
  	for (i = 0; i < req->count; i++) {
  		if (req->ents[i].vol_id < 0 ||
  		    req->ents[i].vol_id >= ubi->vtbl_slots)
  			return -EINVAL;
  		if (req->ents[i].name_len < 0)
  			return -EINVAL;
  		if (req->ents[i].name_len > UBI_VOL_NAME_MAX)
  			return -ENAMETOOLONG;
  		req->ents[i].name[req->ents[i].name_len] = '\0';
  		n = strlen(req->ents[i].name);
  		if (n != req->ents[i].name_len)
7fbbd0579   Dan Carpenter   UBI: return on er...
664
  			return -EINVAL;
f40ac9cdf   Artem Bityutskiy   UBI: implement mu...
665
666
667
668
669
670
  	}
  
  	/* Make sure volume IDs and names are unique */
  	for (i = 0; i < req->count - 1; i++) {
  		for (n = i + 1; n < req->count; n++) {
  			if (req->ents[i].vol_id == req->ents[n].vol_id) {
e2986827d   Artem Bityutskiy   UBI: get rid of d...
671
  				ubi_err("duplicated volume id %d",
f40ac9cdf   Artem Bityutskiy   UBI: implement mu...
672
673
674
675
  					req->ents[i].vol_id);
  				return -EINVAL;
  			}
  			if (!strcmp(req->ents[i].name, req->ents[n].name)) {
e2986827d   Artem Bityutskiy   UBI: get rid of d...
676
  				ubi_err("duplicated volume name \"%s\"",
f40ac9cdf   Artem Bityutskiy   UBI: implement mu...
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
  					req->ents[i].name);
  				return -EINVAL;
  			}
  		}
  	}
  
  	/* Create the re-name list */
  	INIT_LIST_HEAD(&rename_list);
  	for (i = 0; i < req->count; i++) {
  		int vol_id = req->ents[i].vol_id;
  		int name_len = req->ents[i].name_len;
  		const char *name = req->ents[i].name;
  
  		re = kzalloc(sizeof(struct ubi_rename_entry), GFP_KERNEL);
  		if (!re) {
  			err = -ENOMEM;
  			goto out_free;
  		}
778c7eb82   Ezequiel Garcia   UBI: weaken the '...
695
  		re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_READWRITE);
f40ac9cdf   Artem Bityutskiy   UBI: implement mu...
696
697
  		if (IS_ERR(re->desc)) {
  			err = PTR_ERR(re->desc);
e2986827d   Artem Bityutskiy   UBI: get rid of d...
698
  			ubi_err("cannot open volume %d, error %d", vol_id, err);
f40ac9cdf   Artem Bityutskiy   UBI: implement mu...
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
  			kfree(re);
  			goto out_free;
  		}
  
  		/* Skip this re-naming if the name does not really change */
  		if (re->desc->vol->name_len == name_len &&
  		    !memcmp(re->desc->vol->name, name, name_len)) {
  			ubi_close_volume(re->desc);
  			kfree(re);
  			continue;
  		}
  
  		re->new_name_len = name_len;
  		memcpy(re->new_name, name, name_len);
  		list_add_tail(&re->list, &rename_list);
719bb8401   Artem Bityutskiy   UBI: print less
714
  		dbg_gen("will rename volume %d from \"%s\" to \"%s\"",
f40ac9cdf   Artem Bityutskiy   UBI: implement mu...
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
  			vol_id, re->desc->vol->name, name);
  	}
  
  	if (list_empty(&rename_list))
  		return 0;
  
  	/* Find out the volumes which have to be removed */
  	list_for_each_entry(re, &rename_list, list) {
  		struct ubi_volume_desc *desc;
  		int no_remove_needed = 0;
  
  		/*
  		 * Volume @re->vol_id is going to be re-named to
  		 * @re->new_name, while its current name is @name. If a volume
  		 * with name @re->new_name currently exists, it has to be
  		 * removed, unless it is also re-named in the request (@req).
  		 */
  		list_for_each_entry(re1, &rename_list, list) {
  			if (re->new_name_len == re1->desc->vol->name_len &&
  			    !memcmp(re->new_name, re1->desc->vol->name,
  				    re1->desc->vol->name_len)) {
  				no_remove_needed = 1;
  				break;
  			}
  		}
  
  		if (no_remove_needed)
  			continue;
  
  		/*
  		 * It seems we need to remove volume with name @re->new_name,
  		 * if it exists.
  		 */
f2863c54f   Artem Bityutskiy   UBI: fix checkpat...
748
749
  		desc = ubi_open_volume_nm(ubi->ubi_num, re->new_name,
  					  UBI_EXCLUSIVE);
f40ac9cdf   Artem Bityutskiy   UBI: implement mu...
750
751
752
753
754
755
756
  		if (IS_ERR(desc)) {
  			err = PTR_ERR(desc);
  			if (err == -ENODEV)
  				/* Re-naming into a non-existing volume name */
  				continue;
  
  			/* The volume exists but busy, or an error occurred */
e2986827d   Artem Bityutskiy   UBI: get rid of d...
757
  			ubi_err("cannot open volume \"%s\", error %d",
f40ac9cdf   Artem Bityutskiy   UBI: implement mu...
758
759
760
  				re->new_name, err);
  			goto out_free;
  		}
01ebc12f5   Julia Lawall   UBI: eliminate up...
761
762
  		re1 = kzalloc(sizeof(struct ubi_rename_entry), GFP_KERNEL);
  		if (!re1) {
f40ac9cdf   Artem Bityutskiy   UBI: implement mu...
763
764
765
766
  			err = -ENOMEM;
  			ubi_close_volume(desc);
  			goto out_free;
  		}
01ebc12f5   Julia Lawall   UBI: eliminate up...
767
768
769
  		re1->remove = 1;
  		re1->desc = desc;
  		list_add(&re1->list, &rename_list);
719bb8401   Artem Bityutskiy   UBI: print less
770
  		dbg_gen("will remove volume %d, name \"%s\"",
01ebc12f5   Julia Lawall   UBI: eliminate up...
771
  			re1->desc->vol->vol_id, re1->desc->vol->name);
f40ac9cdf   Artem Bityutskiy   UBI: implement mu...
772
  	}
f089c0b28   Artem Bityutskiy   UBI: re-name volu...
773
  	mutex_lock(&ubi->device_mutex);
f40ac9cdf   Artem Bityutskiy   UBI: implement mu...
774
  	err = ubi_rename_volumes(ubi, &rename_list);
f089c0b28   Artem Bityutskiy   UBI: re-name volu...
775
  	mutex_unlock(&ubi->device_mutex);
f40ac9cdf   Artem Bityutskiy   UBI: implement mu...
776
777
778
779
780
781
782
783
784
  
  out_free:
  	list_for_each_entry_safe(re, re1, &rename_list, list) {
  		ubi_close_volume(re->desc);
  		list_del(&re->list);
  		kfree(re);
  	}
  	return err;
  }
f429b2ea8   Artem Bityutskiy   UBI: add ioctl co...
785
786
  static long ubi_cdev_ioctl(struct file *file, unsigned int cmd,
  			   unsigned long arg)
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
787
788
789
790
791
  {
  	int err = 0;
  	struct ubi_device *ubi;
  	struct ubi_volume_desc *desc;
  	void __user *argp = (void __user *)arg;
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
792
793
  	if (!capable(CAP_SYS_RESOURCE))
  		return -EPERM;
f429b2ea8   Artem Bityutskiy   UBI: add ioctl co...
794
  	ubi = ubi_get_by_major(imajor(file->f_mapping->host));
e73f4459d   Artem Bityutskiy   UBI: add UBI devi...
795
796
  	if (!ubi)
  		return -ENODEV;
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
797
798
799
800
801
802
  
  	switch (cmd) {
  	/* Create volume command */
  	case UBI_IOCMKVOL:
  	{
  		struct ubi_mkvol_req req;
c8566350a   Artem Bityutskiy   UBI: fix and re-w...
803
  		dbg_gen("create volume");
897a316c9   Artem Bityutskiy   UBI: handle attac...
804
  		err = copy_from_user(&req, argp, sizeof(struct ubi_mkvol_req));
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
805
806
807
808
809
810
811
812
  		if (err) {
  			err = -EFAULT;
  			break;
  		}
  
  		err = verify_mkvol_req(ubi, &req);
  		if (err)
  			break;
f089c0b28   Artem Bityutskiy   UBI: re-name volu...
813
  		mutex_lock(&ubi->device_mutex);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
814
  		err = ubi_create_volume(ubi, &req);
f089c0b28   Artem Bityutskiy   UBI: re-name volu...
815
  		mutex_unlock(&ubi->device_mutex);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
816
817
  		if (err)
  			break;
bf07803a6   Christoph Hellwig   UBI: cleanup ioct...
818
  		err = put_user(req.vol_id, (__user int32_t *)argp);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
819
820
821
822
823
824
825
826
827
828
  		if (err)
  			err = -EFAULT;
  
  		break;
  	}
  
  	/* Remove volume command */
  	case UBI_IOCRMVOL:
  	{
  		int vol_id;
c8566350a   Artem Bityutskiy   UBI: fix and re-w...
829
  		dbg_gen("remove volume");
bf07803a6   Christoph Hellwig   UBI: cleanup ioct...
830
  		err = get_user(vol_id, (__user int32_t *)argp);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
831
832
833
834
835
836
837
838
839
840
  		if (err) {
  			err = -EFAULT;
  			break;
  		}
  
  		desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_EXCLUSIVE);
  		if (IS_ERR(desc)) {
  			err = PTR_ERR(desc);
  			break;
  		}
f089c0b28   Artem Bityutskiy   UBI: re-name volu...
841
  		mutex_lock(&ubi->device_mutex);
f40ac9cdf   Artem Bityutskiy   UBI: implement mu...
842
  		err = ubi_remove_volume(desc, 0);
f089c0b28   Artem Bityutskiy   UBI: re-name volu...
843
  		mutex_unlock(&ubi->device_mutex);
40e4d0c16   Artem Bityutskiy   UBI: tweak volume...
844

450f872a8   Artem Bityutskiy   UBI: get device w...
845
  		/*
40e4d0c16   Artem Bityutskiy   UBI: tweak volume...
846
847
848
  		 * The volume is deleted (unless an error occurred), and the
  		 * 'struct ubi_volume' object will be freed when
  		 * 'ubi_close_volume()' will call 'put_device()'.
450f872a8   Artem Bityutskiy   UBI: get device w...
849
850
  		 */
  		ubi_close_volume(desc);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
851
852
853
854
855
856
857
  		break;
  	}
  
  	/* Re-size volume command */
  	case UBI_IOCRSVOL:
  	{
  		int pebs;
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
858
  		struct ubi_rsvol_req req;
c8566350a   Artem Bityutskiy   UBI: fix and re-w...
859
  		dbg_gen("re-size volume");
897a316c9   Artem Bityutskiy   UBI: handle attac...
860
  		err = copy_from_user(&req, argp, sizeof(struct ubi_rsvol_req));
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
861
862
863
864
865
866
867
868
869
870
871
872
873
874
  		if (err) {
  			err = -EFAULT;
  			break;
  		}
  
  		err = verify_rsvol_req(ubi, &req);
  		if (err)
  			break;
  
  		desc = ubi_open_volume(ubi->ubi_num, req.vol_id, UBI_EXCLUSIVE);
  		if (IS_ERR(desc)) {
  			err = PTR_ERR(desc);
  			break;
  		}
3013ee31b   Artem Bityutskiy   UBI: use nicer 64...
875
876
  		pebs = div_u64(req.bytes + desc->vol->usable_leb_size - 1,
  			       desc->vol->usable_leb_size);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
877

f089c0b28   Artem Bityutskiy   UBI: re-name volu...
878
  		mutex_lock(&ubi->device_mutex);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
879
  		err = ubi_resize_volume(desc, pebs);
f089c0b28   Artem Bityutskiy   UBI: re-name volu...
880
  		mutex_unlock(&ubi->device_mutex);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
881
882
883
  		ubi_close_volume(desc);
  		break;
  	}
f40ac9cdf   Artem Bityutskiy   UBI: implement mu...
884
885
886
887
  	/* Re-name volumes command */
  	case UBI_IOCRNVOL:
  	{
  		struct ubi_rnvol_req *req;
719bb8401   Artem Bityutskiy   UBI: print less
888
  		dbg_gen("re-name volumes");
f40ac9cdf   Artem Bityutskiy   UBI: implement mu...
889
890
891
892
893
894
895
896
897
898
899
900
  		req = kmalloc(sizeof(struct ubi_rnvol_req), GFP_KERNEL);
  		if (!req) {
  			err = -ENOMEM;
  			break;
  		};
  
  		err = copy_from_user(req, argp, sizeof(struct ubi_rnvol_req));
  		if (err) {
  			err = -EFAULT;
  			kfree(req);
  			break;
  		}
f40ac9cdf   Artem Bityutskiy   UBI: implement mu...
901
  		err = rename_volumes(ubi, req);
f40ac9cdf   Artem Bityutskiy   UBI: implement mu...
902
903
904
  		kfree(req);
  		break;
  	}
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
905
906
907
908
  	default:
  		err = -ENOTTY;
  		break;
  	}
e73f4459d   Artem Bityutskiy   UBI: add UBI devi...
909
  	ubi_put_device(ubi);
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
910
911
  	return err;
  }
f429b2ea8   Artem Bityutskiy   UBI: add ioctl co...
912
913
  static long ctrl_cdev_ioctl(struct file *file, unsigned int cmd,
  			    unsigned long arg)
897a316c9   Artem Bityutskiy   UBI: handle attac...
914
915
916
917
918
919
920
921
922
923
924
925
926
  {
  	int err = 0;
  	void __user *argp = (void __user *)arg;
  
  	if (!capable(CAP_SYS_RESOURCE))
  		return -EPERM;
  
  	switch (cmd) {
  	/* Attach an MTD device command */
  	case UBI_IOCATT:
  	{
  		struct ubi_attach_req req;
  		struct mtd_info *mtd;
c8566350a   Artem Bityutskiy   UBI: fix and re-w...
927
  		dbg_gen("attach MTD device");
897a316c9   Artem Bityutskiy   UBI: handle attac...
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
  		err = copy_from_user(&req, argp, sizeof(struct ubi_attach_req));
  		if (err) {
  			err = -EFAULT;
  			break;
  		}
  
  		if (req.mtd_num < 0 ||
  		    (req.ubi_num < 0 && req.ubi_num != UBI_DEV_NUM_AUTO)) {
  			err = -EINVAL;
  			break;
  		}
  
  		mtd = get_mtd_device(NULL, req.mtd_num);
  		if (IS_ERR(mtd)) {
  			err = PTR_ERR(mtd);
  			break;
  		}
  
  		/*
  		 * Note, further request verification is done by
  		 * 'ubi_attach_mtd_dev()'.
  		 */
  		mutex_lock(&ubi_devices_mutex);
256334c31   Richard Genoud   UBI: prepare for ...
951
  		err = ubi_attach_mtd_dev(mtd, req.ubi_num, req.vid_hdr_offset,
db7e21c21   Richard Genoud   UBI: add max_beb_...
952
  					 req.max_beb_per1024);
897a316c9   Artem Bityutskiy   UBI: handle attac...
953
954
955
956
957
958
959
960
961
962
963
964
965
966
  		mutex_unlock(&ubi_devices_mutex);
  		if (err < 0)
  			put_mtd_device(mtd);
  		else
  			/* @err contains UBI device number */
  			err = put_user(err, (__user int32_t *)argp);
  
  		break;
  	}
  
  	/* Detach an MTD device command */
  	case UBI_IOCDET:
  	{
  		int ubi_num;
2ce7be1b7   Peter Meerwald   UBI: fix spelling...
967
  		dbg_gen("detach MTD device");
897a316c9   Artem Bityutskiy   UBI: handle attac...
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
  		err = get_user(ubi_num, (__user int32_t *)argp);
  		if (err) {
  			err = -EFAULT;
  			break;
  		}
  
  		mutex_lock(&ubi_devices_mutex);
  		err = ubi_detach_mtd_dev(ubi_num, 0);
  		mutex_unlock(&ubi_devices_mutex);
  		break;
  	}
  
  	default:
  		err = -ENOTTY;
  		break;
  	}
  
  	return err;
  }
f429b2ea8   Artem Bityutskiy   UBI: add ioctl co...
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
  #ifdef CONFIG_COMPAT
  static long vol_cdev_compat_ioctl(struct file *file, unsigned int cmd,
  				  unsigned long arg)
  {
  	unsigned long translated_arg = (unsigned long)compat_ptr(arg);
  
  	return vol_cdev_ioctl(file, cmd, translated_arg);
  }
  
  static long ubi_cdev_compat_ioctl(struct file *file, unsigned int cmd,
  				  unsigned long arg)
  {
  	unsigned long translated_arg = (unsigned long)compat_ptr(arg);
  
  	return ubi_cdev_ioctl(file, cmd, translated_arg);
  }
  
  static long ctrl_cdev_compat_ioctl(struct file *file, unsigned int cmd,
  				   unsigned long arg)
  {
  	unsigned long translated_arg = (unsigned long)compat_ptr(arg);
  
  	return ctrl_cdev_ioctl(file, cmd, translated_arg);
  }
  #else
  #define vol_cdev_compat_ioctl  NULL
  #define ubi_cdev_compat_ioctl  NULL
  #define ctrl_cdev_compat_ioctl NULL
  #endif
  
  /* UBI volume character device operations */
  const struct file_operations ubi_vol_cdev_operations = {
  	.owner          = THIS_MODULE,
  	.open           = vol_cdev_open,
  	.release        = vol_cdev_release,
  	.llseek         = vol_cdev_llseek,
  	.read           = vol_cdev_read,
  	.write          = vol_cdev_write,
1b24bc3aa   Corentin Chary   UBI: add fsync ca...
1025
  	.fsync		= vol_cdev_fsync,
f429b2ea8   Artem Bityutskiy   UBI: add ioctl co...
1026
1027
  	.unlocked_ioctl = vol_cdev_ioctl,
  	.compat_ioctl   = vol_cdev_compat_ioctl,
9f961b575   Artem Bityutskiy   UBI: add UBI cont...
1028
  };
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
1029
  /* UBI character device operations */
4d187a88d   Jan Engelhardt   UBI: constify fil...
1030
  const struct file_operations ubi_cdev_operations = {
f429b2ea8   Artem Bityutskiy   UBI: add ioctl co...
1031
1032
1033
1034
  	.owner          = THIS_MODULE,
  	.llseek         = no_llseek,
  	.unlocked_ioctl = ubi_cdev_ioctl,
  	.compat_ioctl   = ubi_cdev_compat_ioctl,
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
1035
  };
f429b2ea8   Artem Bityutskiy   UBI: add ioctl co...
1036
1037
1038
1039
1040
  /* UBI control character device operations */
  const struct file_operations ubi_ctrl_cdev_operations = {
  	.owner          = THIS_MODULE,
  	.unlocked_ioctl = ctrl_cdev_ioctl,
  	.compat_ioctl   = ctrl_cdev_compat_ioctl,
e10b376e9   Artem Bityutskiy   UBI: make the con...
1041
  	.llseek		= no_llseek,
801c135ce   Artem B. Bityutskiy   UBI: Unsorted Blo...
1042
  };