summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2012-05-26 05:28:47 +0000
committerkib <kib@FreeBSD.org>2012-05-26 05:28:47 +0000
commit08dbe8fa01b3d86ff4c013895e550837ae597f5e (patch)
tree9c2ce0e5e94220dc096854dc55a7b74d860ced50
parent05218621b4f65a2994d3a5d3ce18d7960b1bf380 (diff)
downloadFreeBSD-src-08dbe8fa01b3d86ff4c013895e550837ae597f5e.zip
FreeBSD-src-08dbe8fa01b3d86ff4c013895e550837ae597f5e.tar.gz
Add a vn_bmap_seekhole(9) vnode helper which can be used by any
filesystem which supports VOP_BMAP(9) to implement SEEK_HOLE/SEEK_DATA commands for lseek(2). MFC after: 2 weeks
-rw-r--r--sys/kern/vfs_vnops.c53
-rw-r--r--sys/sys/vnode.h2
2 files changed, 55 insertions, 0 deletions
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index d4b60f1..56c9829 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -1466,3 +1466,56 @@ vn_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end)
vm_object_page_remove(object, start, end, 0);
VM_OBJECT_UNLOCK(object);
}
+
+int
+vn_bmap_seekhole(struct vnode *vp, u_long cmd, off_t *off, struct ucred *cred)
+{
+ struct vattr va;
+ daddr_t bn, bnp;
+ uint64_t bsize;
+ off_t noff;
+ int error;
+
+ KASSERT(cmd == FIOSEEKHOLE || cmd == FIOSEEKDATA,
+ ("Wrong command %lu", cmd));
+
+ if (vn_lock(vp, LK_SHARED) != 0)
+ return (EBADF);
+ if (vp->v_type != VREG) {
+ error = ENOTTY;
+ goto unlock;
+ }
+ error = VOP_GETATTR(vp, &va, cred);
+ if (error != 0)
+ goto unlock;
+ noff = *off;
+ if (noff >= va.va_size) {
+ error = ENXIO;
+ goto unlock;
+ }
+ bsize = vp->v_mount->mnt_stat.f_iosize;
+ for (bn = noff / bsize; noff < va.va_size; bn++, noff += bsize) {
+ error = VOP_BMAP(vp, bn, NULL, &bnp, NULL, NULL);
+ if (error == EOPNOTSUPP) {
+ error = ENOTTY;
+ goto unlock;
+ }
+ if ((bnp == -1 && cmd == FIOSEEKHOLE) ||
+ (bnp != -1 && cmd == FIOSEEKDATA)) {
+ noff = bn * bsize;
+ if (noff < *off)
+ noff = *off;
+ goto unlock;
+ }
+ }
+ if (noff > va.va_size)
+ noff = va.va_size;
+ /* noff == va.va_size. There is an implicit hole at the end of file. */
+ if (cmd == FIOSEEKDATA)
+ error = ENXIO;
+unlock:
+ VOP_UNLOCK(vp, 0);
+ if (error == 0)
+ *off = noff;
+ return (error);
+}
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index 49f6f5b..0d711f2 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -640,6 +640,8 @@ void vunref(struct vnode *);
void vn_printf(struct vnode *vp, const char *fmt, ...) __printflike(2,3);
#define vprint(label, vp) vn_printf((vp), "%s\n", (label))
int vrecycle(struct vnode *vp);
+int vn_bmap_seekhole(struct vnode *vp, u_long cmd, off_t *off,
+ struct ucred *cred);
int vn_close(struct vnode *vp,
int flags, struct ucred *file_cred, struct thread *td);
void vn_finished_write(struct mount *mp);
OpenPOWER on IntegriCloud