Exemple #1
0
/*
 * Calculate the logical to physical mapping if not done already,
 * then call the device strategy routine.
 *
 * In order to be able to swap to a file, the ext2_bmaparray() operation may not
 * deadlock on memory.  See ext2_bmap() for details.
 */
static int
ext2_strategy(struct vop_strategy_args *ap)
{
	struct buf *bp = ap->a_bp;
	struct vnode *vp = ap->a_vp;
	struct inode *ip;
	struct bufobj *bo;
	int32_t blkno;
	int error;

	ip = VTOI(vp);
	if (vp->v_type == VBLK || vp->v_type == VCHR)
		panic("ext2_strategy: spec");
	if (bp->b_blkno == bp->b_lblkno) {
		error = ext2_bmaparray(vp, bp->b_lblkno, &blkno, NULL, NULL);
		bp->b_blkno = blkno;
		if (error) {
			bp->b_error = error;
			bp->b_ioflags |= BIO_ERROR;
			bufdone(bp);
			return (0);
		}
		if ((long)bp->b_blkno == -1)
			vfs_bio_clrbuf(bp);
	}
	if ((long)bp->b_blkno == -1) {
		bufdone(bp);
		return (0);
	}
	bp->b_iooffset = dbtob(bp->b_blkno);
	bo = VFSTOEXT2(vp->v_mount)->um_bo;
	BO_STRATEGY(bo, bp);
	return (0);
}
Exemple #2
0
/*
    struct vnop_strategy_args {
	struct vnode *a_vp;
	struct buf *a_bp;
    };
*/
static int
fuse_vnop_strategy(struct vop_strategy_args *ap)
{
	struct vnode *vp = ap->a_vp;
	struct buf *bp = ap->a_bp;

	fuse_trace_printf_vnop();

	if (!vp || fuse_isdeadfs(vp)) {
		bp->b_ioflags |= BIO_ERROR;
		bp->b_error = ENXIO;
		bufdone(bp);
		return ENXIO;
	}
	if (bp->b_iocmd == BIO_WRITE)
		fuse_vnode_refreshsize(vp, NOCRED);

	(void)fuse_io_strategy(vp, bp);

	/*
	 * This is a dangerous function. If returns error, that might mean a
	 * panic. We prefer pretty much anything over being forced to panic
	 * by a malicious daemon (a demon?). So we just return 0 anyway. You
	 * should never mind this: this function has its own error
	 * propagation mechanism via the argument buffer, so
	 * not-that-melodramatic residents of the call chain still will be
	 * able to know what to do.
	 */
	return 0;
}
static int
_xfs_strategy(
	struct vop_strategy_args /* {
		struct vnode *a_vp;
		struct buf *a_bp;
	} */ *ap)
{
	daddr_t blkno;
	struct buf *bp;;
	struct bufobj *bo;
	struct vnode *vp;
	struct xfs_mount *xmp;
	int error;

	bp = ap->a_bp;
	vp = ap->a_vp;

	KASSERT(ap->a_vp == ap->a_bp->b_vp, ("%s(%p != %p)",
	    __func__, ap->a_vp, ap->a_bp->b_vp));
	if (bp->b_blkno == bp->b_lblkno) {
		error = VOP_BMAP(vp, bp->b_lblkno, NULL, &blkno, NULL, NULL);
		bp->b_blkno = blkno;
		bp->b_iooffset = (blkno << BBSHIFT);
		if (error) {
			bp->b_error = error;
			bp->b_ioflags |= BIO_ERROR;
			bufdone(bp);
			return (0);
		}
		if ((long)bp->b_blkno == -1)
			vfs_bio_clrbuf(bp);
        }
	if ((long)bp->b_blkno == -1) {
		bufdone(bp);
		return (0);
	}

	xmp = XFS_VFSTOM(MNTTOVFS(vp->v_mount));
	bo = &xmp->m_ddev_targp->specvp->v_bufobj;
	bo->bo_ops->bop_strategy(bo, bp);
	return (0);
}
Exemple #4
0
int
fuse_io_strategy(struct vnode *vp, struct buf *bp)
{
	struct fuse_filehandle *fufh;
	struct fuse_vnode_data *fvdat = VTOFUD(vp);
	struct ucred *cred;
	struct uio *uiop;
	struct uio uio;
	struct iovec io;
	int error = 0;

	const int biosize = fuse_iosize(vp);

	MPASS(vp->v_type == VREG || vp->v_type == VDIR);
	MPASS(bp->b_iocmd == BIO_READ || bp->b_iocmd == BIO_WRITE);
	FS_DEBUG("inode=%ju offset=%jd resid=%ld\n",
	    (uintmax_t)VTOI(vp), (intmax_t)(((off_t)bp->b_blkno) * biosize),
	    bp->b_bcount);

	error = fuse_filehandle_getrw(vp,
	    (bp->b_iocmd == BIO_READ) ? FUFH_RDONLY : FUFH_WRONLY, &fufh);
	if (error) {
		printf("FUSE: strategy: filehandles are closed\n");
		bp->b_ioflags |= BIO_ERROR;
		bp->b_error = error;
		return (error);
	}
	cred = bp->b_iocmd == BIO_READ ? bp->b_rcred : bp->b_wcred;

	uiop = &uio;
	uiop->uio_iov = &io;
	uiop->uio_iovcnt = 1;
	uiop->uio_segflg = UIO_SYSSPACE;
	uiop->uio_td = curthread;

	/*
         * clear BIO_ERROR and B_INVAL state prior to initiating the I/O.  We
         * do this here so we do not have to do it in all the code that
         * calls us.
         */
	bp->b_flags &= ~B_INVAL;
	bp->b_ioflags &= ~BIO_ERROR;

	KASSERT(!(bp->b_flags & B_DONE),
	    ("fuse_io_strategy: bp %p already marked done", bp));
	if (bp->b_iocmd == BIO_READ) {
		io.iov_len = uiop->uio_resid = bp->b_bcount;
		io.iov_base = bp->b_data;
		uiop->uio_rw = UIO_READ;

		uiop->uio_offset = ((off_t)bp->b_blkno) * biosize;
		error = fuse_read_directbackend(vp, uiop, cred, fufh);

		if ((!error && uiop->uio_resid) ||
		    (fsess_opt_brokenio(vnode_mount(vp)) && error == EIO &&
		    uiop->uio_offset < fvdat->filesize && fvdat->filesize > 0 &&
		    uiop->uio_offset >= fvdat->cached_attrs.va_size)) {
			/*
	                 * If we had a short read with no error, we must have
	                 * hit a file hole.  We should zero-fill the remainder.
	                 * This can also occur if the server hits the file EOF.
	                 *
	                 * Holes used to be able to occur due to pending
	                 * writes, but that is not possible any longer.
	                 */
			int nread = bp->b_bcount - uiop->uio_resid;
			int left = uiop->uio_resid;

			if (error != 0) {
				printf("FUSE: Fix broken io: offset %ju, "
				       " resid %zd, file size %ju/%ju\n", 
				       (uintmax_t)uiop->uio_offset,
				    uiop->uio_resid, fvdat->filesize,
				    fvdat->cached_attrs.va_size);
				error = 0;
			}
			if (left > 0)
				bzero((char *)bp->b_data + nread, left);
			uiop->uio_resid = 0;
		}
		if (error) {
			bp->b_ioflags |= BIO_ERROR;
			bp->b_error = error;
		}
	} else {
		/*
	         * If we only need to commit, try to commit
	         */
		if (bp->b_flags & B_NEEDCOMMIT) {
			FS_DEBUG("write: B_NEEDCOMMIT flags set\n");
		}
		/*
	         * Setup for actual write
	         */
		if ((off_t)bp->b_blkno * biosize + bp->b_dirtyend > 
		    fvdat->filesize)
			bp->b_dirtyend = fvdat->filesize - 
				(off_t)bp->b_blkno * biosize;

		if (bp->b_dirtyend > bp->b_dirtyoff) {
			io.iov_len = uiop->uio_resid = bp->b_dirtyend
			    - bp->b_dirtyoff;
			uiop->uio_offset = (off_t)bp->b_blkno * biosize
			    + bp->b_dirtyoff;
			io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
			uiop->uio_rw = UIO_WRITE;

			error = fuse_write_directbackend(vp, uiop, cred, fufh, 0);

			if (error == EINTR || error == ETIMEDOUT
			    || (!error && (bp->b_flags & B_NEEDCOMMIT))) {

				bp->b_flags &= ~(B_INVAL | B_NOCACHE);
				if ((bp->b_flags & B_PAGING) == 0) {
					bdirty(bp);
					bp->b_flags &= ~B_DONE;
				}
				if ((error == EINTR || error == ETIMEDOUT) &&
				    (bp->b_flags & B_ASYNC) == 0)
					bp->b_flags |= B_EINTR;
			} else {
				if (error) {
					bp->b_ioflags |= BIO_ERROR;
					bp->b_flags |= B_INVAL;
					bp->b_error = error;
				}
				bp->b_dirtyoff = bp->b_dirtyend = 0;
			}
		} else {
			bp->b_resid = 0;
			bufdone(bp);
			return (0);
		}
	}
	bp->b_resid = uiop->uio_resid;
	bufdone(bp);
	return (error);
}
Exemple #5
0
/*
 * Do an I/O operation to/from a cache block.
 */
