ttm_backup.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. // SPDX-License-Identifier: MIT
  2. /*
  3. * Copyright © 2024 Intel Corporation
  4. */
  5. #include <drm/ttm/ttm_backup.h>
  6. #include <linux/export.h>
  7. #include <linux/page-flags.h>
  8. #include <linux/swap.h>
  9. /*
  10. * Need to map shmem indices to handle since a handle value
  11. * of 0 means error, following the swp_entry_t convention.
  12. */
  13. static unsigned long ttm_backup_shmem_idx_to_handle(pgoff_t idx)
  14. {
  15. return (unsigned long)idx + 1;
  16. }
  17. static pgoff_t ttm_backup_handle_to_shmem_idx(pgoff_t handle)
  18. {
  19. return handle - 1;
  20. }
  21. /**
  22. * ttm_backup_drop() - release memory associated with a handle
  23. * @backup: The struct backup pointer used to obtain the handle
  24. * @handle: The handle obtained from the @backup_page function.
  25. */
  26. void ttm_backup_drop(struct file *backup, pgoff_t handle)
  27. {
  28. loff_t start = ttm_backup_handle_to_shmem_idx(handle);
  29. start <<= PAGE_SHIFT;
  30. shmem_truncate_range(file_inode(backup), start,
  31. start + PAGE_SIZE - 1);
  32. }
  33. /**
  34. * ttm_backup_copy_page() - Copy the contents of a previously backed
  35. * up page
  36. * @backup: The struct backup pointer used to back up the page.
  37. * @dst: The struct page to copy into.
  38. * @handle: The handle returned when the page was backed up.
  39. * @intr: Try to perform waits interruptible or at least killable.
  40. *
  41. * Return: 0 on success, Negative error code on failure, notably
  42. * -EINTR if @intr was set to true and a signal is pending.
  43. */
  44. int ttm_backup_copy_page(struct file *backup, struct page *dst,
  45. pgoff_t handle, bool intr)
  46. {
  47. struct address_space *mapping = backup->f_mapping;
  48. struct folio *from_folio;
  49. pgoff_t idx = ttm_backup_handle_to_shmem_idx(handle);
  50. from_folio = shmem_read_folio(mapping, idx);
  51. if (IS_ERR(from_folio))
  52. return PTR_ERR(from_folio);
  53. copy_highpage(dst, folio_file_page(from_folio, idx));
  54. folio_put(from_folio);
  55. return 0;
  56. }
  57. /**
  58. * ttm_backup_backup_page() - Backup a page
  59. * @backup: The struct backup pointer to use.
  60. * @page: The page to back up.
  61. * @writeback: Whether to perform immediate writeback of the page.
  62. * This may have performance implications.
  63. * @idx: A unique integer for each page and each struct backup.
  64. * This allows the backup implementation to avoid managing
  65. * its address space separately.
  66. * @page_gfp: The gfp value used when the page was allocated.
  67. * This is used for accounting purposes.
  68. * @alloc_gfp: The gfp to be used when allocating memory.
  69. *
  70. * Context: If called from reclaim context, the caller needs to
  71. * assert that the shrinker gfp has __GFP_FS set, to avoid
  72. * deadlocking on lock_page(). If @writeback is set to true and
  73. * called from reclaim context, the caller also needs to assert
  74. * that the shrinker gfp has __GFP_IO set, since without it,
  75. * we're not allowed to start backup IO.
  76. *
  77. * Return: A handle on success. Negative error code on failure.
  78. *
  79. * Note: This function could be extended to back up a folio and
  80. * implementations would then split the folio internally if needed.
  81. * Drawback is that the caller would then have to keep track of
  82. * the folio size- and usage.
  83. */
  84. s64
  85. ttm_backup_backup_page(struct file *backup, struct page *page,
  86. bool writeback, pgoff_t idx, gfp_t page_gfp,
  87. gfp_t alloc_gfp)
  88. {
  89. struct address_space *mapping = backup->f_mapping;
  90. unsigned long handle = 0;
  91. struct folio *to_folio;
  92. int ret;
  93. to_folio = shmem_read_folio_gfp(mapping, idx, alloc_gfp);
  94. if (IS_ERR(to_folio))
  95. return PTR_ERR(to_folio);
  96. folio_mark_accessed(to_folio);
  97. folio_lock(to_folio);
  98. folio_mark_dirty(to_folio);
  99. copy_highpage(folio_file_page(to_folio, idx), page);
  100. handle = ttm_backup_shmem_idx_to_handle(idx);
  101. if (writeback && !folio_mapped(to_folio) &&
  102. folio_clear_dirty_for_io(to_folio)) {
  103. folio_set_reclaim(to_folio);
  104. ret = shmem_writeout(to_folio, NULL, NULL);
  105. if (!folio_test_writeback(to_folio))
  106. folio_clear_reclaim(to_folio);
  107. /*
  108. * If writeout succeeds, it unlocks the folio. errors
  109. * are otherwise dropped, since writeout is only best
  110. * effort here.
  111. */
  112. if (ret)
  113. folio_unlock(to_folio);
  114. } else {
  115. folio_unlock(to_folio);
  116. }
  117. folio_put(to_folio);
  118. return handle;
  119. }
  120. /**
  121. * ttm_backup_fini() - Free the struct backup resources after last use.
  122. * @backup: Pointer to the struct backup whose resources to free.
  123. *
  124. * After a call to this function, it's illegal to use the @backup pointer.
  125. */
  126. void ttm_backup_fini(struct file *backup)
  127. {
  128. fput(backup);
  129. }
  130. /**
  131. * ttm_backup_bytes_avail() - Report the approximate number of bytes of backup space
  132. * left for backup.
  133. *
  134. * This function is intended also for driver use to indicate whether a
  135. * backup attempt is meaningful.
  136. *
  137. * Return: An approximate size of backup space available.
  138. */
  139. u64 ttm_backup_bytes_avail(void)
  140. {
  141. /*
  142. * The idea behind backing up to shmem is that shmem objects may
  143. * eventually be swapped out. So no point swapping out if there
  144. * is no or low swap-space available. But the accuracy of this
  145. * number also depends on shmem actually swapping out backed-up
  146. * shmem objects without too much buffering.
  147. */
  148. return (u64)get_nr_swap_pages() << PAGE_SHIFT;
  149. }
  150. EXPORT_SYMBOL_GPL(ttm_backup_bytes_avail);
  151. /**
  152. * ttm_backup_shmem_create() - Create a shmem-based struct backup.
  153. * @size: The maximum size (in bytes) to back up.
  154. *
  155. * Create a backup utilizing shmem objects.
  156. *
  157. * Return: A pointer to a struct file on success,
  158. * an error pointer on error.
  159. */
  160. struct file *ttm_backup_shmem_create(loff_t size)
  161. {
  162. return shmem_file_setup("ttm shmem backup", size,
  163. EMPTY_VMA_FLAGS);
  164. }