Home | History | Annotate | Download | only in os
      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, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     23 /*	  All Rights Reserved  	*/
     24 
     25 
     26 /*
     27  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
     28  * Use is subject to license terms.
     29  */
     30 
     31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     32 
     33 #include <sys/types.h>
     34 #include <sys/buf.h>
     35 #include <sys/cmn_err.h>
     36 #include <sys/conf.h>
     37 #include <sys/debug.h>
     38 #include <sys/errno.h>
     39 #include <sys/fbuf.h>
     40 #include <sys/kmem.h>
     41 #include <sys/param.h>
     42 #include <sys/sysmacros.h>
     43 #include <sys/vfs.h>
     44 #include <sys/cred.h>
     45 #include <sys/vnode.h>
     46 #include <vm/hat.h>
     47 #include <vm/as.h>
     48 #include <vm/seg.h>
     49 #include <vm/seg_kmem.h>
     50 #include <vm/seg_map.h>
     51 #include <vm/seg_kpm.h>
     52 
     53 
     54 /*
     55  * Pseudo-bio routines which use a segmap mapping to address file data.
     56  */
     57 
     58 /*
     59  * Return a pointer to locked kernel virtual address for
     60  * the given <vp, off> for len bytes.  It is not allowed to
     61  * have the offset cross a MAXBSIZE boundary over len bytes.
     62  */
     63 int
     64 fbread(vnode_t *vp, offset_t off, uint_t len, enum seg_rw rw,
     65 	struct fbuf **fbpp)
     66 {
     67 	caddr_t addr;
     68 	ulong_t o;
     69 	struct fbuf *fbp;
     70 	faultcode_t err;
     71 	caddr_t	raddr;
     72 	uint_t	rsize;
     73 	uintptr_t pgoff = PAGEOFFSET;
     74 
     75 	o = (ulong_t)(off & (offset_t)MAXBOFFSET);
     76 	if (o + len > MAXBSIZE)
     77 		cmn_err(CE_PANIC, "fbread");
     78 
     79 	if (segmap_kpm) {
     80 		addr = segmap_getmapflt(segkmap, vp, off & (offset_t)MAXBMASK,
     81 					MAXBSIZE, SM_LOCKPROTO, rw);
     82 	} else {
     83 		addr = segmap_getmapflt(segkmap, vp,
     84 				off & (offset_t)MAXBMASK, MAXBSIZE, 0, rw);
     85 	}
     86 
     87 	raddr = (caddr_t)((uintptr_t)(addr + o) & ~pgoff);
     88 	rsize = (((uintptr_t)(addr + o) + len + pgoff) & ~pgoff) -
     89 	    (uintptr_t)raddr;
     90 
     91 	err = segmap_fault(kas.a_hat, segkmap, raddr, rsize, F_SOFTLOCK, rw);
     92 	if (err) {
     93 		(void) segmap_release(segkmap, addr, 0);
     94 		if (FC_CODE(err) == FC_OBJERR)
     95 			return (FC_ERRNO(err));
     96 		else
     97 			return (EIO);
     98 	}
     99 
    100 	*fbpp = fbp = kmem_alloc(sizeof (struct fbuf), KM_SLEEP);
    101 	fbp->fb_addr = addr + o;
    102 	fbp->fb_count = len;
    103 	return (0);
    104 }
    105 
    106 /*
    107  * Similar to fbread() but we call segmap_pagecreate instead of using
    108  * segmap_fault for SOFTLOCK to create the pages without using VOP_GETPAGE
    109  * and then we zero up to the length rounded to a page boundary.
    110  * XXX - this won't work right when bsize < PAGESIZE!!!
    111  */
    112 void
    113 fbzero(vnode_t *vp, offset_t off, uint_t len, struct fbuf **fbpp)
    114 {
    115 	caddr_t addr;
    116 	ulong_t o, zlen;
    117 	struct fbuf *fbp;
    118 
    119 	o = (ulong_t)(off & MAXBOFFSET);
    120 	if (o + len > MAXBSIZE)
    121 		cmn_err(CE_PANIC, "fbzero: Bad offset/length");
    122 
    123 	if (segmap_kpm) {
    124 		addr = segmap_getmapflt(segkmap, vp, off & (offset_t)MAXBMASK,
    125 				MAXBSIZE, SM_PAGECREATE, S_WRITE) + o;
    126 	} else {
    127 		addr = segmap_getmap(segkmap, vp, off & (offset_t)MAXBMASK) + o;
    128 	}
    129 
    130 	*fbpp = fbp = kmem_alloc(sizeof (struct fbuf), KM_SLEEP);
    131 	fbp->fb_addr = addr;
    132 	fbp->fb_count = len;
    133 
    134 	(void) segmap_pagecreate(segkmap, addr, len, 1);
    135 
    136 	/*
    137 	 * Now we zero all the memory in the mapping we are interested in.
    138 	 */
    139 	zlen = (caddr_t)ptob(btopr((uintptr_t)(len + addr))) - addr;
    140 	if (zlen < len || (o + zlen > MAXBSIZE))
    141 		cmn_err(CE_PANIC, "fbzero: Bad zlen");
    142 	bzero(addr, zlen);
    143 }
    144 
    145 /*
    146  * FBCOMMON() is the common code for fbrelse, fbwrite and variants thereof:
    147  *
    148  * fbrelse()	release fbp
    149  * fbwrite()	direct write
    150  * fbdwrite()	delayed write
    151  */
    152 #define	FBCOMMON(fbp, rw, flags, howtoreturn) \
    153 { \
    154 	caddr_t addr; \
    155 	size_t size; \
    156 	uintptr_t pgoff = PAGEOFFSET; \
    157 	addr = (caddr_t)((uintptr_t)fbp->fb_addr & ~pgoff); \
    158 	size = ((fbp->fb_addr - addr) + fbp->fb_count + pgoff) & ~pgoff; \
    159 	(void) segmap_fault(kas.a_hat, segkmap, addr, size, F_SOFTUNLOCK, rw); \
    160 	addr = (caddr_t)((uintptr_t)fbp->fb_addr & MAXBMASK); \
    161 	kmem_free(fbp, sizeof (struct fbuf)); \
    162 	howtoreturn(segmap_release(segkmap, addr, flags)); \
    163 }
    164 
    165 void
    166 fbrelse(struct fbuf *fbp, enum seg_rw rw)
    167 {
    168 	FBCOMMON(fbp, rw, 0, (void))
    169 }
    170 
    171 int
    172 fbwrite(struct fbuf *fbp)
    173 {
    174 	FBCOMMON(fbp, S_WRITE, SM_WRITE, return)
    175 }
    176 
    177 int
    178 fbdwrite(struct fbuf *fbp)
    179 {
    180 	FBCOMMON(fbp, S_WRITE, 0, return)
    181 }
    182 
    183 /*
    184  * Perform a synchronous indirect write of the given block number
    185  * on the given device, using the given fbuf.  Upon return the fbp
    186  * is invalid.
    187  */
    188 int
    189 fbiwrite(struct fbuf *fbp, vnode_t *devvp, daddr_t bn, int bsize)
    190 {
    191 	struct buf *bp;
    192 	int error, fberror;
    193 
    194 	/*
    195 	 * Allocate a temp bp using pageio_setup, but then use it
    196 	 * for physio to the area mapped by fbuf which is currently
    197 	 * all locked down in place.
    198 	 *
    199 	 * XXX - need to have a generalized bp header facility
    200 	 * which we build up pageio_setup on top of.  Other places
    201 	 * (like here and in device drivers for the raw I/O case)
    202 	 * could then use these new facilities in a more straight
    203 	 * forward fashion instead of playing all these games.
    204 	 */
    205 	bp = pageio_setup((struct page *)NULL, fbp->fb_count, devvp, B_WRITE);
    206 	bp->b_flags &= ~B_PAGEIO;		/* XXX */
    207 	bp->b_un.b_addr = fbp->fb_addr;
    208 
    209 	bp->b_blkno = bn * btod(bsize);
    210 	bp->b_dev = cmpdev(devvp->v_rdev);	/* store in old dev format */
    211 	bp->b_edev = devvp->v_rdev;
    212 	bp->b_proc = NULL;			/* i.e. the kernel */
    213 
    214 	(void) bdev_strategy(bp);
    215 	error = biowait(bp);
    216 	pageio_done(bp);
    217 
    218 	/*CSTYLED*/
    219 	FBCOMMON(fbp, S_OTHER, 0, fberror = )
    220 
    221 	return (error ? error : fberror);
    222 }
    223