pagelist.c 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. #include <linux/module.h>
  2. #include <linux/gfp.h>
  3. #include <linux/pagemap.h>
  4. #include <linux/highmem.h>
  5. #include <linux/ceph/pagelist.h>
  6. static void ceph_pagelist_unmap_tail(struct ceph_pagelist *pl)
  7. {
  8. struct page *page = list_entry(pl->head.prev, struct page,
  9. lru);
  10. kunmap(page);
  11. }
  12. int ceph_pagelist_release(struct ceph_pagelist *pl)
  13. {
  14. if (pl->mapped_tail)
  15. ceph_pagelist_unmap_tail(pl);
  16. while (!list_empty(&pl->head)) {
  17. struct page *page = list_first_entry(&pl->head, struct page,
  18. lru);
  19. list_del(&page->lru);
  20. __free_page(page);
  21. }
  22. return 0;
  23. }
  24. EXPORT_SYMBOL(ceph_pagelist_release);
  25. static int ceph_pagelist_addpage(struct ceph_pagelist *pl)
  26. {
  27. struct page *page = __page_cache_alloc(GFP_NOFS);
  28. if (!page)
  29. return -ENOMEM;
  30. pl->room += PAGE_SIZE;
  31. list_add_tail(&page->lru, &pl->head);
  32. if (pl->mapped_tail)
  33. ceph_pagelist_unmap_tail(pl);
  34. pl->mapped_tail = kmap(page);
  35. return 0;
  36. }
  37. int ceph_pagelist_append(struct ceph_pagelist *pl, const void *buf, size_t len)
  38. {
  39. while (pl->room < len) {
  40. size_t bit = pl->room;
  41. int ret;
  42. memcpy(pl->mapped_tail + (pl->length & ~PAGE_CACHE_MASK),
  43. buf, bit);
  44. pl->length += bit;
  45. pl->room -= bit;
  46. buf += bit;
  47. len -= bit;
  48. ret = ceph_pagelist_addpage(pl);
  49. if (ret)
  50. return ret;
  51. }
  52. memcpy(pl->mapped_tail + (pl->length & ~PAGE_CACHE_MASK), buf, len);
  53. pl->length += len;
  54. pl->room -= len;
  55. return 0;
  56. }
  57. EXPORT_SYMBOL(ceph_pagelist_append);