Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F165012313
D33921.id101618.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
D33921.id101618.diff
View Options
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c
--- a/sys/kern/vfs_bio.c
+++ b/sys/kern/vfs_bio.c
@@ -1702,7 +1702,7 @@
if (freebufs == bd->bd_lofreebuffers)
bufspace_daemon_wakeup(bd);
- error = BUF_LOCK(bp, LK_EXCLUSIVE, NULL);
+ error = BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL);
KASSERT(error == 0, ("%s: BUF_LOCK on free buf %p: %d.", __func__, bp,
error));
(void)error;
diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c
--- a/sys/ufs/ffs/ffs_alloc.c
+++ b/sys/ufs/ffs/ffs_alloc.c
@@ -81,6 +81,7 @@
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/kernel.h>
+#include <sys/stat.h>
#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
@@ -269,7 +270,9 @@
ump = ITOUMP(ip);
fs = ump->um_fs;
bp = NULL;
- gbflags = (flags & BA_UNMAPPED) != 0 ? GB_UNMAPPED : 0;
+retry_snap:
+ gbflags = ((flags & BA_UNMAPPED) != 0 ? GB_UNMAPPED : 0) |
+ (IS_SNAPSHOT(ip) ? GB_LOCK_NOWAIT : 0);
mtx_assert(UFS_MTX(ump), MA_OWNED);
#ifdef INVARIANTS
@@ -303,9 +306,14 @@
* Allocate the extra space in the buffer.
*/
error = bread_gb(vp, lbprev, osize, NOCRED, gbflags, &bp);
- if (error) {
- return (error);
+ if (error == EBUSY && IS_SNAPSHOT(ip)) {
+ error = ffs_snap_relock(vp);
+ if (error == EBADF)
+ return (error);
+ goto retry_snap;
}
+ if (error != 0)
+ return (error);
if (bp->b_blkno == bp->b_lblkno) {
if (lbprev >= UFS_NDADDR)
diff --git a/sys/ufs/ffs/ffs_balloc.c b/sys/ufs/ffs/ffs_balloc.c
--- a/sys/ufs/ffs/ffs_balloc.c
+++ b/sys/ufs/ffs/ffs_balloc.c
@@ -70,6 +70,7 @@
#include <sys/buf.h>
#include <sys/lock.h>
#include <sys/mount.h>
+#include <sys/stat.h>
#include <sys/vnode.h>
#include <sys/vmmeter.h>
@@ -587,6 +588,42 @@
return (error);
}
+static int
+ffs_balloc_bread(struct vnode *vp, daddr_t lbn, int size, struct ucred *cred,
+ int gbflags, struct buf **bpp)
+{
+ int error;
+
+ for (;;) {
+ error = bread_gb(vp, lbn, size, cred, gbflags |
+ (IS_SNAPSHOT(VTOI(vp)) ? GB_LOCK_NOWAIT : 0), bpp);
+ if (error == 0)
+ return (0);
+ if (error == EBUSY && IS_SNAPSHOT(VTOI(vp)))
+ error = ffs_snap_relock(vp);
+ if (error != 0)
+ return (error);
+ }
+}
+
+static int
+ffs_balloc_getblk(struct vnode *vp, daddr_t lbn, int size, int gbflags,
+ struct buf **bpp)
+{
+ int error;
+
+ for (;;) {
+ error = getblkx(vp, lbn, 0, size, 0, 0, gbflags |
+ (IS_SNAPSHOT(VTOI(vp)) ? GB_LOCK_NOWAIT : 0), bpp);
+ if (error == 0)
+ return (0);
+ if (error == EBUSY && IS_SNAPSHOT(VTOI(vp)))
+ error = ffs_snap_relock(vp);
+ if (error != 0)
+ return (error);
+ }
+}
+
/*
* Balloc defines the structure of file system storage
* by allocating the physical blocks on a device given
@@ -681,9 +718,9 @@
panic("ffs_balloc_ufs2: BA_METAONLY for ext block");
nb = dp->di_extb[lbn];
if (nb != 0 && dp->di_extsize >= smalllblktosize(fs, lbn + 1)) {
- error = bread_gb(vp, -1 - lbn, fs->fs_bsize, NOCRED,
- gbflags, &bp);
- if (error)
+ error = ffs_balloc_bread(vp, -1 - lbn, fs->fs_bsize,
+ NOCRED, gbflags, &bp);
+ if (error != 0)
goto done;
bp->b_blkno = fsbtodb(fs, nb);
bp->b_xflags |= BX_ALTDATA;
@@ -697,9 +734,9 @@
osize = fragroundup(fs, blkoff(fs, dp->di_extsize));
nsize = fragroundup(fs, size);
if (nsize <= osize) {
- error = bread_gb(vp, -1 - lbn, osize, NOCRED,
- gbflags, &bp);
- if (error)
+ error = ffs_balloc_bread(vp, -1 - lbn, osize,
+ NOCRED, gbflags, &bp);
+ if (error != 0)
goto done;
bp->b_blkno = fsbtodb(fs, nb);
bp->b_xflags |= BX_ALTDATA;
@@ -729,7 +766,12 @@
nsize, flags, cred, &newb);
if (error)
goto done;
- bp = getblk(vp, -1 - lbn, nsize, 0, 0, gbflags);
+ error = ffs_balloc_getblk(vp, -1 - lbn, nsize, gbflags,
+ &bp);
+ if (error != 0) {
+ /* XXXKIB free newb */
+ goto done;
+ }
bp->b_blkno = fsbtodb(fs, newb);
bp->b_xflags |= BX_ALTDATA;
if (flags & BA_CLRBUF)
@@ -786,17 +828,15 @@
nb = dp->di_db[lbn];
if (nb != 0 && ip->i_size >= smalllblktosize(fs, lbn + 1)) {
if ((flags & BA_CLRBUF) != 0) {
- error = bread_gb(vp, lbn, fs->fs_bsize, NOCRED,
- gbflags, &bp);
+ error = ffs_balloc_bread(vp, lbn, fs->fs_bsize,
+ NOCRED, gbflags, &bp);
if (error != 0)
goto done;
} else {
- bp = getblk(vp, lbn, fs->fs_bsize, 0, 0,
- gbflags);
- if (bp == NULL) {
- error = EIO;
+ error = ffs_balloc_getblk(vp, lbn,
+ fs->fs_bsize, gbflags, &bp);
+ if (error != 0)
goto done;
- }
vfs_bio_clrbuf(bp);
}
bp->b_blkno = fsbtodb(fs, nb);
@@ -811,9 +851,9 @@
osize = fragroundup(fs, blkoff(fs, ip->i_size));
nsize = fragroundup(fs, size);
if (nsize <= osize) {
- error = bread_gb(vp, lbn, osize, NOCRED,
+ error = ffs_balloc_bread(vp, lbn, osize, NOCRED,
gbflags, &bp);
- if (error)
+ if (error != 0)
goto done;
bp->b_blkno = fsbtodb(fs, nb);
} else {
@@ -838,9 +878,13 @@
error = ffs_alloc(ip, lbn,
ffs_blkpref_ufs2(ip, lbn, (int)lbn,
&dp->di_db[0]), nsize, flags, cred, &newb);
- if (error)
+ if (error != 0)
goto done;
- bp = getblk(vp, lbn, nsize, 0, 0, gbflags);
+ error = ffs_balloc_getblk(vp, lbn, nsize, gbflags, &bp);
+ if (error != 0) {
+ /* XXXKIB free newb */
+ goto done;
+ }
bp->b_blkno = fsbtodb(fs, newb);
if (flags & BA_CLRBUF)
vfs_bio_clrbuf(bp);
@@ -888,8 +932,12 @@
MPASS(lbns_remfree < lbns + nitems(lbns));
*allocblk++ = nb;
*lbns_remfree++ = indirs[1].in_lbn;
- bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0,
- GB_UNMAPPED);
+ error = ffs_balloc_getblk(vp, indirs[1].in_lbn, fs->fs_bsize,
+ GB_UNMAPPED, &bp);
+ if (error != 0) {
+ /* XXXKIB free newb */
+ goto done;
+ }
bp->b_blkno = fsbtodb(fs, nb);
vfs_bio_clrbuf(bp);
if (DOINGSOFTDEP(vp)) {
@@ -914,11 +962,10 @@
*/
retry:
for (i = 1;;) {
- error = bread(vp,
- indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp);
- if (error) {
+ error = ffs_balloc_bread(vp, indirs[i].in_lbn,
+ (int)fs->fs_bsize, NOCRED, 0, &bp);
+ if (error != 0)
goto fail;
- }
bap = (ufs2_daddr_t *)bp->b_data;
nb = bap[indirs[i].in_off];
if ((error = UFS_CHECK_BLKNO(mp, ip->i_number, nb,
@@ -969,8 +1016,8 @@
MPASS(lbns_remfree < lbns + nitems(lbns));
*allocblk++ = nb;
*lbns_remfree++ = indirs[i].in_lbn;
- nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0,
- GB_UNMAPPED);
+ error = ffs_balloc_getblk(vp, indirs[i].in_lbn, fs->fs_bsize,
+ GB_UNMAPPED, &nbp);
nbp->b_blkno = fsbtodb(fs, nb);
vfs_bio_clrbuf(nbp);
if (DOINGSOFTDEP(vp)) {
@@ -1054,7 +1101,9 @@
MPASS(lbns_remfree < lbns + nitems(lbns));
*allocblk++ = nb;
*lbns_remfree++ = lbn;
- nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0, gbflags);
+ error = ffs_balloc_getblk(vp, lbn, fs->fs_bsize, gbflags, &nbp);
+ if (error != 0)
+ goto fail;
nbp->b_blkno = fsbtodb(fs, nb);
if (flags & BA_CLRBUF)
vfs_bio_clrbuf(nbp);
@@ -1091,10 +1140,11 @@
(vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0 &&
!(vm_page_count_severe() || buf_dirty_count_severe())) {
error = cluster_read(vp, ip->i_size, lbn,
- (int)fs->fs_bsize, NOCRED,
- MAXBSIZE, seqcount, gbflags, &nbp);
+ (int)fs->fs_bsize, NOCRED, MAXBSIZE, seqcount,
+ gbflags | (IS_SNAPSHOT(ip) ? GB_LOCK_NOWAIT : 0),
+ &nbp);
} else {
- error = bread_gb(vp, lbn, (int)fs->fs_bsize,
+ error = ffs_balloc_bread(vp, lbn, (int)fs->fs_bsize,
NOCRED, gbflags, &nbp);
}
if (error) {
@@ -1102,7 +1152,9 @@
goto fail;
}
} else {
- nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0, gbflags);
+ error = ffs_balloc_getblk(vp, lbn, fs->fs_bsize, gbflags, &nbp);
+ if (error != 0)
+ goto fail;
nbp->b_blkno = fsbtodb(fs, nb);
}
curthread_pflags_restore(saved_inbdflush);
@@ -1131,15 +1183,16 @@
* XXX Still have to journal the free below
*/
(void) ffs_syncvnode(vp, MNT_WAIT, 0);
+
for (deallocated = 0, blkp = allociblk, lbns_remfree = lbns;
blkp < allocblk; blkp++, lbns_remfree++) {
/*
* We shall not leave the freed blocks on the vnode
* buffer object lists.
*/
- bp = getblk(vp, *lbns_remfree, fs->fs_bsize, 0, 0,
- GB_NOCREAT | GB_UNMAPPED);
- if (bp != NULL) {
+ error = ffs_balloc_getblk(vp, *lbns_remfree, fs->fs_bsize,
+ GB_NOCREAT | GB_UNMAPPED, &bp);
+ if (error == 0) {
KASSERT(bp->b_blkno == fsbtodb(fs, *blkp),
("mismatch2 l %jd %jd b %ju %ju",
(intmax_t)bp->b_lblkno, (uintmax_t)*lbns_remfree,
@@ -1148,6 +1201,10 @@
bp->b_flags |= B_INVAL | B_RELBUF | B_NOCACHE;
bp->b_flags &= ~(B_ASYNC | B_CACHE);
brelse(bp);
+ } else if (error != EEXIST) {
+ /* XXXKIB what to do? */
+ printf("Can not getblk() to deallocate block, error %d",
+ error);
}
deallocated += fs->fs_bsize;
}
@@ -1156,10 +1213,10 @@
} else if (unwindidx >= 0) {
int r;
- r = bread(vp, indirs[unwindidx].in_lbn,
- (int)fs->fs_bsize, NOCRED, &bp);
- if (r) {
- panic("Could not unwind indirect block, error %d", r);
+ r = ffs_balloc_bread(vp, indirs[unwindidx].in_lbn,
+ (int)fs->fs_bsize, NOCRED, 0, &bp);
+ if (r != 0) {
+ printf("Could not unwind indirect block, error %d", r);
brelse(bp);
} else {
bap = (ufs2_daddr_t *)bp->b_data;
@@ -1192,9 +1249,9 @@
#ifdef INVARIANTS
if (blkp == allociblk)
lbns_remfree = lbns;
- bp = getblk(vp, *lbns_remfree, fs->fs_bsize, 0, 0,
- GB_NOCREAT | GB_UNMAPPED);
- if (bp != NULL) {
+ error = ffs_balloc_getblk(vp, *lbns_remfree, fs->fs_bsize,
+ GB_NOCREAT | GB_UNMAPPED, &bp);
+ if (error == 0) {
panic("zombie2 %jd %ju %ju",
(intmax_t)bp->b_lblkno, (uintmax_t)bp->b_blkno,
(uintmax_t)fsbtodb(fs, *blkp));
diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h
--- a/sys/ufs/ffs/ffs_extern.h
+++ b/sys/ufs/ffs/ffs_extern.h
@@ -99,6 +99,7 @@
int ffs_snapblkfree(struct fs *, struct vnode *, ufs2_daddr_t, long, ino_t,
enum vtype, struct workhead *);
void ffs_snapremove(struct vnode *vp);
+int ffs_snap_relock(struct vnode *vp);
int ffs_snapshot(struct mount *mp, char *snapfile);
void ffs_snapshot_mount(struct mount *mp);
void ffs_snapshot_unmount(struct mount *mp);
diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c
--- a/sys/ufs/ffs/ffs_inode.c
+++ b/sys/ufs/ffs/ffs_inode.c
@@ -161,25 +161,8 @@
if (error != EBUSY || (flags & GB_LOCK_NOWAIT) == 0)
return (error);
- /*
- * Wait for our inode block to become available.
- *
- * Hold a reference to the vnode to protect against
- * ffs_snapgone(). Since we hold a reference, it can only
- * get reclaimed (VIRF_DOOMED flag) in a forcible downgrade
- * or unmount. For an unmount, the entire filesystem will be
- * gone, so we cannot attempt to touch anything associated
- * with it while the vnode is unlocked; all we can do is
- * pause briefly and try again. If when we relock the vnode
- * we discover that it has been reclaimed, updating it is no
- * longer necessary and we can just return an error.
- */
- vref(vp);
- VOP_UNLOCK(vp);
- pause("ffsupd", 1);
- vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
- vrele(vp);
- if (VN_IS_DOOMED(vp))
+ error = ffs_snap_relock(vp);
+ if (error == EBADF)
return (ENOENT);
/*
diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c
--- a/sys/ufs/ffs/ffs_snapshot.c
+++ b/sys/ufs/ffs/ffs_snapshot.c
@@ -139,6 +139,12 @@
{
}
+int
+ffs_snap_relock(struct vnode *vp __unused)
+{
+ return (0);
+}
+
#else
FEATURE(ffs_snapshot, "FFS snapshot support");
@@ -2745,4 +2751,33 @@
return (sn);
}
+/*
+ * This function should be used after bread_gb(GB_LOCK_NOWAIT)
+ * returned EBUSY, when caller owns the snapshot lock. It temporarily
+ * unlocks the snapshot vnode to allow for the block to become
+ * available.
+ */
+int
+ffs_snap_relock(struct vnode *vp)
+{
+ int locked;
+
+ MPASS(IS_SNAPSHOT(VTOI(vp)));
+
+ /*
+ * Hold a reference to the vnode to protect against
+ * ffs_snapgone(), in case caller does not.
+ */
+ vref(vp);
+
+ locked = VOP_ISLOCKED(vp);
+ VOP_UNLOCK(vp);
+ pause("slkrd", 1);
+ vn_lock(vp, locked | LK_RETRY);
+ vrele(vp);
+ if (!IS_UFS(vp))
+ return (EBADF);
+ return (0);
+}
+
#endif
diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c
--- a/sys/ufs/ffs/ffs_vnops.c
+++ b/sys/ufs/ffs/ffs_vnops.c
@@ -690,7 +690,9 @@
uio->uio_offset >= fs->fs_maxfilesize)
return (EOVERFLOW);
- bflag = GB_UNMAPPED | (uio->uio_segflg == UIO_NOCOPY ? 0 : GB_NOSPARSE);
+ bflag = GB_UNMAPPED |
+ (uio->uio_segflg == UIO_NOCOPY ? 0 : GB_NOSPARSE) |
+ (IS_SNAPSHOT(ip) ? GB_LOCK_NOWAIT : 0);
for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0)
break;
@@ -759,6 +761,12 @@
*/
error = bread_gb(vp, lbn, size, NOCRED, bflag, &bp);
}
+ if (error == EBUSY && IS_SNAPSHOT(ip)) {
+ error = ffs_snap_relock(vp);
+ if (error == EBADF)
+ break;
+ continue;
+ }
if (error == EJUSTRETURN) {
error = ffs_read_hole(uio, xfersize, &size);
if (error == 0)
@@ -2066,7 +2074,7 @@
* and respond to dead vnodes by returning ESTALE.
*/
VOP_LOCK(vp, vp_locked | LK_RETRY);
- if (!VN_IS_DOOMED(vp))
+ if (IS_UFS(vp))
return (0);
/*
diff --git a/sys/ufs/ufs/inode.h b/sys/ufs/ufs/inode.h
--- a/sys/ufs/ufs/inode.h
+++ b/sys/ufs/ufs/inode.h
@@ -247,6 +247,7 @@
} while (0)
#define IS_SNAPSHOT(ip) ((ip)->i_flags & SF_SNAPSHOT)
+#define IS_UFS(vp) ((vp)->v_data != NULL)
/*
* Structure used to pass around logical block paths generated by
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Aug 6, 8:07 AM (1 h, 57 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
36100797
Default Alt Text
D33921.id101618.diff (13 KB)
Attached To
Mode
D33921: ufs: handle LoR between snap lock and buffer lock
Attached
Detach File
Event Timeline
Log In to Comment