aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2011-04-29 21:18:41 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2011-04-29 21:18:41 +0000
commit0abd21bdb8a4a8d0376d383d21fb02a217f1fd43 (patch)
tree45cb2dbfd2eb62c2f83ce239dde87046d43d19bf
parent1d29baf81e60e82a87cef3819a0b64efc6572bbe (diff)
downloadsrc-0abd21bdb8a4a8d0376d383d21fb02a217f1fd43.tar.gz
src-0abd21bdb8a4a8d0376d383d21fb02a217f1fd43.zip
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
Notes
Notes: svn path=/head/; revision=221229
-rw-r--r--sys/dev/md/md.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c
index 1ed5b71db95d..79bf19c4e5b2 100644
--- a/sys/dev/md/md.c
+++ b/sys/dev/md/md.c
@@ -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;