@@ -374,6 +374,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
374
374
unsigned int num_pages , offset , i ;
375
375
char * addr , * base_addr , * next_addr ;
376
376
int run , addridx , actual_pages ;
377
+ unsigned long * need_release ;
377
378
378
379
offset = (unsigned int )buf & (PAGE_SIZE - 1 );
379
380
num_pages = (count + offset + PAGE_SIZE - 1 ) / PAGE_SIZE ;
@@ -384,38 +385,55 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
384
385
** list
385
386
*/
386
387
pagelist = kmalloc (sizeof (PAGELIST_T ) +
387
- (num_pages * sizeof (unsigned long )) +
388
- (num_pages * sizeof (pages [0 ])),
389
- GFP_KERNEL );
388
+ (num_pages * sizeof (unsigned long )) +
389
+ sizeof (unsigned long ) +
390
+ (num_pages * sizeof (pages [0 ])),
391
+ GFP_KERNEL );
390
392
391
393
vchiq_log_trace (vchiq_arm_log_level ,
392
394
"create_pagelist - %x" , (unsigned int )pagelist );
393
395
if (!pagelist )
394
396
return - ENOMEM ;
395
397
396
398
addrs = pagelist -> addrs ;
397
- pages = (struct page * * )(addrs + num_pages );
399
+ need_release = (unsigned long * )(addrs + num_pages );
400
+ pages = (struct page * * )(addrs + num_pages + 1 );
398
401
399
- down_read (& task -> mm -> mmap_sem );
400
- actual_pages = get_user_pages (task , task -> mm ,
401
- (unsigned long )buf & ~(PAGE_SIZE - 1 ), num_pages ,
402
- (type == PAGELIST_READ ) /*Write */ , 0 /*Force */ ,
403
- pages , NULL /*vmas */ );
404
- up_read (& task -> mm -> mmap_sem );
405
-
406
- if (actual_pages != num_pages )
407
- {
408
- /* This is probably due to the process being killed */
409
- while (actual_pages > 0 )
410
- {
411
- actual_pages -- ;
412
- page_cache_release (pages [actual_pages ]);
413
- }
414
- kfree (pagelist );
415
- if (actual_pages == 0 )
416
- actual_pages = - ENOMEM ;
417
- return actual_pages ;
418
- }
402
+ if (is_vmalloc_addr (buf )) {
403
+ for (actual_pages = 0 ; actual_pages < num_pages ; actual_pages ++ ) {
404
+ pages [actual_pages ] = vmalloc_to_page (buf + (actual_pages * PAGE_SIZE ));
405
+ }
406
+ * need_release = 0 ; /* do not try and release vmalloc pages */
407
+ } else {
408
+ down_read (& task -> mm -> mmap_sem );
409
+ actual_pages = get_user_pages (task , task -> mm ,
410
+ (unsigned long )buf & ~(PAGE_SIZE - 1 ),
411
+ num_pages ,
412
+ (type == PAGELIST_READ ) /*Write */ ,
413
+ 0 /*Force */ ,
414
+ pages ,
415
+ NULL /*vmas */ );
416
+ up_read (& task -> mm -> mmap_sem );
417
+
418
+ if (actual_pages != num_pages ) {
419
+ vchiq_log_info (vchiq_arm_log_level ,
420
+ "create_pagelist - only %d/%d pages locked" ,
421
+ actual_pages ,
422
+ num_pages );
423
+
424
+ /* This is probably due to the process being killed */
425
+ while (actual_pages > 0 )
426
+ {
427
+ actual_pages -- ;
428
+ page_cache_release (pages [actual_pages ]);
429
+ }
430
+ kfree (pagelist );
431
+ if (actual_pages == 0 )
432
+ actual_pages = - ENOMEM ;
433
+ return actual_pages ;
434
+ }
435
+ * need_release = 1 ; /* release user pages */
436
+ }
419
437
420
438
pagelist -> length = count ;
421
439
pagelist -> type = type ;
@@ -482,6 +500,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
482
500
static void
483
501
free_pagelist (PAGELIST_T * pagelist , int actual )
484
502
{
503
+ unsigned long * need_release ;
485
504
struct page * * pages ;
486
505
unsigned int num_pages , i ;
487
506
@@ -492,7 +511,8 @@ free_pagelist(PAGELIST_T *pagelist, int actual)
492
511
(pagelist -> length + pagelist -> offset + PAGE_SIZE - 1 ) /
493
512
PAGE_SIZE ;
494
513
495
- pages = (struct page * * )(pagelist -> addrs + num_pages );
514
+ need_release = (unsigned long * )(pagelist -> addrs + num_pages );
515
+ pages = (struct page * * )(pagelist -> addrs + num_pages + 1 );
496
516
497
517
/* Deal with any partial cache lines (fragments) */
498
518
if (pagelist -> type >= PAGELIST_READ_WITH_FRAGMENTS ) {
@@ -528,11 +548,14 @@ free_pagelist(PAGELIST_T *pagelist, int actual)
528
548
up (& g_free_fragments_sema );
529
549
}
530
550
531
- for (i = 0 ; i < num_pages ; i ++ ) {
532
- if (pagelist -> type != PAGELIST_WRITE )
533
- set_page_dirty (pages [i ]);
534
- page_cache_release (pages [i ]);
535
- }
551
+ if (* need_release ) {
552
+ for (i = 0 ; i < num_pages ; i ++ ) {
553
+ if (pagelist -> type != PAGELIST_WRITE )
554
+ set_page_dirty (pages [i ]);
555
+
556
+ page_cache_release (pages [i ]);
557
+ }
558
+ }
536
559
537
560
kfree (pagelist );
538
561
}
0 commit comments