page_actor.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2013
  4. * Phillip Lougher <phillip@squashfs.org.uk>
  5. */
  6. #include <linux/kernel.h>
  7. #include <linux/slab.h>
  8. #include <linux/pagemap.h>
  9. #include "squashfs_fs_sb.h"
  10. #include "decompressor.h"
  11. #include "page_actor.h"
  12. /*
  13. * This file contains implementations of page_actor for decompressing into
  14. * an intermediate buffer, and for decompressing directly into the
  15. * page cache.
  16. *
  17. * Calling code should avoid sleeping between calls to squashfs_first_page()
  18. * and squashfs_finish_page().
  19. */
  20. /* Implementation of page_actor for decompressing into intermediate buffer */
  21. static void *cache_first_page(struct squashfs_page_actor *actor)
  22. {
  23. actor->next_page = 1;
  24. return actor->buffer[0];
  25. }
  26. static void *cache_next_page(struct squashfs_page_actor *actor)
  27. {
  28. if (actor->next_page == actor->pages)
  29. return NULL;
  30. return actor->buffer[actor->next_page++];
  31. }
  32. static void cache_finish_page(struct squashfs_page_actor *actor)
  33. {
  34. /* empty */
  35. }
  36. struct squashfs_page_actor *squashfs_page_actor_init(void **buffer,
  37. int pages, int length)
  38. {
  39. struct squashfs_page_actor *actor = kmalloc_obj(*actor);
  40. if (actor == NULL)
  41. return NULL;
  42. actor->length = length ? : pages * PAGE_SIZE;
  43. actor->buffer = buffer;
  44. actor->pages = pages;
  45. actor->next_page = 0;
  46. actor->tmp_buffer = NULL;
  47. actor->squashfs_first_page = cache_first_page;
  48. actor->squashfs_next_page = cache_next_page;
  49. actor->squashfs_finish_page = cache_finish_page;
  50. return actor;
  51. }
  52. /* Implementation of page_actor for decompressing directly into page cache. */
  53. static loff_t page_next_index(struct squashfs_page_actor *actor)
  54. {
  55. return page_folio(actor->page[actor->next_page])->index;
  56. }
  57. static void *handle_next_page(struct squashfs_page_actor *actor)
  58. {
  59. int max_pages = (actor->length + PAGE_SIZE - 1) >> PAGE_SHIFT;
  60. if (actor->returned_pages == max_pages)
  61. return NULL;
  62. if ((actor->next_page == actor->pages) ||
  63. (actor->next_index != page_next_index(actor))) {
  64. actor->next_index++;
  65. actor->returned_pages++;
  66. actor->last_page = NULL;
  67. return actor->alloc_buffer ? actor->tmp_buffer : ERR_PTR(-ENOMEM);
  68. }
  69. actor->next_index++;
  70. actor->returned_pages++;
  71. actor->last_page = actor->page[actor->next_page];
  72. return actor->pageaddr = kmap_local_page(actor->page[actor->next_page++]);
  73. }
  74. static void *direct_first_page(struct squashfs_page_actor *actor)
  75. {
  76. return handle_next_page(actor);
  77. }
  78. static void *direct_next_page(struct squashfs_page_actor *actor)
  79. {
  80. if (actor->pageaddr) {
  81. kunmap_local(actor->pageaddr);
  82. actor->pageaddr = NULL;
  83. }
  84. return handle_next_page(actor);
  85. }
  86. static void direct_finish_page(struct squashfs_page_actor *actor)
  87. {
  88. if (actor->pageaddr)
  89. kunmap_local(actor->pageaddr);
  90. }
  91. struct squashfs_page_actor *squashfs_page_actor_init_special(struct squashfs_sb_info *msblk,
  92. struct page **page, int pages, int length, loff_t start_index)
  93. {
  94. struct squashfs_page_actor *actor = kmalloc_obj(*actor);
  95. if (actor == NULL)
  96. return NULL;
  97. if (msblk->decompressor->alloc_buffer) {
  98. actor->tmp_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
  99. if (actor->tmp_buffer == NULL) {
  100. kfree(actor);
  101. return NULL;
  102. }
  103. } else
  104. actor->tmp_buffer = NULL;
  105. actor->length = length ? : pages * PAGE_SIZE;
  106. actor->page = page;
  107. actor->pages = pages;
  108. actor->next_page = 0;
  109. actor->returned_pages = 0;
  110. actor->next_index = start_index >> PAGE_SHIFT;
  111. actor->pageaddr = NULL;
  112. actor->last_page = NULL;
  113. actor->alloc_buffer = msblk->decompressor->alloc_buffer;
  114. actor->squashfs_first_page = direct_first_page;
  115. actor->squashfs_next_page = direct_next_page;
  116. actor->squashfs_finish_page = direct_finish_page;
  117. return actor;
  118. }