Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 458426
Collapse All | Expand All

(-)a/drivers/char/Kconfig (+2 lines)
Lines 6-11 menu "Character devices" Link Here
6
6
7
source "drivers/tty/Kconfig"
7
source "drivers/tty/Kconfig"
8
8
9
source "drivers/char/kcopy/Kconfig"
10
9
config DEVKMEM
11
config DEVKMEM
10
	bool "/dev/kmem virtual device support"
12
	bool "/dev/kmem virtual device support"
11
	default y
13
	default y
(-)a/drivers/char/Makefile (+2 lines)
Lines 64-66 obj-$(CONFIG_JS_RTC) += js-rtc.o Link Here
64
js-rtc-y = rtc.o
64
js-rtc-y = rtc.o
65
65
66
obj-$(CONFIG_TILE_SROM)		+= tile-srom.o
66
obj-$(CONFIG_TILE_SROM)		+= tile-srom.o
67
68
obj-$(CONFIG_KCOPY)		+= kcopy/
(-)a/drivers/char/kcopy/Kconfig (+17 lines)
Line 0 Link Here
1
#
2
# KCopy character device configuration
3
#
4
5
menu "KCopy"
6
7
config KCOPY
8
	tristate "Memory-to-memory copies using kernel assist"
9
	default m
10
	---help---
11
	  High-performance inter-process memory copies.  Can often save a
12
	  memory copy to shared memory in the application.   Useful at least
13
	  for MPI applications where the point-to-point nature of vmsplice
14
	  and pipes can be a limiting factor in performance.
15
16
endmenu
17
(-)a/drivers/char/kcopy/Makefile (+4 lines)
Line 0 Link Here
1
#
2
# Makefile for the kernel character device drivers.
3
#
4
obj-$(CONFIG_KCOPY)	+= kcopy.o
(-)a/drivers/char/kcopy/kcopy.c (-1 / +646 lines)
Line 0 Link Here
0
- 
1
#include <linux/module.h>
2
#include <linux/fs.h>
3
#include <linux/cdev.h>
4
#include <linux/device.h>
5
#include <linux/mutex.h>
6
#include <linux/mman.h>
7
#include <linux/highmem.h>
8
#include <linux/spinlock.h>
9
#include <linux/sched.h>
10
#include <linux/rbtree.h>
11
#include <linux/rcupdate.h>
12
#include <linux/uaccess.h>
13
#include <linux/slab.h>
14
15
MODULE_LICENSE("GPL");
16
MODULE_AUTHOR("Arthur Jones <arthur.jones@qlogic.com>");
17
MODULE_DESCRIPTION("QLogic kcopy driver");
18
19
#define KCOPY_ABI		1
20
#define KCOPY_MAX_MINORS	64
21
22
struct kcopy_device {
23
	struct cdev cdev;
24
	struct class *class;
25
	struct device *devp[KCOPY_MAX_MINORS];
26
	dev_t dev;
27
28
	struct kcopy_file *kf[KCOPY_MAX_MINORS];
29
	struct mutex open_lock;
30
};
31
32
static struct kcopy_device kcopy_dev;
33
34
/* per file data / one of these is shared per minor */
35
struct kcopy_file {
36
	int count;
37
38
	/* pid indexed */
39
	struct rb_root live_map_tree;
40
41
	struct mutex map_lock;
42
};
43
44
struct kcopy_map_entry {
45
	int    count;
46
	struct task_struct *task;
47
	pid_t  pid;
48
	struct kcopy_file *file; /* file backpointer */
49
50
	struct list_head list; /* free map list */
51
	struct rb_node   node; /* live map tree */
52
};
53
54
#define KCOPY_GET_SYSCALL 1
55
#define KCOPY_PUT_SYSCALL 2
56
#define KCOPY_ABI_SYSCALL 3
57
58
struct kcopy_syscall {
59
	__u32 tag;
60
	pid_t pid;
61
	__u64 n;
62
	__u64 src;
63
	__u64 dst;
64
};
65
66
static const void __user *kcopy_syscall_src(const struct kcopy_syscall *ks)
67
{
68
	return (const void __user *) (unsigned long) ks->src;
69
}
70
71
static void __user *kcopy_syscall_dst(const struct kcopy_syscall *ks)
72
{
73
	return (void __user *) (unsigned long) ks->dst;
74
}
75
76
static unsigned long kcopy_syscall_n(const struct kcopy_syscall *ks)
77
{
78
	return (unsigned long) ks->n;
79
}
80
81
static struct kcopy_map_entry *kcopy_create_entry(struct kcopy_file *file)
82
{
83
	struct kcopy_map_entry *kme =
84
		kmalloc(sizeof(struct kcopy_map_entry), GFP_KERNEL);
85
86
	if (!kme)
87
		return NULL;
88
89
	kme->count = 1;
90
	kme->file = file;
91
	kme->task = current;
92
	kme->pid = current->tgid;
93
	INIT_LIST_HEAD(&kme->list);
94
95
	return kme;
96
}
97
98
static struct kcopy_map_entry *
99
kcopy_lookup_pid(struct rb_root *root, pid_t pid)
100
{
101
	struct rb_node *node = root->rb_node;
102
103
	while (node) {
104
		struct kcopy_map_entry *kme =
105
			container_of(node, struct kcopy_map_entry, node);
106
107
		if (pid < kme->pid)
108
			node = node->rb_left;
109
		else if (pid > kme->pid)
110
			node = node->rb_right;
111
		else
112
			return kme;
113
	}
114
115
	return NULL;
116
}
117
118
static int kcopy_insert(struct rb_root *root, struct kcopy_map_entry *kme)
119
{
120
	struct rb_node **new = &(root->rb_node);
121
	struct rb_node *parent = NULL;
122
123
	while (*new) {
124
		struct kcopy_map_entry *tkme =
125
			container_of(*new, struct kcopy_map_entry, node);
126
127
		parent = *new;
128
		if (kme->pid < tkme->pid)
129
			new = &((*new)->rb_left);
130
		else if (kme->pid > tkme->pid)
131
			new = &((*new)->rb_right);
132
		else {
133
			printk(KERN_INFO "!!! debugging: bad rb tree !!!\n");
134
			return -EINVAL;
135
		}
136
	}
137
138
	rb_link_node(&kme->node, parent, new);
139
	rb_insert_color(&kme->node, root);
140
141
	return 0;
142
}
143
144
static int kcopy_open(struct inode *inode, struct file *filp)
145
{
146
	int ret;
147
	const int minor = iminor(inode);
148
	struct kcopy_file *kf = NULL;
149
	struct kcopy_map_entry *kme;
150
	struct kcopy_map_entry *okme;
151
152
	if (minor < 0 || minor >= KCOPY_MAX_MINORS)
153
		return -ENODEV;
154
155
	mutex_lock(&kcopy_dev.open_lock);
156
157
	if (!kcopy_dev.kf[minor]) {
158
		kf = kmalloc(sizeof(struct kcopy_file), GFP_KERNEL);
159
160
		if (!kf) {
161
			ret = -ENOMEM;
162
			goto bail;
163
		}
164
165
		kf->count = 1;
166
		kf->live_map_tree = RB_ROOT;
167
		mutex_init(&kf->map_lock);
168
		kcopy_dev.kf[minor] = kf;
169
	} else {
170
		if (filp->f_flags & O_EXCL) {
171
			ret = -EBUSY;
172
			goto bail;
173
		}
174
		kcopy_dev.kf[minor]->count++;
175
	}
176
177
	kme = kcopy_create_entry(kcopy_dev.kf[minor]);
178
	if (!kme) {
179
		ret = -ENOMEM;
180
		goto err_free_kf;
181
	}
182
183
	kf = kcopy_dev.kf[minor];
184
185
	mutex_lock(&kf->map_lock);
186
187
	okme = kcopy_lookup_pid(&kf->live_map_tree, kme->pid);
188
	if (okme) {
189
		/* pid already exists... */
190
		okme->count++;
191
		kfree(kme);
192
		kme = okme;
193
	} else
194
		ret = kcopy_insert(&kf->live_map_tree, kme);
195
196
	mutex_unlock(&kf->map_lock);
197
198
	filp->private_data = kme;
199
200
	ret = 0;
201
	goto bail;
202
203
err_free_kf:
204
	if (kf) {
205
		kcopy_dev.kf[minor] = NULL;
206
		kfree(kf);
207
	}
208
bail:
209
	mutex_unlock(&kcopy_dev.open_lock);
210
	return ret;
211
}
212
213
static int kcopy_flush(struct file *filp, fl_owner_t id)
214
{
215
	struct kcopy_map_entry *kme = filp->private_data;
216
	struct kcopy_file *kf = kme->file;
217
218
	if (file_count(filp) == 1) {
219
		mutex_lock(&kf->map_lock);
220
		kme->count--;
221
222
		if (!kme->count) {
223
			rb_erase(&kme->node, &kf->live_map_tree);
224
			kfree(kme);
225
		}
226
		mutex_unlock(&kf->map_lock);
227
	}
228
229
	return 0;
230
}
231
232
static int kcopy_release(struct inode *inode, struct file *filp)
233
{
234
	const int minor = iminor(inode);
235
236
	mutex_lock(&kcopy_dev.open_lock);
237
	kcopy_dev.kf[minor]->count--;
238
	if (!kcopy_dev.kf[minor]->count) {
239
		kfree(kcopy_dev.kf[minor]);
240
		kcopy_dev.kf[minor] = NULL;
241
	}
242
	mutex_unlock(&kcopy_dev.open_lock);
243
244
	return 0;
245
}
246
247
static void kcopy_put_pages(struct page **pages, int npages)
248
{
249
	int j;
250
251
	for (j = 0; j < npages; j++)
252
		put_page(pages[j]);
253
}
254
255
static int kcopy_validate_task(struct task_struct *p)
256
{
257
	return p && (uid_eq(current_euid(), task_euid(p)) || uid_eq(current_euid(), task_uid(p)));
258
}
259
260
static int kcopy_get_pages(struct kcopy_file *kf, pid_t pid,
261
			   struct page **pages, void __user *addr,
262
			   int write, size_t npages)