int
smbfs_doio(struct vnode *vp, struct buf *bp, struct ucred *cr, struct thread *td)
{
	struct smbmount *smp = VFSTOSMBFS(vp->v_mount);
	struct smbnode *np = VTOSMB(vp);
	struct uio *uiop;
	struct iovec io;
	struct smb_cred *scred;
	int error = 0;

	uiop = malloc(sizeof(struct uio), M_SMBFSDATA, M_WAITOK);
	uiop->uio_iov = &io;
	uiop->uio_iovcnt = 1;
	uiop->uio_segflg = UIO_SYSSPACE;
	uiop->uio_td = td;

	scred = smbfs_malloc_scred();
	smb_makescred(scred, td, cr);

	if (bp->b_iocmd == BIO_READ) {
	    io.iov_len = uiop->uio_resid = bp->b_bcount;
	    io.iov_base = bp->b_data;
	    uiop->uio_rw = UIO_READ;
	    switch (vp->v_type) {
	      case VREG:
		uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE;
		error = smb_read(smp->sm_share, np->n_fid, uiop, scred);
		if (error)
			break;
		if (uiop->uio_resid) {
			int left = uiop->uio_resid;
			int nread = bp->b_bcount - left;
			if (left > 0)
			    bzero((char *)bp->b_data + nread, left);
		}
		break;
	    default:
		printf("smbfs_doio:  type %x unexpected\n",vp->v_type);
		break;
	    };
	    if (error) {
		bp->b_error = error;
		bp->b_ioflags |= BIO_ERROR;
	    }
	} else { /* write */
	    if (((bp->b_blkno * DEV_BSIZE) + bp->b_dirtyend) > np->n_size)
		bp->b_dirtyend = np->n_size - (bp->b_blkno * DEV_BSIZE);

	    if (bp->b_dirtyend > bp->b_dirtyoff) {
		io.iov_len = uiop->uio_resid = bp->b_dirtyend - bp->b_dirtyoff;
		uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
		io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
		uiop->uio_rw = UIO_WRITE;
		error = smb_write(smp->sm_share, np->n_fid, uiop, scred);

		/*
		 * For an interrupted write, the buffer is still valid
		 * and the write hasn't been pushed to the server yet,
		 * so we can't set BIO_ERROR and report the interruption
		 * by setting B_EINTR. For the B_ASYNC case, B_EINTR
		 * is not relevant, so the rpc attempt is essentially
		 * a noop.  For the case of a V3 write rpc not being
		 * committed to stable storage, the block is still
		 * dirty and requires either a commit rpc or another
		 * write rpc with iomode == NFSV3WRITE_FILESYNC before
		 * the block is reused. This is indicated by setting
		 * the B_DELWRI and B_NEEDCOMMIT flags.
		 */
		if (error == EINTR
		    || (!error && (bp->b_flags & B_NEEDCOMMIT))) {
			int s;

			s = splbio();
			bp->b_flags &= ~(B_INVAL|B_NOCACHE);
			if ((bp->b_flags & B_ASYNC) == 0)
			    bp->b_flags |= B_EINTR;
			if ((bp->b_flags & B_PAGING) == 0) {
			    bdirty(bp);
			    bp->b_flags &= ~B_DONE;
			}
			if ((bp->b_flags & B_ASYNC) == 0)
			    bp->b_flags |= B_EINTR;
			splx(s);
		} else {
			if (error) {
				bp->b_ioflags |= BIO_ERROR;
				bp->b_error = error;
			}
			bp->b_dirtyoff = bp->b_dirtyend = 0;
		}
	    } else {
		bp->b_resid = 0;
		bufdone(bp);
		free(uiop, M_SMBFSDATA);
		smbfs_free_scred(scred);
		return 0;
	    }
	}
	bp->b_resid = uiop->uio_resid;
	bufdone(bp);
	free(uiop, M_SMBFSDATA);
	smbfs_free_scred(scred);
	return error;
}