int vdev_disk_physio(vdev_t *vd, caddr_t data, size_t size, uint64_t offset, int flags, boolean_t isdump) { int rc = EIO; vdev_disk_t *dvd; rw_enter(&vd->vdev_tsd_lock, RW_READER); dvd = vd->vdev_tsd; /* * If the vdev is closed, it's likely in the REMOVED or FAULTED state. * Nothing to be done here but return failure. */ if (dvd == NULL || dvd->vd_lh == NULL) goto out; ASSERT(vd->vdev_ops == &vdev_disk_ops); /* * If in the context of an active crash dump, use the ldi_dump(9F) * call instead of ldi_strategy(9F) as usual. */ if (isdump) { ASSERT3P(dvd, !=, NULL); rc = ldi_dump(dvd->vd_lh, data, lbtodb(offset), lbtodb(size)); goto out; } rc = vdev_disk_ldi_physio(dvd->vd_lh, data, size, offset, flags); out: rw_exit(&vd->vdev_tsd_lock); return (rc); }
int vdev_disk_physio(vdev_t *vd, caddr_t data, size_t size, uint64_t offset, int flags, boolean_t isdump) { vdev_disk_t *dvd = vd->vdev_tsd; /* * If the vdev is closed, it's likely in the REMOVED or FAULTED state. * Nothing to be done here but return failure. */ if (dvd == NULL || (dvd->vd_ldi_offline && dvd->vd_lh == NULL)) return (EIO); ASSERT(vd->vdev_ops == &vdev_disk_ops); /* XXX Apple - no equivalent crash dump mechanism on OS X */ #ifdef illumos /* * If in the context of an active crash dump, use the ldi_dump(9F) * call instead of ldi_strategy(9F) as usual. */ if (isdump) { ASSERT3P(dvd, !=, NULL); return (ldi_dump(dvd->vd_lh, data, lbtodb(offset), lbtodb(size))); } #endif return (vdev_disk_ldi_physio(dvd->vd_lh, data, size, offset, flags)); }
int vdev_disk_ldi_physio(ldi_handle_t vd_lh, caddr_t data, size_t size, uint64_t offset, int flags) { #ifdef illumos buf_t *bp; #else ldi_buf_t *bp; #endif int error = 0; if (vd_lh == NULL) return (SET_ERROR(EINVAL)); ASSERT(flags & B_READ || flags & B_WRITE); bp = getrbuf(KM_SLEEP); bp->b_flags = flags | B_BUSY | B_NOCACHE | B_FAILFAST; bp->b_bcount = size; bp->b_un.b_addr = (void *)data; bp->b_lblkno = lbtodb(offset); bp->b_bufsize = size; error = ldi_strategy(vd_lh, bp); ASSERT(error == 0); if ((error = biowait(bp)) == 0 && bp->b_resid != 0) error = SET_ERROR(EIO); freerbuf(bp); return (error); }
static void zvol_size_changed(zvol_state_t *zv, dev_t dev) { dev = makedevice(getmajor(dev), zv->zv_minor); VERIFY(ddi_prop_update_int64(dev, zfs_dip, "Size", zv->zv_volsize) == DDI_SUCCESS); VERIFY(ddi_prop_update_int64(dev, zfs_dip, "Nblocks", lbtodb(zv->zv_volsize)) == DDI_SUCCESS); }
static void zvol_size_changed(uint64_t volsize, major_t maj, minor_t min) { dev_t dev = makedevice(maj, min); VERIFY(ddi_prop_update_int64(dev, zfs_dip, "Size", volsize) == DDI_SUCCESS); VERIFY(ddi_prop_update_int64(dev, zfs_dip, "Nblocks", lbtodb(volsize)) == DDI_SUCCESS); /* Notify specfs to invalidate the cached size */ spec_size_invalidate(dev, VBLK); spec_size_invalidate(dev, VCHR); }
/* * Called from roll thread; * buffer set for reading master * Returns * 0 - success, can continue with next buffer * 1 - failure due to logmap deltas being in use */ int top_read_roll(rollbuf_t *rbp, ml_unit_t *ul) { buf_t *bp = &rbp->rb_bh; offset_t mof = ldbtob(bp->b_blkno); /* * get a list of deltas */ if (logmap_list_get_roll(ul->un_logmap, mof, rbp)) { /* logmap deltas are in use */ return (1); } /* * no deltas were found, nothing to roll */ if (rbp->rb_age == NULL) { bp->b_flags |= B_INVAL; return (0); } /* * If there is one cached roll buffer that cover all the deltas then * we can use that instead of copying to a separate roll buffer. */ if (rbp->rb_crb) { rbp->rb_bh.b_blkno = lbtodb(rbp->rb_crb->c_mof); return (0); } /* * Set up the read. * If no read is needed logmap_setup_read() returns 0. */ if (logmap_setup_read(rbp->rb_age, rbp)) { /* * async read the data from master */ logstats.ls_rreads.value.ui64++; bp->b_bcount = MAPBLOCKSIZE; (void) bdev_strategy(bp); lwp_stat_update(LWP_STAT_INBLK, 1); } else { sema_v(&bp->b_io); /* mark read as complete */ } return (0); }
static int vdev_file_io_start(zio_t *zio) { spa_t *spa = zio->io_spa; vdev_t *vd = zio->io_vd; vdev_file_t *vf = vd->vdev_tsd; vdev_buf_t *vb; buf_t *bp; if (zio->io_type == ZIO_TYPE_IOCTL) { /* XXPOLICY */ if (!vdev_readable(vd)) { zio->io_error = ENXIO; return (ZIO_PIPELINE_CONTINUE); } switch (zio->io_cmd) { case DKIOCFLUSHWRITECACHE: zio->io_error = VOP_FSYNC(vf->vf_vnode, FSYNC | FDSYNC, kcred, NULL); break; default: zio->io_error = ENOTSUP; } return (ZIO_PIPELINE_CONTINUE); } vb = kmem_alloc(sizeof (vdev_buf_t), KM_SLEEP); vb->vb_io = zio; bp = &vb->vb_buf; bioinit(bp); bp->b_flags = (zio->io_type == ZIO_TYPE_READ ? B_READ : B_WRITE); bp->b_bcount = zio->io_size; bp->b_un.b_addr = zio->io_data; bp->b_lblkno = lbtodb(zio->io_offset); bp->b_bufsize = zio->io_size; bp->b_private = vf->vf_vnode; bp->b_iodone = (int (*)())vdev_file_io_intr; taskq_dispatch_ent(spa->spa_zio_taskq[ZIO_TYPE_FREE][ZIO_TASKQ_ISSUE], vdev_file_io_strategy, bp, 0, &zio->io_tqent); return (ZIO_PIPELINE_STOP); }
static void vdev_disk_io_start(zio_t *zio) { vdev_t *vd = zio->io_vd; vdev_disk_t *dvd; vdev_buf_t *vb; struct dk_callback *dkc; buf_t *bp; int error; rw_enter(&vd->vdev_tsd_lock, RW_READER); dvd = vd->vdev_tsd; /* * If the vdev is closed, it's likely in the REMOVED or FAULTED state. * Nothing to be done here but return failure. */ if (dvd == NULL || dvd->vd_lh == NULL) { zio->io_error = ENXIO; rw_exit(&vd->vdev_tsd_lock); zio_interrupt(zio); return; } if (zio->io_type == ZIO_TYPE_IOCTL) { /* XXPOLICY */ if (!vdev_readable(vd)) { zio->io_error = SET_ERROR(ENXIO); rw_exit(&vd->vdev_tsd_lock); zio_interrupt(zio); return; } switch (zio->io_cmd) { case DKIOCFLUSHWRITECACHE: if (zfs_nocacheflush) break; if (vd->vdev_nowritecache) { zio->io_error = SET_ERROR(ENOTSUP); break; } zio->io_vsd = dkc = kmem_alloc(sizeof (*dkc), KM_SLEEP); zio->io_vsd_ops = &vdev_disk_vsd_ops; dkc->dkc_callback = vdev_disk_ioctl_done; dkc->dkc_flag = FLUSH_VOLATILE; dkc->dkc_cookie = zio; error = ldi_ioctl(dvd->vd_lh, zio->io_cmd, (uintptr_t)dkc, FKIOCTL, kcred, NULL); if (error == 0) { /* * The ioctl will be done asychronously, * and will call vdev_disk_ioctl_done() * upon completion. */ rw_exit(&vd->vdev_tsd_lock); return; } if (error == ENOTSUP || error == ENOTTY) { /* * If we get ENOTSUP or ENOTTY, we know that * no future attempts will ever succeed. * In this case we set a persistent bit so * that we don't bother with the ioctl in the * future. */ vd->vdev_nowritecache = B_TRUE; } zio->io_error = error; break; case DKIOCFREE: /* * We perform device support checks here instead of * in zio_trim(), as zio_trim() might be invoked on * top of a top-level vdev, whereas vdev_disk_io_start * is guaranteed to be operating a leaf vdev. */ if (vd->vdev_notrim && spa_get_force_trim(vd->vdev_spa) != SPA_FORCE_TRIM_ON) { zio->io_error = SET_ERROR(ENOTSUP); break; } /* * zio->io_private contains a dkioc_free_list_t * specifying which offsets are to be freed */ ASSERT(zio->io_private != NULL); error = ldi_ioctl(dvd->vd_lh, zio->io_cmd, (uintptr_t)zio->io_private, FKIOCTL, kcred, NULL); if (error == ENOTSUP || error == ENOTTY) vd->vdev_notrim = B_TRUE; zio->io_error = error; break; default: zio->io_error = SET_ERROR(ENOTSUP); } rw_exit(&vd->vdev_tsd_lock); zio_execute(zio); return; } vb = kmem_alloc(sizeof (vdev_buf_t), KM_SLEEP); vb->vb_io = zio; bp = &vb->vb_buf; bioinit(bp); bp->b_flags = B_BUSY | B_NOCACHE | (zio->io_type == ZIO_TYPE_READ ? B_READ : B_WRITE); if (!(zio->io_flags & (ZIO_FLAG_IO_RETRY | ZIO_FLAG_TRYHARD))) bp->b_flags |= B_FAILFAST; bp->b_bcount = zio->io_size; bp->b_un.b_addr = zio->io_data; bp->b_lblkno = lbtodb(zio->io_offset); bp->b_bufsize = zio->io_size; bp->b_iodone = (int (*)())vdev_disk_io_intr; /* ldi_strategy() will return non-zero only on programming errors */ VERIFY(ldi_strategy(dvd->vd_lh, bp) == 0); rw_exit(&vd->vdev_tsd_lock); }
static int vdev_disk_io_start(zio_t *zio) { vdev_t *vd = zio->io_vd; vdev_disk_t *dvd = vd->vdev_tsd; vdev_buf_t *vb; struct dk_callback *dkc; buf_t *bp; int error; /* * If the vdev is closed, it's likely in the REMOVED or FAULTED state. * Nothing to be done here but return failure. */ if (dvd == NULL || (dvd->vd_ldi_offline && dvd->vd_lh == NULL)) { zio->io_error = ENXIO; return (ZIO_PIPELINE_CONTINUE); } if (zio->io_type == ZIO_TYPE_IOCTL) { /* XXPOLICY */ if (!vdev_readable(vd)) { zio->io_error = SET_ERROR(ENXIO); return (ZIO_PIPELINE_CONTINUE); } switch (zio->io_cmd) { case DKIOCFLUSHWRITECACHE: if (zfs_nocacheflush) break; if (vd->vdev_nowritecache) { zio->io_error = SET_ERROR(ENOTSUP); break; } zio->io_vsd = dkc = kmem_alloc(sizeof (*dkc), KM_SLEEP); zio->io_vsd_ops = &vdev_disk_vsd_ops; dkc->dkc_callback = vdev_disk_ioctl_done; dkc->dkc_flag = FLUSH_VOLATILE; dkc->dkc_cookie = zio; error = ldi_ioctl(dvd->vd_lh, zio->io_cmd, (uintptr_t)dkc, FKIOCTL, kcred, NULL); if (error == 0) { /* * The ioctl will be done asychronously, * and will call vdev_disk_ioctl_done() * upon completion. */ return (ZIO_PIPELINE_STOP); } if (error == ENOTSUP || error == ENOTTY) { /* * If we get ENOTSUP or ENOTTY, we know that * no future attempts will ever succeed. * In this case we set a persistent bit so * that we don't bother with the ioctl in the * future. */ vd->vdev_nowritecache = B_TRUE; } zio->io_error = error; break; default: zio->io_error = SET_ERROR(ENOTSUP); } return (ZIO_PIPELINE_CONTINUE); } vb = kmem_alloc(sizeof (vdev_buf_t), KM_SLEEP); vb->vb_io = zio; bp = &vb->vb_buf; bioinit(bp); bp->b_flags = B_BUSY | B_NOCACHE | (zio->io_type == ZIO_TYPE_READ ? B_READ : B_WRITE); if (!(zio->io_flags & (ZIO_FLAG_IO_RETRY | ZIO_FLAG_TRYHARD))) bp->b_flags |= B_FAILFAST; bp->b_bcount = zio->io_size; bp->b_un.b_addr = zio->io_data; bp->b_lblkno = lbtodb(zio->io_offset); bp->b_bufsize = zio->io_size; bp->b_iodone = (int (*)())vdev_disk_io_intr; zfs_zone_zio_start(zio); /* ldi_strategy() will return non-zero only on programming errors */ VERIFY(ldi_strategy(dvd->vd_lh, bp) == 0); return (ZIO_PIPELINE_STOP); }
/* * Find something to roll, then if we don't have cached roll buffers * covering all the deltas in that MAPBLOCK then read the master * and overlay the deltas. * returns; * 0 if sucessful * 1 on finding nothing to roll * 2 on error */ int log_roll_read(ml_unit_t *ul, rollbuf_t *rbs, int nmblk, caddr_t roll_bufs, int *retnbuf) { offset_t mof; buf_t *bp; rollbuf_t *rbp; mt_map_t *logmap = ul->un_logmap; daddr_t mblkno; int i; int error; int nbuf; /* * Make sure there is really something to roll */ mof = 0; if (!logmap_next_roll(logmap, &mof)) { return (1); } /* * build some master blocks + deltas to roll forward */ rw_enter(&logmap->mtm_rwlock, RW_READER); nbuf = 0; do { mof = mof & (offset_t)MAPBLOCKMASK; mblkno = lbtodb(mof); /* * Check for the case of a new delta to a set up buffer */ for (i = 0, rbp = rbs; i < nbuf; ++i, ++rbp) { if (P2ALIGN(rbp->rb_bh.b_blkno, MAPBLOCKSIZE / DEV_BSIZE) == mblkno) { TNF_PROBE_0(trans_roll_new_delta, "lufs", /* CSTYLED */); trans_roll_new_delta++; /* Flush out the current set of buffers */ goto flush_bufs; } } /* * Work out what to roll next. If it isn't cached then read * it asynchronously from the master. */ bp = &rbp->rb_bh; bp->b_blkno = mblkno; bp->b_flags = B_READ; bp->b_un.b_addr = roll_bufs + (nbuf << MAPBLOCKSHIFT); bp->b_bufsize = MAPBLOCKSIZE; if (top_read_roll(rbp, ul)) { /* logmap deltas were in use */ if (nbuf == 0) { /* * On first buffer wait for the logmap user * to finish by grabbing the logmap lock * exclusively rather than spinning */ rw_exit(&logmap->mtm_rwlock); lrr_wait++; rw_enter(&logmap->mtm_rwlock, RW_WRITER); rw_exit(&logmap->mtm_rwlock); return (1); } /* we have at least one buffer - flush it */ goto flush_bufs; } if ((bp->b_flags & B_INVAL) == 0) { nbuf++; } mof += MAPBLOCKSIZE; } while ((nbuf < nmblk) && logmap_next_roll(logmap, &mof));