Page MenuHomeFreeBSD

D21032.id60033.diff
No OneTemporary

D21032.id60033.diff

Index: sys/kern/vfs_subr.c
===================================================================
--- sys/kern/vfs_subr.c
+++ sys/kern/vfs_subr.c
@@ -118,6 +118,8 @@
static void vfs_knl_assert_unlocked(void *arg);
static void vnlru_return_batches(struct vfsops *mnt_op);
static void destroy_vpollinfo(struct vpollinfo *vi);
+static int v_inval_buf_range1(struct vnode *vp, struct bufobj *bo,
+ daddr_t startlbn, daddr_t endlbn);
/*
* These fences are intended for cases where some synchronization is
@@ -1954,9 +1956,8 @@
vtruncbuf(struct vnode *vp, off_t length, int blksize)
{
struct buf *bp, *nbp;
- int anyfreed;
- daddr_t trunclbn;
struct bufobj *bo;
+ daddr_t startlbn;
CTR4(KTR_VFS, "%s: vp %p with block %d:%ju", __func__,
vp, blksize, (uintmax_t)length);
@@ -1964,22 +1965,114 @@
/*
* Round up to the *next* lbn.
*/
- trunclbn = howmany(length, blksize);
+ startlbn = howmany(length, blksize);
ASSERT_VOP_LOCKED(vp, "vtruncbuf");
+
restart:
bo = &vp->v_bufobj;
BO_LOCK(bo);
+ if (v_inval_buf_range1(vp, bo, startlbn, INT64_MAX) == EAGAIN)
+ goto restart;
+
+ if (length > 0) {
+restartsync:
+ TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) {
+ if (bp->b_lblkno > 0)
+ continue;
+ /*
+ * Since we hold the vnode lock this should only
+ * fail if we're racing with the buf daemon.
+ */
+ if (BUF_LOCK(bp,
+ LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK,
+ BO_LOCKPTR(bo)) == ENOLCK) {
+ goto restart;
+ }
+ VNASSERT((bp->b_flags & B_DELWRI), vp,
+ ("buf(%p) on dirty queue without DELWRI", bp));
+
+ bremfree(bp);
+ bawrite(bp);
+ BO_LOCK(bo);
+ goto restartsync;
+ }
+ }
+
+ bufobj_wwait(bo, 0, 0);
+ BO_UNLOCK(bo);
+ vnode_pager_setsize(vp, length);
+
+ return (0);
+}
+
+/*
+ * Invalidate the cached pages of a file's buffer within the range of block
+ * numbers [startlbn, endlbn). Every buffer that overlaps that range will be
+ * invalidated. This must not result in any dirty data being lost.
+ */
+void
+v_inval_buf_range(struct vnode *vp, off_t start, off_t end, int blksize)
+{
+ struct bufobj *bo;
+ daddr_t startlbn, endlbn;
+ vm_pindex_t startp, endp;
+
+ /* Round "outwards" */
+ startlbn = start / blksize;
+ endlbn = howmany(end, blksize);
+ startp = OFF_TO_IDX(start);
+ endp = OFF_TO_IDX(end + PAGE_SIZE - 1);
+
+ ASSERT_VOP_LOCKED(vp, "v_inval_buf_range");
+
+restart:
+ bo = &vp->v_bufobj;
+ BO_LOCK(bo);
+
+#ifdef INVARIANTS
+ struct buf *bp, *nbp;
+
+ TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) {
+ /*
+ * Disallow invalidating dirty data outside of the requested
+ * offsets. Assume that data within the requested offsets is
+ * being invalidated for a good reason.
+ */
+ off_t blkstart, blkend;
+
+ blkstart = bp->b_offset;
+ blkend = bp->b_offset + bp->b_bcount;
+ KASSERT(blkstart >= start && blkend <= end,
+ ("Invalidating extra dirty data!"));
+ }
+#endif
+
+ if (v_inval_buf_range1(vp, bo, startlbn, endlbn) == EAGAIN)
+ goto restart;
+
+ BO_UNLOCK(bo);
+ vn_pages_remove(vp, startp, endp);
+}
+
+/* Like v_inval_buf_range, but operates on whole buffers instead of offsets */
+static int
+v_inval_buf_range1(struct vnode *vp, struct bufobj *bo,
+ daddr_t startlbn, daddr_t endlbn)
+{
+ struct buf *bp, *nbp;
+ int anyfreed;
+
anyfreed = 1;
for (;anyfreed;) {
anyfreed = 0;
TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, nbp) {
- if (bp->b_lblkno < trunclbn)
+ if (bp->b_lblkno < startlbn || bp->b_lblkno >= endlbn)
continue;
if (BUF_LOCK(bp,
LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK,
BO_LOCKPTR(bo)) == ENOLCK)
- goto restart;
+ return EAGAIN;
bremfree(bp);
bp->b_flags |= (B_INVAL | B_RELBUF);
@@ -1993,17 +2086,17 @@
(nbp->b_vp != vp) ||
(nbp->b_flags & B_DELWRI))) {
BO_UNLOCK(bo);
- goto restart;
+ return EAGAIN;
}
}
TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) {
- if (bp->b_lblkno < trunclbn)
+ if (bp->b_lblkno < startlbn || bp->b_lblkno >= endlbn)
continue;
if (BUF_LOCK(bp,
LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK,
BO_LOCKPTR(bo)) == ENOLCK)
- goto restart;
+ return EAGAIN;
bremfree(bp);
bp->b_flags |= (B_INVAL | B_RELBUF);
bp->b_flags &= ~B_ASYNC;
@@ -2016,40 +2109,11 @@
(nbp->b_vp != vp) ||
(nbp->b_flags & B_DELWRI) == 0)) {
BO_UNLOCK(bo);
- goto restart;
+ return EAGAIN;
}
}
}
-
- if (length > 0) {
-restartsync:
- TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) {
- if (bp->b_lblkno > 0)
- continue;
- /*
- * Since we hold the vnode lock this should only
- * fail if we're racing with the buf daemon.
- */
- if (BUF_LOCK(bp,
- LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK,
- BO_LOCKPTR(bo)) == ENOLCK) {
- goto restart;
- }
- VNASSERT((bp->b_flags & B_DELWRI), vp,
- ("buf(%p) on dirty queue without DELWRI", bp));
-
- bremfree(bp);
- bawrite(bp);
- BO_LOCK(bo);
- goto restartsync;
- }
- }
-
- bufobj_wwait(bo, 0, 0);
- BO_UNLOCK(bo);
- vnode_pager_setsize(vp, length);
-
- return (0);
+ return 0;
}
static void
Index: sys/sys/vnode.h
===================================================================
--- sys/sys/vnode.h
+++ sys/sys/vnode.h
@@ -659,6 +659,8 @@
void vinactive(struct vnode *, struct thread *);
int vinvalbuf(struct vnode *vp, int save, int slpflag, int slptimeo);
int vtruncbuf(struct vnode *vp, off_t length, int blksize);
+void v_inval_buf_range(struct vnode *vp, off_t start, off_t end,
+ int blksize);
void vunref(struct vnode *);
void vn_printf(struct vnode *vp, const char *fmt, ...) __printflike(2,3);
int vrecycle(struct vnode *vp);

File Metadata

Mime Type
text/plain
Expires
Tue, Jun 16, 6:21 PM (16 h, 2 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33997551
Default Alt Text
D21032.id60033.diff (5 KB)

Event Timeline