blob: aa14c37d0216a6d098fecf115eb1e2182e858379 [file] [log] [blame]
Mike Marshall274dcf52015-07-17 10:38:13 -04001/*
2 * (C) 2001 Clemson University and The University of Chicago
3 *
4 * See COPYING in top-level directory.
5 */
6#include "protocol.h"
7#include "pvfs2-kernel.h"
8#include "pvfs2-bufmap.h"
9
10DECLARE_WAIT_QUEUE_HEAD(pvfs2_bufmap_init_waitq);
11
12struct pvfs2_bufmap {
13 atomic_t refcnt;
14
15 int desc_size;
16 int desc_shift;
17 int desc_count;
18 int total_size;
19 int page_count;
20
21 struct page **page_array;
22 struct pvfs_bufmap_desc *desc_array;
23
24 /* array to track usage of buffer descriptors */
25 int *buffer_index_array;
26 spinlock_t buffer_index_lock;
27
28 /* array to track usage of buffer descriptors for readdir */
29 int readdir_index_array[PVFS2_READDIR_DEFAULT_DESC_COUNT];
30 spinlock_t readdir_index_lock;
31} *__pvfs2_bufmap;
32
33static DEFINE_SPINLOCK(pvfs2_bufmap_lock);
34
35static void
36pvfs2_bufmap_unmap(struct pvfs2_bufmap *bufmap)
37{
38 int i;
39
40 for (i = 0; i < bufmap->page_count; i++)
41 page_cache_release(bufmap->page_array[i]);
42}
43
44static void
45pvfs2_bufmap_free(struct pvfs2_bufmap *bufmap)
46{
47 kfree(bufmap->page_array);
48 kfree(bufmap->desc_array);
49 kfree(bufmap->buffer_index_array);
50 kfree(bufmap);
51}
52
53struct pvfs2_bufmap *pvfs2_bufmap_ref(void)
54{
55 struct pvfs2_bufmap *bufmap = NULL;
56
57 spin_lock(&pvfs2_bufmap_lock);
58 if (__pvfs2_bufmap) {
59 bufmap = __pvfs2_bufmap;
60 atomic_inc(&bufmap->refcnt);
61 }
62 spin_unlock(&pvfs2_bufmap_lock);
63 return bufmap;
64}
65
66void pvfs2_bufmap_unref(struct pvfs2_bufmap *bufmap)
67{
68 if (atomic_dec_and_lock(&bufmap->refcnt, &pvfs2_bufmap_lock)) {
69 __pvfs2_bufmap = NULL;
70 spin_unlock(&pvfs2_bufmap_lock);
71
72 pvfs2_bufmap_unmap(bufmap);
73 pvfs2_bufmap_free(bufmap);
74 }
75}
76
77inline int pvfs_bufmap_size_query(void)
78{
79 struct pvfs2_bufmap *bufmap = pvfs2_bufmap_ref();
80 int size = bufmap ? bufmap->desc_size : 0;
81
82 pvfs2_bufmap_unref(bufmap);
83 return size;
84}
85
86inline int pvfs_bufmap_shift_query(void)
87{
88 struct pvfs2_bufmap *bufmap = pvfs2_bufmap_ref();
89 int shift = bufmap ? bufmap->desc_shift : 0;
90
91 pvfs2_bufmap_unref(bufmap);
92 return shift;
93}
94
95static DECLARE_WAIT_QUEUE_HEAD(bufmap_waitq);
96static DECLARE_WAIT_QUEUE_HEAD(readdir_waitq);
97
98/*
99 * get_bufmap_init
100 *
101 * If bufmap_init is 1, then the shared memory system, including the
102 * buffer_index_array, is available. Otherwise, it is not.
103 *
104 * returns the value of bufmap_init
105 */
106int get_bufmap_init(void)
107{
108 return __pvfs2_bufmap ? 1 : 0;
109}
110
111
112static struct pvfs2_bufmap *
113pvfs2_bufmap_alloc(struct PVFS_dev_map_desc *user_desc)
114{
115 struct pvfs2_bufmap *bufmap;
116
117 bufmap = kzalloc(sizeof(*bufmap), GFP_KERNEL);
118 if (!bufmap)
119 goto out;
120
121 atomic_set(&bufmap->refcnt, 1);
122 bufmap->total_size = user_desc->total_size;
123 bufmap->desc_count = user_desc->count;
124 bufmap->desc_size = user_desc->size;
125 bufmap->desc_shift = ilog2(bufmap->desc_size);
126
127 spin_lock_init(&bufmap->buffer_index_lock);
128 bufmap->buffer_index_array =
129 kcalloc(bufmap->desc_count, sizeof(int), GFP_KERNEL);
130 if (!bufmap->buffer_index_array) {
131 gossip_err("pvfs2: could not allocate %d buffer indices\n",
132 bufmap->desc_count);
133 goto out_free_bufmap;
134 }
135 spin_lock_init(&bufmap->readdir_index_lock);
136
137 bufmap->desc_array =
138 kcalloc(bufmap->desc_count, sizeof(struct pvfs_bufmap_desc),
139 GFP_KERNEL);
140 if (!bufmap->desc_array) {
141 gossip_err("pvfs2: could not allocate %d descriptors\n",
142 bufmap->desc_count);
143 goto out_free_index_array;
144 }
145
146 bufmap->page_count = bufmap->total_size / PAGE_SIZE;
147
148 /* allocate storage to track our page mappings */
149 bufmap->page_array =
150 kcalloc(bufmap->page_count, sizeof(struct page *), GFP_KERNEL);
151 if (!bufmap->page_array)
152 goto out_free_desc_array;
153
154 return bufmap;
155
156out_free_desc_array:
157 kfree(bufmap->desc_array);
158out_free_index_array:
159 kfree(bufmap->buffer_index_array);
160out_free_bufmap:
161 kfree(bufmap);
162out:
163 return NULL;
164}
165
166static int
167pvfs2_bufmap_map(struct pvfs2_bufmap *bufmap,
168 struct PVFS_dev_map_desc *user_desc)
169{
170 int pages_per_desc = bufmap->desc_size / PAGE_SIZE;
171 int offset = 0, ret, i;
172
173 /* map the pages */
174 down_write(&current->mm->mmap_sem);
175 ret = get_user_pages(current,
176 current->mm,
177 (unsigned long)user_desc->ptr,
178 bufmap->page_count,
179 1,
180 0,
181 bufmap->page_array,
182 NULL);
183 up_write(&current->mm->mmap_sem);
184
185 if (ret < 0)
186 return ret;
187
188 if (ret != bufmap->page_count) {
189 gossip_err("pvfs2 error: asked for %d pages, only got %d.\n",
190 bufmap->page_count, ret);
191
192 for (i = 0; i < ret; i++) {
193 SetPageError(bufmap->page_array[i]);
194 page_cache_release(bufmap->page_array[i]);
195 }
196 return -ENOMEM;
197 }
198
199 /*
200 * ideally we want to get kernel space pointers for each page, but
201 * we can't kmap that many pages at once if highmem is being used.
202 * so instead, we just kmap/kunmap the page address each time the
203 * kaddr is needed.
204 */
205 for (i = 0; i < bufmap->page_count; i++)
206 flush_dcache_page(bufmap->page_array[i]);
207
208 /* build a list of available descriptors */
209 for (offset = 0, i = 0; i < bufmap->desc_count; i++) {
210 bufmap->desc_array[i].page_array = &bufmap->page_array[offset];
211 bufmap->desc_array[i].array_count = pages_per_desc;
212 bufmap->desc_array[i].uaddr =
213 (user_desc->ptr + (i * pages_per_desc * PAGE_SIZE));
214 offset += pages_per_desc;
215 }
216
217 return 0;
218}
219
220/*
221 * pvfs_bufmap_initialize()
222 *
223 * initializes the mapped buffer interface
224 *
225 * returns 0 on success, -errno on failure
226 */
227int pvfs_bufmap_initialize(struct PVFS_dev_map_desc *user_desc)
228{
229 struct pvfs2_bufmap *bufmap;
230 int ret = -EINVAL;
231
232 gossip_debug(GOSSIP_BUFMAP_DEBUG,
233 "pvfs_bufmap_initialize: called (ptr ("
234 "%p) sz (%d) cnt(%d).\n",
235 user_desc->ptr,
236 user_desc->size,
237 user_desc->count);
238
239 /*
240 * sanity check alignment and size of buffer that caller wants to
241 * work with
242 */
243 if (PAGE_ALIGN((unsigned long)user_desc->ptr) !=
244 (unsigned long)user_desc->ptr) {
245 gossip_err("pvfs2 error: memory alignment (front). %p\n",
246 user_desc->ptr);
247 goto out;
248 }
249
250 if (PAGE_ALIGN(((unsigned long)user_desc->ptr + user_desc->total_size))
251 != (unsigned long)(user_desc->ptr + user_desc->total_size)) {
252 gossip_err("pvfs2 error: memory alignment (back).(%p + %d)\n",
253 user_desc->ptr,
254 user_desc->total_size);
255 goto out;
256 }
257
258 if (user_desc->total_size != (user_desc->size * user_desc->count)) {
259 gossip_err("pvfs2 error: user provided an oddly sized buffer: (%d, %d, %d)\n",
260 user_desc->total_size,
261 user_desc->size,
262 user_desc->count);
263 goto out;
264 }
265
266 if ((user_desc->size % PAGE_SIZE) != 0) {
267 gossip_err("pvfs2 error: bufmap size not page size divisible (%d).\n",
268 user_desc->size);
269 goto out;
270 }
271
272 ret = -ENOMEM;
273 bufmap = pvfs2_bufmap_alloc(user_desc);
274 if (!bufmap)
275 goto out;
276
277 ret = pvfs2_bufmap_map(bufmap, user_desc);
278 if (ret)
279 goto out_free_bufmap;
280
281
282 spin_lock(&pvfs2_bufmap_lock);
283 if (__pvfs2_bufmap) {
284 spin_unlock(&pvfs2_bufmap_lock);
285 gossip_err("pvfs2: error: bufmap already initialized.\n");
286 ret = -EALREADY;
287 goto out_unmap_bufmap;
288 }
289 __pvfs2_bufmap = bufmap;
290 spin_unlock(&pvfs2_bufmap_lock);
291
292 /*
293 * If there are operations in pvfs2_bufmap_init_waitq, wake them up.
294 * This scenario occurs when the client-core is restarted and I/O
295 * requests in the in-progress or waiting tables are restarted. I/O
296 * requests cannot be restarted until the shared memory system is
297 * completely re-initialized, so we put the I/O requests in this
298 * waitq until initialization has completed. NOTE: the I/O requests
299 * are also on a timer, so they don't wait forever just in case the
300 * client-core doesn't come back up.
301 */
302 wake_up_interruptible(&pvfs2_bufmap_init_waitq);
303
304 gossip_debug(GOSSIP_BUFMAP_DEBUG,
305 "pvfs_bufmap_initialize: exiting normally\n");
306 return 0;
307
308out_unmap_bufmap:
309 pvfs2_bufmap_unmap(bufmap);
310out_free_bufmap:
311 pvfs2_bufmap_free(bufmap);
312out:
313 return ret;
314}
315
316/*
317 * pvfs_bufmap_finalize()
318 *
319 * shuts down the mapped buffer interface and releases any resources
320 * associated with it
321 *
322 * no return value
323 */
324void pvfs_bufmap_finalize(void)
325{
326 gossip_debug(GOSSIP_BUFMAP_DEBUG, "pvfs2_bufmap_finalize: called\n");
327 BUG_ON(!__pvfs2_bufmap);
328 pvfs2_bufmap_unref(__pvfs2_bufmap);
329 gossip_debug(GOSSIP_BUFMAP_DEBUG,
330 "pvfs2_bufmap_finalize: exiting normally\n");
331}
332
333struct slot_args {
334 int slot_count;
335 int *slot_array;
336 spinlock_t *slot_lock;
337 wait_queue_head_t *slot_wq;
338};
339
340static int wait_for_a_slot(struct slot_args *slargs, int *buffer_index)
341{
342 int ret = -1;
343 int i = 0;
344 DECLARE_WAITQUEUE(my_wait, current);
345
346
347 add_wait_queue_exclusive(slargs->slot_wq, &my_wait);
348
349 while (1) {
350 set_current_state(TASK_INTERRUPTIBLE);
351
352 /*
353 * check for available desc, slot_lock is the appropriate
354 * index_lock
355 */
356 spin_lock(slargs->slot_lock);
357 for (i = 0; i < slargs->slot_count; i++)
358 if (slargs->slot_array[i] == 0) {
359 slargs->slot_array[i] = 1;
360 *buffer_index = i;
361 ret = 0;
362 break;
363 }
364 spin_unlock(slargs->slot_lock);
365
366 /* if we acquired a buffer, then break out of while */
367 if (ret == 0)
368 break;
369
370 if (!signal_pending(current)) {
371 int timeout =
372 MSECS_TO_JIFFIES(1000 * slot_timeout_secs);
373 gossip_debug(GOSSIP_BUFMAP_DEBUG,
374 "[BUFMAP]: waiting %d "
375 "seconds for a slot\n",
376 slot_timeout_secs);
377 if (!schedule_timeout(timeout)) {
378 gossip_debug(GOSSIP_BUFMAP_DEBUG,
379 "*** wait_for_a_slot timed out\n");
380 ret = -ETIMEDOUT;
381 break;
382 }
383 gossip_debug(GOSSIP_BUFMAP_DEBUG,
384 "[BUFMAP]: woken up by a slot becoming available.\n");
385 continue;
386 }
387
388 gossip_debug(GOSSIP_BUFMAP_DEBUG, "pvfs2: %s interrupted.\n",
389 __func__);
390 ret = -EINTR;
391 break;
392 }
393
394 set_current_state(TASK_RUNNING);
395 remove_wait_queue(slargs->slot_wq, &my_wait);
396 return ret;
397}
398
399static void put_back_slot(struct slot_args *slargs, int buffer_index)
400{
401 /* slot_lock is the appropriate index_lock */
402 spin_lock(slargs->slot_lock);
403 if (buffer_index < 0 || buffer_index >= slargs->slot_count) {
404 spin_unlock(slargs->slot_lock);
405 return;
406 }
407
408 /* put the desc back on the queue */
409 slargs->slot_array[buffer_index] = 0;
410 spin_unlock(slargs->slot_lock);
411
412 /* wake up anyone who may be sleeping on the queue */
413 wake_up_interruptible(slargs->slot_wq);
414}
415
416/*
417 * pvfs_bufmap_get()
418 *
419 * gets a free mapped buffer descriptor, will sleep until one becomes
420 * available if necessary
421 *
422 * returns 0 on success, -errno on failure
423 */
424int pvfs_bufmap_get(struct pvfs2_bufmap **mapp, int *buffer_index)
425{
426 struct pvfs2_bufmap *bufmap = pvfs2_bufmap_ref();
427 struct slot_args slargs;
428 int ret;
429
430 if (!bufmap) {
431 gossip_err("pvfs2: please confirm that pvfs2-client daemon is running.\n");
432 return -EIO;
433 }
434
435 slargs.slot_count = bufmap->desc_count;
436 slargs.slot_array = bufmap->buffer_index_array;
437 slargs.slot_lock = &bufmap->buffer_index_lock;
438 slargs.slot_wq = &bufmap_waitq;
439 ret = wait_for_a_slot(&slargs, buffer_index);
440 if (ret)
441 pvfs2_bufmap_unref(bufmap);
442 *mapp = bufmap;
443 return ret;
444}
445
446/*
447 * pvfs_bufmap_put()
448 *
449 * returns a mapped buffer descriptor to the collection
450 *
451 * no return value
452 */
453void pvfs_bufmap_put(struct pvfs2_bufmap *bufmap, int buffer_index)
454{
455 struct slot_args slargs;
456
457 slargs.slot_count = bufmap->desc_count;
458 slargs.slot_array = bufmap->buffer_index_array;
459 slargs.slot_lock = &bufmap->buffer_index_lock;
460 slargs.slot_wq = &bufmap_waitq;
461 put_back_slot(&slargs, buffer_index);
462 pvfs2_bufmap_unref(bufmap);
463}
464
465/*
466 * readdir_index_get()
467 *
468 * gets a free descriptor, will sleep until one becomes
469 * available if necessary.
470 * Although the readdir buffers are not mapped into kernel space
471 * we could do that at a later point of time. Regardless, these
472 * indices are used by the client-core.
473 *
474 * returns 0 on success, -errno on failure
475 */
476int readdir_index_get(struct pvfs2_bufmap **mapp, int *buffer_index)
477{
478 struct pvfs2_bufmap *bufmap = pvfs2_bufmap_ref();
479 struct slot_args slargs;
480 int ret;
481
482 if (!bufmap) {
483 gossip_err("pvfs2: please confirm that pvfs2-client daemon is running.\n");
484 return -EIO;
485 }
486
487 slargs.slot_count = PVFS2_READDIR_DEFAULT_DESC_COUNT;
488 slargs.slot_array = bufmap->readdir_index_array;
489 slargs.slot_lock = &bufmap->readdir_index_lock;
490 slargs.slot_wq = &readdir_waitq;
491 ret = wait_for_a_slot(&slargs, buffer_index);
492 if (ret)
493 pvfs2_bufmap_unref(bufmap);
494 *mapp = bufmap;
495 return ret;
496}
497
498void readdir_index_put(struct pvfs2_bufmap *bufmap, int buffer_index)
499{
500 struct slot_args slargs;
501
502 slargs.slot_count = PVFS2_READDIR_DEFAULT_DESC_COUNT;
503 slargs.slot_array = bufmap->readdir_index_array;
504 slargs.slot_lock = &bufmap->readdir_index_lock;
505 slargs.slot_wq = &readdir_waitq;
506 put_back_slot(&slargs, buffer_index);
507 pvfs2_bufmap_unref(bufmap);
508}
509
510/*
511 * pvfs_bufmap_copy_iovec_from_user()
512 *
513 * copies data from several user space address's in an iovec
514 * to a mapped buffer
515 *
516 * Note that the mapped buffer is a series of pages and therefore
517 * the copies have to be split by PAGE_SIZE bytes at a time.
518 * Note that this routine checks that summation of iov_len
519 * across all the elements of iov is equal to size.
520 *
521 * returns 0 on success, -errno on failure
522 */
523int pvfs_bufmap_copy_iovec_from_user(struct pvfs2_bufmap *bufmap,
524 int buffer_index,
525 const struct iovec *iov,
526 unsigned long nr_segs,
527 size_t size)
528{
529 size_t ret = 0;
530 size_t amt_copied = 0;
531 size_t cur_copy_size = 0;
532 unsigned int to_page_offset = 0;
533 unsigned int to_page_index = 0;
534 void *to_kaddr = NULL;
535 void __user *from_addr = NULL;
536 struct iovec *copied_iovec = NULL;
537 struct pvfs_bufmap_desc *to;
538 unsigned int seg;
539 char *tmp_printer = NULL;
540 int tmp_int = 0;
541
542 gossip_debug(GOSSIP_BUFMAP_DEBUG,
543 "pvfs_bufmap_copy_iovec_from_user: index %d, "
544 "size %zd\n",
545 buffer_index,
546 size);
547
548 to = &bufmap->desc_array[buffer_index];
549
550 /*
551 * copy the passed in iovec so that we can change some of its fields
552 */
553 copied_iovec = kmalloc_array(nr_segs,
554 sizeof(*copied_iovec),
555 PVFS2_BUFMAP_GFP_FLAGS);
556 if (copied_iovec == NULL)
557 return -ENOMEM;
558
559 memcpy(copied_iovec, iov, nr_segs * sizeof(*copied_iovec));
560 /*
561 * Go through each segment in the iovec and make sure that
562 * the summation of iov_len matches the given size.
563 */
564 for (seg = 0, amt_copied = 0; seg < nr_segs; seg++)
565 amt_copied += copied_iovec[seg].iov_len;
566 if (amt_copied != size) {
567 gossip_err(
568 "pvfs2_bufmap_copy_iovec_from_user: computed total ("
569 "%zd) is not equal to (%zd)\n",
570 amt_copied,
571 size);
572 kfree(copied_iovec);
573 return -EINVAL;
574 }
575
576 to_page_index = 0;
577 to_page_offset = 0;
578 amt_copied = 0;
579 seg = 0;
580 /*
581 * Go through each segment in the iovec and copy its
582 * buffer into the mapped buffer one page at a time though
583 */
584 while (amt_copied < size) {
585 struct iovec *iv = &copied_iovec[seg];
586 int inc_to_page_index;
587
588 if (iv->iov_len < (PAGE_SIZE - to_page_offset)) {
589 cur_copy_size =
590 PVFS_util_min(iv->iov_len, size - amt_copied);
591 seg++;
592 from_addr = iv->iov_base;
593 inc_to_page_index = 0;
594 } else if (iv->iov_len == (PAGE_SIZE - to_page_offset)) {
595 cur_copy_size =
596 PVFS_util_min(iv->iov_len, size - amt_copied);
597 seg++;
598 from_addr = iv->iov_base;
599 inc_to_page_index = 1;
600 } else {
601 cur_copy_size =
602 PVFS_util_min(PAGE_SIZE - to_page_offset,
603 size - amt_copied);
604 from_addr = iv->iov_base;
605 iv->iov_base += cur_copy_size;
606 iv->iov_len -= cur_copy_size;
607 inc_to_page_index = 1;
608 }
609 to_kaddr = pvfs2_kmap(to->page_array[to_page_index]);
610 ret =
611 copy_from_user(to_kaddr + to_page_offset,
612 from_addr,
613 cur_copy_size);
614 if (!PageReserved(to->page_array[to_page_index]))
615 SetPageDirty(to->page_array[to_page_index]);
616
617 if (!tmp_printer) {
618 tmp_printer = (char *)(to_kaddr + to_page_offset);
619 tmp_int += tmp_printer[0];
620 gossip_debug(GOSSIP_BUFMAP_DEBUG,
621 "First character (integer value) in pvfs_bufmap_copy_from_user: %d\n",
622 tmp_int);
623 }
624
625 pvfs2_kunmap(to->page_array[to_page_index]);
626 if (ret) {
627 gossip_err("Failed to copy data from user space\n");
628 kfree(copied_iovec);
629 return -EFAULT;
630 }
631
632 amt_copied += cur_copy_size;
633 if (inc_to_page_index) {
634 to_page_offset = 0;
635 to_page_index++;
636 } else {
637 to_page_offset += cur_copy_size;
638 }
639 }
640 kfree(copied_iovec);
641 return 0;
642}
643
644/*
645 * pvfs_bufmap_copy_iovec_from_kernel()
646 *
647 * copies data from several kernel space address's in an iovec
648 * to a mapped buffer
649 *
650 * Note that the mapped buffer is a series of pages and therefore
651 * the copies have to be split by PAGE_SIZE bytes at a time.
652 * Note that this routine checks that summation of iov_len
653 * across all the elements of iov is equal to size.
654 *
655 * returns 0 on success, -errno on failure
656 */
657int pvfs_bufmap_copy_iovec_from_kernel(struct pvfs2_bufmap *bufmap,
658 int buffer_index, const struct iovec *iov,
659 unsigned long nr_segs, size_t size)
660{
661 size_t amt_copied = 0;
662 size_t cur_copy_size = 0;
663 int to_page_index = 0;
664 void *to_kaddr = NULL;
665 void *from_kaddr = NULL;
666 struct iovec *copied_iovec = NULL;
667 struct pvfs_bufmap_desc *to;
668 unsigned int seg;
669 unsigned to_page_offset = 0;
670
671 gossip_debug(GOSSIP_BUFMAP_DEBUG,
672 "pvfs_bufmap_copy_iovec_from_kernel: index %d, "
673 "size %zd\n",
674 buffer_index,
675 size);
676
677 to = &bufmap->desc_array[buffer_index];
678 /*
679 * copy the passed in iovec so that we can change some of its fields
680 */
681 copied_iovec = kmalloc_array(nr_segs,
682 sizeof(*copied_iovec),
683 PVFS2_BUFMAP_GFP_FLAGS);
684 if (copied_iovec == NULL)
685 return -ENOMEM;
686
687 memcpy(copied_iovec, iov, nr_segs * sizeof(*copied_iovec));
688 /*
689 * Go through each segment in the iovec and make sure that
690 * the summation of iov_len matches the given size.
691 */
692 for (seg = 0, amt_copied = 0; seg < nr_segs; seg++)
693 amt_copied += copied_iovec[seg].iov_len;
694 if (amt_copied != size) {
695 gossip_err("pvfs2_bufmap_copy_iovec_from_kernel: computed total(%zd) is not equal to (%zd)\n",
696 amt_copied,
697 size);
698 kfree(copied_iovec);
699 return -EINVAL;
700 }
701
702 to_page_index = 0;
703 amt_copied = 0;
704 seg = 0;
705 to_page_offset = 0;
706 /*
707 * Go through each segment in the iovec and copy its
708 * buffer into the mapped buffer one page at a time though
709 */
710 while (amt_copied < size) {
711 struct iovec *iv = &copied_iovec[seg];
712 int inc_to_page_index;
713
714 if (iv->iov_len < (PAGE_SIZE - to_page_offset)) {
715 cur_copy_size =
716 PVFS_util_min(iv->iov_len, size - amt_copied);
717 seg++;
718 from_kaddr = iv->iov_base;
719 inc_to_page_index = 0;
720 } else if (iv->iov_len == (PAGE_SIZE - to_page_offset)) {
721 cur_copy_size =
722 PVFS_util_min(iv->iov_len, size - amt_copied);
723 seg++;
724 from_kaddr = iv->iov_base;
725 inc_to_page_index = 1;
726 } else {
727 cur_copy_size =
728 PVFS_util_min(PAGE_SIZE - to_page_offset,
729 size - amt_copied);
730 from_kaddr = iv->iov_base;
731 iv->iov_base += cur_copy_size;
732 iv->iov_len -= cur_copy_size;
733 inc_to_page_index = 1;
734 }
735 to_kaddr = pvfs2_kmap(to->page_array[to_page_index]);
736 memcpy(to_kaddr + to_page_offset, from_kaddr, cur_copy_size);
737 if (!PageReserved(to->page_array[to_page_index]))
738 SetPageDirty(to->page_array[to_page_index]);
739 pvfs2_kunmap(to->page_array[to_page_index]);
740 amt_copied += cur_copy_size;
741 if (inc_to_page_index) {
742 to_page_offset = 0;
743 to_page_index++;
744 } else {
745 to_page_offset += cur_copy_size;
746 }
747 }
748 kfree(copied_iovec);
749 return 0;
750}
751
752/*
753 * pvfs_bufmap_copy_to_user_iovec()
754 *
755 * copies data to several user space address's in an iovec
756 * from a mapped buffer
757 *
758 * returns 0 on success, -errno on failure
759 */
760int pvfs_bufmap_copy_to_user_iovec(struct pvfs2_bufmap *bufmap,
761 int buffer_index, const struct iovec *iov,
762 unsigned long nr_segs, size_t size)
763{
764 size_t ret = 0;
765 size_t amt_copied = 0;
766 size_t cur_copy_size = 0;
767 int from_page_index = 0;
768 void *from_kaddr = NULL;
769 void __user *to_addr = NULL;
770 struct iovec *copied_iovec = NULL;
771 struct pvfs_bufmap_desc *from;
772 unsigned int seg;
773 unsigned from_page_offset = 0;
774 char *tmp_printer = NULL;
775 int tmp_int = 0;
776
777 gossip_debug(GOSSIP_BUFMAP_DEBUG,
778 "pvfs_bufmap_copy_to_user_iovec: index %d, size %zd\n",
779 buffer_index,
780 size);
781
782 from = &bufmap->desc_array[buffer_index];
783 /*
784 * copy the passed in iovec so that we can change some of its fields
785 */
786 copied_iovec = kmalloc_array(nr_segs,
787 sizeof(*copied_iovec),
788 PVFS2_BUFMAP_GFP_FLAGS);
789 if (copied_iovec == NULL)
790 return -ENOMEM;
791
792 memcpy(copied_iovec, iov, nr_segs * sizeof(*copied_iovec));
793 /*
794 * Go through each segment in the iovec and make sure that
795 * the summation of iov_len is greater than the given size.
796 */
797 for (seg = 0, amt_copied = 0; seg < nr_segs; seg++)
798 amt_copied += copied_iovec[seg].iov_len;
799 if (amt_copied < size) {
800 gossip_err("pvfs2_bufmap_copy_to_user_iovec: computed total (%zd) is less than (%zd)\n",
801 amt_copied,
802 size);
803 kfree(copied_iovec);
804 return -EINVAL;
805 }
806
807 from_page_index = 0;
808 amt_copied = 0;
809 seg = 0;
810 from_page_offset = 0;
811 /*
812 * Go through each segment in the iovec and copy from the mapper buffer,
813 * but make sure that we do so one page at a time.
814 */
815 while (amt_copied < size) {
816 struct iovec *iv = &copied_iovec[seg];
817 int inc_from_page_index;
818
819 if (iv->iov_len < (PAGE_SIZE - from_page_offset)) {
820 cur_copy_size =
821 PVFS_util_min(iv->iov_len, size - amt_copied);
822 seg++;
823 to_addr = iv->iov_base;
824 inc_from_page_index = 0;
825 } else if (iv->iov_len == (PAGE_SIZE - from_page_offset)) {
826 cur_copy_size =
827 PVFS_util_min(iv->iov_len, size - amt_copied);
828 seg++;
829 to_addr = iv->iov_base;
830 inc_from_page_index = 1;
831 } else {
832 cur_copy_size =
833 PVFS_util_min(PAGE_SIZE - from_page_offset,
834 size - amt_copied);
835 to_addr = iv->iov_base;
836 iv->iov_base += cur_copy_size;
837 iv->iov_len -= cur_copy_size;
838 inc_from_page_index = 1;
839 }
840 from_kaddr = pvfs2_kmap(from->page_array[from_page_index]);
841 if (!tmp_printer) {
842 tmp_printer = (char *)(from_kaddr + from_page_offset);
843 tmp_int += tmp_printer[0];
844 gossip_debug(GOSSIP_BUFMAP_DEBUG,
845 "First character (integer value) in pvfs_bufmap_copy_to_user_iovec: %d\n",
846 tmp_int);
847 }
848 ret =
849 copy_to_user(to_addr,
850 from_kaddr + from_page_offset,
851 cur_copy_size);
852 pvfs2_kunmap(from->page_array[from_page_index]);
853 if (ret) {
854 gossip_err("Failed to copy data to user space\n");
855 kfree(copied_iovec);
856 return -EFAULT;
857 }
858
859 amt_copied += cur_copy_size;
860 if (inc_from_page_index) {
861 from_page_offset = 0;
862 from_page_index++;
863 } else {
864 from_page_offset += cur_copy_size;
865 }
866 }
867 kfree(copied_iovec);
868 return 0;
869}
870
871/*
872 * pvfs_bufmap_copy_to_kernel_iovec()
873 *
874 * copies data to several kernel space address's in an iovec
875 * from a mapped buffer
876 *
877 * returns 0 on success, -errno on failure
878 */
879int pvfs_bufmap_copy_to_kernel_iovec(struct pvfs2_bufmap *bufmap,
880 int buffer_index, const struct iovec *iov,
881 unsigned long nr_segs, size_t size)
882{
883 size_t amt_copied = 0;
884 size_t cur_copy_size = 0;
885 int from_page_index = 0;
886 void *from_kaddr = NULL;
887 void *to_kaddr = NULL;
888 struct iovec *copied_iovec = NULL;
889 struct pvfs_bufmap_desc *from;
890 unsigned int seg;
891 unsigned int from_page_offset = 0;
892
893 gossip_debug(GOSSIP_BUFMAP_DEBUG,
894 "pvfs_bufmap_copy_to_kernel_iovec: index %d, size %zd\n",
895 buffer_index,
896 size);
897
898 from = &bufmap->desc_array[buffer_index];
899 /*
900 * copy the passed in iovec so that we can change some of its fields
901 */
902 copied_iovec = kmalloc_array(nr_segs,
903 sizeof(*copied_iovec),
904 PVFS2_BUFMAP_GFP_FLAGS);
905 if (copied_iovec == NULL)
906 return -ENOMEM;
907
908 memcpy(copied_iovec, iov, nr_segs * sizeof(*copied_iovec));
909 /*
910 * Go through each segment in the iovec and make sure that
911 * the summation of iov_len is greater than the given size.
912 */
913 for (seg = 0, amt_copied = 0; seg < nr_segs; seg++)
914 amt_copied += copied_iovec[seg].iov_len;
915
916 if (amt_copied < size) {
917 gossip_err("pvfs2_bufmap_copy_to_kernel_iovec: computed total (%zd) is less than (%zd)\n",
918 amt_copied,
919 size);
920 kfree(copied_iovec);
921 return -EINVAL;
922 }
923
924 from_page_index = 0;
925 amt_copied = 0;
926 seg = 0;
927 from_page_offset = 0;
928 /*
929 * Go through each segment in the iovec and copy from the mapper buffer,
930 * but make sure that we do so one page at a time.
931 */
932 while (amt_copied < size) {
933 struct iovec *iv = &copied_iovec[seg];
934 int inc_from_page_index;
935
936 if (iv->iov_len < (PAGE_SIZE - from_page_offset)) {
937 cur_copy_size =
938 PVFS_util_min(iv->iov_len, size - amt_copied);
939 seg++;
940 to_kaddr = iv->iov_base;
941 inc_from_page_index = 0;
942 } else if (iv->iov_len == (PAGE_SIZE - from_page_offset)) {
943 cur_copy_size =
944 PVFS_util_min(iv->iov_len, size - amt_copied);
945 seg++;
946 to_kaddr = iv->iov_base;
947 inc_from_page_index = 1;
948 } else {
949 cur_copy_size =
950 PVFS_util_min(PAGE_SIZE - from_page_offset,
951 size - amt_copied);
952 to_kaddr = iv->iov_base;
953 iv->iov_base += cur_copy_size;
954 iv->iov_len -= cur_copy_size;
955 inc_from_page_index = 1;
956 }
957 from_kaddr = pvfs2_kmap(from->page_array[from_page_index]);
958 memcpy(to_kaddr, from_kaddr + from_page_offset, cur_copy_size);
959 pvfs2_kunmap(from->page_array[from_page_index]);
960 amt_copied += cur_copy_size;
961 if (inc_from_page_index) {
962 from_page_offset = 0;
963 from_page_index++;
964 } else {
965 from_page_offset += cur_copy_size;
966 }
967 }
968 kfree(copied_iovec);
969 return 0;
970}