Gentoo Archives: gentoo-commits

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