Blame view

drivers/char/raw.c 8.28 KB
09c434b8a   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
13
  /*
   * linux/drivers/char/raw.c
   *
   * Front-end raw character devices.  These can be bound to any block
   * devices to provide genuine Unix raw character device semantics.
   *
   * We reserve minor number 0 for a control interface.  ioctl()s on this
   * device are used to bind the other minor numbers to block devices.
   */
  
  #include <linux/init.h>
  #include <linux/fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
  #include <linux/major.h>
  #include <linux/blkdev.h>
66114cad6   Tejun Heo   writeback: separa...
16
  #include <linux/backing-dev.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
21
22
  #include <linux/module.h>
  #include <linux/raw.h>
  #include <linux/capability.h>
  #include <linux/uio.h>
  #include <linux/cdev.h>
  #include <linux/device.h>
8ed965d61   Arjan van de Ven   [PATCH] sem2mutex...
23
  #include <linux/mutex.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
24
  #include <linux/gfp.h>
c4a047272   Al Viro   fix rawctl compat...
25
  #include <linux/compat.h>
0078bff52   Jan Kara   Allow setting of ...
26
  #include <linux/vmalloc.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27

7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
28
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
  
  struct raw_device_data {
5a56ad788   Christoph Hellwig   raw: don't keep u...
31
32
  	dev_t binding;
  	struct block_device *bdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
  	int inuse;
  };
ca8eca688   Greg Kroah-Hartman   [PATCH] class: co...
35
  static struct class *raw_class;
0078bff52   Jan Kara   Allow setting of ...
36
  static struct raw_device_data *raw_devices;
8ed965d61   Arjan van de Ven   [PATCH] sem2mutex...
37
  static DEFINE_MUTEX(raw_mutex);
62322d255   Arjan van de Ven   [PATCH] make more...
38
  static const struct file_operations raw_ctl_fops; /* forward declaration */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39

04aaca197   Masahiro Yamada   char: raw: do not...
40
  static int max_raw_minors = CONFIG_MAX_RAW_DEVS;
