page_actor.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /*
  2. * Copyright (c) 2013
  3. * Phillip Lougher <phillip@squashfs.org.uk>
  4. *
  5. * This work is licensed under the terms of the GNU GPL, version 2. See
  6. * the COPYING file in the top-level directory.
  7. */
  8. #include <linux/kernel.h>
  9. #include <linux/slab.h>
  10. #include <linux/pagemap.h>
  11. #include <linux/buffer_head.h>
  12. #include "page_actor.h"
  13. struct squashfs_page_actor *squashfs_page_actor_init(struct page **page,
  14. int pages, int length, void (*release_pages)(struct page **, int, int))
  15. {
  16. struct squashfs_page_actor *actor = kmalloc(sizeof(*actor), GFP_KERNEL);
  17. if (actor == NULL)
  18. return NULL;
  19. actor->length = length ? : pages * PAGE_SIZE;
  20. actor->page = page;
  21. actor->pages = pages;
  22. actor->next_page = 0;
  23. actor->pageaddr = NULL;
  24. actor->release_pages = release_pages;
  25. return actor;
  26. }
  27. void squashfs_page_actor_free(struct squashfs_page_actor *actor, int error)
  28. {
  29. if (!actor)
  30. return;
  31. if (actor->release_pages)
  32. actor->release_pages(actor->page, actor->pages, error);
  33. kfree(actor);
  34. }
  35. void squashfs_actor_to_buf(struct squashfs_page_actor *actor, void *buf,
  36. int length)
  37. {
  38. void *pageaddr;
  39. int i, avail, pos = 0;
  40. for (i = 0; i < actor->pages && pos < length; ++i) {
  41. avail = min_t(int, length - pos, PAGE_SIZE);
  42. if (actor->page[i]) {
  43. pageaddr = kmap_atomic(actor->page[i]);
  44. memcpy(buf + pos, pageaddr, avail);
  45. kunmap_atomic(pageaddr);
  46. }
  47. pos += avail;
  48. }
  49. }
  50. void squashfs_buf_to_actor(void *buf, struct squashfs_page_actor *actor,
  51. int length)
  52. {
  53. void *pageaddr;
  54. int i, avail, pos = 0;
  55. for (i = 0; i < actor->pages && pos < length; ++i) {
  56. avail = min_t(int, length - pos, PAGE_SIZE);
  57. if (actor->page[i]) {
  58. pageaddr = kmap_atomic(actor->page[i]);
  59. memcpy(pageaddr, buf + pos, avail);
  60. kunmap_atomic(pageaddr);
  61. }
  62. pos += avail;
  63. }
  64. }
  65. void squashfs_bh_to_actor(struct buffer_head **bh, int nr_buffers,
  66. struct squashfs_page_actor *actor, int offset, int length, int blksz)
  67. {
  68. void *kaddr = NULL;
  69. int bytes = 0, pgoff = 0, b = 0, p = 0, i, avail;
  70. while (bytes < length) {
  71. if (actor->page[p]) {
  72. kaddr = kmap_atomic(actor->page[p]);
  73. while (pgoff < PAGE_SIZE && bytes < length) {
  74. avail = min_t(int, blksz - offset,
  75. PAGE_SIZE - pgoff);
  76. memcpy(kaddr + pgoff, bh[b]->b_data + offset,
  77. avail);
  78. pgoff += avail;
  79. bytes += avail;
  80. offset = (offset + avail) % blksz;
  81. if (!offset) {
  82. put_bh(bh[b]);
  83. ++b;
  84. }
  85. }
  86. kunmap_atomic(kaddr);
  87. pgoff = 0;
  88. } else {
  89. for (i = 0; i < PAGE_SIZE / blksz; ++i) {
  90. if (bh[b])
  91. put_bh(bh[b]);
  92. ++b;
  93. }
  94. bytes += PAGE_SIZE;
  95. }
  96. ++p;
  97. }
  98. }
  99. void squashfs_bh_to_buf(struct buffer_head **bh, int nr_buffers, void *buf,
  100. int offset, int length, int blksz)
  101. {
  102. int i, avail, bytes = 0;
  103. for (i = 0; i < nr_buffers && bytes < length; ++i) {
  104. avail = min_t(int, length - bytes, blksz - offset);
  105. if (bh[i]) {
  106. memcpy(buf + bytes, bh[i]->b_data + offset, avail);
  107. put_bh(bh[i]);
  108. }
  109. bytes += avail;
  110. offset = 0;
  111. }
  112. }
  113. void free_page_array(struct page **page, int nr_pages)
  114. {
  115. int i;
  116. for (i = 0; i < nr_pages; ++i)
  117. __free_page(page[i]);
  118. kfree(page);
  119. }
  120. struct page **alloc_page_array(int nr_pages, int gfp_mask)
  121. {
  122. int i;
  123. struct page **page;
  124. page = kcalloc(nr_pages, sizeof(struct page *), gfp_mask);
  125. if (!page)
  126. return NULL;
  127. for (i = 0; i < nr_pages; ++i) {
  128. page[i] = alloc_page(gfp_mask);
  129. if (!page[i]) {
  130. free_page_array(page, i);
  131. return NULL;
  132. }
  133. }
  134. return page;
  135. }