263
{
264
	int err;
265
	struct mm_struct *mm;
266
	struct kcopy_map_entry *rkme;
267
268
	mutex_lock(&kf->map_lock);
269
270
	rkme = kcopy_lookup_pid(&kf->live_map_tree, pid);
271
	if (!rkme || !kcopy_validate_task(rkme->task)) {
272
		err = -EINVAL;
273
		goto bail_unlock;
274
	}
275
276
	mm = get_task_mm(rkme->task);
277
	if (unlikely(!mm)) {
278
		err = -ENOMEM;
279
		goto bail_unlock;
280
	}
281
282
	down_read(&mm->mmap_sem);
283
	err = get_user_pages(rkme->task, mm,
284
			     (unsigned long) addr, npages, write, 0,
285
			     pages, NULL);
286
287
	if (err < npages && err > 0) {
288
		kcopy_put_pages(pages, err);
289
		err = -ENOMEM;
290
	} else if (err == npages)
291
		err = 0;
292
293
	up_read(&mm->mmap_sem);
294
295
	mmput(mm);
296
297
bail_unlock:
298
	mutex_unlock(&kf->map_lock);
299
300
	return err;
301
}
302
303
static unsigned long kcopy_copy_pages_from_user(void __user *src,
304
						struct page **dpages,
305
						unsigned doff,
306
						unsigned long n)
307
{
308
	struct page *dpage = *dpages;
309
	char *daddr = kmap(dpage);
310
	int ret = 0;
311
312
	while (1) {
313
		const unsigned long nleft = PAGE_SIZE - doff;
314
		const unsigned long nc = (n < nleft) ? n : nleft;
315
316
		/* if (copy_from_user(daddr + doff, src, nc)) { */
317
		if (__copy_from_user_nocache(daddr + doff, src, nc)) {
318
			ret = -EFAULT;
319
			goto bail;
320
		}
321
322
		n -= nc;
323
		if (n == 0)
324
			break;
325
326
		doff += nc;
327
		doff &= ~PAGE_MASK;
328
		if (doff == 0) {
329
			kunmap(dpage);
330
			dpages++;
331
			dpage = *dpages;
332
			daddr = kmap(dpage);
333
		}
334
335
		src += nc;
336
	}
337
338
bail:
339
	kunmap(dpage);
340
341
	return ret;
342
}
343
344
static unsigned long kcopy_copy_pages_to_user(void __user *dst,
345
					      struct page **spages,
346
					      unsigned soff,
347
					      unsigned long n)
348
{
349
	struct page *spage = *spages;
350
	const char *saddr = kmap(spage);
351
	int ret = 0;
352
353
	while (1) {
354
		const unsigned long nleft = PAGE_SIZE - soff;
355
		const unsigned long nc = (n < nleft) ? n : nleft;
356
357
		if (copy_to_user(dst, saddr + soff, nc)) {
358
			ret = -EFAULT;
359
			goto bail;
360
		}
361
362
		n -= nc;
363
		if (n == 0)
364
			break;
365
366
		soff += nc;
367
		soff &= ~PAGE_MASK;
368
		if (soff == 0) {
369
			kunmap(spage);
370
			spages++;
371
			spage = *spages;
372
			saddr = kmap(spage);
373
		}
374
375
		dst += nc;
376
	}
377
378
bail:
379
	kunmap(spage);
380
381
	return ret;
382
}
383
384
static unsigned long kcopy_copy_to_user(void __user *dst,
385
					struct kcopy_file *kf, pid_t pid,
386
					void __user *src,
387
					unsigned long n)
