Gentoo Archives: gentoo-commits

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