diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/filemap.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 7b8be78cfd9e..1e215fc36c83 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -1499,6 +1499,74 @@ repeat: | |||
1499 | } | 1499 | } |
1500 | EXPORT_SYMBOL(find_get_pages_tag); | 1500 | EXPORT_SYMBOL(find_get_pages_tag); |
1501 | 1501 | ||
1502 | /** | ||
1503 | * find_get_entries_tag - find and return entries that match @tag | ||
1504 | * @mapping: the address_space to search | ||
1505 | * @start: the starting page cache index | ||
1506 | * @tag: the tag index | ||
1507 | * @nr_entries: the maximum number of entries | ||
1508 | * @entries: where the resulting entries are placed | ||
1509 | * @indices: the cache indices corresponding to the entries in @entries | ||
1510 | * | ||
1511 | * Like find_get_entries, except we only return entries which are tagged with | ||
1512 | * @tag. | ||
1513 | */ | ||
1514 | unsigned find_get_entries_tag(struct address_space *mapping, pgoff_t start, | ||
1515 | int tag, unsigned int nr_entries, | ||
1516 | struct page **entries, pgoff_t *indices) | ||
1517 | { | ||
1518 | void **slot; | ||
1519 | unsigned int ret = 0; | ||
1520 | struct radix_tree_iter iter; | ||
1521 | |||
1522 | if (!nr_entries) | ||
1523 | return 0; | ||
1524 | |||
1525 | rcu_read_lock(); | ||
1526 | restart: | ||
1527 | radix_tree_for_each_tagged(slot, &mapping->page_tree, | ||
1528 | &iter, start, tag) { | ||
1529 | struct page *page; | ||
1530 | repeat: | ||
1531 | page = radix_tree_deref_slot(slot); | ||
1532 | if (unlikely(!page)) | ||
1533 | continue; | ||
1534 | if (radix_tree_exception(page)) { | ||
1535 | if (radix_tree_deref_retry(page)) { | ||
1536 | /* | ||
1537 | * Transient condition which can only trigger | ||
1538 | * when entry at index 0 moves out of or back | ||
1539 | * to root: none yet gotten, safe to restart. | ||
1540 | */ | ||
1541 | goto restart; | ||
1542 | } | ||
1543 | |||
1544 | /* | ||
1545 | * A shadow entry of a recently evicted page, a swap | ||
1546 | * entry from shmem/tmpfs or a DAX entry. Return it | ||
1547 | * without attempting to raise page count. | ||
1548 | */ | ||
1549 | goto export; | ||
1550 | } | ||
1551 | if (!page_cache_get_speculative(page)) | ||
1552 | goto repeat; | ||
1553 | |||
1554 | /* Has the page moved? */ | ||
1555 | if (unlikely(page != *slot)) { | ||
1556 | page_cache_release(page); | ||
1557 | goto repeat; | ||
1558 | } | ||
1559 | export: | ||
1560 | indices[ret] = iter.index; | ||
1561 | entries[ret] = page; | ||
1562 | if (++ret == nr_entries) | ||
1563 | break; | ||
1564 | } | ||
1565 | rcu_read_unlock(); | ||
1566 | return ret; | ||
1567 | } | ||
1568 | EXPORT_SYMBOL(find_get_entries_tag); | ||
1569 | |||
1502 | /* | 1570 | /* |
1503 | * CD/DVDs are error prone. When a medium error occurs, the driver may fail | 1571 | * CD/DVDs are error prone. When a medium error occurs, the driver may fail |
1504 | * a _large_ part of the i/o request. Imagine the worst scenario: | 1572 | * a _large_ part of the i/o request. Imagine the worst scenario: |