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); |