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
fbread(vnode_t * vp,offset_t off,uint_t len,enum seg_rw rw,struct fbuf ** fbpp)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
fbzero(vnode_t * vp,offset_t off,uint_t len,struct fbuf ** fbpp)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
fbrelse(struct fbuf * fbp,enum seg_rw rw)164 fbrelse(struct fbuf *fbp, enum seg_rw rw)
165 {
166 FBCOMMON(fbp, rw, 0, (void))
167 }
168
169 int
fbwrite(struct fbuf * fbp)170 fbwrite(struct fbuf *fbp)
171 {
172 FBCOMMON(fbp, S_WRITE, SM_WRITE, return)
173 }
174
175 int
fbdwrite(struct fbuf * fbp)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
fbiwrite(struct fbuf * fbp,vnode_t * devvp,daddr_t bn,int bsize)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