Module Name: src
Committed By: jdolecek
Date: Fri Oct 28 20:38:12 UTC 2016
Modified Files:
src/sys/kern: vfs_wapbl.c
src/sys/sys: wapbl.h
src/sys/ufs/ffs: ffs_alloc.c ffs_inode.c ffs_snapshot.c
src/sys/ufs/ufs: ufs_extern.h ufs_inode.c ufs_rename.c ufs_vnops.c
ufs_wapbl.h
Log Message:
reorganize ffs_truncate()/ffs_indirtrunc() to be able to partially
succeed; change wapbl_register_deallocation() to return EAGAIN
rather than panic when code hits the limit
callers changed to either loop calling ffs_truncate() using new
utility ufs_truncate_retry() if their semantics requires it, or
just ignore the failure; remove ufs_wapbl_truncate()
this fixes possible user-triggerable panic during truncate, and
resolves WAPBL performance issue with truncates of large files
PR kern/47146 and kern/49175
To generate a diff of this commit:
cvs rdiff -u -r1.84 -r1.85 src/sys/kern/vfs_wapbl.c
cvs rdiff -u -r1.18 -r1.19 src/sys/sys/wapbl.h
cvs rdiff -u -r1.152 -r1.153 src/sys/ufs/ffs/ffs_alloc.c
cvs rdiff -u -r1.117 -r1.118 src/sys/ufs/ffs/ffs_inode.c
cvs rdiff -u -r1.142 -r1.143 src/sys/ufs/ffs/ffs_snapshot.c
cvs rdiff -u -r1.82 -r1.83 src/sys/ufs/ufs/ufs_extern.h
cvs rdiff -u -r1.96 -r1.97 src/sys/ufs/ufs/ufs_inode.c
cvs rdiff -u -r1.12 -r1.13 src/sys/ufs/ufs/ufs_rename.c
cvs rdiff -u -r1.232 -r1.233 src/sys/ufs/ufs/ufs_vnops.c
cvs rdiff -u -r1.11 -r1.12 src/sys/ufs/ufs/ufs_wapbl.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/kern/vfs_wapbl.c
diff -u src/sys/kern/vfs_wapbl.c:1.84 src/sys/kern/vfs_wapbl.c:1.85
--- src/sys/kern/vfs_wapbl.c:1.84 Sun Oct 2 16:52:27 2016
+++ src/sys/kern/vfs_wapbl.c Fri Oct 28 20:38:12 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: vfs_wapbl.c,v 1.84 2016/10/02 16:52:27 jdolecek Exp $ */
+/* $NetBSD: vfs_wapbl.c,v 1.85 2016/10/28 20:38:12 jdolecek Exp $ */
/*-
* Copyright (c) 2003, 2008, 2009 The NetBSD Foundation, Inc.
@@ -36,7 +36,7 @@
#define WAPBL_INTERNAL
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_wapbl.c,v 1.84 2016/10/02 16:52:27 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_wapbl.c,v 1.85 2016/10/28 20:38:12 jdolecek Exp $");
#include <sys/param.h>
#include <sys/bitops.h>
@@ -1929,22 +1929,35 @@ wapbl_dump(struct wapbl *wl)
/****************************************************************/
-void
-wapbl_register_deallocation(struct wapbl *wl, daddr_t blk, int len)
+int
+wapbl_register_deallocation(struct wapbl *wl, daddr_t blk, int len, bool force)
{
struct wapbl_dealloc *wd;
+ int error = 0;
wapbl_jlock_assert(wl);
mutex_enter(&wl->wl_mtx);
- /* XXX should eventually instead tie this into resource estimation */
- /*
- * XXX this panic needs locking/mutex analysis and the
- * ability to cope with the failure.
- */
- /* XXX this XXX doesn't have enough XXX */
- if (__predict_false(wl->wl_dealloccnt >= wl->wl_dealloclim))
- panic("wapbl_register_deallocation: out of resources");
+
+ if (__predict_false(wl->wl_dealloccnt >= wl->wl_dealloclim)) {
+ if (!force) {
+ error = EAGAIN;
+ goto out;
+ }
+
+ /*
+ * Forced registration can only be used when:
+ * 1) the caller can't cope with failure
+ * 2) the path can be triggered only bounded, small
+ * times per transaction
+ * If this is not fullfilled, and the path would be triggered
+ * many times, this could overflow maximum transaction size
+ * and panic later.
+ */
+ printf("%s: forced dealloc registration over limit: %d >= %d\n",
+ wl->wl_mount->mnt_stat.f_mntonname,
+ wl->wl_dealloccnt, wl->wl_dealloclim);
+ }
wl->wl_dealloccnt++;
mutex_exit(&wl->wl_mtx);
@@ -1955,10 +1968,15 @@ wapbl_register_deallocation(struct wapbl
mutex_enter(&wl->wl_mtx);
SIMPLEQ_INSERT_TAIL(&wl->wl_dealloclist, wd, wd_entries);
+
+ out:
mutex_exit(&wl->wl_mtx);
WAPBL_PRINTF(WAPBL_PRINT_ALLOC,
- ("wapbl_register_deallocation: blk=%"PRId64" len=%d\n", blk, len));
+ ("wapbl_register_deallocation: blk=%"PRId64" len=%d error=%d\n",
+ blk, len, error));
+
+ return error;
}
/****************************************************************/
Index: src/sys/sys/wapbl.h
diff -u src/sys/sys/wapbl.h:1.18 src/sys/sys/wapbl.h:1.19
--- src/sys/sys/wapbl.h:1.18 Sat Oct 1 13:15:45 2016
+++ src/sys/sys/wapbl.h Fri Oct 28 20:38:12 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: wapbl.h,v 1.18 2016/10/01 13:15:45 jdolecek Exp $ */
+/* $NetBSD: wapbl.h,v 1.19 2016/10/28 20:38:12 jdolecek Exp $ */
/*-
* Copyright (c) 2003,2008 The NetBSD Foundation, Inc.
@@ -173,7 +173,7 @@ void wapbl_unregister_inode(struct wapbl
* the corresponding blocks from being reused as data
* blocks until the log is on disk.
*/
-void wapbl_register_deallocation(struct wapbl *, daddr_t, int);
+int wapbl_register_deallocation(struct wapbl *, daddr_t, int, bool);
void wapbl_jlock_assert(struct wapbl *wl);
void wapbl_junlock_assert(struct wapbl *wl);
Index: src/sys/ufs/ffs/ffs_alloc.c
diff -u src/sys/ufs/ffs/ffs_alloc.c:1.152 src/sys/ufs/ffs/ffs_alloc.c:1.153
--- src/sys/ufs/ffs/ffs_alloc.c:1.152 Sun Sep 25 17:14:59 2016
+++ src/sys/ufs/ffs/ffs_alloc.c Fri Oct 28 20:38:12 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ffs_alloc.c,v 1.152 2016/09/25 17:14:59 jdolecek Exp $ */
+/* $NetBSD: ffs_alloc.c,v 1.153 2016/10/28 20:38:12 jdolecek Exp $ */
/*-
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -70,7 +70,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ffs_alloc.c,v 1.152 2016/09/25 17:14:59 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ffs_alloc.c,v 1.153 2016/10/28 20:38:12 jdolecek Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ffs.h"
@@ -478,11 +478,20 @@ ffs_realloccg(struct inode *ip, daddr_t
}
bno = ffs_hashalloc(ip, cg, bpref, request, nsize, 0, ffs_alloccg);
if (bno > 0) {
+ /*
+ * Use forced deallocation registration, we can't handle
+ * failure here. This is safe, as this place is ever hit
+ * maximum once per write operation, when fragment is extended
+ * to longer fragment, or a full block.
+ */
if ((ip->i_ump->um_mountp->mnt_wapbl) &&
(ITOV(ip)->v_type != VREG)) {
- UFS_WAPBL_REGISTER_DEALLOCATION(
+ /* this should never fail */
+ error = UFS_WAPBL_REGISTER_DEALLOCATION_FORCE(
ip->i_ump->um_mountp, FFS_FSBTODB(fs, bprev),
osize);
+ if (error)
+ panic("ffs_realloccg: dealloc registration failed");
} else {
ffs_blkfree(fs, ip->i_devvp, bprev, (long)osize,
ip->i_number);
Index: src/sys/ufs/ffs/ffs_inode.c
diff -u src/sys/ufs/ffs/ffs_inode.c:1.117 src/sys/ufs/ffs/ffs_inode.c:1.118
--- src/sys/ufs/ffs/ffs_inode.c:1.117 Sat Mar 28 19:24:04 2015
+++ src/sys/ufs/ffs/ffs_inode.c Fri Oct 28 20:38:12 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ffs_inode.c,v 1.117 2015/03/28 19:24:04 maxv Exp $ */
+/* $NetBSD: ffs_inode.c,v 1.118 2016/10/28 20:38:12 jdolecek Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -61,7 +61,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ffs_inode.c,v 1.117 2015/03/28 19:24:04 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ffs_inode.c,v 1.118 2016/10/28 20:38:12 jdolecek Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ffs.h"
@@ -212,13 +212,15 @@ ffs_truncate(struct vnode *ovp, off_t le
daddr_t blks[UFS_NDADDR + UFS_NIADDR];
struct fs *fs;
int offset, pgoffset, level;
- int64_t count, blocksreleased = 0;
+ int64_t blocksreleased = 0;
int i, aflag, nblocks;
int error, allerror = 0;
off_t osize;
int sync;
struct ufsmount *ump = oip->i_ump;
+ UFS_WAPBL_JLOCK_ASSERT(ip->i_ump->um_mountp);
+
if (ovp->v_type == VCHR || ovp->v_type == VBLK ||
ovp->v_type == VFIFO || ovp->v_type == VSOCK) {
KASSERT(oip->i_size == 0);
@@ -418,19 +420,22 @@ ffs_truncate(struct vnode *ovp, off_t le
bn = ufs_rw64(oip->i_ffs2_ib[level],UFS_FSNEEDSWAP(fs));
if (bn != 0) {
error = ffs_indirtrunc(oip, indir_lbn[level],
- FFS_FSBTODB(fs, bn), lastiblock[level], level, &count);
+ FFS_FSBTODB(fs, bn), lastiblock[level], level,
+ &blocksreleased);
if (error)
- allerror = error;
- blocksreleased += count;
+ goto out;
+
if (lastiblock[level] < 0) {
- DIP_ASSIGN(oip, ib[level], 0);
if (oip->i_ump->um_mountp->mnt_wapbl) {
- UFS_WAPBL_REGISTER_DEALLOCATION(
+ error = UFS_WAPBL_REGISTER_DEALLOCATION(
oip->i_ump->um_mountp,
FFS_FSBTODB(fs, bn), fs->fs_bsize);
+ if (error)
+ goto out;
} else
ffs_blkfree(fs, oip->i_devvp, bn,
fs->fs_bsize, oip->i_number);
+ DIP_ASSIGN(oip, ib[level], 0);
blocksreleased += nblocks;
}
}
@@ -450,14 +455,18 @@ ffs_truncate(struct vnode *ovp, off_t le
bn = ufs_rw64(oip->i_ffs2_db[i], UFS_FSNEEDSWAP(fs));
if (bn == 0)
continue;
- DIP_ASSIGN(oip, db[i], 0);
+
bsize = ffs_blksize(fs, oip, i);
if ((oip->i_ump->um_mountp->mnt_wapbl) &&
(ovp->v_type != VREG)) {
- UFS_WAPBL_REGISTER_DEALLOCATION(oip->i_ump->um_mountp,
+ error = UFS_WAPBL_REGISTER_DEALLOCATION(
+ oip->i_ump->um_mountp,
FFS_FSBTODB(fs, bn), bsize);
+ if (error)
+ goto out;
} else
ffs_blkfree(fs, oip->i_devvp, bn, bsize, oip->i_number);
+ DIP_ASSIGN(oip, db[i], 0);
blocksreleased += btodb(bsize);
}
if (lastblock < 0)
@@ -493,9 +502,11 @@ ffs_truncate(struct vnode *ovp, off_t le
bn += ffs_numfrags(fs, newspace);
if ((oip->i_ump->um_mountp->mnt_wapbl) &&
(ovp->v_type != VREG)) {
- UFS_WAPBL_REGISTER_DEALLOCATION(
+ error = UFS_WAPBL_REGISTER_DEALLOCATION(
oip->i_ump->um_mountp, FFS_FSBTODB(fs, bn),
oldspace - newspace);
+ if (error)
+ goto out;
} else
ffs_blkfree(fs, oip->i_devvp, bn,
oldspace - newspace, oip->i_number);
@@ -515,6 +526,17 @@ done:
(!LIST_EMPTY(&ovp->v_cleanblkhd) || !LIST_EMPTY(&ovp->v_dirtyblkhd)))
panic("itrunc3");
#endif /* DIAGNOSTIC */
+
+out:
+ /*
+ * Set length back to old size if deallocation failed. Some indirect
+ * blocks were deallocated creating a hole, but that is okay.
+ */
+ if (error == EAGAIN) {
+ length = osize;
+ uvm_vnp_setsize(ovp, length);
+ }
+
/*
* Put back the real size.
*/
@@ -551,11 +573,11 @@ ffs_indirtrunc(struct inode *ip, daddr_t
int64_t *bap2 = NULL;
struct vnode *vp;
daddr_t nb, nlbn, last;
- char *copy = NULL;
- int64_t blkcount, factor, blocksreleased = 0;
- int nblocks;
- int error = 0, allerror = 0;
+ int64_t factor;
+ int64_t nblocks;
+ int error = 0;
const int needswap = UFS_FSNEEDSWAP(fs);
+
#define RBAP(ip, i) (((ip)->i_ump->um_fstype == UFS1) ? \
ufs_rw32(bap1[i], needswap) : ufs_rw64(bap2[i], needswap))
#define BAP_ASSIGN(ip, i, value) \
@@ -580,7 +602,7 @@ ffs_indirtrunc(struct inode *ip, daddr_t
nblocks = btodb(fs->fs_bsize);
/*
* Get buffer of block pointers, zero those entries corresponding
- * to blocks to be free'd, and update on disk copy first. Since
+ * to blocks to be free'd, and update on disk copy. Since
* double(triple) indirect before single(double) indirect, calls
* to bmap on these blocks will fail. However, we already have
* the on disk address, so we have to set the b_blkno field
@@ -588,10 +610,9 @@ ffs_indirtrunc(struct inode *ip, daddr_t
*/
vp = ITOV(ip);
error = ffs_getblk(vp, lbn, FFS_NOBLK, fs->fs_bsize, false, &bp);
- if (error) {
- *countp = 0;
+ if (error)
return error;
- }
+
if (bp->b_oflags & (BO_DONE | BO_DELWRI)) {
/* Braces must be here in case trace evaluates to nothing. */
trace(TR_BREADHIT, pack(vp, fs->fs_bsize), lbn);
@@ -611,77 +632,69 @@ ffs_indirtrunc(struct inode *ip, daddr_t
}
if (error) {
brelse(bp, 0);
- *countp = 0;
- return (error);
+ return error;
}
if (ip->i_ump->um_fstype == UFS1)
bap1 = (int32_t *)bp->b_data;
else
bap2 = (int64_t *)bp->b_data;
- if (lastbn >= 0) {
- copy = kmem_alloc(fs->fs_bsize, KM_SLEEP);
- memcpy((void *)copy, bp->b_data, (u_int)fs->fs_bsize);
- for (i = last + 1; i < FFS_NINDIR(fs); i++)
- BAP_ASSIGN(ip, i, 0);
- error = bwrite(bp);
- if (error)
- allerror = error;
- if (ip->i_ump->um_fstype == UFS1)
- bap1 = (int32_t *)copy;
- else
- bap2 = (int64_t *)copy;
- }
/*
- * Recursively free totally unused blocks.
+ * Recursively free totally unused blocks, starting from first.
*/
for (i = FFS_NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last;
i--, nlbn += factor) {
nb = RBAP(ip, i);
if (nb == 0)
continue;
+
if (level > SINGLE) {
error = ffs_indirtrunc(ip, nlbn, FFS_FSBTODB(fs, nb),
- (daddr_t)-1, level - 1,
- &blkcount);
+ (daddr_t)-1, level - 1, countp);
if (error)
- allerror = error;
- blocksreleased += blkcount;
+ goto out;
}
+
if ((ip->i_ump->um_mountp->mnt_wapbl) &&
((level > SINGLE) || (ITOV(ip)->v_type != VREG))) {
- UFS_WAPBL_REGISTER_DEALLOCATION(ip->i_ump->um_mountp,
+ error = UFS_WAPBL_REGISTER_DEALLOCATION(
+ ip->i_ump->um_mountp,
FFS_FSBTODB(fs, nb), fs->fs_bsize);
+ if (error)
+ goto out;
} else
ffs_blkfree(fs, ip->i_devvp, nb, fs->fs_bsize,
ip->i_number);
- blocksreleased += nblocks;
+
+ BAP_ASSIGN(ip, i, 0);
+ *countp += nblocks;
}
/*
- * Recursively free last partial block.
+ * Recursively free blocks on the now last partial indirect block.
*/
if (level > SINGLE && lastbn >= 0) {
- last = lastbn % factor;
- nb = RBAP(ip, i);
+ nb = RBAP(ip, last);
if (nb != 0) {
error = ffs_indirtrunc(ip, nlbn, FFS_FSBTODB(fs, nb),
- last, level - 1, &blkcount);
+ lastbn % factor, level - 1,
+ countp);
if (error)
- allerror = error;
- blocksreleased += blkcount;
+ goto out;
}
}
- if (copy != NULL) {
- kmem_free(copy, fs->fs_bsize);
- } else {
+out:
+ if (RBAP(ip, 0) == 0) {
+ /* all freed, release without writing back */
brelse(bp, BC_INVAL);
+ } else {
+ /* only partially freed, write the updated block */
+ (void) bwrite(bp);
}
- *countp = blocksreleased;
- return (allerror);
+ return (error);
}
void
Index: src/sys/ufs/ffs/ffs_snapshot.c
diff -u src/sys/ufs/ffs/ffs_snapshot.c:1.142 src/sys/ufs/ffs/ffs_snapshot.c:1.143
--- src/sys/ufs/ffs/ffs_snapshot.c:1.142 Fri Oct 21 19:28:03 2016
+++ src/sys/ufs/ffs/ffs_snapshot.c Fri Oct 28 20:38:12 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ffs_snapshot.c,v 1.142 2016/10/21 19:28:03 jdolecek Exp $ */
+/* $NetBSD: ffs_snapshot.c,v 1.143 2016/10/28 20:38:12 jdolecek Exp $ */
/*
* Copyright 2000 Marshall Kirk McKusick. All Rights Reserved.
@@ -38,7 +38,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ffs_snapshot.c,v 1.142 2016/10/21 19:28:03 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ffs_snapshot.c,v 1.143 2016/10/28 20:38:12 jdolecek Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ffs.h"
@@ -402,6 +402,12 @@ out:
}
if (error) {
if (UFS_WAPBL_BEGIN(mp) == 0) {
+ /*
+ * We depend on ffs_truncate() to call ffs_snapremove()
+ * before it may return an error. On failed
+ * ffs_truncate() we have normal file with leaked
+ * (meta-) data, but no snapshot to use.
+ */
(void) ffs_truncate(vp, (off_t)0, 0, NOCRED);
UFS_WAPBL_END(mp);
}
@@ -437,7 +443,12 @@ snapshot_setup(struct mount *mp, struct
return EACCES;
if (vp->v_size != 0) {
- error = ffs_truncate(vp, 0, 0, NOCRED);
+ /*
+ * Must completely truncate the file here. Allocated
+ * blocks on a snapshot mean that block has been copied
+ * on write, see ffs_copyonwrite() testing "blkno != 0"
+ */
+ error = ufs_truncate_retry(vp, 0, NOCRED);
if (error)
return error;
}
Index: src/sys/ufs/ufs/ufs_extern.h
diff -u src/sys/ufs/ufs/ufs_extern.h:1.82 src/sys/ufs/ufs/ufs_extern.h:1.83
--- src/sys/ufs/ufs/ufs_extern.h:1.82 Tue Apr 12 16:12:22 2016
+++ src/sys/ufs/ufs/ufs_extern.h Fri Oct 28 20:38:12 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ufs_extern.h,v 1.82 2016/04/12 16:12:22 christos Exp $ */
+/* $NetBSD: ufs_extern.h,v 1.83 2016/10/28 20:38:12 jdolecek Exp $ */
/*-
* Copyright (c) 1991, 1993, 1994
@@ -111,7 +111,7 @@ int ufs_getlbns(struct vnode *, daddr_t,
/* ufs_inode.c */
int ufs_reclaim(struct vnode *);
int ufs_balloc_range(struct vnode *, off_t, off_t, kauth_cred_t, int);
-int ufs_truncate(struct vnode *, uint64_t, kauth_cred_t);
+int ufs_truncate_retry(struct vnode *, uint64_t, kauth_cred_t);
/* ufs_lookup.c */
void ufs_dirbad(struct inode *, doff_t, const char *);
Index: src/sys/ufs/ufs/ufs_inode.c
diff -u src/sys/ufs/ufs/ufs_inode.c:1.96 src/sys/ufs/ufs/ufs_inode.c:1.97
--- src/sys/ufs/ufs/ufs_inode.c:1.96 Sat Aug 20 12:37:10 2016
+++ src/sys/ufs/ufs/ufs_inode.c Fri Oct 28 20:38:12 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ufs_inode.c,v 1.96 2016/08/20 12:37:10 hannken Exp $ */
+/* $NetBSD: ufs_inode.c,v 1.97 2016/10/28 20:38:12 jdolecek Exp $ */
/*
* Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_inode.c,v 1.96 2016/08/20 12:37:10 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_inode.c,v 1.97 2016/10/28 20:38:12 jdolecek Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ffs.h"
@@ -92,17 +92,28 @@ ufs_inactive(void *v)
UFS_WAPBL_JUNLOCK_ASSERT(mp);
fstrans_start(mp, FSTRANS_LAZY);
+
/*
* Ignore inodes related to stale file handles.
*/
if (ip->i_mode == 0)
goto out;
+
if (ip->i_nlink <= 0 && (mp->mnt_flag & MNT_RDONLY) == 0) {
#ifdef UFS_EXTATTR
ufs_extattr_vnode_inactive(vp, curlwp);
#endif
- if (ip->i_size != 0)
- allerror = ufs_truncate(vp, 0, NOCRED);
+
+ /*
+ * All file blocks must be freed before we can let the vnode
+ * be reclaimed, so can't postpone full truncating any further.
+ */
+ if (ip->i_size != 0) {
+ allerror = ufs_truncate_retry(vp, 0, NOCRED);
+ if (allerror)
+ goto out;
+ }
+
#if defined(QUOTA) || defined(QUOTA2)
error = UFS_WAPBL_BEGIN(mp);
if (error) {
@@ -280,49 +291,30 @@ ufs_balloc_range(struct vnode *vp, off_t
return error;
}
-static int
-ufs_wapbl_truncate(struct vnode *vp, uint64_t newsize, kauth_cred_t cred)
+int
+ufs_truncate_retry(struct vnode *vp, uint64_t newsize, kauth_cred_t cred)
{
struct inode *ip = VTOI(vp);
+ struct mount *mp = vp->v_mount;
int error = 0;
- uint64_t base, incr;
- base = UFS_NDADDR << vp->v_mount->mnt_fs_bshift;
- incr = MNINDIR(ip->i_ump) << vp->v_mount->mnt_fs_bshift;/* Power of 2 */
- while (ip->i_size > base + incr &&
- (newsize == 0 || ip->i_size > newsize + incr)) {
- /*
- * round down to next full indirect
- * block boundary.
- */
- uint64_t nsize = base + ((ip->i_size - base - 1) & ~(incr - 1));
- error = UFS_TRUNCATE(vp, nsize, 0, cred);
- if (error)
- break;
- UFS_WAPBL_END(vp->v_mount);
- error = UFS_WAPBL_BEGIN(vp->v_mount);
- if (error)
- return error;
- }
- return error;
-}
-
-int
-ufs_truncate(struct vnode *vp, uint64_t newsize, kauth_cred_t cred)
-{
- int error;
-
- error = UFS_WAPBL_BEGIN(vp->v_mount);
- if (error)
- return error;
+ UFS_WAPBL_JUNLOCK_ASSERT(mp);
- if (vp->v_mount->mnt_wapbl)
- error = ufs_wapbl_truncate(vp, newsize, cred);
+ /*
+ * Truncate might temporarily fail, loop until done.
+ */
+ while (ip->i_size != newsize) {
+ error = UFS_WAPBL_BEGIN(mp);
+ if (error)
+ goto out;
- if (error == 0)
error = UFS_TRUNCATE(vp, newsize, 0, cred);
- UFS_WAPBL_END(vp->v_mount);
+ UFS_WAPBL_END(mp);
+ if (error != 0 && error != EAGAIN)
+ goto out;
+ }
+
+ out:
return error;
}
-
Index: src/sys/ufs/ufs/ufs_rename.c
diff -u src/sys/ufs/ufs/ufs_rename.c:1.12 src/sys/ufs/ufs/ufs_rename.c:1.13
--- src/sys/ufs/ufs/ufs_rename.c:1.12 Fri Mar 27 17:27:56 2015
+++ src/sys/ufs/ufs/ufs_rename.c Fri Oct 28 20:38:12 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ufs_rename.c,v 1.12 2015/03/27 17:27:56 riastradh Exp $ */
+/* $NetBSD: ufs_rename.c,v 1.13 2016/10/28 20:38:12 jdolecek Exp $ */
/*-
* Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_rename.c,v 1.12 2015/03/27 17:27:56 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_rename.c,v 1.13 2016/10/28 20:38:12 jdolecek Exp $");
#include <sys/param.h>
#include <sys/buf.h>
@@ -469,9 +469,7 @@ ufs_gro_rename(struct mount *mp, kauth_c
"hard-linked directory");
VTOI(tvp)->i_nlink = 0;
DIP_ASSIGN(VTOI(tvp), nlink, 0);
- error = UFS_TRUNCATE(tvp, (off_t)0, IO_SYNC, cred);
- if (error)
- goto whymustithurtsomuch;
+ (void) UFS_TRUNCATE(tvp, (off_t)0, IO_SYNC, cred);
}
}
Index: src/sys/ufs/ufs/ufs_vnops.c
diff -u src/sys/ufs/ufs/ufs_vnops.c:1.232 src/sys/ufs/ufs/ufs_vnops.c:1.233
--- src/sys/ufs/ufs/ufs_vnops.c:1.232 Thu May 19 18:32:03 2016
+++ src/sys/ufs/ufs/ufs_vnops.c Fri Oct 28 20:38:12 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ufs_vnops.c,v 1.232 2016/05/19 18:32:03 riastradh Exp $ */
+/* $NetBSD: ufs_vnops.c,v 1.233 2016/10/28 20:38:12 jdolecek Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -66,7 +66,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_vnops.c,v 1.232 2016/05/19 18:32:03 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_vnops.c,v 1.233 2016/10/28 20:38:12 jdolecek Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ffs.h"
@@ -472,6 +472,8 @@ ufs_setattr(void *v)
return (EINVAL);
}
+ UFS_WAPBL_JUNLOCK_ASSERT(vp->v_mount);
+
fstrans_start(vp->v_mount, FSTRANS_SHARED);
if (vap->va_flags != VNOVAL) {
@@ -568,7 +570,7 @@ ufs_setattr(void *v)
error = EPERM;
goto out;
}
- error = ufs_truncate(vp, vap->va_size, cred);
+ error = ufs_truncate_retry(vp, vap->va_size, cred);
if (error)
goto out;
break;
@@ -1156,7 +1158,7 @@ ufs_rmdir(void *v)
ip->i_nlink--;
DIP_ASSIGN(ip, nlink, ip->i_nlink);
ip->i_flag |= IN_CHANGE;
- error = UFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred);
+ (void) UFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred);
cache_purge(vp);
/*
* Unlock the log while we still have reference to unlinked
Index: src/sys/ufs/ufs/ufs_wapbl.h
diff -u src/sys/ufs/ufs/ufs_wapbl.h:1.11 src/sys/ufs/ufs/ufs_wapbl.h:1.12
--- src/sys/ufs/ufs/ufs_wapbl.h:1.11 Thu May 19 18:32:20 2016
+++ src/sys/ufs/ufs/ufs_wapbl.h Fri Oct 28 20:38:12 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ufs_wapbl.h,v 1.11 2016/05/19 18:32:20 riastradh Exp $ */
+/* $NetBSD: ufs_wapbl.h,v 1.12 2016/10/28 20:38:12 jdolecek Exp $ */
/*-
* Copyright (c) 2003,2006,2008 The NetBSD Foundation, Inc.
@@ -147,7 +147,14 @@ ufs_wapbl_end(struct mount *mp)
if (mp->mnt_wapbl) wapbl_unregister_inode(mp->mnt_wapbl, ino, mode)
#define UFS_WAPBL_REGISTER_DEALLOCATION(mp, blk, len) \
- if (mp->mnt_wapbl) wapbl_register_deallocation(mp->mnt_wapbl, blk, len)
+ (mp->mnt_wapbl) \
+ ? wapbl_register_deallocation(mp->mnt_wapbl, blk, len, false) : 0
+
+#define UFS_WAPBL_REGISTER_DEALLOCATION_FORCE(mp, blk, len) \
+ ( \
+ (mp->mnt_wapbl) \
+ ? wapbl_register_deallocation(mp->mnt_wapbl, blk, len, true) : 0 \
+ )
#else /* ! WAPBL */
#define UFS_WAPBL_BEGIN(mp) (__USE(mp), 0)
@@ -157,7 +164,8 @@ ufs_wapbl_end(struct mount *mp)
#define UFS_WAPBL_JUNLOCK_ASSERT(mp)
#define UFS_WAPBL_REGISTER_INODE(mp, ino, mode) do { } while (0)
#define UFS_WAPBL_UNREGISTER_INODE(mp, ino, mode) do { } while (0)
-#define UFS_WAPBL_REGISTER_DEALLOCATION(mp, blk, len)
+#define UFS_WAPBL_REGISTER_DEALLOCATION(mp, blk, len) 0
+#define UFS_WAPBL_REGISTER_DEALLOCATION_FORCE(mp, blk, len) 0
#endif
#endif /* !_UFS_UFS_UFS_WAPBL_H_ */