0078bff52   Jan Kara   Allow setting of ...
41
42
43
  
  module_param(max_raw_minors, int, 0);
  MODULE_PARM_DESC(max_raw_minors, "Maximum number of raw devices (1-65536)");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
  /*
   * Open/close code for raw IO.
   *
   * We just rewrite the i_mapping for the /dev/raw/rawN file descriptor to
   * point at the blockdev's address_space and set the file handle to use
   * O_DIRECT.
   *
   * Set the device's soft blocksize to the minimum possible.  This gives the
   * finest possible alignment and has no adverse impact on performance.
   */
  static int raw_open(struct inode *inode, struct file *filp)
  {
  	const int minor = iminor(inode);
  	struct block_device *bdev;
  	int err;
  
  	if (minor == 0) {	/* It is the control device */
  		filp->f_op = &raw_ctl_fops;
  		return 0;
  	}
c48239835   Christoph Hellwig   raw: deprecate th...
64
65
66
67
68
69
  	pr_warn_ratelimited(
  		"process %s (pid %d) is using the deprecated raw device
  "
  		"support will be removed in Linux 5.14.
  ",
  		current->comm, current->pid);
8ed965d61   Arjan van de Ven   [PATCH] sem2mutex...
70
  	mutex_lock(&raw_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
  
  	/*
  	 * All we need to do on open is check that the device is bound.
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  	err = -ENODEV;
5a56ad788   Christoph Hellwig   raw: don't keep u...
76
  	if (!raw_devices[minor].binding)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
  		goto out;
5a56ad788   Christoph Hellwig   raw: don't keep u...
78
79
80
81
  	bdev = blkdev_get_by_dev(raw_devices[minor].binding,
  				 filp->f_mode | FMODE_EXCL, raw_open);
  	if (IS_ERR(bdev)) {
  		err = PTR_ERR(bdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  		goto out;
5a56ad788   Christoph Hellwig   raw: don't keep u...
83
  	}
e1defc4ff   Martin K. Petersen   block: Do away wi...
84
  	err = set_blocksize(bdev, bdev_logical_block_size(bdev));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
  	if (err)
e525fd89d   Tejun Heo   block: make blkde...
86
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
89
  	filp->f_flags |= O_DIRECT;
  	filp->f_mapping = bdev->bd_inode->i_mapping;
  	if (++raw_devices[minor].inuse == 1)
496ad9aa8   Al Viro   new helper: file_...
90
  		file_inode(filp)->i_mapping =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
  			bdev->bd_inode->i_mapping;
  	filp->private_data = bdev;
5a56ad788   Christoph Hellwig   raw: don't keep u...
93
  	raw_devices[minor].bdev = bdev;
8ed965d61   Arjan van de Ven   [PATCH] sem2mutex...
94
  	mutex_unlock(&raw_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
  out1:
e525fd89d   Tejun Heo   block: make blkde...
97
  	blkdev_put(bdev, filp->f_mode | FMODE_EXCL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  out:
8ed965d61   Arjan van de Ven   [PATCH] sem2mutex...
99
  	mutex_unlock(&raw_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
102
103
104
105
106
107
108
109
110
  	return err;
  }
  
  /*
   * When the final fd which refers to this character-special node is closed, we
   * make its ->mapping point back at its own i_data.
   */
  static int raw_release(struct inode *inode, struct file *filp)
  {
  	const int minor= iminor(inode);
  	struct block_device *bdev;
8ed965d61   Arjan van de Ven   [PATCH] sem2mutex...
111
  	mutex_lock(&raw_mutex);
5a56ad788   Christoph Hellwig   raw: don't keep u...
112
  	bdev = raw_devices[minor].bdev;
b83ae6d42   Christoph Hellwig   fs: remove mappin...
113
  	if (--raw_devices[minor].inuse == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
  		/* Here  inode->i_mapping == bdev->bd_inode->i_mapping  */
  		inode->i_mapping = &inode->i_data;
8ed965d61   Arjan van de Ven   [PATCH] sem2mutex...
116
  	mutex_unlock(&raw_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117

e525fd89d   Tejun Heo   block: make blkde...
118
  	blkdev_put(bdev, filp->f_mode | FMODE_EXCL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
121
122
123
124
  	return 0;
  }
  
  /*
   * Forward ioctls to the underlying block device.
   */
55929332c   Arnd Bergmann   drivers: Push dow...
125
126
  static long
  raw_ioctl(struct file *filp, unsigned int command, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
  {
  	struct block_device *bdev = filp->private_data;
c4a047272   Al Viro   fix rawctl compat...
129
130
131
132
133
134
  	return blkdev_ioctl(bdev, 0, command, arg);
  }
  
  static int bind_set(int number, u64 major, u64 minor)
  {
  	dev_t dev = MKDEV(major, minor);
5a56ad788   Christoph Hellwig   raw: don't keep u...
135
  	dev_t raw = MKDEV(RAW_MAJOR, number);
c4a047272   Al Viro   fix rawctl compat...
136
137
  	struct raw_device_data *rawdev;
  	int err = 0;
0078bff52   Jan Kara   Allow setting of ...
138
  	if (number <= 0 || number >= max_raw_minors)
c4a047272   Al Viro   fix rawctl compat...
139
140
141
142
143
144
  		return -EINVAL;
  
  	if (MAJOR(dev) != major || MINOR(dev) != minor)
  		return -EINVAL;
  
  	rawdev = &raw_devices[number];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145

c4a047272   Al Viro   fix rawctl compat...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  	/*
  	 * This is like making block devices, so demand the
  	 * same capability
  	 */
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  
  	/*
  	 * For now, we don't need to check that the underlying
  	 * block device is present or not: we can do that when
  	 * the raw device is opened.  Just check that the
  	 * major/minor numbers make sense.
  	 */
  
  	if (MAJOR(dev) == 0 && dev != 0)
  		return -EINVAL;
55929332c   Arnd Bergmann   drivers: Push dow...
162

c4a047272   Al Viro   fix rawctl compat...
163
164
165
166
167
  	mutex_lock(&raw_mutex);
  	if (rawdev->inuse) {
  		mutex_unlock(&raw_mutex);
  		return -EBUSY;
  	}
5a56ad788   Christoph Hellwig   raw: don't keep u...
168
  	if (rawdev->binding)
c4a047272   Al Viro   fix rawctl compat...
169
  		module_put(THIS_MODULE);
5a56ad788   Christoph Hellwig   raw: don't keep u...
170
171
  
  	rawdev->binding = dev;
c4a047272   Al Viro   fix rawctl compat...
172
173
  	if (!dev) {
  		/* unbind */
5a56ad788   Christoph Hellwig   raw: don't keep u...
174
  		device_destroy(raw_class, raw);
c4a047272   Al Viro   fix rawctl compat...
175
  	} else {
5a56ad788   Christoph Hellwig   raw: don't keep u...
176
177
178
  		__module_get(THIS_MODULE);
  		device_destroy(raw_class, raw);
  		device_create(raw_class, NULL, raw, NULL, "raw%d", number);
c4a047272   Al Viro   fix rawctl compat...
179
180
181
  	}
  	mutex_unlock(&raw_mutex);
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
  }
c4a047272   Al Viro   fix rawctl compat...
183
  static int bind_get(int number, dev_t *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
  {
5bbb2ae3d   Paul Bolle   raw: test against...
185
  	if (number <= 0 || number >= max_raw_minors)
c4a047272   Al Viro   fix rawctl compat...
186
  		return -EINVAL;
5a56ad788   Christoph Hellwig   raw: don't keep u...
187
  	*dev = raw_devices[number].binding;
c4a047272   Al Viro   fix rawctl compat...
188
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
191
192
193
194
  }
  
  /*
   * Deal with ioctls against the raw-device control interface, to bind
   * and unbind other raw devices.
   */
55929332c   Arnd Bergmann   drivers: Push dow...
195
196
  static long raw_ctl_ioctl(struct file *filp, unsigned int command,
  			  unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
198
  {
  	struct raw_config_request rq;
c4a047272   Al Viro   fix rawctl compat...
199
200
  	dev_t dev;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
202
203
  
  	switch (command) {
  	case RAW_SETBIND:
c4a047272   Al Viro   fix rawctl compat...
204
205
206
207
  		if (copy_from_user(&rq, (void __user *) arg, sizeof(rq)))
  			return -EFAULT;
  
  		return bind_set(rq.raw_minor, rq.block_major, rq.block_minor);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
  	case RAW_GETBIND:
c4a047272   Al Viro   fix rawctl compat...
209
210
  		if (copy_from_user(&rq, (void __user *) arg, sizeof(rq)))
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211

c4a047272   Al Viro   fix rawctl compat...
212
213
214
  		err = bind_get(rq.raw_minor, &dev);
  		if (err)
  			return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215

c4a047272   Al Viro   fix rawctl compat...
216
217
  		rq.block_major = MAJOR(dev);
  		rq.block_minor = MINOR(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218

c4a047272   Al Viro   fix rawctl compat...
219
220
221
222
  		if (copy_to_user((void __user *)arg, &rq, sizeof(rq)))
  			return -EFAULT;
  
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
  	}
c4a047272   Al Viro   fix rawctl compat...
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  
  	return -EINVAL;
  }
  
  #ifdef CONFIG_COMPAT
  struct raw32_config_request {
  	compat_int_t	raw_minor;
  	compat_u64	block_major;
  	compat_u64	block_minor;
  };
  
  static long raw_ctl_compat_ioctl(struct file *file, unsigned int cmd,
  				unsigned long arg)
  {
  	struct raw32_config_request __user *user_req = compat_ptr(arg);
  	struct raw32_config_request rq;
  	dev_t dev;
  	int err = 0;
  
  	switch (cmd) {
  	case RAW_SETBIND:
  		if (copy_from_user(&rq, user_req, sizeof(rq)))
  			return -EFAULT;
  
  		return bind_set(rq.raw_minor, rq.block_major, rq.block_minor);
  
  	case RAW_GETBIND:
  		if (copy_from_user(&rq, user_req, sizeof(rq)))
  			return -EFAULT;
  
  		err = bind_get(rq.raw_minor, &dev);
  		if (err)
  			return err;
  
  		rq.block_major = MAJOR(dev);
  		rq.block_minor = MINOR(dev);
  
  		if (copy_to_user(user_req, &rq, sizeof(rq)))
  			return -EFAULT;
  
  		return 0;
  	}
  
  	return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  }
c4a047272   Al Viro   fix rawctl compat...
269
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270

62322d255   Arjan van de Ven   [PATCH] make more...
271
  static const struct file_operations raw_fops = {
b2de525f0   David Jeffery   Return short read...
272
  	.read_iter	= blkdev_read_iter,
1456c0a87   Al Viro   blkdev_aio_write(...
273
  	.write_iter	= blkdev_write_iter,
55929332c   Arnd Bergmann   drivers: Push dow...
274
275
276
277
  	.fsync		= blkdev_fsync,
  	.open		= raw_open,
  	.release	= raw_release,
  	.unlocked_ioctl = raw_ioctl,
cb3b9cf81   Arnd Bergmann   raw: use explicit...
278
  	.llseek		= default_llseek,
55929332c   Arnd Bergmann   drivers: Push dow...
279
  	.owner		= THIS_MODULE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
  };
62322d255   Arjan van de Ven   [PATCH] make more...
281
  static const struct file_operations raw_ctl_fops = {
55929332c   Arnd Bergmann   drivers: Push dow...
282
  	.unlocked_ioctl = raw_ctl_ioctl,
c4a047272   Al Viro   fix rawctl compat...
283
284
285
  #ifdef CONFIG_COMPAT
  	.compat_ioctl	= raw_ctl_compat_ioctl,
  #endif
55929332c   Arnd Bergmann   drivers: Push dow...
286
287
  	.open		= raw_open,
  	.owner		= THIS_MODULE,
cb3b9cf81   Arnd Bergmann   raw: use explicit...
288
  	.llseek		= noop_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
  };
7e7654a92   Greg Kroah-Hartman   cdev: remove unne...
290
  static struct cdev raw_cdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291

2c9ede55e   Al Viro   switch device_get...
292
  static char *raw_devnode(struct device *dev, umode_t *mode)
6fd469337   Kay Sievers   Driver Core: raw:...
293
294
295
  {
  	return kasprintf(GFP_KERNEL, "raw/%s", dev_name(dev));
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
  static int __init raw_init(void)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
  	dev_t dev = MKDEV(RAW_MAJOR, 0);
3e26a423e   Rolf Eike Beer   [PATCH] Return be...
299
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300

0078bff52   Jan Kara   Allow setting of ...
301
  	if (max_raw_minors < 1 || max_raw_minors > 65536) {
04aaca197   Masahiro Yamada   char: raw: do not...
302
303
304
305
  		pr_warn("raw: invalid max_raw_minors (must be between 1 and 65536), using %d
  ",
  			CONFIG_MAX_RAW_DEVS);
  		max_raw_minors = CONFIG_MAX_RAW_DEVS;
0078bff52   Jan Kara   Allow setting of ...
306
  	}
fad953ce0   Kees Cook   treewide: Use arr...
307
308
  	raw_devices = vzalloc(array_size(max_raw_minors,
  					 sizeof(struct raw_device_data)));
0078bff52   Jan Kara   Allow setting of ...
309
310
311
312
313
314
  	if (!raw_devices) {
  		printk(KERN_ERR "Not enough memory for raw device structures
  ");
  		ret = -ENOMEM;
  		goto error;
  	}
0078bff52   Jan Kara   Allow setting of ...
315
316
  
  	ret = register_chrdev_region(dev, max_raw_minors, "raw");
3e26a423e   Rolf Eike Beer   [PATCH] Return be...
317
  	if (ret)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
  		goto error;
  
  	cdev_init(&raw_cdev, &raw_fops);
0078bff52   Jan Kara   Allow setting of ...
321
  	ret = cdev_add(&raw_cdev, dev, max_raw_minors);
202cdb6f8   Bhumika Goyal   drivers: char: ra...
322
  	if (ret)
3e26a423e   Rolf Eike Beer   [PATCH] Return be...
323
  		goto error_region;
ca8eca688   Greg Kroah-Hartman   [PATCH] class: co...
324
  	raw_class = class_create(THIS_MODULE, "raw");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
326
327
328
  	if (IS_ERR(raw_class)) {
  		printk(KERN_ERR "Error creating raw class.
  ");
  		cdev_del(&raw_cdev);
3e26a423e   Rolf Eike Beer   [PATCH] Return be...
329
330
  		ret = PTR_ERR(raw_class);
  		goto error_region;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
  	}
e454cea20   Kay Sievers   Driver-Core: exte...
332
  	raw_class->devnode = raw_devnode;
03457cd45   Greg Kroah-Hartman   device create: ch...
333
  	device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
  	return 0;
3e26a423e   Rolf Eike Beer   [PATCH] Return be...
336
  error_region:
0078bff52   Jan Kara   Allow setting of ...
337
  	unregister_chrdev_region(dev, max_raw_minors);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
  error:
0078bff52   Jan Kara   Allow setting of ...
339
  	vfree(raw_devices);
3e26a423e   Rolf Eike Beer   [PATCH] Return be...
340
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
343
344
  }
  
  static void __exit raw_exit(void)
  {
38ca6c34d   Greg Kroah-Hartman   Driver core: conv...
345
  	device_destroy(raw_class, MKDEV(RAW_MAJOR, 0));
ca8eca688   Greg Kroah-Hartman   [PATCH] class: co...
346
  	class_destroy(raw_class);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
  	cdev_del(&raw_cdev);
0078bff52   Jan Kara   Allow setting of ...
348
  	unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), max_raw_minors);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
351
352
353
  }
  
  module_init(raw_init);
  module_exit(raw_exit);
  MODULE_LICENSE("GPL");