^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/vmalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/pagemap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * get_vaddr_frames() - map virtual addresses to pfns
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * @start: starting user address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * @nr_frames: number of pages / pfns from start to map
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * @gup_flags: flags modifying lookup behaviour
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * @vec: structure which receives pages / pfns of the addresses mapped.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * It should have space for at least nr_frames entries.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * This function maps virtual addresses from @start and fills @vec structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * with page frame numbers or page pointers to corresponding pages (choice
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * depends on the type of the vma underlying the virtual address). If @start
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * belongs to a normal vma, the function grabs reference to each of the pages
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * to pin them in memory. If @start belongs to VM_IO | VM_PFNMAP vma, we don't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * touch page structures and the caller must make sure pfns aren't reused for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * anything else while he is using them.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * The function returns number of pages mapped which may be less than
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * @nr_frames. In particular we stop mapping if there are more vmas of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * different type underlying the specified range of virtual addresses.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * When the function isn't able to map a single page, it returns error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * This function takes care of grabbing mmap_lock as necessary.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) unsigned int gup_flags, struct frame_vector *vec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct mm_struct *mm = current->mm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct vm_area_struct *vma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) int locked;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) if (nr_frames == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) if (WARN_ON_ONCE(nr_frames > vec->nr_allocated))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) nr_frames = vec->nr_allocated;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) start = untagged_addr(start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) mmap_read_lock(mm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) locked = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) vma = find_vma_intersection(mm, start, start + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) if (!vma) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * While get_vaddr_frames() could be used for transient (kernel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * controlled lifetime) pinning of memory pages all current
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * users establish long term (userspace controlled lifetime)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * page pinning. Treat get_vaddr_frames() like
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * get_user_pages_longterm() and disallow it for filesystem-dax
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * mappings.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (vma_is_fsdax(vma)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) ret = -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) vec->got_ref = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) vec->is_pfns = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) ret = pin_user_pages_locked(start, nr_frames,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) gup_flags, (struct page **)(vec->ptrs), &locked);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) vec->got_ref = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) vec->is_pfns = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) unsigned long *nums = frame_vector_pfns(vec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) while (ret < nr_frames && start + PAGE_SIZE <= vma->vm_end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) err = follow_pfn(vma, start, &nums[ret]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) ret = err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) start += PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) ret++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * We stop if we have enough pages or if VMA doesn't completely
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * cover the tail page.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (ret >= nr_frames || start < vma->vm_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) vma = find_vma_intersection(mm, start, start + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) } while (vma && vma->vm_flags & (VM_IO | VM_PFNMAP));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) if (locked)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) mmap_read_unlock(mm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) ret = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (ret > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) vec->nr_frames = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) EXPORT_SYMBOL(get_vaddr_frames);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) * put_vaddr_frames() - drop references to pages if get_vaddr_frames() acquired
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) * them
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * @vec: frame vector to put
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * Drop references to pages if get_vaddr_frames() acquired them. We also
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * invalidate the frame vector so that it is prepared for the next call into
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * get_vaddr_frames().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) void put_vaddr_frames(struct frame_vector *vec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) struct page **pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (!vec->got_ref)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) pages = frame_vector_pages(vec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * frame_vector_pages() might needed to do a conversion when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * get_vaddr_frames() got pages but vec was later converted to pfns.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * But it shouldn't really fail to convert pfns back...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (WARN_ON(IS_ERR(pages)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) unpin_user_pages(pages, vec->nr_frames);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) vec->got_ref = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) vec->nr_frames = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) EXPORT_SYMBOL(put_vaddr_frames);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * frame_vector_to_pages - convert frame vector to contain page pointers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * @vec: frame vector to convert
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * Convert @vec to contain array of page pointers. If the conversion is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * successful, return 0. Otherwise return an error. Note that we do not grab
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * page references for the page structures.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) int frame_vector_to_pages(struct frame_vector *vec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) unsigned long *nums;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) struct page **pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (!vec->is_pfns)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) nums = frame_vector_pfns(vec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) for (i = 0; i < vec->nr_frames; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (!pfn_valid(nums[i]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) pages = (struct page **)nums;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) for (i = 0; i < vec->nr_frames; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) pages[i] = pfn_to_page(nums[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) vec->is_pfns = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) EXPORT_SYMBOL(frame_vector_to_pages);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) * frame_vector_to_pfns - convert frame vector to contain pfns
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) * @vec: frame vector to convert
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) * Convert @vec to contain array of pfns.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) void frame_vector_to_pfns(struct frame_vector *vec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) unsigned long *nums;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) struct page **pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) if (vec->is_pfns)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) pages = (struct page **)(vec->ptrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) nums = (unsigned long *)pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) for (i = 0; i < vec->nr_frames; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) nums[i] = page_to_pfn(pages[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) vec->is_pfns = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) EXPORT_SYMBOL(frame_vector_to_pfns);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) * frame_vector_create() - allocate & initialize structure for pinned pfns
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) * @nr_frames: number of pfns slots we should reserve
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) * Allocate and initialize struct pinned_pfns to be able to hold @nr_pfns
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) * pfns.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct frame_vector *frame_vector_create(unsigned int nr_frames)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) struct frame_vector *vec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) int size = sizeof(struct frame_vector) + sizeof(void *) * nr_frames;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (WARN_ON_ONCE(nr_frames == 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) * This is absurdly high. It's here just to avoid strange effects when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) * arithmetics overflows.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (WARN_ON_ONCE(nr_frames > INT_MAX / sizeof(void *) / 2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * Avoid higher order allocations, use vmalloc instead. It should
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) * be rare anyway.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) vec = kvmalloc(size, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if (!vec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) vec->nr_allocated = nr_frames;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) vec->nr_frames = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) return vec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) EXPORT_SYMBOL(frame_vector_create);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) * frame_vector_destroy() - free memory allocated to carry frame vector
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) * @vec: Frame vector to free
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) * Free structure allocated by frame_vector_create() to carry frames.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) void frame_vector_destroy(struct frame_vector *vec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) /* Make sure put_vaddr_frames() got called properly... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) VM_BUG_ON(vec->nr_frames > 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) kvfree(vec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) EXPORT_SYMBOL(frame_vector_destroy);