}
/*
+ * This is the same as uiomove() except (cp, n) is within the bounds of
+ * the passed, locked buffer. Under certain circumstances a VM fault
+ * occuring with a locked buffer held can result in a deadlock or an
+ * attempt to recursively lock the buffer.
+ *
+ * This procedure deals with these cases.
+ *
+ * If the buffer represents a regular file, is B_CACHE, but the last VM page
+ * is not fully valid we fix-up the last VM page. This should handle the
+ * recursive lock issue.
+ *
+ * Deadlocks are another issue. We are holding the vp and the bp locked
+ * and could deadlock against a different vp and/or bp if another thread is
+ * trying to access us while we accessing it. The only solution here is
+ * to release the bp and vnode lock and do the uio to/from a system buffer,
+ * then regain the locks and copyback (if applicable). XXX TODO.
+ */
+int
+uiomovebp(struct buf *bp, caddr_t cp, size_t n, struct uio *uio)
+{
+ int count;
+ vm_page_t m;
+
+ if (bp->b_vp && bp->b_vp->v_type == VREG &&
+ (bp->b_flags & B_CACHE) &&
+ (count = bp->b_xio.xio_npages) != 0 &&
+ (m = bp->b_xio.xio_pages[count-1])->valid != VM_PAGE_BITS_ALL) {
+ vm_page_zero_invalid(m, TRUE);
+ }
+ return (uiomove(cp, n, uio));
+}
+
+/*
* Like uiomove() but copies zero-fill. Only allowed for UIO_READ,
* for obvious reasons.
*/
* iov uses an unsigned quantity, DragonFly will use the (unsigned)
* size_t.
*/
+struct buf;
+
struct uio {
struct iovec *uio_iov;
int uio_iovcnt;
struct vm_page;
int uiomove (caddr_t, size_t, struct uio *);
+int uiomovebp (struct buf *, caddr_t, size_t, struct uio *);
int uiomovez (size_t, struct uio *);
int uiomove_frombuf (void *buf, size_t buflen, struct uio *uio);
int uiomove_fromphys(struct vm_page *ma[], vm_offset_t offset,
* read()s on mmap()'d spaces.
*/
bp->b_flags |= B_AGE;
- bqhold(bp);
+ error = uiomovebp(bp, (char *)bp->b_data + offset, n, uio);
bqrelse(bp);
- error = uiomove((char *)bp->b_data + offset, n, uio);
- bqdrop(bp);
if (got_fstoken)
lwkt_gettoken(&hmp->fs_token);
}
if (error == 0) {
lwkt_reltoken(&hmp->fs_token);
- error = uiomove(bp->b_data + offset, n, uio);
+ error = uiomovebp(bp, bp->b_data + offset, n, uio);
lwkt_gettoken(&hmp->fs_token);
}
diff = blsize - bp->b_resid;
if (diff < n)
n = diff;
- error = uiomove(bp->b_data + on, (size_t)n, uio);
+ error = uiomovebp(bp, bp->b_data + on, (size_t)n, uio);
brelse(bp);
} while (error == 0 && uio->uio_resid > 0 && n != 0);
if (!isadir && (error == 0 || uio->uio_resid != orig_resid) &&
/*
* Copy the data from user space into the buf header.
*/
- error = uiomove(bp->b_data + croffset, (size_t)n, uio);
+ error = uiomovebp(bp, bp->b_data + croffset, (size_t)n, uio);
if (error) {
brelse(bp);
break;
switch (vp->v_type) {
case VREG:
if (n > 0)
- error = uiomove(bp->b_data + boff, n, uio);
+ error = uiomovebp(bp, bp->b_data + boff, n, uio);
break;
case VLNK:
if (n > 0)
- error = uiomove(bp->b_data + boff, n, uio);
+ error = uiomovebp(bp, bp->b_data + boff, n, uio);
n = 0;
break;
case VDIR:
goto again;
}
- error = uiomove(bp->b_data + boff, bytes, uio);
+ error = uiomovebp(bp, bp->b_data + boff, bytes, uio);
/*
* Since this block is being modified, it must be written
}
}
if (uio)
- uiomove(bp->b_data + off, tocopy, uio);
+ uiomovebp(bp, bp->b_data + off, tocopy, uio);
else
memcpy(bp->b_data + off, data, tocopy);
bawrite(bp);
return (error);
}
if (uio) {
- uiomove(bp->b_data + off,
+ uiomovebp(bp, bp->b_data + off,
tocopy, uio);
} else {
memcpy(data, bp->b_data + off,
break;
}
- error = uiomove(bp->b_data + off, toread - off, uio);
+ error = uiomovebp(bp, bp->b_data + off, toread - off, uio);
if(error) {
brelse(bp);
break;
if (len > node->tn_size - uio->uio_offset)
len = (size_t)(node->tn_size - uio->uio_offset);
- error = uiomove((char *)bp->b_data + offset, len, uio);
+ error = uiomovebp(bp, (char *)bp->b_data + offset, len, uio);
bqrelse(bp);
if (error) {
kprintf("tmpfs_read uiomove error %d\n", error);
* So just use bread() to do the right thing.
*/
error = bread(vp, base_offset, BSIZE, &bp);
- error = uiomove((char *)bp->b_data + offset, len, uio);
+ error = uiomovebp(bp, (char *)bp->b_data + offset, len, uio);
if (error) {
kprintf("tmpfs_write uiomove error %d\n", error);
brelse(bp);
/*
* otherwise use the general form
*/
- error = uiomove(bp->b_data + blkoffset, (int)xfersize, uio);
+ error = uiomovebp(bp, bp->b_data + blkoffset, xfersize, uio);
if (error)
break;
if (size < xfersize)
xfersize = size;
- error = uiomove(bp->b_data + blkoffset, (int)xfersize, uio);
+ error = uiomovebp(bp, bp->b_data + blkoffset, xfersize, uio);
if ((ioflag & (IO_VMIO|IO_DIRECT)) &&
(LIST_FIRST(&bp->b_dep) == NULL)) {
bp->b_flags |= B_RELBUF;