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