static int tmpfs_read (struct vop_read_args *ap) { struct buf *bp; struct vnode *vp = ap->a_vp; struct uio *uio = ap->a_uio; struct tmpfs_node *node; off_t base_offset; size_t offset; size_t len; size_t resid; int error; /* * Check the basics */ if (uio->uio_offset < 0) return (EINVAL); if (vp->v_type != VREG) return (EINVAL); /* * Extract node, try to shortcut the operation through * the VM page cache, allowing us to avoid buffer cache * overheads. */ node = VP_TO_TMPFS_NODE(vp); resid = uio->uio_resid; error = vop_helper_read_shortcut(ap); if (error) return error; if (uio->uio_resid == 0) { if (resid) goto finished; return error; } /* * Fall-through to our normal read code. */ while (uio->uio_resid > 0 && uio->uio_offset < node->tn_size) { /* * Use buffer cache I/O (via tmpfs_strategy) */ offset = (size_t)uio->uio_offset & TMPFS_BLKMASK64; base_offset = (off_t)uio->uio_offset - offset; bp = getcacheblk(vp, base_offset, TMPFS_BLKSIZE, 0); if (bp == NULL) { error = bread(vp, base_offset, TMPFS_BLKSIZE, &bp); if (error) { brelse(bp); kprintf("tmpfs_read bread error %d\n", error); break; } /* * tmpfs pretty much fiddles directly with the VM * system, don't let it exhaust it or we won't play * nice with other processes. * * Only do this if the VOP is coming from a normal * read/write. The VM system handles the case for * UIO_NOCOPY. */ if (uio->uio_segflg != UIO_NOCOPY) vm_wait_nominal(); } bp->b_flags |= B_CLUSTEROK; /* * Figure out how many bytes we can actually copy this loop. */ len = TMPFS_BLKSIZE - offset; if (len > uio->uio_resid) len = uio->uio_resid; if (len > node->tn_size - uio->uio_offset) len = (size_t)(node->tn_size - uio->uio_offset); error = uiomovebp(bp, (char *)bp->b_data + offset, len, uio); bqrelse(bp); if (error) { kprintf("tmpfs_read uiomove error %d\n", error); break; } } finished: if ((node->tn_status & TMPFS_NODE_ACCESSED) == 0) { TMPFS_NODE_LOCK(node); node->tn_status |= TMPFS_NODE_ACCESSED; TMPFS_NODE_UNLOCK(node); } return (error); }
static int tmpfs_read (struct vop_read_args *ap) { struct buf *bp; struct vnode *vp = ap->a_vp; struct uio *uio = ap->a_uio; struct tmpfs_node *node; off_t base_offset; size_t offset; size_t len; int error; error = 0; if (uio->uio_resid == 0) { return error; } node = VP_TO_TMPFS_NODE(vp); if (uio->uio_offset < 0) return (EINVAL); if (vp->v_type != VREG) return (EINVAL); while (uio->uio_resid > 0 && uio->uio_offset < node->tn_size) { /* * Use buffer cache I/O (via tmpfs_strategy) */ offset = (size_t)uio->uio_offset & BMASK; base_offset = (off_t)uio->uio_offset - offset; bp = getcacheblk(vp, base_offset, BSIZE, 0); if (bp == NULL) { lwkt_gettoken(&vp->v_mount->mnt_token); error = bread(vp, base_offset, BSIZE, &bp); if (error) { brelse(bp); lwkt_reltoken(&vp->v_mount->mnt_token); kprintf("tmpfs_read bread error %d\n", error); break; } lwkt_reltoken(&vp->v_mount->mnt_token); } /* * Figure out how many bytes we can actually copy this loop. */ len = BSIZE - offset; if (len > uio->uio_resid) len = uio->uio_resid; if (len > node->tn_size - uio->uio_offset) len = (size_t)(node->tn_size - uio->uio_offset); error = uiomovebp(bp, (char *)bp->b_data + offset, len, uio); bqrelse(bp); if (error) { kprintf("tmpfs_read uiomove error %d\n", error); break; } } TMPFS_NODE_LOCK(node); node->tn_status |= TMPFS_NODE_ACCESSED; TMPFS_NODE_UNLOCK(node); return(error); }