📄 mmap.c
字号:
/* * Copyright (c) 1997-2003 Erez Zadok * Copyright (c) 2001-2003 Stony Brook University * Copyright (c) 1997-2000 Columbia University * * For specific licensing information, see the COPYING file distributed with * this package, or get one from ftp://ftp.filesystems.org/pub/fist/COPYING. * * This Copyright notice must be kept intact and distributed with all * fistgen sources INCLUDING sources generated by fistgen. *//* * Copyright (c) 1992 by Sun Microsystems, Inc. */#ifdef HAVE_CONFIG_H# include <config.h>#endif /* HAVE_CONFIG_H */#ifdef FISTGEN# include "fist_wrapfs.h"#endif /* FISTGEN */#include <fist.h>#include <wrapfs.h>#if 0#include <sys/param.h>#include <sys/systm.h>#include <sys/errno.h>#include <sys/vnode.h>#include <sys/vfs.h>#include <sys/uio.h>#include <sys/cred.h>#include <sys/pathname.h>#include <sys/dirent.h>#include <sys/debug.h>#include <sys/sysmacros.h>#include <sys/tiuser.h>#include <sys/cmn_err.h>#include <sys/stat.h>#include <sys/mode.h>#include <rpc/types.h>#include <rpc/auth.h>#include <rpc/clnt.h>#include <sys/fs_subr.h>#include <sys/mman.h>#include <sys/vm.h>#include <vm/as.h>#include <vm/pvn.h>#include <vm/seg_vn.h>#include <vm/seg_kp.h>#include <vm/seg_map.h>#include <vm/page.h>#include <fist.h>#include <wrapfs.h>#endif/* are these two #defines (copied from 2.5.1) correct in 2.6/2.7? */#ifndef se_assert# define se_assert(x) (*(x) > 0 || *(x) == -1)#endif /* not se_assert */#ifndef se_shared_assert# define se_shared_assert(x) (*(x) > 0)#endif /* not se_shared_assert */#define PAGE_UNLOCK(p) { \/* ASSERT(se_assert(&((p)->p_selock))); \ */ \ page_unlock(p); \}#define PAGE_IO_UNLOCK(p) { \ ASSERT(page_iolock_assert(p)); \ page_io_unlock(p); \}/* * Vnode mmap ops for fist_wrapfs */extern int wrapfs_getpage(vnode_t *, u_offset_t, u_int, u_int *, page_t **, u_int, struct seg *, caddr_t, enum seg_rw, cred_t *);extern int wrapfs_getapage(vnode_t *, u_offset_t, u_int, u_int *, page_t **, u_int, struct seg *, caddr_t, enum seg_rw, cred_t *);extern int wrapfs_putpage(vnode_t *, offset_t, u_int, int, cred_t *);extern int wrapfs_putapage(struct vnode *vp, page_t * pp, u_offset_t * offp, u_int * lenp, int flags, struct cred *cr);extern int wrapfs_map(vnode_t *, offset_t, struct as *, caddr_t *, u_int, u_char, u_char, u_int, cred_t *);extern int wrapfs_addmap(vnode_t *, offset_t, struct as *, caddr_t, u_int, u_char, u_char, u_int, cred_t *);extern int wrapfs_delmap(vnode_t *, offset_t, struct as *, caddr_t, u_int, u_int, u_int, u_int, cred_t *);/* * Called from pvn_getpages or wrapfs_getpage to get a particular page. * Return one pages from [off..off+len] in given file. * rw is S_{READ,WRITE,EXEC,CREAT} flags from <vm/seg_enum.h>. */intwrapfs_getapage( vnode_t * vp, /* vnode */ u_offset_t offset, /* offset */ u_int len, /* length (can be 0) */ u_int * protp, /* out arg: modified protection? */ page_t * plarr[], /* out arg: pages array to fill in? */ u_int plsz, /* length of pl[] array */ struct seg *seg, /* segment in question? */ caddr_t addr, /* address? */ enum seg_rw rw, /* read/write flag (of WHAT?) */ cred_t * cr /* user credentials */){ int error = EPERM; vnode_t *hidden_vp = NULL; caddr_t va; page_t *this_pp, *hidden_pp = NULL; int ret; fist_dprint(4, "wrapfs_getapage vp %x, v_pages 0x%x, offset=%d, len=%d, rw=0x%x, protp=0x%x, addr=0x%x, plsz=%d\n", vp, vp->v_pages, offset, len, rw, (protp ? *protp : -1), addr, plsz); if (len > PAGESIZE) { fist_dprint(6, "GETAPAGE: len %d is greater than PAGESIZE, truncating.\n", len, PAGESIZE); len = PAGESIZE; } /* try to find this page in memory, and return it if found */ this_pp = page_lookup(vp, offset, SE_EXCL); if (this_pp) { fist_dprint(6, "WRAPFS_GETAPAGE: found page lookup\n"); plarr[0] = this_pp; plarr[1] = NULL; error = 0; goto out; } /* if this page was not found, create it because we would need it later */ this_pp = page_create(vp, offset, PAGESIZE, PG_WAIT|PG_EXCL); /* * if returns NULL, page may exist in hidden_vp by a thread which ran in * between our page_lookup and page_create! or memory exhaused. * either way, it is a bad thing */ if (!this_pp) { printk("%s:%d: no more memory\n", __FUNCTION__, __LINE__); error = ENOMEM; goto out; } /* remove unnecessary lock only if needed */ if (page_iolock_assert(this_pp)) PAGE_IO_UNLOCK(this_pp); /* find underlying vnode */ hidden_vp = vntofwn(vp)->fwn_vnodep; /* * if hidden page not found, call VOP_GETPAGE (which will zfod it if it * does not exist! */ /* XXX: take out this next "if" */ if (!hidden_pp) { error = VOP_GETPAGE(hidden_vp, (offset_t) offset, len, protp, plarr, PAGESIZE, /* pass PAGESIZE b/c we want only 1 page */ seg, addr, rw, /* XXX: should this be S_READ always? */ cr); if (error) { /* if gets here, something really bad happend! */ printk("VOP_GETPAGE failed with error=%d\n", error); PAGE_UNLOCK(this_pp); hat_pagesync(this_pp, HAT_SYNC_ZERORM); /* must be done before PP_CLRREFMOD */ page_clr_all_props(this_pp); /* XXX: EZK: new in 2.6 */ // PP_CLRREFMOD(this_pp); goto out; } hidden_pp = plarr[0]; if (page_iolock_assert(hidden_pp)) PAGE_IO_UNLOCK(hidden_pp); } /* got hidden page from hidden vnode: copy and decode it */ ppcopy(hidden_pp, this_pp); va = ppmapin(this_pp, PROT_READ | PROT_WRITE, (caddr_t) -1); ret = wrapfs_decode_block(va, va, len, vp, vp->v_vfsp); ppmapout(va); /* cleanup locks on hidden_pp as needed! */ ASSERT(!page_iolock_assert(hidden_pp)); PAGE_UNLOCK(hidden_pp); ASSERT(!page_iolock_assert(this_pp)); /* do not page_unlock(this_pp), b/c upper layer would */ /* final stage: set outgoing arguments */ plarr[0] = this_pp; plarr[1] = NULL; error = 0;out: print_location(); return (error);}/* Return all the pages from [off..off+len] in given file */intwrapfs_getpage( vnode_t * vp, /* vnode */ u_offset_t offset, /* offset */ u_int len, /* length */ u_int * protp, /* out arg: modified protection? */ page_t * plarr[], /* out arg: pages array to fill in? */ u_int plsz, /* actual size to return? */ struct seg *seg, /* segment in question? */ caddr_t addr, /* address? */ enum seg_rw rw, /* read/write flag (of WHAT?) */ cred_t * cr /* user credentials */){ int error = EPERM; fist_dprint(4, "wrapfs_getpage vp %x, offset=%d, len=%d, rw=0x%x, plsz=%d\n", vp, (u_int) offset, len, rw, plsz); if (plarr == NULL) { error = 0; goto out; } if (vp->v_flag & VNOMAP) { error = ENOSYS; goto out; } if (protp != NULL) *protp = PROT_ALL;again: if (len <= PAGESIZE) { fist_dprint(6, "GETPAGE is calling getapage with len=%d, pagesize=%d\n", len, PAGESIZE); error = wrapfs_getapage(vp, offset, len, protp, plarr, plsz, seg, addr, rw, cr); fist_dprint(6, "GETPAGE is back from calling getapage\n"); } else { fist_dprint(6, "GETPAGE is calling pvn_getpages with len=%d, pagesize=%d\n", len, PAGESIZE); error = pvn_getpages(wrapfs_getapage, vp, offset, len, protp, plarr, plsz, seg, addr, rw, cr); fist_dprint(6, "GETPAGE is back from calling pvn_getpages\n"); } if (error == ENOSPC || error == EAGAIN) { fist_dprint(6, "WRAPFS: getpage is trying again...\n"); goto again; }out: print_location(); return (error);}intwrapfs_putapage( struct vnode *vp, page_t * pp, u_offset_t * offp, u_int * lenp, /* return values */ int flags, struct cred *cr){ int error = EPERM; vnode_t *hidden_vp = NULL; caddr_t va; u_int offset = pp->p_offset; page_t *this_pp = pp; page_t *hidden_pp = NULL; int ret; fist_dprint(4, "wrapfs_putapage vp %x, offp 0x%x, lenp 0x%x, flags 0x%x, pp->p_state=0x%x\n", vp, offp, lenp, flags, (int) pp->p_state); /* verify that this page has at least a shared lock */ ASSERT(!se_shared_assert(&(this_pp->p_selock))); /* find interposed vnode */ hidden_vp = vntofwn(vp)->fwn_vnodep; /* lookup for hidden page with same offset and lock if exclusively */ hidden_pp = page_lookup(hidden_vp, offset, SE_EXCL); /* if not found, create new page and lock it exclusively */ if (!hidden_pp) { hidden_pp = page_create(hidden_vp, offset, PAGESIZE, PG_WAIT|PG_EXCL); /* * if returns NULL, page may exist in hidden_vp by a thread which ran in * between our page_lookup and page_create! or memory exhaused. * either way, it is a bad thing */ if (!hidden_pp) { printk("%s:%d: no more memory\n", __FUNCTION__, __LINE__); error = ENOMEM; goto out; } /* remove this unnecessary lock, leaving only the regular lock */ if (page_iolock_assert(hidden_pp)) PAGE_IO_UNLOCK(hidden_pp); } /* copy data from this page to the hidden page */ ppcopy(this_pp, hidden_pp); /* map page into kernel virtual memory */ va = ppmapin(hidden_pp, PROT_READ | PROT_WRITE, (caddr_t) -1); /* encode hidden page using key in vp */ wrapfs_encode_block(va, va, PAGESIZE, vp, vp->v_vfsp); /* unmap page */ ppmapout(va); /* mark hidden page as dirty and unlock it */ /* the next 3 lines are crucial, else we deadlock */ ASSERT(!page_iolock_assert(hidden_pp)); PAGE_UNLOCK(hidden_pp); page_set_props(hidden_pp, P_MOD); // PP_SETMOD(hidden_pp); /* set dirty bit */ /* pass operation to hidden filesystem, and return status */ error = VOP_PUTPAGE(hidden_vp, (offset_t) offset, PAGESIZE, /* was 0 or PAGESIZE */ flags, /* was | B_DONTNEED | B_FREE */ cr); /* was cr */ if (error) { printk("VOP_PUTPAGE failed with error %d.\n", error); goto out; } hat_pagesync(this_pp, HAT_SYNC_ZERORM); /* must do before PP_CLRREFMOD */ page_clr_all_props(this_pp); /* XXX: EZK: new in 2.6 */ // PP_CLRREFMOD(this_pp); ret = pvn_getdirty(this_pp, flags);out: print_location(); return (error);}/* * Flags are composed of {B_INVAL, B_FREE, B_DONTNEED, B_FORCE} * If len == 0, do from off to EOF. * * B_* are from <sys/buf.h> * * The normal cases should be len == 0 & off == 0 (entire vp list), * len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE * (from pageout). * Note len can be greater than one page! */intwrapfs_putpage( vnode_t * vp, offset_t offset, u_int len, int flags, cred_t * cr){ int error = 0; page_t *this_pp; offset_t cur_offset = offset; /* OK */ fist_dprint(4, "PUTPAGE vp 0x%x, v_pages=0x%x, fstype %d, offset=0x%x, len=%d, flags=0x%x\n", vp, vp->v_pages, vp->v_vfsp->vfs_fstype, (u_int) offset, len, flags); if(cr==kcred){ printk("putpage called with kcred, ignoring\n"); error=0; goto out; } /* if no pages are left in this vnode, then all is OK */ if (vp->v_pages == NULL) { error = 0; goto out; } /* deal with len==0 case by flushing all pages w/ offset>=offset */ if (len == 0) { error = pvn_vplist_dirty(vp, (u_int) offset, wrapfs_putapage, flags, cr); goto out; } /* now handle one or more pages */ for (cur_offset = offset; cur_offset < offset+len; cur_offset += PAGESIZE) { /* get an exclusive lock on the page b/c we are going to modify it */ this_pp = page_lookup(vp, (u_int) cur_offset, SE_EXCL); if (!this_pp) { fist_dprint(6, "WRAPFS: putpage failed to find page at cur_offset 0x%x\n", (u_int) cur_offset); continue; /* NOT AN ERROR: go on looking for next page */ } fist_dprint(6, "PUTPAGE page_lookup ok cur_offset 0x%x!\n", (u_int) cur_offset); error = wrapfs_putapage(vp, this_pp, NULL, NULL, flags, cr); if (error) { printk("PUTPAGE: putapage failed with error %d\n", error); goto out; /* XXX: continue loop or abort? */ } } /* end of "for (cur_offset..." loop */out: print_location(); return (error);}intwrapfs_map( vnode_t * vp, offset_t offset, struct as *as, caddr_t * addrp, u_int len, u_char prot, u_char maxprot, u_int flags, cred_t * cr){ struct segvn_crargs vn_a; int error; fist_dprint(4, "wrapfs_map vp %x\n", vp); fist_dprint(4, "wrapfs_map offset=%d, len=%d, prot=0x%x, maxprot=0x%x, flags=0x%x\n", (int) offset, /* from mmap() */ (int) len, /* from mmap() */ (int) prot, /* from mmap() | PROT_USER */ (int) maxprot, /* PROT_ALL */ (int) flags); /* from mmap() */ /* addrp is returned to user from mmap(2) */ if (vp->v_flag & VNOMAP) return (ENOSYS); if ((int) offset < 0 || (int) (offset + len) < 0) return (EINVAL); as_rangelock(as); if ((flags & MAP_FIXED) == 0) { map_addr(addrp, len, (off_t) offset, 1); if (*addrp == NULL) { as_rangeunlock(as); return (ENOMEM); } } else { /* * User specified address - blow away any previous mappings */ (void) as_unmap(as, *addrp, len); } vn_a.vp = vp; vn_a.offset = (u_int) offset; vn_a.type = flags & MAP_TYPE; vn_a.prot = prot; vn_a.maxprot = maxprot; vn_a.flags = flags & ~MAP_TYPE; vn_a.cred = cr; vn_a.amp = NULL; error = as_map(as, *addrp, len, segvn_create, (caddr_t) & vn_a); as_rangeunlock(as); return (error);}intwrapfs_addmap( vnode_t * vp, offset_t offset, struct as *as, caddr_t addr, u_int len, u_char prot, u_char maxprot, u_int flags, cred_t * cr){ fist_wrapfs_node_t *fwnp = vntofwn(vp); fist_dprint(4, "wrapfs_addmap vp 0x%x, v_pages 0x%x\n", vp, vp->v_pages); if (vp->v_flag & VNOMAP) return (ENOSYS); /* increment mapped pages counter */ /* * This whole thing is for a program which does open(), then mmap(), * then close(), and THEN access the bytes of the page! */ mutex_enter(&fwnp->fwn_lock); if (fwnp->fwn_mapcnt == 0) VN_HOLD(vp); fwnp->fwn_mapcnt += btopr(len); fist_dprint(6, "WRAPFS_ADDMAP: fwnp->fwn_mapcnt %d.\n", fwnp->fwn_mapcnt); mutex_exit(&fwnp->fwn_lock); return 0;}intwrapfs_delmap( vnode_t * vp, offset_t offset, struct as *as, caddr_t addr, u_int len, u_int prot, u_int maxprot, u_int flags, cred_t * cr){ vnode_t *hidden_vp; fist_wrapfs_node_t *fwnp = vntofwn(vp); hidden_vp = vntofwn(vp)->fwn_vnodep; fist_dprint(4, "wrapfs_delmap vp 0x%x, v_pages=0x%x, hidden_pages=0x%x\n", vp, (int) vp->v_pages, (int) hidden_vp->v_pages); if (vp->v_flag & VNOMAP) return (ENOSYS); /* decrement mapped pages counter */ mutex_enter(&fwnp->fwn_lock); fwnp->fwn_mapcnt -= btopr(len); if (fwnp->fwn_mapcnt == 0) VN_RELE(vp); fist_dprint(6, "WRAPFS_DELMAP: fwnp->fwn_mapcnt %d.\n", fwnp->fwn_mapcnt); mutex_exit(&fwnp->fwn_lock); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -