vpm.h revision a5652762e5f7bf683d19f18542e5e39df63bad79
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _VM_VPM_H
#define _VM_VPM_H
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef __cplusplus
extern "C" {
#endif
/*
* The vnode page mappings(VPM) interfaces.
* "Commitment level - Consolidation private". They are subject
* to change without notice. Use them at your own risk.
*
* At this stage these interfaces are provided only to utilize the
* segkpm mappings and are enabled for solaris x64. Therefore these
* interfaces have to be used under the 'vpm_enable' check as an
* alternative to segmap interfaces where applicable.
*
* The VPM interfaces provide temporary mappings to file pages. They
* return the mappings in a scatter gather list(SGL).
* The SGL elements are the structure 'vmap_t'.
*
* typedef struct vmap {
* caddr_t vs_addr; / public /
* size_t vs_len; / public - Currently not used /
* void *vs_data; / opaque - private data /
* } vmap_t;
*
* An array of this structure has to be passed to the interface routines
* along with the size(# of elements) of the SGL array. Depending on the
* requested length and mapped chunk sizes(PAGESIZE here), the number of
* valid mappings returned can be less then actual size of the SGL array.
* Always, an element in the SGL will have 'vs_addr' set to NULL which
* marks the end of the valid entires in the SGL.
*
* The vmap_t structure members are populated with the mapped address
* in 'vs_addr' and length of the mapping in 'vs_len'. Currently the
* mapping length is fixed at PAGESIZE. The 'vs_data' member is private
* and the caller should not access or modify it.
*
* Using a scatter gather list to return the mappings and length makes it
* possible to provide mappings of variable length. Currently mapping length
* of only 'PAGESIZE' per vmap_t is possible. Also, similar to the segmap
* interfaces, on each request, the max length of 'MAXBSIZE' is supported
* for now. The MAXBSIZE mappings will be returned in 1 or 2 vmap_t elements
* of the SGL depending on the PAGESIZE. The scatter gather list array size
* needs to be a minimum of MINVMAPS elements to accommodate MAXBSIZE.
* The MAXBSIZE restriction exists because the filesystems are not capable
* of handling more(disk block allocations at a time) for now.
*
*
* Interfaces:
*
* int vpm_map_pages( struct vnode *vp, u_offset_t off, size_t len,
* int fetchpage, vmap_t *vml, int vmlsz,
* int *newpagecreated, enum seg_rw rw);
*
* This function returns mappings to vnode pages.
*
* It takes a vnode, offset and length and returns mappings to the pages
* covering the range [off, off +len) in the vmap_t SGL array 'vml'.
* Currently these interfaces are subject to restrictions similar to the segmap
* interfaces. The length passed in should satisfy the following criteria.
* '(off + len) <= ((off & PAGEMASK) + MAXBSIZE)'
* The mapped address returned, in 'vs_addr', are for the page boundary.
*
* The 'vmlsz' is the size(# elements) of the 'vml' array.
*
* When the 'fetchpage' flag is set, the vnode(file) pages will be fetched
* (calls VOP_GETPAGE) from the backing store(disk) if not found in the
* system page cache. If 'fetchpage == 0', the vnode(file) pages for the
* given offset will be just created if they are not already present in the
* system page cache. The 'newpagecreated' flag is set on return if new pages
* are created when 'fetchpage == 0'(requested to just create new pages).
*
* The 'seg_rw rw' indicates the intended operation on these mappings
* (S_WRITE or S_READ).
*
* Currently these interfaces only return segkpm mappings. Therefore the
* vnode pages that are being accessed will be locked(at least SHARED locked)
* for the duration these mappings are in use. After use, the unmap
* function, vpm_unmap_pages(), has to be called and the same SGL array
* needs to be passed to the unmap function.
*
*
* void vpm_unmap_pages(vpmap_t *vml, enum seg_rw rw);.
*
* This function unmaps the pages that where mapped by vpm_map_pages.
* The SGL array 'vml' has to be the one that was passed to vpm_map_pages().
*
*
* ex:
* To copy file data of vnode(file) 'vp' at offset 'off' to a kernel buffer
* 'buf' the following code snippet shows how to use the above two interfaces.
* Here the the copy length is till the MAXBSIZE boundary. This code can be
* executed repeatedly, in a loop to copy more then MAXBSIZE length of data.
*
* vmap_t vml[MINVMAPS];
* int err, i, newpage, len;
* int pon;
*
* pon = (off & PAGEOFFSET);
* len = MAXBSIZE - pon;
*
* if (vpm_enable) {
* err = vpm_map_pages(vp, off, len, 0, vml, MINVMAPS,
* &newpage, S_WRITE);
*
* if (err)
* return;
*
* for (i=0; vml[i].vs_addr != NULL); i++) {
* bcopy (buf, vml[i].vs_addr + pon,
* PAGESIZE - pon);
* buf += (PAGESIZE - pon);
* pon = 0;
* }
*
* if (newpage) {
* pon = (off & PAGEOFFSET);
* bzero(vml[i-1].vs_addr + pon, PAGESIZE - pon);
* }
*
* vpm_unmap_pages(vml, S_WRITE);
* }
*
*
*
*
* int vpm_data_copy(struct vnode *vp, u_offset_t off, size_t len,
* struct uio *uio, int fetchpage, int *newpagecreated,
* int zerostart, enum seg_rw rw);
*
* This function can be called if the need is to just transfer data to/from
* the vnode pages. It takes a 'uio' structure and calls 'uiomove()' to
* do the data transfer. It can be used in the context of read and write
* system calls to transfer data between a user buffer, which is specified
* in the uio structure, and the vnode pages. If the data needs to be
* transferred between a kernel buffer and the pages, like in the above
* example, a uio structure can be set up accordingly and passed. The 'rw'
* parameter will determine the direction of the data transfer.
*
* The 'fetchpage' and 'newpagecreated' are same as explained before.
* The 'zerostart' flag when set will zero fill start of the page till the
* offset 'off' in the first page. i.e from 'off & PAGEMASK' to 'off'.
* Here too the MAXBSIZE restriction mentioned above applies to the length
* requested.
*
*
* int vpm_sync_pages(struct vnode *vp, u_offset_t off,
* size_t len, uint_t flags)
*
* This function can be called to flush or sync the vnode(file) pages that
* have been accessed. It will call VOP_PUTPAGE().
*
* For the given vnode, off and len the pages covering the range
* [off, off + len) are flushed. Currently it uses the same flags that
* are used with segmap_release() interface. Refer vm/seg_map.h.
* (SM_DONTNEED, SM_ASYNC, SM_FREE, SM_INVAL, SM_DESTROY)
*
*/
/*
* vpm cache related definitions.
*/
#define VPMAP_MINCACHE (64 * 1024 * 1024)
/*
* vpm caching mode
*/
#define VPMCACHE_LRU 0
#define VPMCACHE_RANDOM 1
/*
* Data structures to manage the cache of pages referenced by
* the vpm interfaces. There is one vpmap struct per page in the cache.
*/
struct vpmap {
kmutex_t vpm_mtx; /* protects non list fields */
struct vnode *vpm_vp; /* pointer to vnode of cached page */
struct vpmap *vpm_next; /* free list pointers */
struct vpmap *vpm_prev;
u_offset_t vpm_off; /* offset of the page */
page_t *vpm_pp; /* page pointer */
ushort_t vpm_refcnt; /* Number active references */
ushort_t vpm_ndxflg; /* indicates which queue */
ushort_t vpm_free_ndx; /* freelist it belongs to */
};
/*
* Multiple vpmap free lists are maintaned so that allocations
* scale with cpu count. To further reduce contentions between
* allocation and deallocations, each list is made up of two queues.
*/
#define VPM_FREEQ_PAD 64
union vpm_freeq {
struct {
struct vpmap *vpmsq_free;
kmutex_t vpmsq_mtx;
} vpmfq;
char vpmq_pad[VPM_FREEQ_PAD];
};
#define vpmq_free vpmfq.vpmsq_free
#define vpmq_mtx vpmfq.vpmsq_mtx
struct vpmfree {
union vpm_freeq vpm_freeq[2]; /* alloc and release queue */
union vpm_freeq *vpm_allocq; /* current alloc queue */
union vpm_freeq *vpm_releq; /* current release queue */
kcondvar_t vpm_free_cv;
ushort_t vpm_want;
};
#define VPMALLOCQ 0
#define VPMRELEQ 1
/*
* VPM Interface definitions.
*/
/*
* This structure is the scatter gather list element. The page
* mappings will be returned in this structure. A pointer to an
* array of this structure is passed to the interface routines.
*/
typedef struct vmap {
caddr_t vs_addr; /* mapped address */
size_t vs_len; /* length, currently fixed at PAGESIZE */
void *vs_data; /* opaque - private data */
} vmap_t;
/*
* The minimum and maximum number of array elements in the scatter
* gather list.
*/
#define MINVMAPS 3 /* ((MAXBSIZE/4096 + 1) min # mappings */
#define MAXVMAPS 10 /* Max # the scatter gather list */
#ifdef _KERNEL
extern int vpm_enable;
/*
* vpm page mapping operations.
*/
extern void vpm_init(void);
extern int vpm_map_pages(struct vnode *, u_offset_t, size_t, int,
vmap_t *, int, int *, enum seg_rw);
extern void vpm_unmap_pages(vmap_t *, enum seg_rw);
extern int vpm_sync_pages(struct vnode *, u_offset_t, size_t, uint_t);
extern int vpm_data_copy(struct vnode *, u_offset_t, size_t,
struct uio *, int, int *, int, enum seg_rw rw);
#endif /* _KERNEL */
#ifdef __cplusplus
}
#endif
#endif /* _VM_VPM_H */