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