diff options
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/pagemap.h | 64 |
1 files changed, 62 insertions, 2 deletions
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index cfaaa6949b8..c93a9a9bcd3 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h | |||
| @@ -426,7 +426,7 @@ static inline int fault_in_pages_writeable(char __user *uaddr, int size) | |||
| 426 | */ | 426 | */ |
| 427 | if (((unsigned long)uaddr & PAGE_MASK) != | 427 | if (((unsigned long)uaddr & PAGE_MASK) != |
| 428 | ((unsigned long)end & PAGE_MASK)) | 428 | ((unsigned long)end & PAGE_MASK)) |
| 429 | ret = __put_user(0, end); | 429 | ret = __put_user(0, end); |
| 430 | } | 430 | } |
| 431 | return ret; | 431 | return ret; |
| 432 | } | 432 | } |
| @@ -445,13 +445,73 @@ static inline int fault_in_pages_readable(const char __user *uaddr, int size) | |||
| 445 | 445 | ||
| 446 | if (((unsigned long)uaddr & PAGE_MASK) != | 446 | if (((unsigned long)uaddr & PAGE_MASK) != |
| 447 | ((unsigned long)end & PAGE_MASK)) { | 447 | ((unsigned long)end & PAGE_MASK)) { |
| 448 | ret = __get_user(c, end); | 448 | ret = __get_user(c, end); |
| 449 | (void)c; | 449 | (void)c; |
| 450 | } | 450 | } |
| 451 | } | 451 | } |
| 452 | return ret; | 452 | return ret; |
| 453 | } | 453 | } |
| 454 | 454 | ||
| 455 | /* | ||
| 456 | * Multipage variants of the above prefault helpers, useful if more than | ||
| 457 | * PAGE_SIZE of data needs to be prefaulted. These are separate from the above | ||
| 458 | * functions (which only handle up to PAGE_SIZE) to avoid clobbering the | ||
| 459 | * filemap.c hotpaths. | ||
| 460 | */ | ||
| 461 | static inline int fault_in_multipages_writeable(char __user *uaddr, int size) | ||
| 462 | { | ||
| 463 | int ret; | ||
| 464 | const char __user *end = uaddr + size - 1; | ||
| 465 | |||
| 466 | if (unlikely(size == 0)) | ||
| 467 | return 0; | ||
| 468 | |||
| 469 | /* | ||
| 470 | * Writing zeroes into userspace here is OK, because we know that if | ||
| 471 | * the zero gets there, we'll be overwriting it. | ||
| 472 | */ | ||
| 473 | while (uaddr <= end) { | ||
| 474 | ret = __put_user(0, uaddr); | ||
| 475 | if (ret != 0) | ||
| 476 | return ret; | ||
| 477 | uaddr += PAGE_SIZE; | ||
| 478 | } | ||
| 479 | |||
| 480 | /* Check whether the range spilled into the next page. */ | ||
| 481 | if (((unsigned long)uaddr & PAGE_MASK) == | ||
| 482 | ((unsigned long)end & PAGE_MASK)) | ||
| 483 | ret = __put_user(0, end); | ||
| 484 | |||
| 485 | return ret; | ||
| 486 | } | ||
| 487 | |||
| 488 | static inline int fault_in_multipages_readable(const char __user *uaddr, | ||
| 489 | int size) | ||
| 490 | { | ||
| 491 | volatile char c; | ||
| 492 | int ret; | ||
| 493 | const char __user *end = uaddr + size - 1; | ||
| 494 | |||
| 495 | if (unlikely(size == 0)) | ||
| 496 | return 0; | ||
| 497 | |||
| 498 | while (uaddr <= end) { | ||
| 499 | ret = __get_user(c, uaddr); | ||
| 500 | if (ret != 0) | ||
| 501 | return ret; | ||
| 502 | uaddr += PAGE_SIZE; | ||
| 503 | } | ||
| 504 | |||
| 505 | /* Check whether the range spilled into the next page. */ | ||
| 506 | if (((unsigned long)uaddr & PAGE_MASK) == | ||
| 507 | ((unsigned long)end & PAGE_MASK)) { | ||
| 508 | ret = __get_user(c, end); | ||
| 509 | (void)c; | ||
| 510 | } | ||
| 511 | |||
| 512 | return ret; | ||
| 513 | } | ||
| 514 | |||
| 455 | int add_to_page_cache_locked(struct page *page, struct address_space *mapping, | 515 | int add_to_page_cache_locked(struct page *page, struct address_space *mapping, |
| 456 | pgoff_t index, gfp_t gfp_mask); | 516 | pgoff_t index, gfp_t gfp_mask); |
| 457 | int add_to_page_cache_lru(struct page *page, struct address_space *mapping, | 517 | int add_to_page_cache_lru(struct page *page, struct address_space *mapping, |