388
{
389
	struct page **pages;
390
	const int pages_len = PAGE_SIZE / sizeof(struct page *);
391
	int ret = 0;
392
393
	pages = (struct page **) __get_free_page(GFP_KERNEL);
394
	if (!pages) {
395
		ret = -ENOMEM;
396
		goto bail;
397
	}
398
399
	while (n) {
400
		const unsigned long soff = (unsigned long) src & ~PAGE_MASK;
401
		const unsigned long spages_left =
402
			(soff + n + PAGE_SIZE - 1) >> PAGE_SHIFT;
403
		const unsigned long spages_cp =
404
			min_t(unsigned long, spages_left, pages_len);
405
		const unsigned long sbytes =
406
			PAGE_SIZE - soff + (spages_cp - 1) * PAGE_SIZE;
407
		const unsigned long nbytes = min_t(unsigned long, sbytes, n);
408
409
		ret = kcopy_get_pages(kf, pid, pages, src, 0, spages_cp);
410
		if (unlikely(ret))
411
			goto bail_free;
412
413
		ret = kcopy_copy_pages_to_user(dst, pages, soff, nbytes);
414
		kcopy_put_pages(pages, spages_cp);
415
		if (ret)
416
			goto bail_free;
417
		dst = (char *) dst + nbytes;
418
		src = (char *) src + nbytes;
419
420
		n -= nbytes;
421
	}
422
423
bail_free:
424
	free_page((unsigned long) pages);
425
bail:
426
	return ret;
427
}
428
429
static unsigned long kcopy_copy_from_user(const void __user *src,
430
					  struct kcopy_file *kf, pid_t pid,
431
					  void __user *dst,
432
					  unsigned long n)
433
{
434
	struct page **pages;
435
	const int pages_len = PAGE_SIZE / sizeof(struct page *);
436
	int ret = 0;
437
438
	pages = (struct page **) __get_free_page(GFP_KERNEL);
439
	if (!pages) {
440
		ret = -ENOMEM;
441
		goto bail;
442
	}
443
444
	while (n) {
445
		const unsigned long doff = (unsigned long) dst & ~PAGE_MASK;
446
		const unsigned long dpages_left =
447
			(doff + n + PAGE_SIZE - 1) >> PAGE_SHIFT;
448
		const unsigned long dpages_cp =
449
			min_t(unsigned long, dpages_left, pages_len);
450
		const unsigned long dbytes =
451
			PAGE_SIZE - doff + (dpages_cp - 1) * PAGE_SIZE;
452
		const unsigned long nbytes = min_t(unsigned long, dbytes, n);
453
454
		ret = kcopy_get_pages(kf, pid, pages, dst, 1, dpages_cp);
455
		if (unlikely(ret))
456
			goto bail_free;
457
458
		ret = kcopy_copy_pages_from_user((void __user *) src,
459
						 pages, doff, nbytes);
460
		kcopy_put_pages(pages, dpages_cp);
461
		if (ret)
462
			goto bail_free;
463
464
		dst = (char *) dst + nbytes;
465
		src = (char *) src + nbytes;
466
467
		n -= nbytes;
468
	}
469
470
bail_free:
471
	free_page((unsigned long) pages);
472
bail:
473
	return ret;
474
}
475
476
static int kcopy_do_get(struct kcopy_map_entry *kme, pid_t pid,
477
			const void __user *src, void __user *dst,
478
			unsigned long n)
479
{
480
	struct kcopy_file *kf = kme->file;
481
	int ret = 0;
482
483
	if (n == 0) {
484
		ret = -EINVAL;
485
		goto bail;
486
	}
487
488
	ret = kcopy_copy_to_user(dst, kf, pid, (void __user *) src, n);
489
490
bail:
491
	return ret;
492
}
493
494
static int kcopy_do_put(struct kcopy_map_entry *kme, const void __user *src,
495
			pid_t pid, void __user *dst,
496
			unsigned long n)
497
{
498
	struct kcopy_file *kf = kme->file;
499
	int ret = 0;
500
501
	if (n == 0) {
502
		ret = -EINVAL;
503
		goto bail;
504
	}
505
506
	ret = kcopy_copy_from_user(src, kf, pid, (void __user *) dst, n);
507
508
bail:
509
	return ret;
510
}
511
512
static int kcopy_do_abi(u32 __user *dst)
513
{
514
	u32 val = KCOPY_ABI;
515
	int err;
516
517
	err = put_user(val, dst);
518
	if (err)
519
		return -EFAULT;
520
521
	return 0;
522
}
523
524
ssize_t kcopy_write(struct file *filp, const char __user *data, size_t cnt,
525
		    loff_t *o)
