1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #ifndef _VM_VPM_H 27 #define _VM_VPM_H 28 29 30 #ifdef __cplusplus 31 extern "C" { 32 #endif 33 34 /* 35 * The vnode page mappings(VPM) interfaces. 36 * "Commitment level - Consolidation private". They are subject 37 * to change without notice. Use them at your own risk. 38 * 39 * At this stage these interfaces are provided only to utilize the 40 * segkpm mappings. Therefore these interfaces have to be used under 41 * the 'vpm_enable' check as an alternative to segmap interfaces where 42 * applicable. 43 * 44 * The VPM interfaces provide temporary mappings to file pages. They 45 * return the mappings in a scatter gather list(SGL). 46 * The SGL elements are the structure 'vmap_t'. 47 * 48 * typedef struct vmap { 49 * caddr_t vs_addr; / public - mapped address / 50 * size_t vs_len; / public - length of mapping / 51 * void *vs_data; / opaque - private data / 52 * } vmap_t; 53 * 54 * An array of this structure has to be passed to the interface routines 55 * along with the size(# of elements) of the SGL array. Depending on the 56 * requested length and mapped chunk sizes(PAGESIZE here), the number of 57 * valid mappings returned can be less then actual size of the SGL array. 58 * Always, an element in the SGL will have 'vs_addr' set to NULL which 59 * marks the end of the valid entires in the SGL. 60 * 61 * The vmap_t structure members are populated with the mapped address 62 * in 'vs_addr' and length of the mapping in 'vs_len'. Currently the 63 * mapping length is fixed at PAGESIZE. The 'vs_data' member is private 64 * and the caller should not access or modify it. 65 * 66 * Using a scatter gather list to return the mappings and length makes it 67 * possible to provide mappings of variable length. Mapping length upto 68 * VPMMAXLEN is supported. The scatter gather list array size needs to 69 * be a minimum of MINVMAPS elements. 70 * 71 * Interfaces: 72 * 73 * int vpm_map_pages( struct vnode *vp, u_offset_t off, size_t len, 74 * int fetchpage, vmap_t *vml, int vmlsz, 75 * int *newpagecreated, enum seg_rw rw); 76 * 77 * This function returns mappings to vnode pages. 78 * 79 * It takes a vnode, offset and length and returns mappings to the pages 80 * covering the range [off, off + len) in the vmap_t SGL array 'vml'. 81 * The length passed in should satisfy the following criteria 82 * '(off + len) <= ((off & PAGEMASK) + VPMMAXLEN)' 83 * The mapped address returned, in 'vs_addr', of first vml[] entry 84 * is at begining of page containing 'off'. 85 * 86 * The 'vmlsz' is the size(# elements) of the 'vml' array. 87 * 88 * When the 'fetchpage' flag is set, the vnode(file) pages will be fetched 89 * (calls VOP_GETPAGE) from the backing store(disk) if not found in the 90 * system page cache. If 'fetchpage == 0', the vnode(file) pages for the 91 * given offset will be just created if they are not already present in the 92 * system page cache. The 'newpagecreated' flag is set on return if new pages 93 * are created when 'fetchpage == 0'(requested to just create new pages). 94 * 95 * The 'seg_rw rw' indicates the intended operation on these mappings 96 * (S_WRITE or S_READ). 97 * 98 * Currently these interfaces only return segkpm mappings. The vnode pages 99 * that are being accessed will be locked(at least SHARED locked) for the 100 * duration these mappings are in use. After use, the unmap function, 101 * vpm_unmap_pages(), has to be called and the same SGL array 102 * needs to be passed to the unmap function. 103 * 104 * 105 * void vpm_unmap_pages(vpmap_t *vml, enum seg_rw rw);. 106 * 107 * This function unmaps the pages that where mapped by vpm_map_pages. 108 * The SGL array 'vml' has to be the one that was passed to vpm_map_pages(). 109 * 110 * 111 * ex: 112 * To copy file data of vnode(file) 'vp' at offset 'off' to a kernel buffer 113 * 'buf' the following code snippet shows how to use the above two interfaces. 114 * Here the the copy length is till the MAXBSIZE boundary. This code can be 115 * executed repeatedly, in a loop to copy more then MAXBSIZE length of data. 116 * 117 * vmap_t vml[MINVMAPS]; 118 * int err, i, newpage, len; 119 * int pon; 120 * 121 * pon = (off & PAGEOFFSET); 122 * len = MAXBSIZE - pon; 123 * 124 * if (vpm_enable) { 125 * err = vpm_map_pages(vp, off, len, 0, vml, MINVMAPS, 126 * &newpage, S_WRITE); 127 * 128 * if (err) 129 * return; 130 * 131 * for (i=0; vml[i].vs_addr != NULL); i++) { 132 * bcopy (buf, vml[i].vs_addr + pon, 133 * PAGESIZE - pon); 134 * buf += (PAGESIZE - pon); 135 * pon = 0; 136 * } 137 * 138 * if (newpage) { 139 * pon = (off & PAGEOFFSET); 140 * bzero(vml[i-1].vs_addr + pon, PAGESIZE - pon); 141 * } 142 * 143 * vpm_unmap_pages(vml, S_WRITE); 144 * } 145 * 146 * 147 * 148 * 149 * int vpm_data_copy(struct vnode *vp, u_offset_t off, size_t len, 150 * struct uio *uio, int fetchpage, int *newpagecreated, 151 * int zerostart, enum seg_rw rw); 152 * 153 * This function can be called if the need is to just transfer data to/from 154 * the vnode pages. It takes a 'uio' structure and calls 'uiomove()' to 155 * do the data transfer. It can be used in the context of read and write 156 * system calls to transfer data between a user buffer, which is specified 157 * in the uio structure, and the vnode pages. If the data needs to be 158 * transferred between a kernel buffer and the pages, like in the above 159 * example, a uio structure can be set up accordingly and passed. The 'rw' 160 * parameter will determine the direction of the data transfer. 161 * 162 * The 'fetchpage' and 'newpagecreated' are same as explained before. 163 * The 'zerostart' flag when set will zero fill start of the page till the 164 * offset 'off' in the first page. i.e from 'off & PAGEMASK' to 'off'. 165 * 166 * 167 * int vpm_sync_pages(struct vnode *vp, u_offset_t off, 168 * size_t len, uint_t flags) 169 * 170 * This function can be called to flush or sync the vnode(file) pages that 171 * have been accessed. It will call VOP_PUTPAGE(). 172 * 173 * For the given vnode, off and len the pages covering the range 174 * [off, off + len) are flushed. Currently it uses the same flags that 175 * are used with segmap_release() interface. Refer vm/seg_map.h. 176 * (SM_DONTNEED, SM_ASYNC, SM_FREE, SM_INVAL, SM_DESTROY) 177 * 178 */ 179 180 181 /* 182 * vpm cache related definitions. 183 */ 184 #define VPMAP_MINCACHE (64 * 1024 * 1024) 185 #define VPMAP_MAXCACHE (256L * 1024L * 1024L * 1024L) /* 256G */ 186 187 188 /* 189 * vpm caching mode 190 */ 191 #define VPMCACHE_LRU 0 192 #define VPMCACHE_RANDOM 1 193 /* 194 * Data structures to manage the cache of pages referenced by 195 * the vpm interfaces. There is one vpmap struct per page in the cache. 196 */ 197 struct vpmap { 198 kmutex_t vpm_mtx; /* protects non list fields */ 199 struct vnode *vpm_vp; /* pointer to vnode of cached page */ 200 struct vpmap *vpm_next; /* free list pointers */ 201 struct vpmap *vpm_prev; 202 u_offset_t vpm_off; /* offset of the page */ 203 page_t *vpm_pp; /* page pointer */ 204 ushort_t vpm_refcnt; /* Number active references */ 205 ushort_t vpm_ndxflg; /* indicates which queue */ 206 ushort_t vpm_free_ndx; /* freelist it belongs to */ 207 }; 208 209 /* 210 * Multiple vpmap free lists are maintaned so that allocations 211 * scale with cpu count. To further reduce contentions between 212 * allocation and deallocations, each list is made up of two queues. 213 */ 214 #define VPM_FREEQ_PAD 64 215 union vpm_freeq { 216 struct { 217 struct vpmap *vpmsq_free; 218 kmutex_t vpmsq_mtx; 219 } vpmfq; 220 char vpmq_pad[VPM_FREEQ_PAD]; 221 }; 222 223 #define vpmq_free vpmfq.vpmsq_free 224 #define vpmq_mtx vpmfq.vpmsq_mtx 225 226 struct vpmfree { 227 union vpm_freeq vpm_freeq[2]; /* alloc and release queue */ 228 union vpm_freeq *vpm_allocq; /* current alloc queue */ 229 union vpm_freeq *vpm_releq; /* current release queue */ 230 kcondvar_t vpm_free_cv; 231 ushort_t vpm_want; 232 }; 233 234 #define VPMALLOCQ 0 235 #define VPMRELEQ 1 236 237 /* 238 * VPM Interface definitions. 239 */ 240 241 /* 242 * This structure is the scatter gather list element. The page 243 * mappings will be returned in this structure. A pointer to an 244 * array of this structure is passed to the interface routines. 245 */ 246 typedef struct vmap { 247 caddr_t vs_addr; /* mapped address */ 248 size_t vs_len; /* length, currently fixed at PAGESIZE */ 249 void *vs_data; /* opaque - private data */ 250 } vmap_t; 251 252 #define VPM_FETCHPAGE 0x01 /* fault in pages */ 253 254 /* 255 * Max request length - Needs to be a multiple of 256 * 8192 (PAGESIZE on sparc) so it works properly on both 257 * x86 & sparc systems. Max set to 128k. 258 */ 259 #define VPMMAXLEN (128*1024) 260 261 /* 262 * The minimum and maximum number of array elements in the scatter 263 * gather list. 264 */ 265 #define MINVMAPS 3 /* ((MAXBSIZE/4096 + 1) min # mappings */ 266 #if defined(__sparc) 267 #define VPMMAXPGS (VPMMAXLEN/8192) /* Max # pages at a time */ 268 #else 269 #define VPMMAXPGS (VPMMAXLEN/4096) 270 #endif 271 #define MAXVMAPS (VPMMAXPGS + 1) /* Max # elements in the */ 272 /* scatter gather list */ 273 /* +1 element to mark the */ 274 /* end of the list of valid */ 275 /* mappings */ 276 277 #ifdef _KERNEL 278 279 extern int vpm_enable; 280 /* 281 * vpm page mapping operations. 282 */ 283 extern void vpm_init(void); 284 extern int vpm_map_pages(struct vnode *, u_offset_t, size_t, int, 285 vmap_t *, int, int *, enum seg_rw); 286 287 extern void vpm_unmap_pages(vmap_t *, enum seg_rw); 288 extern int vpm_sync_pages(struct vnode *, u_offset_t, size_t, uint_t); 289 extern int vpm_data_copy(struct vnode *, u_offset_t, size_t, 290 struct uio *, int, int *, int, enum seg_rw rw); 291 #endif /* _KERNEL */ 292 293 #ifdef __cplusplus 294 } 295 #endif 296 297 #endif /* _VM_VPM_H */ 298