Index: lib/libstand/cd9660.c =================================================================== --- lib/libstand/cd9660.c +++ lib/libstand/cd9660.c @@ -143,7 +143,7 @@ if (bcmp(sh->type, SUSP_CONTINUATION, 2) == 0) { shc = (ISO_RRIP_CONT *)sh; error = f->f_dev->dv_strategy(f->f_devdata, F_READ, - cdb2devb(isonum_733(shc->location)), + cdb2devb(isonum_733(shc->location)), 0, ISO_DEFAULT_BLOCK_SIZE, susp_buffer, &read); /* Bail if it fails. */ @@ -288,7 +288,7 @@ for (bno = 16;; bno++) { twiddle(1); rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), - ISO_DEFAULT_BLOCK_SIZE, buf, &read); + 0, ISO_DEFAULT_BLOCK_SIZE, buf, &read); if (rc) goto out; if (read != ISO_DEFAULT_BLOCK_SIZE) { @@ -322,7 +322,7 @@ twiddle(1); rc = f->f_dev->dv_strategy (f->f_devdata, F_READ, - cdb2devb(bno + boff), + cdb2devb(bno + boff), 0, ISO_DEFAULT_BLOCK_SIZE, buf, &read); if (rc) @@ -381,7 +381,7 @@ bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length); twiddle(1); rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, cdb2devb(bno), - ISO_DEFAULT_BLOCK_SIZE, buf, &read); + 0, ISO_DEFAULT_BLOCK_SIZE, buf, &read); if (rc) goto out; if (read != ISO_DEFAULT_BLOCK_SIZE) { @@ -438,7 +438,8 @@ twiddle(16); rc = f->f_dev->dv_strategy(f->f_devdata, F_READ, - cdb2devb(blkno), ISO_DEFAULT_BLOCK_SIZE, fp->f_buf, &read); + cdb2devb(blkno), 0, ISO_DEFAULT_BLOCK_SIZE, + fp->f_buf, &read); if (rc) return (rc); if (read != ISO_DEFAULT_BLOCK_SIZE) Index: lib/libstand/dosfs.h =================================================================== --- lib/libstand/dosfs.h +++ lib/libstand/dosfs.h @@ -96,8 +96,6 @@ typedef struct { struct open_file *fd; /* file descriptor */ - u_char *buf; /* buffer */ - u_int bufsec; /* buffered sector */ u_int links; /* active links to structure */ u_int spc; /* sectors per cluster */ u_int bsize; /* cluster size in bytes */ Index: lib/libstand/dosfs.c =================================================================== --- lib/libstand/dosfs.c +++ lib/libstand/dosfs.c @@ -131,7 +131,18 @@ #define stclus(sz, de) ((sz) != 32 ? cv2((de)->clus) : \ ((u_int)cv2((de)->dex.h_clus) << 16) | \ cv2((de)->clus)) - + +/* + * fat cache metadata + */ +struct fatcache { + int unit; /* disk unit number */ + int size; /* buffer (and fat) size in sectors */ + u_char *buf; +}; + +static struct fatcache fat; + static int dosunmount(DOS_FS *); static int parsebs(DOS_FS *, DOS_BS *); static int namede(DOS_FS *, const char *, DOS_DE **); @@ -143,8 +154,36 @@ static int fatget(DOS_FS *, u_int *); static int fatend(u_int, u_int); static int ioread(DOS_FS *, u_int, void *, u_int); -static int iobuf(DOS_FS *, u_int); -static int ioget(struct open_file *, u_int, void *, u_int); +static int ioget(struct open_file *, daddr_t, size_t, void *, u_int); + +static void +dos_read_fat(DOS_FS *fs, struct open_file *fd) +{ + struct devdesc *dd = fd->f_devdata; + + if (fat.buf != NULL) { /* can we reuse old buffer? */ + if (fat.size != fs->spf) { + free(fat.buf); /* no, free old buffer */ + fat.buf = NULL; + } + } + + if (fat.buf == NULL) + fat.buf = malloc(secbyt(fs->spf)); + + if (fat.buf != NULL) { + if (ioget(fd, fs->lsnfat, 0, fat.buf, secbyt(fs->spf)) == 0) { + fat.size = fs->spf; + fat.unit = dd->d_unit; + return; + } + } + if (fat.buf != NULL) /* got IO error */ + free(fat.buf); + fat.buf = NULL; + fat.unit = -1; /* impossible unit */ + fat.size = 0; +} /* * Mount DOS filesystem @@ -153,15 +192,25 @@ dos_mount(DOS_FS *fs, struct open_file *fd) { int err; + struct devdesc *dd = fd->f_devdata; + u_char *buf; bzero(fs, sizeof(DOS_FS)); fs->fd = fd; - if ((err = !(fs->buf = malloc(SECSIZ)) ? errno : 0) || - (err = ioget(fs->fd, 0, fs->buf, 1)) || - (err = parsebs(fs, (DOS_BS *)fs->buf))) { + + if ((err = !(buf = malloc(secbyt(1))) ? errno : 0) || + (err = ioget(fs->fd, 0, 0, buf, secbyt(1))) || + (err = parsebs(fs, (DOS_BS *)buf))) { + if (buf != NULL) + free(buf); (void)dosunmount(fs); return(err); } + free(buf); + + if (fat.buf == NULL || fat.unit != dd->d_unit) + dos_read_fat(fs, fd); + fs->root = dot[0]; fs->root.name[0] = ' '; if (fs->fatsz == 32) { @@ -194,8 +243,6 @@ static int dosunmount(DOS_FS *fs) { - if (fs->buf) - free(fs->buf); free(fs); return(0); } @@ -252,42 +299,47 @@ DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; int err = 0; + /* + * as ioget() can be called *a lot*, use twiddle here. + * also 4 seems to be good value not to slow loading down too much: + * with 270MB file (~540k ioget() calls, twiddle can easily waste 4-5sec. + */ + twiddle(4); nb = (u_int)nbyte; if ((size = fsize(f->fs, &f->de)) == -1) return EINVAL; if (nb > (n = size - f->offset)) - nb = n; + nb = n; off = f->offset; if ((clus = stclus(f->fs->fatsz, &f->de))) - off &= f->fs->bsize - 1; + off &= f->fs->bsize - 1; c = f->c; cnt = nb; while (cnt) { - n = 0; - if (!c) { - if ((c = clus)) - n = bytblk(f->fs, f->offset); - } else if (!off) - n++; - while (n--) { - if ((err = fatget(f->fs, &c))) + n = 0; + if (!c) { + if ((c = clus)) + n = bytblk(f->fs, f->offset); + } else if (!off) + n++; + while (n--) { + if ((err = fatget(f->fs, &c))) goto out; - if (!okclus(f->fs, c)) { + if (!okclus(f->fs, c)) { err = EINVAL; goto out; } - } - if (!clus || (n = f->fs->bsize - off) > cnt) - n = cnt; - if ((err = ioread(f->fs, (c ? blkoff(f->fs, c) : - secbyt(f->fs->lsndir)) + off, - buf, n))) + } + if (!clus || (n = f->fs->bsize - off) > cnt) + n = cnt; + if ((err = ioread(f->fs, (c ? blkoff(f->fs, c) : + secbyt(f->fs->lsndir)) + off, buf, n))) goto out; - f->offset += n; - f->c = c; - off = 0; - buf = (char *)buf + n; - cnt -= n; + f->offset += n; + f->c = c; + off = 0; + buf = (char *)buf + n; + cnt -= n; } out: if (resid) @@ -364,6 +416,23 @@ } static int +dos_checksum(char *name, char *ext) +{ + int x, i; + char buf[11]; + + bcopy(name, buf, 8); + bcopy(ext, buf+8, 3); + x = 0; + for (i = 0; i < 11; i++) { + x = ((x & 1) << 7) | (x >> 1); + x += buf[i]; + x &= 0xff; + } + return (x); +} + +static int dos_readdir(struct open_file *fd, struct dirent *d) { /* DOS_FILE *f = (DOS_FILE *)fd->f_fsdata; */ @@ -417,12 +486,7 @@ } } else { if (xdn == 1) { - x = 0; - for (i = 0; i < 11; i++) { - x = ((x & 1) << 7) | (x >> 1); - x += dd.de.name[i]; - x &= 0xff; - } + x = dos_checksum(dd.de.name, dd.de.ext); if (x == chk) break; } else { @@ -555,7 +619,7 @@ else return EINVAL; for (sec = 0; sec < nsec; sec++) { - if ((err = ioget(fs->fd, lsec + sec, dir, 1))) + if ((err = ioget(fs->fd, lsec + sec, 0, dir, secbyt(1)))) return err; for (ent = 0; ent < DEPSEC; ent++) { if (!*dir[ent].de.name) @@ -577,9 +641,7 @@ } } else if (!(dir[ent].de.attr & FA_LABEL)) { if ((ok = xdn == 1)) { - for (x = 0, i = 0; i < 11; i++) - x = ((((x & 1) << 7) | (x >> 1)) + - dir[ent].de.name[i]) & 0xff; + x = dos_checksum(dir[ent].de.name, dir[ent].de.ext); ok = chk == x && !strcasecmp(name, (const char *)lfn); } @@ -699,22 +761,52 @@ } /* - * Get next cluster in cluster chain + * Get next cluster in cluster chain. Use in core fat cache unless another + * device replaced it. */ static int fatget(DOS_FS *fs, u_int *c) { u_char buf[4]; - u_int x; - int err; + u_char *s; + u_int x, offset, off, n, nbyte, lsec; + struct devdesc *dd = fs->fd->f_devdata; + int err = 0; + + if (fat.unit != dd->d_unit) { + /* fat cache was changed to another device, dont use it */ + err = ioread(fs, secbyt(fs->lsnfat) + fatoff(fs->fatsz, *c), buf, + fs->fatsz != 32 ? 2 : 4); + if (err) + return err; + } else { + offset = fatoff(fs->fatsz, *c); + nbyte = fs->fatsz != 32 ? 2 : 4; + + s = buf; + if ((off = offset & (SECSIZ - 1))) { + offset -= off; + lsec = bytsec(offset); + offset += SECSIZ; + if ((n = SECSIZ - off) > nbyte) + n = nbyte; + memcpy(s, fat.buf + secbyt(lsec) + off, n); + s += n; + nbyte -= n; + } + n = nbyte & (SECSIZ - 1); + if (nbyte -= n) { + memcpy(s, fat.buf + secbyt(bytsec(offset)), nbyte); + offset += nbyte; + s += nbyte; + } + if (n) + memcpy(s, fat.buf + secbyt(bytsec(offset)), n); + } - err = ioread(fs, secbyt(fs->lsnfat) + fatoff(fs->fatsz, *c), buf, - fs->fatsz != 32 ? 2 : 4); - if (err) - return err; x = fs->fatsz != 32 ? cv2(buf) : cv4(buf); *c = fs->fatsz == 12 ? *c & 1 ? x >> 4 : x & 0xfff : x; - return 0; + return (0); } /* @@ -739,42 +831,24 @@ s = buf; if ((off = offset & (SECSIZ - 1))) { offset -= off; - if ((err = iobuf(fs, bytsec(offset)))) - return err; - offset += SECSIZ; if ((n = SECSIZ - off) > nbyte) n = nbyte; - memcpy(s, fs->buf + off, n); + if ((err = ioget(fs->fd, bytsec(offset), off, s, n))) + return err; + offset += SECSIZ; s += n; nbyte -= n; } n = nbyte & (SECSIZ - 1); if (nbyte -= n) { - if ((err = ioget(fs->fd, bytsec(offset), s, bytsec(nbyte)))) + if ((err = ioget(fs->fd, bytsec(offset), 0, s, nbyte))) return err; offset += nbyte; s += nbyte; } if (n) { - if ((err = iobuf(fs, bytsec(offset)))) - return err; - memcpy(s, fs->buf, n); - } - return 0; -} - -/* - * Buffered sector-based I/O primitive - */ -static int -iobuf(DOS_FS *fs, u_int lsec) -{ - int err; - - if (fs->bufsec != lsec) { - if ((err = ioget(fs->fd, lsec, fs->buf, 1))) + if ((err = ioget(fs->fd, bytsec(offset), 0, s, n))) return err; - fs->bufsec = lsec; } return 0; } @@ -783,13 +857,8 @@ * Sector-based I/O primitive */ static int -ioget(struct open_file *fd, u_int lsec, void *buf, u_int nsec) +ioget(struct open_file *fd, daddr_t lsec, size_t offset, void *buf, u_int size) { - int err; - - twiddle(1); - if ((err = (fd->f_dev->dv_strategy)(fd->f_devdata, F_READ, lsec, - secbyt(nsec), buf, NULL))) - return(err); - return(0); + return ((fd->f_dev->dv_strategy)(fd->f_devdata, F_READ, lsec, offset, + size, buf, NULL)); } Index: lib/libstand/ext2fs.c =================================================================== --- lib/libstand/ext2fs.c +++ lib/libstand/ext2fs.c @@ -355,7 +355,7 @@ fp->f_fs = fs; twiddle(1); error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - EXT2_SBLOCK, EXT2_SBSIZE, (char *)fs, &buf_size); + EXT2_SBLOCK, 0, EXT2_SBSIZE, (char *)fs, &buf_size); if (error) goto out; @@ -397,7 +397,7 @@ fp->f_bg = malloc(len); twiddle(1); error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - EXT2_SBLOCK + EXT2_SBSIZE / DEV_BSIZE, len, + EXT2_SBLOCK + EXT2_SBSIZE / DEV_BSIZE, 0, len, (char *)fp->f_bg, &buf_size); if (error) goto out; @@ -509,7 +509,7 @@ twiddle(1); error = (f->f_dev->dv_strategy)(f->f_devdata, - F_READ, fsb_to_db(fs, disk_block), + F_READ, fsb_to_db(fs, disk_block), 0, fs->fs_bsize, buf, &buf_size); if (error) goto out; @@ -570,7 +570,7 @@ buf = malloc(fs->fs_bsize); twiddle(1); error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - ino_to_db(fs, fp->f_bg, inumber), fs->fs_bsize, buf, &rsize); + ino_to_db(fs, fp->f_bg, inumber), 0, fs->fs_bsize, buf, &rsize); if (error) goto out; if (rsize != fs->fs_bsize) { @@ -667,7 +667,7 @@ malloc(fs->fs_bsize); twiddle(1); error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - fsb_to_db(fp->f_fs, ind_block_num), fs->fs_bsize, + fsb_to_db(fp->f_fs, ind_block_num), 0, fs->fs_bsize, fp->f_blk[level], &fp->f_blksize[level]); if (error) return (error); @@ -725,7 +725,7 @@ } else { twiddle(4); error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - fsb_to_db(fs, disk_block), block_size, + fsb_to_db(fs, disk_block), 0, block_size, fp->f_buf, &fp->f_buf_size); if (error) goto done; Index: lib/libstand/read.c =================================================================== --- lib/libstand/read.c +++ lib/libstand/read.c @@ -79,7 +79,7 @@ if (f->f_flags & F_RAW) { twiddle(4); errno = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - btodb(f->f_offset), bcount, dest, &resid); + btodb(f->f_offset), 0, bcount, dest, &resid); if (errno) return (-1); f->f_offset += resid; Index: lib/libstand/stand.h =================================================================== --- lib/libstand/stand.h +++ lib/libstand/stand.h @@ -138,8 +138,8 @@ const char dv_name[8]; int dv_type; /* opaque type constant, arch-dependant */ int (*dv_init)(void); /* early probe call */ - int (*dv_strategy)(void *devdata, int rw, daddr_t blk, size_t size, - char *buf, size_t *rsize); + int (*dv_strategy)(void *devdata, int rw, daddr_t blk, + size_t offset, size_t size, char *buf, size_t *rsize); int (*dv_open)(struct open_file *f, ...); int (*dv_close)(struct open_file *f); int (*dv_ioctl)(struct open_file *f, u_long cmd, void *data); @@ -154,6 +154,24 @@ extern int errno; +/* + * Generic device specifier; architecture-dependent + * versions may be larger, but should be allowed to + * overlap. + */ +struct devdesc +{ + struct devsw *d_dev; + int d_type; +#define DEVT_NONE 0 +#define DEVT_DISK 1 +#define DEVT_NET 2 +#define DEVT_CD 3 +#define DEVT_ZFS 4 + int d_unit; + void *d_opendata; +}; + struct open_file { int f_flags; /* see F_* below */ struct devsw *f_dev; /* pointer to device operations */ Index: lib/libstand/ufs.c =================================================================== --- lib/libstand/ufs.c +++ lib/libstand/ufs.c @@ -157,7 +157,7 @@ buf = malloc(fs->fs_bsize); twiddle(1); rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, + fsbtodb(fs, ino_to_fsba(fs, inumber)), 0, fs->fs_bsize, buf, &rsize); if (rc) goto out; @@ -267,7 +267,7 @@ malloc(fs->fs_bsize); twiddle(1); rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - fsbtodb(fp->f_fs, ind_block_num), + fsbtodb(fp->f_fs, ind_block_num), 0, fs->fs_bsize, fp->f_blk[level], &fp->f_blksize[level]); @@ -348,7 +348,7 @@ twiddle(4); rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - fsbtodb(fs, disk_block), + fsbtodb(fs, disk_block), 0, block_size, fp->f_buf, &fp->f_buf_size); if (rc) return (rc); @@ -367,7 +367,7 @@ twiddle(4); rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE, - fsbtodb(fs, disk_block), + fsbtodb(fs, disk_block), 0, block_size, fp->f_buf, &fp->f_buf_size); return (rc); } @@ -408,7 +408,7 @@ } else { twiddle(4); rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - fsbtodb(fs, disk_block), + fsbtodb(fs, disk_block), 0, block_size, fp->f_buf, &fp->f_buf_size); if (rc) return (rc); @@ -521,7 +521,7 @@ */ for (i = 0; sblock_try[i] != -1; i++) { rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, - sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, + sblock_try[i] / DEV_BSIZE, 0, SBLOCKSIZE, (char *)fs, &buf_size); if (rc) goto out; @@ -651,7 +651,7 @@ twiddle(1); rc = (f->f_dev->dv_strategy)(f->f_devdata, - F_READ, fsbtodb(fs, disk_block), + F_READ, fsbtodb(fs, disk_block), 0, fs->fs_bsize, buf, &buf_size); if (rc) goto out; Index: lib/libstand/write.c =================================================================== --- lib/libstand/write.c +++ lib/libstand/write.c @@ -82,7 +82,7 @@ if (f->f_flags & F_RAW) { twiddle(4); errno = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE, - btodb(f->f_offset), bcount, dest, &resid); + btodb(f->f_offset), 0, bcount, dest, &resid); if (errno) return (-1); f->f_offset += resid; Index: sys/boot/common/bcache.c =================================================================== --- sys/boot/common/bcache.c +++ sys/boot/common/bcache.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1998 Michael Smith + * Copyright 2015 Toomas Soome * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,99 +26,155 @@ */ #include +#include __FBSDID("$FreeBSD$"); /* - * Simple LRU block cache + * Simple hashed block cache */ #include #include #include -#include +#include #include "bootstrap.h" /* #define BCACHE_DEBUG */ #ifdef BCACHE_DEBUG -#define BCACHE_TIMEOUT 10 # define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) #else -#define BCACHE_TIMEOUT 2 # define DEBUG(fmt, args...) #endif - struct bcachectl { daddr_t bc_blkno; - time_t bc_stamp; int bc_count; }; -static struct bcachectl *bcache_ctl; -static caddr_t bcache_data; -static bitstr_t *bcache_miss; -static u_int bcache_nblks; -static u_int bcache_blksize; -static u_int bcache_hits, bcache_misses, bcache_ops, bcache_bypasses; -static u_int bcache_flushes; -static u_int bcache_bcount; - -static void bcache_invalidate(daddr_t blkno); -static void bcache_insert(caddr_t buf, daddr_t blkno); -static int bcache_lookup(caddr_t buf, daddr_t blkno); +/* + * bcache per device node. cache is allocated on device first open and freed + * on last close, to save memory. The issue there is the size; biosdisk + * supports up to 31 (0x1f) devices. Classic setup would use single disk + * to boot from, but this has changed with zfs. + */ +struct bcache { + struct bcachectl *bcache_ctl; + caddr_t bcache_data; + u_int bcache_nblks; + size_t ra; +}; + +static u_int bcache_total_nblks; /* set by bcache_init */ +static u_int bcache_blksize; /* set by bcache_init */ +static u_int bcache_numdev; /* set by bcache_add_dev */ +/* statistics */ +static u_int bcache_units; /* number of devices with cache */ +static u_int bcache_unit_nblks; /* nblocks per unit */ +static u_int bcache_hits; +static u_int bcache_misses; +static u_int bcache_ops; +static u_int bcache_bypasses; +static u_int bcache_bcount; +static u_int bcache_rablks; + +#define BHASH(bc, blkno) ((blkno) & ((bc)->bcache_nblks - 1)) +#define BCACHE_LOOKUP(bc, blkno) \ + ((bc)->bcache_ctl[BHASH((bc), (blkno))].bc_blkno != (blkno)) +#define BCACHE_READAHEAD 256 +#define BCACHE_MINREADAHEAD 32 + +static void bcache_invalidate(struct bcache *bc, daddr_t blkno); +static void bcache_insert(struct bcache *bc, daddr_t blkno); +static void bcache_free_instance(struct bcache *bc); /* * Initialise the cache for (nblks) of (bsize). */ -int +void bcache_init(u_int nblks, size_t bsize) { - /* discard any old contents */ - if (bcache_data != NULL) { - free(bcache_data); - bcache_data = NULL; - free(bcache_ctl); - } - - /* Allocate control structures */ - bcache_nblks = nblks; + /* set up control data */ + bcache_total_nblks = nblks; bcache_blksize = bsize; - bcache_data = malloc(bcache_nblks * bcache_blksize); - bcache_ctl = (struct bcachectl *)malloc(bcache_nblks * sizeof(struct bcachectl)); - bcache_miss = bit_alloc((bcache_nblks + 1) / 2); - if ((bcache_data == NULL) || (bcache_ctl == NULL) || (bcache_miss == NULL)) { - if (bcache_miss) - free(bcache_miss); - if (bcache_ctl) - free(bcache_ctl); - if (bcache_data) - free(bcache_data); - bcache_data = NULL; - return(ENOMEM); - } - - return(0); } /* - * Flush the cache + * add number of devices to bcache. we have to divide cache space + * between the devices, so bcache_add_dev() can be used to set up the + * number. The issue is, we need to get the number before actual allocations. + * bcache_add_dev() is supposed to be called from device init() call, so the + * assumption is, devsw dv_init is called for plain devices first, and + * for zfs, last. */ void -bcache_flush(void) +bcache_add_dev(int devices) { - u_int i; + bcache_numdev += devices; +} - bcache_flushes++; +void * +bcache_allocate(void) +{ + u_int i; + struct bcache *bc = malloc(sizeof (struct bcache)); + int disks = bcache_numdev; + + if (disks == 0) + disks = 1; /* safe guard */ + + if (bc == NULL) { + errno = ENOMEM; + return (bc); + } + + /* + * the bcache block count must be power of 2 for hash function + */ + i = fls(disks) - 1; /* highbit - 1 */ + if (disks > (1 << i)) /* next power of 2 */ + i++; + + bc->bcache_nblks = bcache_total_nblks >> i; + bcache_unit_nblks = bc->bcache_nblks; + bc->bcache_data = malloc(bc->bcache_nblks * bcache_blksize); + if (bc->bcache_data == NULL) { + /* dont error out yet. fall back to 32 blocks and try again */ + bc->bcache_nblks = 32; + bc->bcache_data = malloc(bc->bcache_nblks * bcache_blksize); + } + + bc->bcache_ctl = malloc(bc->bcache_nblks * sizeof(struct bcachectl)); + + if ((bc->bcache_data == NULL) || (bc->bcache_ctl == NULL)) { + bcache_free_instance(bc); + errno = ENOMEM; + return(NULL); + } /* Flush the cache */ - for (i = 0; i < bcache_nblks; i++) { - bcache_ctl[i].bc_count = -1; - bcache_ctl[i].bc_blkno = -1; - } + for (i = 0; i < bc->bcache_nblks; i++) { + bc->bcache_ctl[i].bc_count = -1; + bc->bcache_ctl[i].bc_blkno = -1; + } + bcache_units++; + bc->ra = BCACHE_READAHEAD; /* optimistic read ahead */ + return (bc); +} + +void +bcache_free(void *cache) +{ + struct bcache *bc = cache; + + if (bc == NULL) + return; + + bcache_free_instance(bc); + bcache_units--; } /* @@ -125,31 +182,22 @@ * cache with the new values. */ static int -write_strategy(void *devdata, int unit, int rw, daddr_t blk, size_t size, - char *buf, size_t *rsize) +write_strategy(void *devdata, int rw, daddr_t blk, size_t offset, + size_t size, char *buf, size_t *rsize) { struct bcache_devdata *dd = (struct bcache_devdata *)devdata; + struct bcache *bc = dd->dv_cache; daddr_t i, nblk; - int err; nblk = size / bcache_blksize; /* Invalidate the blocks being written */ for (i = 0; i < nblk; i++) { - bcache_invalidate(blk + i); + bcache_invalidate(bc, blk + i); } /* Write the blocks */ - err = dd->dv_strategy(dd->dv_devdata, rw, blk, size, buf, rsize); - - /* Populate the block cache with the new data */ - if (err == 0) { - for (i = 0; i < nblk; i++) { - bcache_insert(buf + (i * bcache_blksize),blk + i); - } - } - - return err; + return (dd->dv_strategy(dd->dv_devdata, rw, blk, offset, size, buf, rsize)); } /* @@ -158,61 +206,87 @@ * device I/O and then use the I/O results to populate the cache. */ static int -read_strategy(void *devdata, int unit, int rw, daddr_t blk, size_t size, - char *buf, size_t *rsize) +read_strategy(void *devdata, int rw, daddr_t blk, size_t offset, + size_t size, char *buf, size_t *rsize) { struct bcache_devdata *dd = (struct bcache_devdata *)devdata; - int p_size, result; - daddr_t p_blk, i, j, nblk; + struct bcache *bc = dd->dv_cache; + size_t i, nblk, p_size, r_size, complete, ra; + int result; + daddr_t p_blk; caddr_t p_buf; + if (bc == NULL) { + errno = ENODEV; + return (-1); + } + + if (rsize != NULL) + *rsize = 0; + nblk = size / bcache_blksize; + if ((nblk == 0 && size != 0) || offset != 0) + nblk++; result = 0; + complete = 1; - /* Satisfy any cache hits up front */ + /* Satisfy any cache hits up front, break on first miss */ for (i = 0; i < nblk; i++) { - if (bcache_lookup(buf + (bcache_blksize * i), blk + i)) { - bit_set(bcache_miss, i); /* cache miss */ - bcache_misses++; + if (BCACHE_LOOKUP(bc, (daddr_t)(blk + i))) { + bcache_misses += (nblk - i); + complete = 0; + if (nblk - i > BCACHE_MINREADAHEAD && bc->ra > BCACHE_MINREADAHEAD) + bc->ra >>= 1; /* reduce read ahead */ + break; } else { - bit_clear(bcache_miss, i); /* cache hit */ bcache_hits++; } } - /* Go back and fill in any misses XXX optimise */ - p_blk = -1; - p_buf = NULL; - p_size = 0; - for (i = 0; i < nblk; i++) { - if (bit_test(bcache_miss, i)) { - /* miss, add to pending transfer */ - if (p_blk == -1) { - p_blk = blk + i; - p_buf = buf + (bcache_blksize * i); - p_size = 1; - } else { - p_size++; - } - } else if (p_blk != -1) { - /* hit, complete pending transfer */ - result = dd->dv_strategy(dd->dv_devdata, rw, p_blk, p_size * bcache_blksize, p_buf, NULL); - if (result != 0) - goto done; - for (j = 0; j < p_size; j++) - bcache_insert(p_buf + (j * bcache_blksize), p_blk + j); - p_blk = -1; - } - } - if (p_blk != -1) { - /* pending transfer left */ - result = dd->dv_strategy(dd->dv_devdata, rw, p_blk, p_size * bcache_blksize, p_buf, NULL); - if (result != 0) - goto done; - for (j = 0; j < p_size; j++) - bcache_insert(p_buf + (j * bcache_blksize), p_blk + j); - } - + if (complete) { /* whole set was in cache, return it */ + if (bc->ra < BCACHE_READAHEAD) + bc->ra <<= 1; /* increase read ahead */ + bcopy(bc->bcache_data + (bcache_blksize * BHASH(bc, blk)) + offset, + buf, size); + goto done; + } + + /* + * Fill in any misses. From check we have i pointing to first missing + * block, read in all remaining blocks + readahead. + * We have space at least for nblk - i before bcache wraps. + */ + p_blk = blk + i; + p_buf = bc->bcache_data + (bcache_blksize * BHASH(bc, p_blk)); + r_size = bc->bcache_nblks - BHASH(bc, p_blk); /* remaining blocks */ + + p_size = MIN(r_size, nblk - i); /* read at least those blocks */ + + ra = bc->bcache_nblks - BHASH(bc, p_blk + p_size); + if (ra != bc->bcache_nblks) { /* do we have RA space? */ + ra = MIN(bc->ra, ra); + p_size += ra; + } + + /* invalidate bcache */ + for (i = 0; i < p_size; i++) { + bcache_invalidate(bc, p_blk + i); + } + r_size = 0; + result = dd->dv_strategy(dd->dv_devdata, rw, p_blk, 0, + p_size * bcache_blksize, p_buf, &r_size); + + if (result) + goto done; + + r_size /= bcache_blksize; + for (i = 0; i < r_size; i++) + bcache_insert(bc, p_blk + i); + + bcache_rablks += ra; + bcopy(bc->bcache_data + (bcache_blksize * BHASH(bc, blk)) + offset, buf, + size); + done: if ((result == 0) && (rsize != NULL)) *rsize = size; @@ -220,130 +294,144 @@ } /* - * Requests larger than 1/2 the cache size will be bypassed and go + * Requests larger than 1/2 cache size will be bypassed and go * directly to the disk. XXX tune this. */ int -bcache_strategy(void *devdata, int unit, int rw, daddr_t blk, size_t size, - char *buf, size_t *rsize) +bcache_strategy(void *devdata, int rw, daddr_t blk, size_t offset, + size_t size, char *buf, size_t *rsize) { - static int bcache_unit = -1; struct bcache_devdata *dd = (struct bcache_devdata *)devdata; + struct bcache *bc = dd->dv_cache; + u_int bcache_nblks = 0; + int nblk, cblk, ret; + size_t csize, isize, total; bcache_ops++; - if(bcache_unit != unit) { - bcache_flush(); - bcache_unit = unit; - } + if (bc != NULL) + bcache_nblks = bc->bcache_nblks; /* bypass large requests, or when the cache is inactive */ - if ((bcache_data == NULL) || ((size * 2 / bcache_blksize) > bcache_nblks)) { + if (bc == NULL || + (offset == 0 && ((size * 2 / bcache_blksize) > bcache_nblks))) { DEBUG("bypass %d from %d", size / bcache_blksize, blk); bcache_bypasses++; - return(dd->dv_strategy(dd->dv_devdata, rw, blk, size, buf, rsize)); + return (dd->dv_strategy(dd->dv_devdata, rw, blk, offset, size, buf, + rsize)); + } + + /* normalize offset */ + while (offset >= bcache_blksize) { + blk++; + offset -= bcache_blksize; } switch (rw) { case F_READ: - return read_strategy(devdata, unit, rw, blk, size, buf, rsize); + nblk = size / bcache_blksize; + if (offset || (size != 0 && nblk == 0)) + nblk++; /* read at least one block */ + + ret = 0; + total = 0; + while(size) { + cblk = bcache_nblks - BHASH(bc, blk); /* # of blocks left */ + cblk = MIN(cblk, nblk); + + if (size <= bcache_blksize) + csize = size; + else { + csize = cblk * bcache_blksize; + if (offset) + csize -= (bcache_blksize - offset); + } + + ret = read_strategy(devdata, rw, blk, offset, + csize, buf+total, &isize); + if (ret != 0) + return (ret); + blk += (offset+isize) / bcache_blksize; + offset = 0; + total += isize; + size -= isize; + nblk = size / bcache_blksize; + } + + if (rsize) + *rsize = total; + + return (ret); case F_WRITE: - return write_strategy(devdata, unit, rw, blk, size, buf, rsize); + return write_strategy(devdata, rw, blk, offset, size, buf, rsize); } return -1; } - /* - * Insert a block into the cache. Retire the oldest block to do so, if required. - * - * XXX the LRU algorithm will fail after 2^31 blocks have been transferred. + * Free allocated bcache instance */ static void -bcache_insert(caddr_t buf, daddr_t blkno) +bcache_free_instance(struct bcache *bc) { - time_t now; - int cand, ocount; - u_int i; - - time(&now); - cand = 0; /* assume the first block */ - ocount = bcache_ctl[0].bc_count; - - /* find the oldest block */ - for (i = 1; i < bcache_nblks; i++) { - if (bcache_ctl[i].bc_blkno == blkno) { - /* reuse old entry */ - cand = i; - break; - } - if (bcache_ctl[i].bc_count < ocount) { - ocount = bcache_ctl[i].bc_count; - cand = i; - } + if (bc != NULL) { + if (bc->bcache_ctl) + free(bc->bcache_ctl); + if (bc->bcache_data) + free(bc->bcache_data); + free(bc); } - - DEBUG("insert blk %d -> %d @ %d # %d", blkno, cand, now, bcache_bcount); - bcopy(buf, bcache_data + (bcache_blksize * cand), bcache_blksize); - bcache_ctl[cand].bc_blkno = blkno; - bcache_ctl[cand].bc_stamp = now; - bcache_ctl[cand].bc_count = bcache_bcount++; } /* - * Look for a block in the cache. Blocks more than BCACHE_TIMEOUT seconds old - * may be stale (removable media) and thus are discarded. Copy the block out - * if successful and return zero, or return nonzero on failure. + * Insert a block into the cache. */ -static int -bcache_lookup(caddr_t buf, daddr_t blkno) +static void +bcache_insert(struct bcache *bc, daddr_t blkno) { - time_t now; - u_int i; + u_int cand; - time(&now); + cand = BHASH(bc, blkno); - for (i = 0; i < bcache_nblks; i++) - /* cache hit? */ - if ((bcache_ctl[i].bc_blkno == blkno) && ((bcache_ctl[i].bc_stamp + BCACHE_TIMEOUT) >= now)) { - bcopy(bcache_data + (bcache_blksize * i), buf, bcache_blksize); - DEBUG("hit blk %d <- %d (now %d then %d)", blkno, i, now, bcache_ctl[i].bc_stamp); - return(0); - } - return(ENOENT); + DEBUG("insert blk %llu -> %u # %d", blkno, cand, bcache_bcount); + bc->bcache_ctl[cand].bc_blkno = blkno; + bc->bcache_ctl[cand].bc_count = bcache_bcount++; } /* * Invalidate a block from the cache. */ static void -bcache_invalidate(daddr_t blkno) +bcache_invalidate(struct bcache *bc, daddr_t blkno) { u_int i; - for (i = 0; i < bcache_nblks; i++) { - if (bcache_ctl[i].bc_blkno == blkno) { - bcache_ctl[i].bc_count = -1; - bcache_ctl[i].bc_blkno = -1; - DEBUG("invalidate blk %d", blkno); - break; - } + i = BHASH(bc, blkno); + if (bc->bcache_ctl[i].bc_blkno == blkno) { + bc->bcache_ctl[i].bc_count = -1; + bc->bcache_ctl[i].bc_blkno = -1; + DEBUG("invalidate blk %llu", blkno); } } +#ifndef BOOT2 COMMAND_SET(bcachestat, "bcachestat", "get disk block cache stats", command_bcache); static int command_bcache(int argc, char *argv[]) { - u_int i; - - for (i = 0; i < bcache_nblks; i++) { - printf("%08jx %04x %04x|", (uintmax_t)bcache_ctl[i].bc_blkno, (unsigned int)bcache_ctl[i].bc_stamp & 0xffff, bcache_ctl[i].bc_count & 0xffff); - if (((i + 1) % 4) == 0) - printf("\n"); + if (argc != 1) { + command_errmsg = "wrong number of arguments"; + return(CMD_ERROR); } - printf("\n%d ops %d bypasses %d hits %d misses %d flushes\n", bcache_ops, bcache_bypasses, bcache_hits, bcache_misses, bcache_flushes); + + printf("\ncache blocks: %d\n", bcache_total_nblks); + printf("cache blocksz: %d\n", bcache_blksize); + printf("cache readahead: %d\n", bcache_rablks); + printf("unit cache blocks: %d\n", bcache_unit_nblks); + printf("cached units: %d\n", bcache_units); + printf("%d ops %d bypasses %d hits %d misses\n", bcache_ops, + bcache_bypasses, bcache_hits, bcache_misses); return(CMD_OK); } - +#endif Index: sys/boot/common/bootstrap.h =================================================================== --- sys/boot/common/bootstrap.h +++ sys/boot/common/bootstrap.h @@ -33,24 +33,6 @@ #include #include -/* - * Generic device specifier; architecture-dependant - * versions may be larger, but should be allowed to - * overlap. - */ -struct devdesc -{ - struct devsw *d_dev; - int d_type; -#define DEVT_NONE 0 -#define DEVT_DISK 1 -#define DEVT_NET 2 -#define DEVT_CD 3 -#define DEVT_ZFS 4 - int d_unit; - void *d_opendata; -}; - /* Commands and return values; nonzero return sets command_errmsg != NULL */ typedef int (bootblk_cmd_t)(int argc, char *argv[]); extern char *command_errmsg; @@ -90,9 +72,11 @@ void *alloc_pread(int fd, off_t off, size_t len); /* bcache.c */ -int bcache_init(u_int nblks, size_t bsize); -void bcache_flush(void); -int bcache_strategy(void *devdata, int unit, int rw, daddr_t blk, +void bcache_init(u_int nblks, size_t bsize); +void bcache_add_dev(int); +void *bcache_allocate(void); +void bcache_free(void *); +int bcache_strategy(void *devdata, int rw, daddr_t blk, size_t offset, size_t size, char *buf, size_t *rsize); /* @@ -100,8 +84,10 @@ */ struct bcache_devdata { - int (*dv_strategy)(void *devdata, int rw, daddr_t blk, size_t size, char *buf, size_t *rsize); + int (*dv_strategy)(void *devdata, int rw, daddr_t blk, + size_t offset, size_t size, char *buf, size_t *rsize); void *dv_devdata; + void *dv_cache; }; /* Index: sys/boot/common/disk.c =================================================================== --- sys/boot/common/disk.c +++ sys/boot/common/disk.c @@ -178,7 +178,7 @@ dev = (struct disk_devdesc *)d; od = (struct open_disk *)dev->d_opendata; - return (dev->d_dev->dv_strategy(dev, F_READ, offset, + return (dev->d_dev->dv_strategy(dev, F_READ, offset, 0, blocks * od->sectorsize, (char *)buf, NULL)); } @@ -239,7 +239,7 @@ int ret; od = (struct open_disk *)dev->d_opendata; - ret = dev->d_dev->dv_strategy(dev, F_READ, dev->d_offset + offset, + ret = dev->d_dev->dv_strategy(dev, F_READ, dev->d_offset + offset, 0, blocks * od->sectorsize, buf, NULL); return (ret); @@ -252,7 +252,7 @@ int ret; od = (struct open_disk *)dev->d_opendata; - ret = dev->d_dev->dv_strategy(dev, F_WRITE, dev->d_offset + offset, + ret = dev->d_dev->dv_strategy(dev, F_WRITE, dev->d_offset + offset, 0, blocks * od->sectorsize, buf, NULL); return (ret); Index: sys/boot/common/md.c =================================================================== --- sys/boot/common/md.c +++ sys/boot/common/md.c @@ -60,7 +60,7 @@ /* devsw I/F */ static int md_init(void); -static int md_strategy(void *, int, daddr_t, size_t, char *, size_t *); +static int md_strategy(void *, int, daddr_t, size_t, size_t, char *, size_t *); static int md_open(struct open_file *, ...); static int md_close(struct open_file *); static void md_print(int); @@ -84,8 +84,8 @@ } static int -md_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, - size_t *rsize) +md_strategy(void *devdata, int rw, daddr_t blk, size_t offset, size_t size, + char *buf, size_t *rsize) { struct devdesc *dev = (struct devdesc *)devdata; size_t ofs; Index: sys/boot/common/module.c =================================================================== --- sys/boot/common/module.c +++ sys/boot/common/module.c @@ -769,7 +769,7 @@ intp = (int*)recptr; reclen = *intp++; ival = *intp++; - cp = (char*)intp; + cp = (u_char*)intp; switch (ival) { case MDT_VERSION: clen = *cp++; @@ -801,9 +801,9 @@ * Finally check if KLD is in the place */ if (found) - result = file_lookup(mdp->d_path, cp, clen, NULL); + result = file_lookup(mdp->d_path, (const char *)cp, clen, NULL); else if (best) - result = file_lookup(mdp->d_path, best, blen, NULL); + result = file_lookup(mdp->d_path, (const char *)best, blen, NULL); bad: /* * If nothing found or hints is absent - fallback to the old way Index: sys/boot/efi/libefi/efipart.c =================================================================== --- sys/boot/efi/libefi/efipart.c +++ sys/boot/efi/libefi/efipart.c @@ -42,7 +42,10 @@ static EFI_GUID devpath_guid = DEVICE_PATH_PROTOCOL; static int efipart_init(void); -static int efipart_strategy(void *, int, daddr_t, size_t, char *, size_t *); +static int efipart_strategy(void *, int, daddr_t, size_t, size_t, char *, + size_t *); +static int efipart_realstrategy(void *, int, daddr_t, size_t, size_t, char *, + size_t *); static int efipart_open(struct open_file *, ...); static int efipart_close(struct open_file *); static void efipart_print(int); @@ -59,6 +62,21 @@ .dv_cleanup = NULL }; +/* + * info structure to support bcache + */ +#define MAXPDDEV 31 /* see MAXDEV in libi386.h */ + +static struct pdinfo +{ + int pd_unit; /* unit number */ + int pd_open; /* reference counter */ + void *pd_bcache; /* buffer cache data */ +} pdinfo [MAXPDDEV]; +static int npdinfo = 0; + +#define PD(dev) (pdinfo[(dev)->d_unit]) + static int efipart_init(void) { @@ -140,8 +158,13 @@ } else hout[nout] = hin[n]; nout++; + pdinfo[npdinfo].pd_open = 0; + pdinfo[npdinfo].pd_bcache = NULL; + pdinfo[npdinfo].pd_unit = npdinfo; + npdinfo++; } + bcache_add_dev(npdinfo); err = efi_register_handles(&efipart_dev, hout, aliases, nout); free(hin); return (err); @@ -173,7 +196,7 @@ } } -static int +static int efipart_open(struct open_file *f, ...) { va_list args; @@ -198,10 +221,13 @@ return (EAGAIN); dev->d_opendata = blkio; + PD(dev).pd_open++; + if (PD(dev).pd_bcache == NULL) + PD(dev).pd_bcache = bcache_allocate(); return (0); } -static int +static int efipart_close(struct open_file *f) { struct devdesc *dev; @@ -211,6 +237,11 @@ return (EINVAL); dev->d_opendata = NULL; + PD(dev).pd_open--; + if (PD(dev).pd_open == 0) { + bcache_free(PD(dev).pd_bcache); + PD(dev).pd_bcache = NULL; + } return (0); } @@ -254,9 +285,24 @@ return (efi_status_to_errno(status)); } -static int -efipart_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, - size_t *rsize) +static int +efipart_strategy(void *devdata, int rw, daddr_t blk, size_t offset, + size_t size, char *buf, size_t *rsize) +{ + struct bcache_devdata bcd; + struct devdesc *dev; + + dev = (struct devdesc *)devdata; + bcd.dv_strategy = efipart_realstrategy; + bcd.dv_devdata = devdata; + bcd.dv_cache = PD(dev).pd_bcache; + return (bcache_strategy(&bcd, rw, blk, offset, size, + buf, rsize)); +} + +static int +efipart_realstrategy(void *devdata, int rw, daddr_t blk, size_t offset, + size_t size, char *buf, size_t *rsize) { struct devdesc *dev = (struct devdesc *)devdata; EFI_BLOCK_IO *blkio; Index: sys/boot/efi/libefi/libefi.c =================================================================== --- sys/boot/efi/libefi/libefi.c +++ sys/boot/efi/libefi/libefi.c @@ -102,7 +102,7 @@ (void)console_control->SetMode(console_control, EfiConsoleControlScreenText); - heapsize = 3 * 1024 * 1024; + heapsize = 64 * 1024 * 1024; status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, EFI_SIZE_TO_PAGES(heapsize), &heap); if (status != EFI_SUCCESS) Index: sys/boot/efi/loader/main.c =================================================================== --- sys/boot/efi/loader/main.c +++ sys/boot/efi/loader/main.c @@ -210,6 +210,11 @@ cons_probe(); /* + * Initialise the block cache. Set the upper limit. + */ + bcache_init(32768, 512); + + /* * Parse the args to set the console settings, etc * boot1.efi passes these in, if it can read /boot.config or /boot/config * or iPXE may be setup to pass these in. Index: sys/boot/i386/libfirewire/firewire.c =================================================================== --- sys/boot/i386/libfirewire/firewire.c +++ sys/boot/i386/libfirewire/firewire.c @@ -66,7 +66,7 @@ static int fw_init(void); static int fw_strategy(void *devdata, int flag, daddr_t dblk, - size_t size, char *buf, size_t *rsize); + size_t offset, size_t size, char *buf, size_t *rsize); static int fw_open(struct open_file *f, ...); static int fw_close(struct open_file *f); static void fw_print(int verbose); @@ -201,7 +201,8 @@ } static int -fw_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) +fw_strategy(void *devdata, int rw, daddr_t dblk, size_t offset, size_t size, + char *buf, size_t *rsize) { return (EIO); } Index: sys/boot/i386/libi386/bioscd.c =================================================================== --- sys/boot/i386/libi386/bioscd.c +++ sys/boot/i386/libi386/bioscd.c @@ -85,13 +85,19 @@ static struct bcinfo { int bc_unit; /* BIOS unit number */ struct specification_packet bc_sp; + int bc_open; /* reference counter */ + void *bc_bcache; /* buffer cache data */ } bcinfo [MAXBCDEV]; static int nbcinfo = 0; +#define BC(dev) (bcinfo[(dev)->d_unit]) + static int bc_read(int unit, daddr_t dblk, int blks, caddr_t dest); static int bc_init(void); static int bc_strategy(void *devdata, int flag, daddr_t dblk, - size_t size, char *buf, size_t *rsize); + size_t offset, size_t size, char *buf, size_t *rsize); +static int bc_realstrategy(void *devdata, int flag, daddr_t dblk, + size_t offset, size_t size, char *buf, size_t *rsize); static int bc_open(struct open_file *f, ...); static int bc_close(struct open_file *f); static void bc_print(int verbose); @@ -164,6 +170,7 @@ printf("BIOS CD is cd%d\n", nbcinfo); nbcinfo++; + bcache_add_dev(nbcinfo); /* register cd device in bcache */ return(0); } @@ -200,19 +207,44 @@ return(ENXIO); } + BC(dev).bc_open++; + if (BC(dev).bc_bcache == NULL) + BC(dev).bc_bcache = bcache_allocate(); return(0); } static int bc_close(struct open_file *f) { + struct i386_devdesc *dev; + dev = (struct i386_devdesc *)f->f_devdata; + BC(dev).bc_open--; + if (BC(dev).bc_open == 0) { + bcache_free(BC(dev).bc_bcache); + BC(dev).bc_bcache = NULL; + } return(0); } +static int +bc_strategy(void *devdata, int rw, daddr_t dblk, size_t offset, size_t size, + char *buf, size_t *rsize) +{ + struct bcache_devdata bcd; + struct i386_devdesc *dev; + + dev = (struct i386_devdesc *)devdata; + bcd.dv_strategy = bc_realstrategy; + bcd.dv_devdata = devdata; + bcd.dv_cache = BC(dev).bc_bcache; + + return (bcache_strategy(&bcd, rw, dblk, offset, size, buf, rsize)); +} + static int -bc_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, - size_t *rsize) +bc_realstrategy(void *devdata, int rw, daddr_t dblk, size_t offset, size_t size, + char *buf, size_t *rsize) { struct i386_devdesc *dev; int unit; Index: sys/boot/i386/libi386/biosdisk.c =================================================================== --- sys/boot/i386/libi386/biosdisk.c +++ sys/boot/i386/libi386/biosdisk.c @@ -86,6 +86,8 @@ int bd_type; /* BIOS 'drive type' (floppy only) */ uint16_t bd_sectorsize; /* Sector size */ uint64_t bd_sectors; /* Disk size */ + int bd_open; /* reference counter */ + void *bd_bcache; /* buffer cache data */ } bdinfo [MAXBDDEV]; static int nbdinfo = 0; @@ -98,9 +100,9 @@ static int bd_int13probe(struct bdinfo *bd); static int bd_init(void); -static int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t size, - char *buf, size_t *rsize); -static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, +static int bd_strategy(void *devdata, int flag, daddr_t dblk, size_t offset, + size_t size, char *buf, size_t *rsize); +static int bd_realstrategy(void *devdata, int flag, daddr_t dblk, size_t offset, size_t size, char *buf, size_t *rsize); static int bd_open(struct open_file *f, ...); static int bd_close(struct open_file *f); @@ -166,6 +168,8 @@ (nfd >= *(unsigned char *)PTOV(BIOS_NUMDRIVES))) break; #endif + bdinfo[nbdinfo].bd_open = 0; + bdinfo[nbdinfo].bd_bcache = NULL; bdinfo[nbdinfo].bd_unit = unit; bdinfo[nbdinfo].bd_flags = unit < 0x80 ? BD_FLOPPY: 0; if (!bd_int13probe(&bdinfo[nbdinfo])) @@ -179,6 +183,7 @@ nfd++; } } + bcache_add_dev(nbdinfo); return(0); } @@ -308,7 +313,9 @@ if (dev->d_unit < 0 || dev->d_unit >= nbdinfo) return (EIO); - + BD(dev).bd_open++; + if (BD(dev).bd_bcache == NULL) + BD(dev).bd_bcache = bcache_allocate(); return (disk_open(dev, BD(dev).bd_sectors * BD(dev).bd_sectorsize, BD(dev).bd_sectorsize, (BD(dev).bd_flags & BD_FLOPPY) ? DISK_F_NOCACHE: 0)); @@ -320,6 +327,11 @@ struct disk_devdesc *dev; dev = (struct disk_devdesc *)f->f_devdata; + BD(dev).bd_open--; + if (BD(dev).bd_open == 0) { + bcache_free(BD(dev).bd_bcache); + BD(dev).bd_bcache = NULL; + } return (disk_close(dev)); } @@ -343,8 +355,8 @@ } static int -bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, - size_t *rsize) +bd_strategy(void *devdata, int rw, daddr_t dblk, size_t offset, size_t size, + char *buf, size_t *rsize) { struct bcache_devdata bcd; struct disk_devdesc *dev; @@ -352,13 +364,14 @@ dev = (struct disk_devdesc *)devdata; bcd.dv_strategy = bd_realstrategy; bcd.dv_devdata = devdata; - return (bcache_strategy(&bcd, BD(dev).bd_unit, rw, dblk + dev->d_offset, + bcd.dv_cache = BD(dev).bd_bcache; + return (bcache_strategy(&bcd, rw, dblk + dev->d_offset, offset, size, buf, rsize)); } static int -bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, - size_t *rsize) +bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t offset, size_t size, + char *buf, size_t *rsize) { struct disk_devdesc *dev = (struct disk_devdesc *)devdata; int blks; Index: sys/boot/i386/libi386/biosmem.c =================================================================== --- sys/boot/i386/libi386/biosmem.c +++ sys/boot/i386/libi386/biosmem.c @@ -56,7 +56,7 @@ /* * The minimum amount of memory to reserve in bios_extmem for the heap. */ -#define HEAP_MIN (3 * 1024 * 1024) +#define HEAP_MIN (64 * 1024 * 1024) /* * Products in this list need quirks to detect Index: sys/boot/i386/libi386/pxe.c =================================================================== --- sys/boot/i386/libi386/pxe.c +++ sys/boot/i386/libi386/pxe.c @@ -72,7 +72,7 @@ static int pxe_init(void); static int pxe_strategy(void *devdata, int flag, daddr_t dblk, - size_t size, char *buf, size_t *rsize); + size_t offset, size_t size, char *buf, size_t *rsize); static int pxe_open(struct open_file *f, ...); static int pxe_close(struct open_file *f); static void pxe_print(int verbose); @@ -247,7 +247,7 @@ static int -pxe_strategy(void *devdata, int flag, daddr_t dblk, size_t size, +pxe_strategy(void *devdata, int flag, daddr_t dblk, size_t offset, size_t size, char *buf, size_t *rsize) { return (EIO); Index: sys/boot/i386/loader/main.c =================================================================== --- sys/boot/i386/loader/main.c +++ sys/boot/i386/loader/main.c @@ -137,9 +137,9 @@ cons_probe(); /* - * Initialise the block cache + * Initialise the block cache. Set the upper limit. */ - bcache_init(32, 512); /* 16k cache XXX tune this */ + bcache_init(32768, 512); /* * Special handling for PXE and CD booting. Index: sys/boot/mips/beri/loader/beri_disk_cfi.c =================================================================== --- sys/boot/mips/beri/loader/beri_disk_cfi.c +++ sys/boot/mips/beri/loader/beri_disk_cfi.c @@ -45,8 +45,8 @@ static int beri_cfi_disk_open(struct open_file *, ...); static int beri_cfi_disk_close(struct open_file *); static void beri_cfi_disk_cleanup(void); -static int beri_cfi_disk_strategy(void *, int, daddr_t, size_t, char *, - size_t *); +static int beri_cfi_disk_strategy(void *, int, daddr_t, size_t, size_t, + char *, size_t *); static void beri_cfi_disk_print(int); struct devsw beri_cfi_disk = { @@ -69,8 +69,8 @@ } static int -beri_cfi_disk_strategy(void *devdata, int flag, daddr_t dblk, size_t size, - char *buf, size_t *rsizep) +beri_cfi_disk_strategy(void *devdata, int flag, daddr_t dblk, size_t offset, + size_t size, char *buf, size_t *rsizep) { int error; Index: sys/boot/mips/beri/loader/beri_disk_sdcard.c =================================================================== --- sys/boot/mips/beri/loader/beri_disk_sdcard.c +++ sys/boot/mips/beri/loader/beri_disk_sdcard.c @@ -45,8 +45,8 @@ static int beri_sdcard_disk_open(struct open_file *, ...); static int beri_sdcard_disk_close(struct open_file *); static void beri_sdcard_disk_cleanup(void); -static int beri_sdcard_disk_strategy(void *, int, daddr_t, size_t, char *, - size_t *); +static int beri_sdcard_disk_strategy(void *, int, daddr_t, size_t, size_t, + char *, size_t *); static void beri_sdcard_disk_print(int); struct devsw beri_sdcard_disk = { @@ -69,8 +69,8 @@ } static int -beri_sdcard_disk_strategy(void *devdata, int flag, daddr_t dblk, size_t size, - char *buf, size_t *rsizep) +beri_sdcard_disk_strategy(void *devdata, int flag, daddr_t dblk, size_t offset, + size_t size, char *buf, size_t *rsizep) { int error; Index: sys/boot/ofw/libofw/ofw_disk.c =================================================================== --- sys/boot/ofw/libofw/ofw_disk.c +++ sys/boot/ofw/libofw/ofw_disk.c @@ -43,7 +43,7 @@ static int ofwd_init(void); static int ofwd_strategy(void *devdata, int flag, daddr_t dblk, - size_t size, char *buf, size_t *rsize); + size_t offset, size_t size, char *buf, size_t *rsize); static int ofwd_open(struct open_file *f, ...); static int ofwd_close(struct open_file *f); static int ofwd_ioctl(struct open_file *f, u_long cmd, void *data); @@ -83,8 +83,8 @@ } static int -ofwd_strategy(void *devdata, int flag __unused, daddr_t dblk, size_t size, - char *buf, size_t *rsize) +ofwd_strategy(void *devdata, int flag __unused, daddr_t dblk, size_t offset, + size_t size, char *buf, size_t *rsize) { struct ofw_devdesc *dp = (struct ofw_devdesc *)devdata; daddr_t pos; Index: sys/boot/pc98/libpc98/bioscd.c =================================================================== --- sys/boot/pc98/libpc98/bioscd.c +++ sys/boot/pc98/libpc98/bioscd.c @@ -84,13 +84,19 @@ static struct bcinfo { int bc_unit; /* BIOS unit number */ struct specification_packet bc_sp; + int bc_open; /* reference counter */ + void *bc_bcache; /* buffer cache data */ } bcinfo [MAXBCDEV]; static int nbcinfo = 0; +#define BC(dev) (bcinfo[(dev)->d_unit]) + static int bc_read(int unit, daddr_t dblk, int blks, caddr_t dest); static int bc_init(void); static int bc_strategy(void *devdata, int flag, daddr_t dblk, - size_t size, char *buf, size_t *rsize); + size_t offset, size_t size, char *buf, size_t *rsize); +static int bc_realstrategy(void *devdata, int flag, daddr_t dblk, + size_t offset, size_t size, char *buf, size_t *rsize); static int bc_open(struct open_file *f, ...); static int bc_close(struct open_file *f); static void bc_print(int verbose); @@ -160,6 +166,7 @@ printf("BIOS CD is cd%d\n", nbcinfo); nbcinfo++; + bcache_add_dev(nbcinfo); /* register cd device in bcache */ return(0); } @@ -196,19 +203,44 @@ return(ENXIO); } + BC(dev).bc_open++; + if (BC(dev).bc_bcache == NULL) + BC(dev).bc_bcache = bcache_allocate(); return(0); } static int bc_close(struct open_file *f) { + struct i386_devdesc *dev; + dev = (struct i386_devdesc *)f->f_devdata; + BC(dev).bc_open--; + if (BC(dev).bc_open == 0) { + bcache_free(BC(dev).bc_bcache); + BC(dev).bc_bcache = NULL; + } return(0); } +static int +bc_strategy(void *devdata, int rw, daddr_t dblk, size_t offset, size_t size, + char *buf, size_t *rsize) +{ + struct bcache_devdata bcd; + struct i386_devdesc *dev; + + dev = (struct i386_devdesc *)devdata; + bcd.dv_strategy = bc_realstrategy; + bcd.dv_devdata = devdata; + bcd.dv_cache = BC(dev).bc_bcache; + + return (bcache_strategy(&bcd, rw, dblk, offset, size, buf, rsize)); +} + static int -bc_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, - size_t *rsize) +bc_realstrategy(void *devdata, int rw, daddr_t dblk, size_t offset, size_t size, + char *buf, size_t *rsize) { struct i386_devdesc *dev; int unit; Index: sys/boot/pc98/libpc98/biosdisk.c =================================================================== --- sys/boot/pc98/libpc98/biosdisk.c +++ sys/boot/pc98/libpc98/biosdisk.c @@ -96,9 +96,13 @@ int bd_flags; int bd_type; /* BIOS 'drive type' (floppy only) */ int bd_da_unit; /* kernel unit number for da */ + int bd_open; /* reference counter */ + void *bd_bcache; /* buffer cache data */ } bdinfo [MAXBDDEV]; static int nbdinfo = 0; +#define BD(dev) (bdinfo[(dev)->d_unit]) + static int bd_getgeom(struct open_disk *od); static int bd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest); @@ -176,6 +180,8 @@ /* sequence 0x90, 0x80, 0xa0 */ for (base = 0x90; base <= 0xa0; base += n, n += 0x30) { for (unit = base; (nbdinfo < MAXBDDEV) || ((unit & 0x0f) < 4); unit++) { + bdinfo[nbdinfo].bd_open = 0; + bdinfo[nbdinfo].bd_bcache = NULL; bdinfo[nbdinfo].bd_unit = unit; bdinfo[nbdinfo].bd_flags = (unit & 0xf0) == 0x90 ? BD_FLOPPY : 0; @@ -205,6 +211,7 @@ nbdinfo++; } } + bcache_add_dev(nbdinfo); return(0); } @@ -427,6 +434,10 @@ if ((error = bd_opendisk(&od, dev))) return(error); + BD(dev).bd_open++; + if (BD(dev).bd_bcache == NULL) + BD(dev).bd_bcache = bcache_allocate(); + /* * Save our context */ @@ -696,7 +707,14 @@ static int bd_close(struct open_file *f) { - struct open_disk *od = (struct open_disk *)(((struct i386_devdesc *)(f->f_devdata))->d_kind.biosdisk.data); + struct i386_devdesc *dev = f->f_devdata; + struct open_disk *od = (struct open_disk *)(dev->d_kind.biosdisk.data); + + BD(dev).bd_open--; + if (BD(dev).bd_open == 0) { + bcache_free(BD(dev).bd_bcache); + BD(dev).bd_bcache = NULL; + } bd_closedisk(od); return(0); @@ -715,18 +733,23 @@ } static int -bd_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) +bd_strategy(void *devdata, int rw, daddr_t dblk, size_t offset, size_t size, + char *buf, size_t *rsize) { struct bcache_devdata bcd; - struct open_disk *od = (struct open_disk *)(((struct i386_devdesc *)devdata)->d_kind.biosdisk.data); + struct i386_devdesc *dev = f->f_devdata; + struct open_disk *od = (struct open_disk *)(dev->d_kind.biosdisk.data); bcd.dv_strategy = bd_realstrategy; bcd.dv_devdata = devdata; - return(bcache_strategy(&bcd, od->od_unit, rw, dblk+od->od_boff, size, buf, rsize)); + bcd.dv_cache = BD(dev).bd_bcache; + return(bcache_strategy(&bcd, od->od_unit, rw, dblk+od->od_boff, offset, + size, buf, rsize)); } static int -bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) +bd_realstrategy(void *devdata, int rw, daddr_t dblk, size_t offset, + size_t size, char *buf, size_t *rsize) { struct open_disk *od = (struct open_disk *)(((struct i386_devdesc *)devdata)->d_kind.biosdisk.data); int blks; Index: sys/boot/pc98/libpc98/biosmem.c =================================================================== --- sys/boot/pc98/libpc98/biosmem.c +++ sys/boot/pc98/libpc98/biosmem.c @@ -40,7 +40,7 @@ /* * The minimum amount of memory to reserve in bios_extmem for the heap. */ -#define HEAP_MIN (3 * 1024 * 1024) +#define HEAP_MIN (64 * 1024 * 1024) void bios_getmem(void) Index: sys/boot/pc98/loader/main.c =================================================================== --- sys/boot/pc98/loader/main.c +++ sys/boot/pc98/loader/main.c @@ -147,9 +147,9 @@ cons_probe(); /* - * Initialise the block cache + * Initialise the block cache. Set the upper limit. */ - bcache_init(32, 512); /* 16k cache XXX tune this */ + bcache_init(32768, 512); /* * Special handling for PXE and CD booting. Index: sys/boot/powerpc/kboot/hostdisk.c =================================================================== --- sys/boot/powerpc/kboot/hostdisk.c +++ sys/boot/powerpc/kboot/hostdisk.c @@ -33,7 +33,7 @@ static int hostdisk_init(void); static int hostdisk_strategy(void *devdata, int flag, daddr_t dblk, - size_t size, char *buf, size_t *rsize); + size_t offset, size_t size, char *buf, size_t *rsize); static int hostdisk_open(struct open_file *f, ...); static int hostdisk_close(struct open_file *f); static int hostdisk_ioctl(struct open_file *f, u_long cmd, void *data); @@ -58,8 +58,8 @@ } static int -hostdisk_strategy(void *devdata, int flag, daddr_t dblk, size_t size, - char *buf, size_t *rsize) +hostdisk_strategy(void *devdata, int flag, daddr_t dblk, size_t offset, + size_t size, char *buf, size_t *rsize) { struct devdesc *desc = devdata; daddr_t pos; Index: sys/boot/powerpc/ps3/ps3cdrom.c =================================================================== --- sys/boot/powerpc/ps3/ps3cdrom.c +++ sys/boot/powerpc/ps3/ps3cdrom.c @@ -46,7 +46,7 @@ static int ps3cdrom_init(void); static int ps3cdrom_strategy(void *devdata, int flag, daddr_t dblk, - size_t size, char *buf, size_t *rsize); + size_t offset, size_t size, char *buf, size_t *rsize); static int ps3cdrom_open(struct open_file *f, ...); static int ps3cdrom_close(struct open_file *f); static void ps3cdrom_print(int verbose); @@ -76,7 +76,7 @@ } static int ps3cdrom_strategy(void *devdata, int flag, daddr_t dblk, - size_t size, char *buf, size_t *rsize) + size_t offset, size_t size, char *buf, size_t *rsize) { struct ps3_devdesc *dev = (struct ps3_devdesc *) devdata; int err; Index: sys/boot/powerpc/ps3/ps3disk.c =================================================================== --- sys/boot/powerpc/ps3/ps3disk.c +++ sys/boot/powerpc/ps3/ps3disk.c @@ -58,7 +58,7 @@ static int ps3disk_init(void); static int ps3disk_strategy(void *devdata, int flag, daddr_t dblk, - size_t size, char *buf, size_t *rsize); + size_t offset, size_t size, char *buf, size_t *rsize); static int ps3disk_open(struct open_file *f, ...); static int ps3disk_close(struct open_file *f); static void ps3disk_print(int verbose); @@ -109,7 +109,7 @@ } static int ps3disk_strategy(void *devdata, int flag, daddr_t dblk, - size_t size, char *buf, size_t *rsize) + size_t offset, size_t size, char *buf, size_t *rsize) { struct ps3_devdesc *dev = (struct ps3_devdesc *) devdata; struct open_dev *od = (struct open_dev *) dev->d_disk.data; Index: sys/boot/uboot/lib/disk.c =================================================================== --- sys/boot/uboot/lib/disk.c +++ sys/boot/uboot/lib/disk.c @@ -73,7 +73,8 @@ /* devsw I/F */ static int stor_init(void); -static int stor_strategy(void *, int, daddr_t, size_t, char *, size_t *); +static int stor_strategy(void *, int, daddr_t, size_t, size_t, char *, + size_t *); static int stor_open(struct open_file *, ...); static int stor_close(struct open_file *); static int stor_ioctl(struct open_file *f, u_long cmd, void *data); @@ -143,8 +144,8 @@ } static int -stor_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, - size_t *rsize) +stor_strategy(void *devdata, int rw, daddr_t blk, size_t offset, size_t size, + char *buf, size_t *rsize) { struct disk_devdesc *dev = (struct disk_devdesc *)devdata; daddr_t bcount; Index: sys/boot/usb/storage/umass_loader.c =================================================================== --- sys/boot/usb/storage/umass_loader.c +++ sys/boot/usb/storage/umass_loader.c @@ -48,7 +48,8 @@ static int umass_disk_close(struct open_file *); static void umass_disk_cleanup(void); static int umass_disk_ioctl(struct open_file *, u_long, void *); -static int umass_disk_strategy(void *, int, daddr_t, size_t, char *, size_t *); +static int umass_disk_strategy(void *, int, daddr_t, size_t, size_t, char *, + size_t *); static void umass_disk_print(int); struct devsw umass_disk = { @@ -84,8 +85,8 @@ } static int -umass_disk_strategy(void *devdata, int flag, daddr_t dblk, size_t size, - char *buf, size_t *rsizep) +umass_disk_strategy(void *devdata, int flag, daddr_t dblk, size_t offset, + size_t size, char *buf, size_t *rsizep) { if (umass_uaa.device == NULL) return (ENXIO); Index: sys/boot/userboot/userboot/host.c =================================================================== --- sys/boot/userboot/userboot/host.c +++ sys/boot/userboot/userboot/host.c @@ -167,8 +167,8 @@ } static int -host_dev_strategy(void *devdata, int rw, daddr_t dblk, size_t size, - char *buf, size_t *rsize) +host_dev_strategy(void *devdata, int rw, daddr_t dblk, size_t offset, + size_t size, char *buf, size_t *rsize) { return (ENOSYS); Index: sys/boot/userboot/userboot/main.c =================================================================== --- sys/boot/userboot/userboot/main.c +++ sys/boot/userboot/userboot/main.c @@ -131,6 +131,10 @@ #endif /* + * Initialise the block cache. Set the upper limit. + */ + bcache_init(32768, 512); + /* * March through the device switch probing for things. */ for (i = 0; devsw[i] != NULL; i++) Index: sys/boot/userboot/userboot/userboot_disk.c =================================================================== --- sys/boot/userboot/userboot/userboot_disk.c +++ sys/boot/userboot/userboot/userboot_disk.c @@ -42,6 +42,8 @@ struct userdisk_info { uint64_t mediasize; uint16_t sectorsize; + int ud_open; /* reference counter */ + void *ud_bcache; /* buffer cache data */ }; int userboot_disk_maxunit = 0; @@ -52,7 +54,9 @@ static int userdisk_init(void); static void userdisk_cleanup(void); static int userdisk_strategy(void *devdata, int flag, daddr_t dblk, - size_t size, char *buf, size_t *rsize); + size_t offset, size_t size, char *buf, size_t *rsize); +static int userdisk_realstrategy(void *devdata, int flag, daddr_t dblk, + size_t offset, size_t size, char *buf, size_t *rsize); static int userdisk_open(struct open_file *f, ...); static int userdisk_close(struct open_file *f); static int userdisk_ioctl(struct open_file *f, u_long cmd, void *data); @@ -92,9 +96,11 @@ return (ENXIO); ud_info[i].mediasize = mediasize; ud_info[i].sectorsize = sectorsize; + ud_info[i].ud_open = 0; + ud_info[i].ud_bcache = NULL; } } - + bcache_add_dev(userdisk_maxunit); return(0); } @@ -148,7 +154,9 @@ if (dev->d_unit < 0 || dev->d_unit >= userdisk_maxunit) return (EIO); - + ud_info[dev->d_unit].ud_open++; + if (ud_info[dev->d_unit].ud_bcache == NULL) + ud_info[dev->d_unit].ud_bcache = bcache_allocate(); return (disk_open(dev, ud_info[dev->d_unit].mediasize, ud_info[dev->d_unit].sectorsize, 0)); } @@ -159,12 +167,32 @@ struct disk_devdesc *dev; dev = (struct disk_devdesc *)f->f_devdata; + ud_info[dev->d_unit].ud_open--; + if (ud_info[dev->d_unit].ud_open == 0) { + bcache_free(ud_info[dev->d_unit].ud_bcache); + ud_info[dev->d_unit].ud_bcache = NULL; + } return (disk_close(dev)); } static int -userdisk_strategy(void *devdata, int rw, daddr_t dblk, size_t size, - char *buf, size_t *rsize) +userdisk_strategy(void *devdata, int rw, daddr_t dblk, size_t offset, + size_t size, char *buf, size_t *rsize) +{ + struct bcache_devdata bcd; + struct disk_devdesc *dev; + + dev = (struct disk_devdesc *)devdata; + bcd.dv_strategy = userdisk_realstrategy; + bcd.dv_devdata = devdata; + bcd.dv_cache = ud_info[dev->d_unit].ud_bcache; + return (bcache_strategy(&bcd, rw, dblk + dev->d_offset, offset, + size, buf, rsize)); +} + +static int +userdisk_realstrategy(void *devdata, int rw, daddr_t dblk, size_t offset, + size_t size, char *buf, size_t *rsize) { struct disk_devdesc *dev = devdata; uint64_t off; @@ -177,7 +205,7 @@ return (EINVAL); if (rsize) *rsize = 0; - off = (dblk + dev->d_offset) * ud_info[dev->d_unit].sectorsize; + off = dblk * ud_info[dev->d_unit].sectorsize; rc = CALLBACK(diskread, dev->d_unit, off, buf, size, &resid); if (rc) return (rc); Index: sys/boot/zfs/zfs.c =================================================================== --- sys/boot/zfs/zfs.c +++ sys/boot/zfs/zfs.c @@ -578,7 +578,7 @@ } static int -zfs_dev_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) +zfs_dev_strategy(void *devdata, int rw, daddr_t dblk, size_t offset, size_t size, char *buf, size_t *rsize) { return (ENOSYS);