uvm_page_status.c revision 1.1.2.1 1 /* $NetBSD: uvm_page_status.c,v 1.1.2.1 2011/11/02 21:55:39 yamt Exp $ */
2
3 /*-
4 * Copyright (c)2011 YAMAMOTO Takashi,
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: uvm_page_status.c,v 1.1.2.1 2011/11/02 21:55:39 yamt Exp $");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34
35 #include <uvm/uvm.h>
36
37 /*
38 * page dirtiness status tracking
39 *
40 * separated from uvm_page.c mainly for rump
41 */
42
43 /*
44 * uvm_pagegetdirty: return the dirtiness status (one of UVM_PAGE_STATUS_
45 * values) of the page.
46 */
47
48 unsigned int
49 uvm_pagegetdirty(struct vm_page *pg)
50 {
51 struct uvm_object * const uobj __unused = pg->uobject;
52 const uint64_t idx __unused = pg->offset >> PAGE_SHIFT;
53
54 KASSERT((~pg->flags & (PG_CLEAN|PG_DIRTY)) != 0);
55 KASSERT(uvm_page_locked_p(pg));
56 KASSERT(uobj == NULL || ((pg->flags & PG_CLEAN) == 0) ==
57 radix_tree_get_tag(&uobj->uo_pages, idx, UVM_PAGE_DIRTY_TAG));
58 return pg->flags & (PG_CLEAN|PG_DIRTY);
59 }
60
61 /*
62 * uvm_pagemarkdirty: set the dirtiness status (one of UVM_PAGE_STATUS_ values)
63 * of the page.
64 */
65
66 void
67 uvm_pagemarkdirty(struct vm_page *pg, unsigned int status)
68 {
69 struct uvm_object * const uobj = pg->uobject;
70 const uint64_t idx = pg->offset >> PAGE_SHIFT;
71
72 KASSERT((~status & (PG_CLEAN|PG_DIRTY)) != 0);
73 KASSERT((status & ~(PG_CLEAN|PG_DIRTY)) == 0);
74 KASSERT(uvm_page_locked_p(pg));
75 KASSERT(uobj == NULL || ((pg->flags & PG_CLEAN) == 0) ==
76 radix_tree_get_tag(&uobj->uo_pages, idx, UVM_PAGE_DIRTY_TAG));
77
78 if (uvm_pagegetdirty(pg) == status) {
79 return;
80 }
81 /*
82 * set UVM_PAGE_DIRTY_TAG tag unless known CLEAN so that putpages can
83 * find possibly-dirty pages quickly.
84 */
85 if (uobj != NULL) {
86 if (status == UVM_PAGE_STATUS_CLEAN) {
87 radix_tree_clear_tag(&uobj->uo_pages, idx,
88 UVM_PAGE_DIRTY_TAG);
89 } else {
90 radix_tree_set_tag(&uobj->uo_pages, idx,
91 UVM_PAGE_DIRTY_TAG);
92 }
93 }
94 if (status == UVM_PAGE_STATUS_UNKNOWN) {
95 /*
96 * start relying on pmap-level dirtiness tracking.
97 */
98 pmap_clear_modify(pg);
99 }
100 pg->flags &= ~(PG_CLEAN|PG_DIRTY);
101 pg->flags |= status;
102 KASSERT(uobj == NULL || ((pg->flags & PG_CLEAN) == 0) ==
103 radix_tree_get_tag(&uobj->uo_pages, idx, UVM_PAGE_DIRTY_TAG));
104 }
105
106 /*
107 * uvm_pagecheckdirty: check if page is dirty, and remove its dirty-marks.
108 *
109 * called with the owner locked.
110 */
111
112 bool
113 uvm_pagecheckdirty(struct vm_page *pg, bool protected)
114 {
115 const unsigned int oldstatus = uvm_pagegetdirty(pg);
116 bool modified;
117
118 KASSERT(uvm_page_locked_p(pg));
119
120 /*
121 * if protected is true, mark the page CLEAN.
122 * otherwise mark the page UNKNOWN unless it's CLEAN.
123 *
124 * possible transitions:
125 *
126 * CLEAN -> CLEAN , modified = false
127 * UNKNOWN -> UNKNOWN, modified = true
128 * UNKNOWN -> UNKNOWN, modified = false
129 * UNKNOWN -> CLEAN , modified = true
130 * UNKNOWN -> CLEAN , modified = false
131 * DIRTY -> UNKNOWN, modified = true
132 * DIRTY -> CLEAN , modified = true
133 *
134 * pmap_clear_modify is necessary if either of
135 * oldstatus or newstatus is UVM_PAGE_STATUS_UNKNOWN.
136 */
137
138 if (oldstatus == UVM_PAGE_STATUS_CLEAN) {
139 modified = false;
140 } else {
141 const unsigned int newstatus =
142 protected ? UVM_PAGE_STATUS_CLEAN : UVM_PAGE_STATUS_UNKNOWN;
143
144 if (oldstatus == UVM_PAGE_STATUS_DIRTY) {
145 modified = true;
146 if (newstatus == UVM_PAGE_STATUS_UNKNOWN) {
147 pmap_clear_modify(pg);
148 }
149 } else {
150 modified = pmap_clear_modify(pg);
151 }
152 uvm_pagemarkdirty(pg, newstatus);
153 }
154 return modified;
155 }
156