1/*- 2 * Copyright (c) 2004 Max Khon |
3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright --- 9 unchanged lines hidden (view full) --- 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> |
28__FBSDID("$FreeBSD: stable/10/sys/geom/uzip/g_uzip.c 266220 2014-05-16 14:28:55Z loos $"); |
29 30#include <sys/param.h> 31#include <sys/bio.h> 32#include <sys/endian.h> 33#include <sys/errno.h> 34#include <sys/kernel.h> 35#include <sys/lock.h> 36#include <sys/mutex.h> --- 44 unchanged lines hidden (view full) --- 81 82 struct mtx last_mtx; 83 uint32_t last_blk; /* last blk no */ 84 char *last_buf; /* last blk data */ 85 int req_total; /* total requests */ 86 int req_cached; /* cached requests */ 87}; 88 |
89static void 90g_uzip_softc_free(struct g_uzip_softc *sc, struct g_geom *gp) 91{ 92 93 if (gp != NULL) { 94 printf("%s: %d requests, %d cached\n", 95 gp->name, sc->req_total, sc->req_cached); 96 } --- 18 unchanged lines hidden (view full) --- 115 116static void 117z_free(void *nil, void *ptr) 118{ 119 120 free(ptr, M_GEOM_UZIP); 121} 122 |
123static void 124g_uzip_done(struct bio *bp) 125{ |
126 int err; |
127 struct bio *bp2; |
128 z_stream zs; 129 struct g_provider *pp, *pp2; |
130 struct g_consumer *cp; 131 struct g_geom *gp; 132 struct g_uzip_softc *sc; |
133 off_t iolen, pos, upos; 134 uint32_t start_blk, i; 135 size_t bsize; |
136 137 bp2 = bp->bio_parent; |
138 pp = bp2->bio_to; 139 gp = pp->geom; 140 cp = LIST_FIRST(&gp->consumer); 141 pp2 = cp->provider; |
142 sc = gp->softc; |
143 DPRINTF(("%s: done\n", gp->name)); |
144 |
145 bp2->bio_error = bp->bio_error; 146 if (bp2->bio_error != 0) 147 goto done; 148 |
149 /* 150 * Uncompress data. 151 */ |
152 zs.zalloc = z_alloc; 153 zs.zfree = z_free; |
154 err = inflateInit(&zs); 155 if (err != Z_OK) { 156 bp2->bio_error = EIO; |
157 goto done; 158 } |
159 start_blk = bp2->bio_offset / sc->blksz; 160 bsize = pp2->sectorsize; 161 iolen = bp->bio_completed; 162 pos = sc->offsets[start_blk] % bsize; 163 upos = 0; 164 DPRINTF(("%s: done: start_blk %d, pos %jd, upos %jd, iolen %jd " 165 "(%jd, %d, %zd)\n", 166 gp->name, start_blk, (intmax_t)pos, (intmax_t)upos, 167 (intmax_t)iolen, (intmax_t)bp2->bio_offset, sc->blksz, bsize)); 168 for (i = start_blk; upos < bp2->bio_length; i++) { 169 off_t len, ulen, uoff; |
170 |
171 uoff = i == start_blk ? bp2->bio_offset % sc->blksz : 0; 172 ulen = MIN(sc->blksz - uoff, bp2->bio_length - upos); 173 len = sc->offsets[i + 1] - sc->offsets[i]; 174 |
175 if (len == 0) { 176 /* All zero block: no cache update */ |
177 bzero(bp2->bio_data + upos, ulen); 178 upos += ulen; 179 bp2->bio_completed += ulen; 180 continue; 181 } 182 if (len > iolen) { 183 DPRINTF(("%s: done: early termination: len (%jd) > " 184 "iolen (%jd)\n", 185 gp->name, (intmax_t)len, (intmax_t)iolen)); |
186 break; |
187 } 188 zs.next_in = bp->bio_data + pos; 189 zs.avail_in = len; 190 zs.next_out = sc->last_buf; 191 zs.avail_out = sc->blksz; 192 mtx_lock(&sc->last_mtx); 193 err = inflate(&zs, Z_FINISH); 194 if (err != Z_STREAM_END) { 195 sc->last_blk = -1; 196 mtx_unlock(&sc->last_mtx); 197 DPRINTF(("%s: done: inflate failed (%jd + %jd -> %jd + %jd + %jd)\n", 198 gp->name, (intmax_t)pos, (intmax_t)len, 199 (intmax_t)uoff, (intmax_t)upos, (intmax_t)ulen)); 200 inflateEnd(&zs); 201 bp2->bio_error = EIO; 202 goto done; 203 } 204 sc->last_blk = i; 205 DPRINTF(("%s: done: inflated %jd + %jd -> %jd + %jd + %jd\n", 206 gp->name, (intmax_t)pos, (intmax_t)len, (intmax_t)uoff, 207 (intmax_t)upos, (intmax_t)ulen)); 208 memcpy(bp2->bio_data + upos, sc->last_buf + uoff, ulen); 209 mtx_unlock(&sc->last_mtx); |
210 |
211 pos += len; 212 iolen -= len; 213 upos += ulen; |
214 bp2->bio_completed += ulen; |
215 err = inflateReset(&zs); 216 if (err != Z_OK) { 217 inflateEnd(&zs); 218 bp2->bio_error = EIO; 219 goto done; 220 } |
221 } |
222 err = inflateEnd(&zs); 223 if (err != Z_OK) { 224 bp2->bio_error = EIO; 225 goto done; 226 } |
227 |
228done: |
229 /* 230 * Finish processing the request. 231 */ 232 DPRINTF(("%s: done: (%d, %jd, %ld)\n", 233 gp->name, bp2->bio_error, (intmax_t)bp2->bio_completed, 234 bp2->bio_resid)); |
235 free(bp->bio_data, M_GEOM_UZIP); 236 g_destroy_bio(bp); |
237 g_io_deliver(bp2, bp2->bio_error); |
238} 239 240static void 241g_uzip_start(struct bio *bp) 242{ |
243 struct bio *bp2; 244 struct g_provider *pp, *pp2; |
245 struct g_geom *gp; |
246 struct g_consumer *cp; |
247 struct g_uzip_softc *sc; |
248 uint32_t start_blk, end_blk; 249 size_t bsize; |
250 251 pp = bp->bio_to; 252 gp = pp->geom; |
253 DPRINTF(("%s: start (%d)\n", gp->name, bp->bio_cmd)); |
254 |
255 if (bp->bio_cmd != BIO_READ) { 256 g_io_deliver(bp, EOPNOTSUPP); 257 return; 258 } |
259 |
260 cp = LIST_FIRST(&gp->consumer); 261 pp2 = cp->provider; |
262 sc = gp->softc; |
263 264 start_blk = bp->bio_offset / sc->blksz; 265 end_blk = (bp->bio_offset + bp->bio_length + sc->blksz - 1) / sc->blksz; 266 KASSERT(start_blk < sc->nblocks, ("start_blk out of range")); 267 KASSERT(end_blk <= sc->nblocks, ("end_blk out of range")); 268 |
269 sc->req_total++; |
270 if (start_blk + 1 == end_blk) { 271 mtx_lock(&sc->last_mtx); 272 if (start_blk == sc->last_blk) { 273 off_t uoff; |
274 |
275 uoff = bp->bio_offset % sc->blksz; 276 KASSERT(bp->bio_length <= sc->blksz - uoff, 277 ("cached data error")); 278 memcpy(bp->bio_data, sc->last_buf + uoff, 279 bp->bio_length); 280 sc->req_cached++; 281 mtx_unlock(&sc->last_mtx); 282 283 DPRINTF(("%s: start: cached 0 + %jd, %jd + 0 + %jd\n", 284 gp->name, (intmax_t)bp->bio_length, (intmax_t)uoff, 285 (intmax_t)bp->bio_length)); 286 bp->bio_completed = bp->bio_length; 287 g_io_deliver(bp, 0); 288 return; 289 } 290 mtx_unlock(&sc->last_mtx); 291 } 292 293 bp2 = g_clone_bio(bp); 294 if (bp2 == NULL) { 295 g_io_deliver(bp, ENOMEM); |
296 return; 297 } |
298 bp2->bio_done = g_uzip_done; 299 DPRINTF(("%s: start (%d..%d), %s: %d + %jd, %s: %d + %jd\n", 300 gp->name, start_blk, end_blk, 301 pp->name, pp->sectorsize, (intmax_t)pp->mediasize, 302 pp2->name, pp2->sectorsize, (intmax_t)pp2->mediasize)); 303 bsize = pp2->sectorsize; 304 bp2->bio_offset = sc->offsets[start_blk] - sc->offsets[start_blk] % bsize; 305 while (1) { 306 bp2->bio_length = sc->offsets[end_blk] - bp2->bio_offset; 307 bp2->bio_length = (bp2->bio_length + bsize - 1) / bsize * bsize; 308 if (bp2->bio_length < MAXPHYS) 309 break; |
310 |
311 end_blk--; 312 DPRINTF(("%s: bio_length (%jd) > MAXPHYS: lowering end_blk " 313 "to %u\n", gp->name, (intmax_t)bp2->bio_length, end_blk)); 314 } 315 DPRINTF(("%s: start %jd + %jd -> %ju + %ju -> %jd + %jd\n", 316 gp->name, 317 (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length, 318 (uintmax_t)sc->offsets[start_blk], 319 (uintmax_t)sc->offsets[end_blk] - sc->offsets[start_blk], 320 (intmax_t)bp2->bio_offset, (intmax_t)bp2->bio_length)); 321 bp2->bio_data = malloc(bp2->bio_length, M_GEOM_UZIP, M_NOWAIT); 322 if (bp2->bio_data == NULL) { 323 g_destroy_bio(bp2); 324 g_io_deliver(bp, ENOMEM); 325 return; 326 } |
327 |
328 g_io_request(bp2, cp); 329 DPRINTF(("%s: start ok\n", gp->name)); |
330} 331 332static void 333g_uzip_orphan(struct g_consumer *cp) 334{ 335 struct g_geom *gp; 336 337 g_trace(G_T_TOPOLOGY, "%s(%p/%s)", __func__, cp, cp->provider->name); --- 224 unchanged lines hidden --- |