2 * Copyright (c) 2011 The FreeBSD Foundation
3 * Copyright (c) 2014-2020 François Tigeot <ftigeot@wolfpond.org>
6 * Portions of this software were developed by Konstantin Belousov
7 * under sponsorship from the FreeBSD Foundation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include <vm/vm_page.h>
34 #include <vm/vm_page2.h>
35 #include <vm/vm_pager.h>
36 #include <vm/vm_extern.h>
38 #include <linux/err.h>
39 #include <linux/shmem_fs.h>
42 * This code is typically called with a normal VM object to access
43 * data from a userspace shared memory mapping. However, handle the
44 * case where it might be called with OBJT_MGTDEVICE anyway.
47 shmem_read_mapping_page(vm_object_t object
, vm_pindex_t pindex
)
52 VM_OBJECT_LOCK(object
);
53 if (object
->type
== OBJT_MGTDEVICE
) {
55 rv
= vm_pager_get_page(object
, pindex
, &m
, 1);
57 return ERR_PTR(-ENOMEM
);
58 if (rv
!= VM_PAGER_OK
) {
60 return ERR_PTR(-ENOMEM
);
63 m
= vm_page_grab(object
, pindex
,
64 VM_ALLOC_NORMAL
| VM_ALLOC_RETRY
);
65 if (m
->valid
!= VM_PAGE_BITS_ALL
) {
66 if (vm_pager_has_page(object
, pindex
)) {
67 rv
= vm_pager_get_page(object
, pindex
, &m
, 1);
68 m
= vm_page_lookup(object
, pindex
);
70 return ERR_PTR(-ENOMEM
);
71 if (rv
!= VM_PAGER_OK
) {
73 return ERR_PTR(-ENOMEM
);
76 pmap_zero_page(VM_PAGE_TO_PHYS(m
));
77 m
->valid
= VM_PAGE_BITS_ALL
;
82 vm_page_wire(m
); /* put_page() undoes this */
84 VM_OBJECT_UNLOCK(object
);
86 return (struct page
*)m
;
90 shmem_read_mapping_page_gfp(struct vm_object
*mapping
,
91 pgoff_t index
, gfp_t gfp_mask
)
93 return shmem_read_mapping_page(mapping
, index
);
99 pagecache_write_begin(struct vm_object
*obj
, struct address_space
*mapping
,
100 loff_t pos
, unsigned len
, unsigned flags
, struct page
**pagep
, void **fsdata
)
102 *pagep
= shmem_read_mapping_page(obj
, OFF_TO_IDX(pos
));
107 /* This is really shmem_write_end() for the i915 gem code */
109 pagecache_write_end(struct vm_object
*obj
, struct address_space
*mapping
,
110 loff_t pos
, unsigned len
, unsigned copied
, struct page
*page
, void *fsdata
)
112 set_page_dirty(page
);
122 get_user_pages(unsigned long start
, unsigned long nr_pages
,
123 unsigned int gup_flags
, struct page
**pages
,
124 struct vm_area_struct
**vmas
)
132 int fault_type
= VM_PROT_READ
;
134 /* returning related vmas not yet supported */
136 KKASSERT(vmas
== NULL
);
137 KKASSERT(td
->td_proc
== NULL
);
138 map
= &td
->td_proc
->p_vmspace
->vm_map
;
141 fault_type
|= VM_PROT_WRITE
;
144 for (i
= 0; i
< nr_pages
; ++i
) {
145 m
= vm_fault_page(map
, start
+ i
* PAGE_SIZE
,
146 fault_type
, VM_FAULT_NORMAL
,
153 vm_page_busy_wait(m
, TRUE
, "drmgup");
158 pages
[i
] = (void *)m
;
171 release_pages(struct page
**pages
, unsigned long nr_pages
)
173 while (nr_pages
> 0) {
175 put_page(pages
[nr_pages
]);
176 pages
[nr_pages
] = NULL
;