Implement BIO_DELETE for vnode devices by simply overwriting the deleted

sectors with all-zeroes.

The zeroes come from a static buffer; null(4) uses a dynamic buffer for
the same purpose (for /dev/zero).  It might be a good idea to have a
static, shared, read-only all-zeroes page somewhere in the kernel that
md(4), null(4) and any other code that needs zeroes could use.

Reviewed by:	kib
MFC after:	3 weeks
This commit is contained in:
Dag-Erling Smørgrav 2011-04-29 21:18:41 +00:00
parent 1d29baf81e
commit 0abd21bdb8
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=221229

View File

@ -205,6 +205,9 @@ struct md_s {
vm_object_t object;
};
/* Used for BIO_DELETE on MD_VNODE */
static u_char zero[PAGE_SIZE];
static struct indir *
new_indir(u_int shift)
{
@ -514,10 +517,12 @@ mdstart_vnode(struct md_s *sc, struct bio *bp)
struct mount *mp;
struct vnode *vp;
struct thread *td;
off_t end, zerosize;
switch (bp->bio_cmd) {
case BIO_READ:
case BIO_WRITE:
case BIO_DELETE:
case BIO_FLUSH:
break;
default:
@ -548,6 +553,43 @@ mdstart_vnode(struct md_s *sc, struct bio *bp)
bzero(&auio, sizeof(auio));
/*
* Special case for BIO_DELETE. On the surface, this is very
* similar to BIO_WRITE, except that we write from our own
* fixed-length buffer, so we have to loop. The net result is
* that the two cases end up having very little in common.
*/
if (bp->bio_cmd == BIO_DELETE) {
zerosize = sizeof(zero) - (sizeof(zero) % sc->sectorsize);
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_offset = (vm_ooffset_t)bp->bio_offset;
auio.uio_segflg = UIO_SYSSPACE;
auio.uio_rw = UIO_WRITE;
auio.uio_td = td;
end = bp->bio_offset + bp->bio_length;
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
(void) vn_start_write(vp, &mp, V_WAIT);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
error = 0;
while (auio.uio_offset < end) {
aiov.iov_base = zero;
aiov.iov_len = end - auio.uio_offset;
if (aiov.iov_len > zerosize)
aiov.iov_len = zerosize;
auio.uio_resid = aiov.iov_len;
error = VOP_WRITE(vp, &auio,
sc->flags & MD_ASYNC ? 0 : IO_SYNC, sc->cred);
if (error != 0)
break;
}
VOP_UNLOCK(vp, 0);
vn_finished_write(mp);
bp->bio_resid = end - auio.uio_offset;
VFS_UNLOCK_GIANT(vfslocked);
return (error);
}
aiov.iov_base = bp->bio_data;
aiov.iov_len = bp->bio_length;
auio.uio_iov = &aiov;