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 #include <sys/types.h> 32 #include <sys/buf.h> 33 #include <sys/cmn_err.h> 34 #include <sys/conf.h> 35 #include <sys/debug.h> 36 #include <sys/errno.h> 37 #include <sys/fbuf.h> 38 #include <sys/kmem.h> 39 #include <sys/param.h> 40 #include <sys/sysmacros.h> 41 #include <sys/vfs.h> 42 #include <sys/cred.h> 43 #include <sys/vnode.h> 44 #include <vm/hat.h> 45 #include <vm/as.h> 46 #include <vm/seg.h> 47 #include <vm/seg_kmem.h> 48 #include <vm/seg_map.h> 49 #include <vm/seg_kpm.h> 50 51 52 /* 53 * Pseudo-bio routines which use a segmap mapping to address file data. 54 */ 55 56 /* 57 * Return a pointer to locked kernel virtual address for 58 * the given <vp, off> for len bytes. It is not allowed to 59 * have the offset cross a MAXBSIZE boundary over len bytes. 60 */ 61 int 62 fbread(vnode_t *vp, offset_t off, uint_t len, enum seg_rw rw, 63 struct fbuf **fbpp) 64 { 65 caddr_t addr; 66 ulong_t o; 67 struct fbuf *fbp; 68 faultcode_t err; 69 caddr_t raddr; 70 uint_t rsize; 71 uintptr_t pgoff = PAGEOFFSET; 72 73 o = (ulong_t)(off & (offset_t)MAXBOFFSET); 74 if (o + len > MAXBSIZE) 75 cmn_err(CE_PANIC, "fbread"); 76 77 if (segmap_kpm) { 78 addr = segmap_getmapflt(segkmap, vp, off & (offset_t)MAXBMASK, 79 MAXBSIZE, SM_LOCKPROTO, rw); 80 } else { 81 addr = segmap_getmapflt(segkmap, vp, 82 off & (offset_t)MAXBMASK, MAXBSIZE, 0, rw); 83 } 84 85 raddr = (caddr_t)((uintptr_t)(addr + o) & ~pgoff); 86 rsize = (((uintptr_t)(addr + o) + len + pgoff) & ~pgoff) - 87 (uintptr_t)raddr; 88 89 err = segmap_fault(kas.a_hat, segkmap, raddr, rsize, F_SOFTLOCK, rw); 90 if (err) { 91 (void) segmap_release(segkmap, addr, 0); 92 if (FC_CODE(err) == FC_OBJERR) 93 return (FC_ERRNO(err)); 94 else 95 return (EIO); 96 } 97 98 *fbpp = fbp = kmem_alloc(sizeof (struct fbuf), KM_SLEEP); 99 fbp->fb_addr = addr + o; 100 fbp->fb_count = len; 101 return (0); 102 } 103 104 /* 105 * Similar to fbread() but we call segmap_pagecreate instead of using 106 * segmap_fault for SOFTLOCK to create the pages without using VOP_GETPAGE 107 * and then we zero up to the length rounded to a page boundary. 108 * XXX - this won't work right when bsize < PAGESIZE!!! 109 */ 110 void 111 fbzero(vnode_t *vp, offset_t off, uint_t len, struct fbuf **fbpp) 112 { 113 caddr_t addr; 114 ulong_t o, zlen; 115 struct fbuf *fbp; 116 117 o = (ulong_t)(off & MAXBOFFSET); 118 if (o + len > MAXBSIZE) 119 cmn_err(CE_PANIC, "fbzero: Bad offset/length"); 120 121 if (segmap_kpm) { 122 addr = segmap_getmapflt(segkmap, vp, off & (offset_t)MAXBMASK, 123 MAXBSIZE, SM_PAGECREATE, S_WRITE) + o; 124 } else { 125 addr = segmap_getmap(segkmap, vp, off & (offset_t)MAXBMASK) + o; 126 } 127 128 *fbpp = fbp = kmem_alloc(sizeof (struct fbuf), KM_SLEEP); 129 fbp->fb_addr = addr; 130 fbp->fb_count = len; 131 132 (void) segmap_pagecreate(segkmap, addr, len, 1); 133 134 /* 135 * Now we zero all the memory in the mapping we are interested in. 136 */ 137 zlen = (caddr_t)ptob(btopr((uintptr_t)(len + addr))) - addr; 138 if (zlen < len || (o + zlen > MAXBSIZE)) 139 cmn_err(CE_PANIC, "fbzero: Bad zlen"); 140 bzero(addr, zlen); 141 } 142 143 /* 144 * FBCOMMON() is the common code for fbrelse, fbwrite and variants thereof: 145 * 146 * fbrelse() release fbp 147 * fbwrite() direct write 148 * fbdwrite() delayed write 149 */ 150 #define FBCOMMON(fbp, rw, flags, howtoreturn) \ 151 { \ 152 caddr_t addr; \ 153 size_t size; \ 154 uintptr_t pgoff = PAGEOFFSET; \ 155 addr = (caddr_t)((uintptr_t)fbp->fb_addr & ~pgoff); \ 156 size = ((fbp->fb_addr - addr) + fbp->fb_count + pgoff) & ~pgoff; \ 157 (void) segmap_fault(kas.a_hat, segkmap, addr, size, F_SOFTUNLOCK, rw); \ 158 addr = (caddr_t)((uintptr_t)fbp->fb_addr & MAXBMASK); \ 159 kmem_free(fbp, sizeof (struct fbuf)); \ 160 howtoreturn(segmap_release(segkmap, addr, flags)); \ 161 } 162 163 void 164 fbrelse(struct fbuf *fbp, enum seg_rw rw) 165 { 166 FBCOMMON(fbp, rw, 0, (void)) 167 } 168 169 int 170 fbwrite(struct fbuf *fbp) 171 { 172 FBCOMMON(fbp, S_WRITE, SM_WRITE, return) 173 } 174 175 int 176 fbdwrite(struct fbuf *fbp) 177 { 178 FBCOMMON(fbp, S_WRITE, 0, return) 179 } 180 181 /* 182 * Perform a synchronous indirect write of the given block number 183 * on the given device, using the given fbuf. Upon return the fbp 184 * is invalid. 185 */ 186 int 187 fbiwrite(struct fbuf *fbp, vnode_t *devvp, daddr_t bn, int bsize) 188 { 189 struct buf *bp; 190 int error, fberror; 191 192 /* 193 * Allocate a temp bp using pageio_setup, but then use it 194 * for physio to the area mapped by fbuf which is currently 195 * all locked down in place. 196 * 197 * XXX - need to have a generalized bp header facility 198 * which we build up pageio_setup on top of. Other places 199 * (like here and in device drivers for the raw I/O case) 200 * could then use these new facilities in a more straight 201 * forward fashion instead of playing all these games. 202 */ 203 bp = pageio_setup((struct page *)NULL, fbp->fb_count, devvp, B_WRITE); 204 bp->b_flags &= ~B_PAGEIO; /* XXX */ 205 bp->b_un.b_addr = fbp->fb_addr; 206 207 bp->b_blkno = bn * btod(bsize); 208 bp->b_dev = cmpdev(devvp->v_rdev); /* store in old dev format */ 209 bp->b_edev = devvp->v_rdev; 210 bp->b_proc = NULL; /* i.e. the kernel */ 211 212 (void) bdev_strategy(bp); 213 error = biowait(bp); 214 pageio_done(bp); 215 216 /*CSTYLED*/ 217 FBCOMMON(fbp, S_OTHER, 0, fberror = ) 218 219 return (error ? error : fberror); 220 } 221