Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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);