526
{
527
	struct kcopy_map_entry *kme = filp->private_data;
528
	struct kcopy_syscall ks;
529
	int err = 0;
530
	const void __user *src;
531
	void __user *dst;
532
	unsigned long n;
533
534
	if (cnt != sizeof(struct kcopy_syscall)) {
535
		err = -EINVAL;
536
		goto bail;
537
	}
538
539
	err = copy_from_user(&ks, data, cnt);
540
	if (unlikely(err))
541
		goto bail;
542
543
	src = kcopy_syscall_src(&ks);
544
	dst = kcopy_syscall_dst(&ks);
545
	n = kcopy_syscall_n(&ks);
546
	if (ks.tag == KCOPY_GET_SYSCALL)
547
		err = kcopy_do_get(kme, ks.pid, src, dst, n);
548
	else if (ks.tag == KCOPY_PUT_SYSCALL)
549
		err = kcopy_do_put(kme, src, ks.pid, dst, n);
550
	else if (ks.tag == KCOPY_ABI_SYSCALL)
551
		err = kcopy_do_abi(dst);
552
	else
553
		err = -EINVAL;
554
555
bail:
556
	return err ? err : cnt;
557
}
558
559
static const struct file_operations kcopy_fops = {
560
	.owner = THIS_MODULE,
561
	.open = kcopy_open,
562
	.release = kcopy_release,
563
	.flush = kcopy_flush,
564
	.write = kcopy_write,
565
};
566
567
static int __init kcopy_init(void)
568
{
569
	int ret;
570
	const char *name = "kcopy";
571
	int i;
572
	int ninit = 0;
573
574
	mutex_init(&kcopy_dev.open_lock);
575
576
	ret = alloc_chrdev_region(&kcopy_dev.dev, 0, KCOPY_MAX_MINORS, name);
577
	if (ret)
578
		goto bail;
579
580
	kcopy_dev.class = class_create(THIS_MODULE, (char *) name);
581
582
	if (IS_ERR(kcopy_dev.class)) {
583
		ret = PTR_ERR(kcopy_dev.class);
584
		printk(KERN_ERR "kcopy: Could not create "
585
			"device class (err %d)\n", -ret);
586
		goto bail_chrdev;
587
	}
588
589
	cdev_init(&kcopy_dev.cdev, &kcopy_fops);
590
	ret = cdev_add(&kcopy_dev.cdev, kcopy_dev.dev, KCOPY_MAX_MINORS);
591
	if (ret < 0) {
592
		printk(KERN_ERR "kcopy: Could not add cdev (err %d)\n",
593
			       -ret);
594
		goto bail_class;
595
	}
596
597
	for (i = 0; i < KCOPY_MAX_MINORS; i++) {
598
		char devname[8];
599
		const int minor = MINOR(kcopy_dev.dev) + i;
600
		const dev_t dev = MKDEV(MAJOR(kcopy_dev.dev), minor);
601
602
		snprintf(devname, sizeof(devname), "kcopy%02d", i);
603
		kcopy_dev.devp[i] =
604
			device_create(kcopy_dev.class, NULL,
605
				dev, NULL, devname);
606
607
		if (IS_ERR(kcopy_dev.devp[i])) {
608
			ret = PTR_ERR(kcopy_dev.devp[i]);
609
			printk(KERN_ERR "kcopy: Could not create "
610
			       "devp %d (err %d)\n", i, -ret);
611
			goto bail_cdev_add;
612
		}
613
614
		ninit++;
615
	}
616
617
	ret = 0;
618
	goto bail;
619
620
bail_cdev_add:
621
	for (i = 0; i < ninit; i++)
622
		device_unregister(kcopy_dev.devp[i]);
623
624
	cdev_del(&kcopy_dev.cdev);
625
bail_class:
626
	class_destroy(kcopy_dev.class);
627
bail_chrdev:
628
	unregister_chrdev_region(kcopy_dev.dev, KCOPY_MAX_MINORS);
629
bail:
630
	return ret;
631
}
632
633
static void __exit kcopy_fini(void)
634
{
635
	int i;
636
637
	for (i = 0; i < KCOPY_MAX_MINORS; i++)
638
		device_unregister(kcopy_dev.devp[i]);
639
640
	cdev_del(&kcopy_dev.cdev);
641
	class_destroy(kcopy_dev.class);
642
	unregister_chrdev_region(kcopy_dev.dev, KCOPY_MAX_MINORS);
643
}
644
645
module_init(kcopy_init);
646
module_exit(kcopy_fini);

Return to bug 458426