Commit | Line | Data |
---|---|---|
274dcf55 MM |
1 | /* |
2 | * (C) 2001 Clemson University and The University of Chicago | |
3 | * | |
4 | * See COPYING in top-level directory. | |
5 | */ | |
6 | #include "protocol.h" | |
575e9461 MM |
7 | #include "orangefs-kernel.h" |
8 | #include "orangefs-bufmap.h" | |
274dcf55 | 9 | |
8bb8aefd | 10 | DECLARE_WAIT_QUEUE_HEAD(orangefs_bufmap_init_waitq); |
274dcf55 | 11 | |
bf89f584 MB |
12 | /* used to describe mapped buffers */ |
13 | struct orangefs_bufmap_desc { | |
14 | void *uaddr; /* user space address pointer */ | |
15 | struct page **page_array; /* array of mapped pages */ | |
16 | int array_count; /* size of above arrays */ | |
17 | struct list_head list_link; | |
18 | }; | |
19 | ||
8bb8aefd | 20 | static struct orangefs_bufmap { |
274dcf55 MM |
21 | atomic_t refcnt; |
22 | ||
23 | int desc_size; | |
24 | int desc_shift; | |
25 | int desc_count; | |
26 | int total_size; | |
27 | int page_count; | |
28 | ||
29 | struct page **page_array; | |
8bb8aefd | 30 | struct orangefs_bufmap_desc *desc_array; |
274dcf55 MM |
31 | |
32 | /* array to track usage of buffer descriptors */ | |
33 | int *buffer_index_array; | |
34 | spinlock_t buffer_index_lock; | |
35 | ||
36 | /* array to track usage of buffer descriptors for readdir */ | |
8bb8aefd | 37 | int readdir_index_array[ORANGEFS_READDIR_DEFAULT_DESC_COUNT]; |
274dcf55 | 38 | spinlock_t readdir_index_lock; |
8bb8aefd | 39 | } *__orangefs_bufmap; |
274dcf55 | 40 | |
8bb8aefd | 41 | static DEFINE_SPINLOCK(orangefs_bufmap_lock); |
274dcf55 MM |
42 | |
43 | static void | |
8bb8aefd | 44 | orangefs_bufmap_unmap(struct orangefs_bufmap *bufmap) |
274dcf55 MM |
45 | { |
46 | int i; | |
47 | ||
48 | for (i = 0; i < bufmap->page_count; i++) | |
49 | page_cache_release(bufmap->page_array[i]); | |
50 | } | |
51 | ||
52 | static void | |
8bb8aefd | 53 | orangefs_bufmap_free(struct orangefs_bufmap *bufmap) |
274dcf55 MM |
54 | { |
55 | kfree(bufmap->page_array); | |
56 | kfree(bufmap->desc_array); | |
57 | kfree(bufmap->buffer_index_array); | |
58 | kfree(bufmap); | |
59 | } | |
60 | ||
bf89f584 | 61 | static struct orangefs_bufmap *orangefs_bufmap_ref(void) |
274dcf55 | 62 | { |
8bb8aefd | 63 | struct orangefs_bufmap *bufmap = NULL; |
274dcf55 | 64 | |
8bb8aefd YL |
65 | spin_lock(&orangefs_bufmap_lock); |
66 | if (__orangefs_bufmap) { | |
67 | bufmap = __orangefs_bufmap; | |
274dcf55 MM |
68 | atomic_inc(&bufmap->refcnt); |
69 | } | |
8bb8aefd | 70 | spin_unlock(&orangefs_bufmap_lock); |
274dcf55 MM |
71 | return bufmap; |
72 | } | |
73 | ||
bf89f584 | 74 | static void orangefs_bufmap_unref(struct orangefs_bufmap *bufmap) |
274dcf55 | 75 | { |
8bb8aefd YL |
76 | if (atomic_dec_and_lock(&bufmap->refcnt, &orangefs_bufmap_lock)) { |
77 | __orangefs_bufmap = NULL; | |
78 | spin_unlock(&orangefs_bufmap_lock); | |
274dcf55 | 79 | |
8bb8aefd YL |
80 | orangefs_bufmap_unmap(bufmap); |
81 | orangefs_bufmap_free(bufmap); | |
274dcf55 MM |
82 | } |
83 | } | |
84 | ||
b09d10df MB |
85 | /* |
86 | * XXX: Can the size and shift change while the caller gives up the | |
87 | * XXX: lock between calling this and doing something useful? | |
88 | */ | |
89 | ||
765a75b3 | 90 | int orangefs_bufmap_size_query(void) |
274dcf55 | 91 | { |
b09d10df MB |
92 | struct orangefs_bufmap *bufmap; |
93 | int size = 0; | |
94 | bufmap = orangefs_bufmap_ref(); | |
95 | if (bufmap) { | |
96 | size = bufmap->desc_size; | |
97 | orangefs_bufmap_unref(bufmap); | |
98 | } | |
274dcf55 MM |
99 | return size; |
100 | } | |
101 | ||
765a75b3 | 102 | int orangefs_bufmap_shift_query(void) |
274dcf55 | 103 | { |
b09d10df MB |
104 | struct orangefs_bufmap *bufmap; |
105 | int shift = 0; | |
106 | bufmap = orangefs_bufmap_ref(); | |
107 | if (bufmap) { | |
108 | shift = bufmap->desc_shift; | |
109 | orangefs_bufmap_unref(bufmap); | |
110 | } | |
274dcf55 MM |
111 | return shift; |
112 | } | |
113 | ||
114 | static DECLARE_WAIT_QUEUE_HEAD(bufmap_waitq); | |
115 | static DECLARE_WAIT_QUEUE_HEAD(readdir_waitq); | |
116 | ||
117 | /* | |
118 | * get_bufmap_init | |
119 | * | |
120 | * If bufmap_init is 1, then the shared memory system, including the | |
121 | * buffer_index_array, is available. Otherwise, it is not. | |
122 | * | |
123 | * returns the value of bufmap_init | |
124 | */ | |
125 | int get_bufmap_init(void) | |
126 | { | |
8bb8aefd | 127 | return __orangefs_bufmap ? 1 : 0; |
274dcf55 MM |
128 | } |
129 | ||
130 | ||
8bb8aefd YL |
131 | static struct orangefs_bufmap * |
132 | orangefs_bufmap_alloc(struct ORANGEFS_dev_map_desc *user_desc) | |
274dcf55 | 133 | { |
8bb8aefd | 134 | struct orangefs_bufmap *bufmap; |
274dcf55 MM |
135 | |
136 | bufmap = kzalloc(sizeof(*bufmap), GFP_KERNEL); | |
137 | if (!bufmap) | |
138 | goto out; | |
139 | ||
140 | atomic_set(&bufmap->refcnt, 1); | |
141 | bufmap->total_size = user_desc->total_size; | |
142 | bufmap->desc_count = user_desc->count; | |
143 | bufmap->desc_size = user_desc->size; | |
144 | bufmap->desc_shift = ilog2(bufmap->desc_size); | |
145 | ||
146 | spin_lock_init(&bufmap->buffer_index_lock); | |
147 | bufmap->buffer_index_array = | |
148 | kcalloc(bufmap->desc_count, sizeof(int), GFP_KERNEL); | |
149 | if (!bufmap->buffer_index_array) { | |
8bb8aefd | 150 | gossip_err("orangefs: could not allocate %d buffer indices\n", |
274dcf55 MM |
151 | bufmap->desc_count); |
152 | goto out_free_bufmap; | |
153 | } | |
154 | spin_lock_init(&bufmap->readdir_index_lock); | |
155 | ||
156 | bufmap->desc_array = | |
8bb8aefd | 157 | kcalloc(bufmap->desc_count, sizeof(struct orangefs_bufmap_desc), |
274dcf55 MM |
158 | GFP_KERNEL); |
159 | if (!bufmap->desc_array) { | |
8bb8aefd | 160 | gossip_err("orangefs: could not allocate %d descriptors\n", |
274dcf55 MM |
161 | bufmap->desc_count); |
162 | goto out_free_index_array; | |
163 | } | |
164 | ||
165 | bufmap->page_count = bufmap->total_size / PAGE_SIZE; | |
166 | ||
167 | /* allocate storage to track our page mappings */ | |
168 | bufmap->page_array = | |
169 | kcalloc(bufmap->page_count, sizeof(struct page *), GFP_KERNEL); | |
170 | if (!bufmap->page_array) | |
171 | goto out_free_desc_array; | |
172 | ||
173 | return bufmap; | |
174 | ||
175 | out_free_desc_array: | |
176 | kfree(bufmap->desc_array); | |
177 | out_free_index_array: | |
178 | kfree(bufmap->buffer_index_array); | |
179 | out_free_bufmap: | |
180 | kfree(bufmap); | |
181 | out: | |
182 | return NULL; | |
183 | } | |
184 | ||
185 | static int | |
8bb8aefd YL |
186 | orangefs_bufmap_map(struct orangefs_bufmap *bufmap, |
187 | struct ORANGEFS_dev_map_desc *user_desc) | |
274dcf55 MM |
188 | { |
189 | int pages_per_desc = bufmap->desc_size / PAGE_SIZE; | |
190 | int offset = 0, ret, i; | |
191 | ||
192 | /* map the pages */ | |
16742f2d AV |
193 | ret = get_user_pages_fast((unsigned long)user_desc->ptr, |
194 | bufmap->page_count, 1, bufmap->page_array); | |
274dcf55 MM |
195 | |
196 | if (ret < 0) | |
197 | return ret; | |
198 | ||
199 | if (ret != bufmap->page_count) { | |
8bb8aefd | 200 | gossip_err("orangefs error: asked for %d pages, only got %d.\n", |
274dcf55 MM |
201 | bufmap->page_count, ret); |
202 | ||
203 | for (i = 0; i < ret; i++) { | |
204 | SetPageError(bufmap->page_array[i]); | |
205 | page_cache_release(bufmap->page_array[i]); | |
206 | } | |
207 | return -ENOMEM; | |
208 | } | |
209 | ||
210 | /* | |
211 | * ideally we want to get kernel space pointers for each page, but | |
212 | * we can't kmap that many pages at once if highmem is being used. | |
213 | * so instead, we just kmap/kunmap the page address each time the | |
214 | * kaddr is needed. | |
215 | */ | |
216 | for (i = 0; i < bufmap->page_count; i++) | |
217 | flush_dcache_page(bufmap->page_array[i]); | |
218 | ||
219 | /* build a list of available descriptors */ | |
220 | for (offset = 0, i = 0; i < bufmap->desc_count; i++) { | |
221 | bufmap->desc_array[i].page_array = &bufmap->page_array[offset]; | |
222 | bufmap->desc_array[i].array_count = pages_per_desc; | |
223 | bufmap->desc_array[i].uaddr = | |
224 | (user_desc->ptr + (i * pages_per_desc * PAGE_SIZE)); | |
225 | offset += pages_per_desc; | |
226 | } | |
227 | ||
228 | return 0; | |
229 | } | |
230 | ||
231 | /* | |
8bb8aefd | 232 | * orangefs_bufmap_initialize() |
274dcf55 MM |
233 | * |
234 | * initializes the mapped buffer interface | |
235 | * | |
236 | * returns 0 on success, -errno on failure | |
237 | */ | |
8bb8aefd | 238 | int orangefs_bufmap_initialize(struct ORANGEFS_dev_map_desc *user_desc) |
274dcf55 | 239 | { |
8bb8aefd | 240 | struct orangefs_bufmap *bufmap; |
274dcf55 MM |
241 | int ret = -EINVAL; |
242 | ||
243 | gossip_debug(GOSSIP_BUFMAP_DEBUG, | |
8bb8aefd | 244 | "orangefs_bufmap_initialize: called (ptr (" |
274dcf55 MM |
245 | "%p) sz (%d) cnt(%d).\n", |
246 | user_desc->ptr, | |
247 | user_desc->size, | |
248 | user_desc->count); | |
249 | ||
250 | /* | |
251 | * sanity check alignment and size of buffer that caller wants to | |
252 | * work with | |
253 | */ | |
254 | if (PAGE_ALIGN((unsigned long)user_desc->ptr) != | |
255 | (unsigned long)user_desc->ptr) { | |
8bb8aefd | 256 | gossip_err("orangefs error: memory alignment (front). %p\n", |
274dcf55 MM |
257 | user_desc->ptr); |
258 | goto out; | |
259 | } | |
260 | ||
261 | if (PAGE_ALIGN(((unsigned long)user_desc->ptr + user_desc->total_size)) | |
262 | != (unsigned long)(user_desc->ptr + user_desc->total_size)) { | |
8bb8aefd | 263 | gossip_err("orangefs error: memory alignment (back).(%p + %d)\n", |
274dcf55 MM |
264 | user_desc->ptr, |
265 | user_desc->total_size); | |
266 | goto out; | |
267 | } | |
268 | ||
269 | if (user_desc->total_size != (user_desc->size * user_desc->count)) { | |
8bb8aefd | 270 | gossip_err("orangefs error: user provided an oddly sized buffer: (%d, %d, %d)\n", |
274dcf55 MM |
271 | user_desc->total_size, |
272 | user_desc->size, | |
273 | user_desc->count); | |
274 | goto out; | |
275 | } | |
276 | ||
277 | if ((user_desc->size % PAGE_SIZE) != 0) { | |
8bb8aefd | 278 | gossip_err("orangefs error: bufmap size not page size divisible (%d).\n", |
274dcf55 MM |
279 | user_desc->size); |
280 | goto out; | |
281 | } | |
282 | ||
283 | ret = -ENOMEM; | |
8bb8aefd | 284 | bufmap = orangefs_bufmap_alloc(user_desc); |
274dcf55 MM |
285 | if (!bufmap) |
286 | goto out; | |
287 | ||
8bb8aefd | 288 | ret = orangefs_bufmap_map(bufmap, user_desc); |
274dcf55 MM |
289 | if (ret) |
290 | goto out_free_bufmap; | |
291 | ||
292 | ||
8bb8aefd YL |
293 | spin_lock(&orangefs_bufmap_lock); |
294 | if (__orangefs_bufmap) { | |
295 | spin_unlock(&orangefs_bufmap_lock); | |
296 | gossip_err("orangefs: error: bufmap already initialized.\n"); | |
274dcf55 MM |
297 | ret = -EALREADY; |
298 | goto out_unmap_bufmap; | |
299 | } | |
8bb8aefd YL |
300 | __orangefs_bufmap = bufmap; |
301 | spin_unlock(&orangefs_bufmap_lock); | |
274dcf55 MM |
302 | |
303 | /* | |
8bb8aefd | 304 | * If there are operations in orangefs_bufmap_init_waitq, wake them up. |
274dcf55 MM |
305 | * This scenario occurs when the client-core is restarted and I/O |
306 | * requests in the in-progress or waiting tables are restarted. I/O | |
307 | * requests cannot be restarted until the shared memory system is | |
308 | * completely re-initialized, so we put the I/O requests in this | |
309 | * waitq until initialization has completed. NOTE: the I/O requests | |
310 | * are also on a timer, so they don't wait forever just in case the | |
311 | * client-core doesn't come back up. | |
312 | */ | |
8bb8aefd | 313 | wake_up_interruptible(&orangefs_bufmap_init_waitq); |
274dcf55 MM |
314 | |
315 | gossip_debug(GOSSIP_BUFMAP_DEBUG, | |
8bb8aefd | 316 | "orangefs_bufmap_initialize: exiting normally\n"); |
274dcf55 MM |
317 | return 0; |
318 | ||
319 | out_unmap_bufmap: | |
8bb8aefd | 320 | orangefs_bufmap_unmap(bufmap); |
274dcf55 | 321 | out_free_bufmap: |
8bb8aefd | 322 | orangefs_bufmap_free(bufmap); |
274dcf55 MM |
323 | out: |
324 | return ret; | |
325 | } | |
326 | ||
327 | /* | |
8bb8aefd | 328 | * orangefs_bufmap_finalize() |
274dcf55 MM |
329 | * |
330 | * shuts down the mapped buffer interface and releases any resources | |
331 | * associated with it | |
332 | * | |
333 | * no return value | |
334 | */ | |
8bb8aefd | 335 | void orangefs_bufmap_finalize(void) |
274dcf55 | 336 | { |
8bb8aefd YL |
337 | gossip_debug(GOSSIP_BUFMAP_DEBUG, "orangefs_bufmap_finalize: called\n"); |
338 | BUG_ON(!__orangefs_bufmap); | |
339 | orangefs_bufmap_unref(__orangefs_bufmap); | |
274dcf55 | 340 | gossip_debug(GOSSIP_BUFMAP_DEBUG, |
8bb8aefd | 341 | "orangefs_bufmap_finalize: exiting normally\n"); |
274dcf55 MM |
342 | } |
343 | ||
344 | struct slot_args { | |
345 | int slot_count; | |
346 | int *slot_array; | |
347 | spinlock_t *slot_lock; | |
348 | wait_queue_head_t *slot_wq; | |
349 | }; | |
350 | ||
351 | static int wait_for_a_slot(struct slot_args *slargs, int *buffer_index) | |
352 | { | |
353 | int ret = -1; | |
354 | int i = 0; | |
ce6c414e | 355 | DEFINE_WAIT(wait_entry); |
274dcf55 MM |
356 | |
357 | while (1) { | |
274dcf55 MM |
358 | /* |
359 | * check for available desc, slot_lock is the appropriate | |
360 | * index_lock | |
361 | */ | |
362 | spin_lock(slargs->slot_lock); | |
ce6c414e MM |
363 | prepare_to_wait_exclusive(slargs->slot_wq, |
364 | &wait_entry, | |
365 | TASK_INTERRUPTIBLE); | |
274dcf55 MM |
366 | for (i = 0; i < slargs->slot_count; i++) |
367 | if (slargs->slot_array[i] == 0) { | |
368 | slargs->slot_array[i] = 1; | |
369 | *buffer_index = i; | |
370 | ret = 0; | |
371 | break; | |
372 | } | |
373 | spin_unlock(slargs->slot_lock); | |
374 | ||
375 | /* if we acquired a buffer, then break out of while */ | |
376 | if (ret == 0) | |
377 | break; | |
378 | ||
379 | if (!signal_pending(current)) { | |
380 | int timeout = | |
381 | MSECS_TO_JIFFIES(1000 * slot_timeout_secs); | |
382 | gossip_debug(GOSSIP_BUFMAP_DEBUG, | |
383 | "[BUFMAP]: waiting %d " | |
384 | "seconds for a slot\n", | |
385 | slot_timeout_secs); | |
386 | if (!schedule_timeout(timeout)) { | |
387 | gossip_debug(GOSSIP_BUFMAP_DEBUG, | |
388 | "*** wait_for_a_slot timed out\n"); | |
389 | ret = -ETIMEDOUT; | |
390 | break; | |
391 | } | |
392 | gossip_debug(GOSSIP_BUFMAP_DEBUG, | |
393 | "[BUFMAP]: woken up by a slot becoming available.\n"); | |
394 | continue; | |
395 | } | |
396 | ||
8bb8aefd | 397 | gossip_debug(GOSSIP_BUFMAP_DEBUG, "orangefs: %s interrupted.\n", |
274dcf55 MM |
398 | __func__); |
399 | ret = -EINTR; | |
400 | break; | |
401 | } | |
402 | ||
ce6c414e MM |
403 | spin_lock(slargs->slot_lock); |
404 | finish_wait(slargs->slot_wq, &wait_entry); | |
405 | spin_unlock(slargs->slot_lock); | |
274dcf55 MM |
406 | return ret; |
407 | } | |
408 | ||
409 | static void put_back_slot(struct slot_args *slargs, int buffer_index) | |
410 | { | |
411 | /* slot_lock is the appropriate index_lock */ | |
412 | spin_lock(slargs->slot_lock); | |
413 | if (buffer_index < 0 || buffer_index >= slargs->slot_count) { | |
414 | spin_unlock(slargs->slot_lock); | |
415 | return; | |
416 | } | |
417 | ||
418 | /* put the desc back on the queue */ | |
419 | slargs->slot_array[buffer_index] = 0; | |
420 | spin_unlock(slargs->slot_lock); | |
421 | ||
422 | /* wake up anyone who may be sleeping on the queue */ | |
423 | wake_up_interruptible(slargs->slot_wq); | |
424 | } | |
425 | ||
426 | /* | |
8bb8aefd | 427 | * orangefs_bufmap_get() |
274dcf55 MM |
428 | * |
429 | * gets a free mapped buffer descriptor, will sleep until one becomes | |
430 | * available if necessary | |
431 | * | |
432 | * returns 0 on success, -errno on failure | |
433 | */ | |
8bb8aefd | 434 | int orangefs_bufmap_get(struct orangefs_bufmap **mapp, int *buffer_index) |
274dcf55 | 435 | { |
8bb8aefd | 436 | struct orangefs_bufmap *bufmap = orangefs_bufmap_ref(); |
274dcf55 MM |
437 | struct slot_args slargs; |
438 | int ret; | |
439 | ||
440 | if (!bufmap) { | |
8bb8aefd | 441 | gossip_err("orangefs: please confirm that pvfs2-client daemon is running.\n"); |
274dcf55 MM |
442 | return -EIO; |
443 | } | |
444 | ||
445 | slargs.slot_count = bufmap->desc_count; | |
446 | slargs.slot_array = bufmap->buffer_index_array; | |
447 | slargs.slot_lock = &bufmap->buffer_index_lock; | |
448 | slargs.slot_wq = &bufmap_waitq; | |
449 | ret = wait_for_a_slot(&slargs, buffer_index); | |
450 | if (ret) | |
8bb8aefd | 451 | orangefs_bufmap_unref(bufmap); |
274dcf55 MM |
452 | *mapp = bufmap; |
453 | return ret; | |
454 | } | |
455 | ||
456 | /* | |
8bb8aefd | 457 | * orangefs_bufmap_put() |
274dcf55 MM |
458 | * |
459 | * returns a mapped buffer descriptor to the collection | |
460 | * | |
461 | * no return value | |
462 | */ | |
8bb8aefd | 463 | void orangefs_bufmap_put(struct orangefs_bufmap *bufmap, int buffer_index) |
274dcf55 MM |
464 | { |
465 | struct slot_args slargs; | |
466 | ||
467 | slargs.slot_count = bufmap->desc_count; | |
468 | slargs.slot_array = bufmap->buffer_index_array; | |
469 | slargs.slot_lock = &bufmap->buffer_index_lock; | |
470 | slargs.slot_wq = &bufmap_waitq; | |
471 | put_back_slot(&slargs, buffer_index); | |
8bb8aefd | 472 | orangefs_bufmap_unref(bufmap); |
274dcf55 MM |
473 | } |
474 | ||
475 | /* | |
476 | * readdir_index_get() | |
477 | * | |
478 | * gets a free descriptor, will sleep until one becomes | |
479 | * available if necessary. | |
480 | * Although the readdir buffers are not mapped into kernel space | |
481 | * we could do that at a later point of time. Regardless, these | |
482 | * indices are used by the client-core. | |
483 | * | |
484 | * returns 0 on success, -errno on failure | |
485 | */ | |
8bb8aefd | 486 | int readdir_index_get(struct orangefs_bufmap **mapp, int *buffer_index) |
274dcf55 | 487 | { |
8bb8aefd | 488 | struct orangefs_bufmap *bufmap = orangefs_bufmap_ref(); |
274dcf55 MM |
489 | struct slot_args slargs; |
490 | int ret; | |
491 | ||
492 | if (!bufmap) { | |
8bb8aefd | 493 | gossip_err("orangefs: please confirm that pvfs2-client daemon is running.\n"); |
274dcf55 MM |
494 | return -EIO; |
495 | } | |
496 | ||
8bb8aefd | 497 | slargs.slot_count = ORANGEFS_READDIR_DEFAULT_DESC_COUNT; |
274dcf55 MM |
498 | slargs.slot_array = bufmap->readdir_index_array; |
499 | slargs.slot_lock = &bufmap->readdir_index_lock; | |
500 | slargs.slot_wq = &readdir_waitq; | |
501 | ret = wait_for_a_slot(&slargs, buffer_index); | |
502 | if (ret) | |
8bb8aefd | 503 | orangefs_bufmap_unref(bufmap); |
274dcf55 MM |
504 | *mapp = bufmap; |
505 | return ret; | |
506 | } | |
507 | ||
8bb8aefd | 508 | void readdir_index_put(struct orangefs_bufmap *bufmap, int buffer_index) |
274dcf55 MM |
509 | { |
510 | struct slot_args slargs; | |
511 | ||
8bb8aefd | 512 | slargs.slot_count = ORANGEFS_READDIR_DEFAULT_DESC_COUNT; |
274dcf55 MM |
513 | slargs.slot_array = bufmap->readdir_index_array; |
514 | slargs.slot_lock = &bufmap->readdir_index_lock; | |
515 | slargs.slot_wq = &readdir_waitq; | |
516 | put_back_slot(&slargs, buffer_index); | |
8bb8aefd | 517 | orangefs_bufmap_unref(bufmap); |
274dcf55 MM |
518 | } |
519 | ||
b5e376ea MM |
520 | /* |
521 | * we've been handed an iovec, we need to copy it to | |
522 | * the shared memory descriptor at "buffer_index". | |
523 | */ | |
8bb8aefd | 524 | int orangefs_bufmap_copy_from_iovec(struct orangefs_bufmap *bufmap, |
54804949 MM |
525 | struct iov_iter *iter, |
526 | int buffer_index, | |
527 | size_t size) | |
274dcf55 | 528 | { |
8bb8aefd | 529 | struct orangefs_bufmap_desc *to = &bufmap->desc_array[buffer_index]; |
4d1c4404 | 530 | int i; |
274dcf55 MM |
531 | |
532 | gossip_debug(GOSSIP_BUFMAP_DEBUG, | |
34204fde | 533 | "%s: buffer_index:%d: size:%zu:\n", |
4d1c4404 | 534 | __func__, buffer_index, size); |
274dcf55 | 535 | |
274dcf55 | 536 | |
4d1c4404 | 537 | for (i = 0; size; i++) { |
34204fde AV |
538 | struct page *page = to->page_array[i]; |
539 | size_t n = size; | |
540 | if (n > PAGE_SIZE) | |
541 | n = PAGE_SIZE; | |
542 | n = copy_page_from_iter(page, 0, n, iter); | |
543 | if (!n) | |
544 | return -EFAULT; | |
545 | size -= n; | |
274dcf55 | 546 | } |
34204fde | 547 | return 0; |
274dcf55 | 548 | |
274dcf55 MM |
549 | } |
550 | ||
551 | /* | |
b5e376ea MM |
552 | * we've been handed an iovec, we need to fill it from |
553 | * the shared memory descriptor at "buffer_index". | |
274dcf55 | 554 | */ |
8bb8aefd | 555 | int orangefs_bufmap_copy_to_iovec(struct orangefs_bufmap *bufmap, |
4d1c4404 | 556 | struct iov_iter *iter, |
5c278228 AV |
557 | int buffer_index, |
558 | size_t size) | |
274dcf55 | 559 | { |
8bb8aefd | 560 | struct orangefs_bufmap_desc *from = &bufmap->desc_array[buffer_index]; |
4d1c4404 | 561 | int i; |
274dcf55 MM |
562 | |
563 | gossip_debug(GOSSIP_BUFMAP_DEBUG, | |
5c278228 AV |
564 | "%s: buffer_index:%d: size:%zu:\n", |
565 | __func__, buffer_index, size); | |
274dcf55 | 566 | |
274dcf55 | 567 | |
5c278228 AV |
568 | for (i = 0; size; i++) { |
569 | struct page *page = from->page_array[i]; | |
570 | size_t n = size; | |
571 | if (n > PAGE_SIZE) | |
572 | n = PAGE_SIZE; | |
573 | n = copy_page_to_iter(page, 0, n, iter); | |
574 | if (!n) | |
575 | return -EFAULT; | |
576 | size -= n; | |
274dcf55 | 577 | } |
5c278228 | 578 | return 0; |
274dcf55 | 579 | } |