mteswap.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <linux/pagemap.h>
  3. #include <linux/xarray.h>
  4. #include <linux/slab.h>
  5. #include <linux/swap.h>
  6. #include <linux/swapops.h>
  7. #include <asm/mte.h>
  8. static DEFINE_XARRAY(mte_pages);
  9. void *mte_allocate_tag_storage(void)
  10. {
  11. /* tags granule is 16 bytes, 2 tags stored per byte */
  12. return kmalloc(MTE_PAGE_TAG_STORAGE, GFP_KERNEL);
  13. }
  14. void mte_free_tag_storage(char *storage)
  15. {
  16. kfree(storage);
  17. }
  18. int mte_save_tags(struct page *page)
  19. {
  20. void *tag_storage, *ret;
  21. if (!page_mte_tagged(page))
  22. return 0;
  23. tag_storage = mte_allocate_tag_storage();
  24. if (!tag_storage)
  25. return -ENOMEM;
  26. mte_save_page_tags(page_address(page), tag_storage);
  27. /* lookup the swap entry.val from the page */
  28. ret = xa_store(&mte_pages, page_swap_entry(page).val, tag_storage,
  29. GFP_KERNEL);
  30. if (WARN(xa_is_err(ret), "Failed to store MTE tags")) {
  31. mte_free_tag_storage(tag_storage);
  32. return xa_err(ret);
  33. } else if (ret) {
  34. /* Entry is being replaced, free the old entry */
  35. mte_free_tag_storage(ret);
  36. }
  37. return 0;
  38. }
  39. void mte_restore_tags(swp_entry_t entry, struct page *page)
  40. {
  41. void *tags = xa_load(&mte_pages, entry.val);
  42. if (!tags)
  43. return;
  44. if (try_page_mte_tagging(page)) {
  45. mte_restore_page_tags(page_address(page), tags);
  46. set_page_mte_tagged(page);
  47. }
  48. }
  49. void mte_invalidate_tags(int type, pgoff_t offset)
  50. {
  51. swp_entry_t entry = swp_entry(type, offset);
  52. void *tags = xa_erase(&mte_pages, entry.val);
  53. mte_free_tag_storage(tags);
  54. }
  55. static inline void __mte_invalidate_tags(struct page *page)
  56. {
  57. swp_entry_t entry = page_swap_entry(page);
  58. mte_invalidate_tags(swp_type(entry), swp_offset(entry));
  59. }
  60. void mte_invalidate_tags_area(int type)
  61. {
  62. swp_entry_t entry = swp_entry(type, 0);
  63. swp_entry_t last_entry = swp_entry(type + 1, 0);
  64. void *tags;
  65. XA_STATE(xa_state, &mte_pages, entry.val);
  66. xa_lock(&mte_pages);
  67. xas_for_each(&xa_state, tags, last_entry.val - 1) {
  68. __xa_erase(&mte_pages, xa_state.xa_index);
  69. mte_free_tag_storage(tags);
  70. }
  71. xa_unlock(&mte_pages);
  72. }
  73. int arch_prepare_to_swap(struct folio *folio)
  74. {
  75. long i, nr;
  76. int err;
  77. if (!system_supports_mte())
  78. return 0;
  79. nr = folio_nr_pages(folio);
  80. for (i = 0; i < nr; i++) {
  81. err = mte_save_tags(folio_page(folio, i));
  82. if (err)
  83. goto out;
  84. }
  85. return 0;
  86. out:
  87. while (i--)
  88. __mte_invalidate_tags(folio_page(folio, i));
  89. return err;
  90. }
  91. void arch_swap_restore(swp_entry_t entry, struct folio *folio)
  92. {
  93. long i, nr;
  94. if (!system_supports_mte())
  95. return;
  96. nr = folio_nr_pages(folio);
  97. for (i = 0; i < nr; i++) {
  98. mte_restore_tags(entry, folio_page(folio, i));
  99. entry.val++;
  100. }
  101. }