Page MenuHomeFreeBSD

D33921.diff
No OneTemporary

D33921.diff

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
@@ -1718,7 +1718,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>
@@ -82,6 +83,11 @@
#include <ufs/ffs/fs.h>
#include <ufs/ffs/ffs_extern.h>
+static int ffs_balloc_bread(struct vnode *vp, daddr_t lbn, int size,
+ struct ucred *cred, int gbflags, struct buf **bpp);
+static int ffs_balloc_getblk(struct vnode *vp, daddr_t lbn, int size,
+ int gbflags, struct buf **bpp);
+
/*
* Balloc defines the structure of filesystem storage
* by allocating the physical blocks on a device given
@@ -681,9 +687,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 +703,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;
@@ -723,13 +729,20 @@
nsize = fragroundup(fs, size);
else
nsize = fs->fs_bsize;
+ error = ffs_balloc_getblk(vp, -1 - lbn, nsize, gbflags,
+ &bp);
+ if (error != 0)
+ goto done;
UFS_LOCK(ump);
error = ffs_alloc(ip, lbn,
ffs_blkpref_ufs2(ip, lbn, (int)lbn, &dp->di_extb[0]),
nsize, flags, cred, &newb);
- if (error)
+ if (error != 0) {
+ bp->b_flags |= B_INVAL | B_RELBUF | B_NOCACHE;
+ bp->b_flags &= ~(B_ASYNC | B_CACHE);
+ brelse(bp);
goto done;
- bp = getblk(vp, -1 - lbn, nsize, 0, 0, gbflags);
+ }
bp->b_blkno = fsbtodb(fs, newb);
bp->b_xflags |= BX_ALTDATA;
if (flags & BA_CLRBUF)
@@ -786,17 +799,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 +822,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 {
@@ -834,13 +845,19 @@
nsize = fragroundup(fs, size);
else
nsize = fs->fs_bsize;
+ error = ffs_balloc_getblk(vp, lbn, nsize, gbflags, &bp);
+ if (error != 0)
+ goto done;
UFS_LOCK(ump);
error = ffs_alloc(ip, lbn,
ffs_blkpref_ufs2(ip, lbn, (int)lbn,
- &dp->di_db[0]), nsize, flags, cred, &newb);
- if (error)
+ &dp->di_db[0]), nsize, flags, cred, &newb);
+ if (error != 0) {
+ bp->b_flags |= B_INVAL | B_RELBUF | B_NOCACHE;
+ bp->b_flags &= ~(B_ASYNC | B_CACHE);
+ brelse(bp);
goto done;
- bp = getblk(vp, lbn, nsize, 0, 0, gbflags);
+ }
bp->b_blkno = fsbtodb(fs, newb);
if (flags & BA_CLRBUF)
vfs_bio_clrbuf(bp);
@@ -888,8 +905,10 @@
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)
+ goto done;
bp->b_blkno = fsbtodb(fs, nb);
vfs_bio_clrbuf(bp);
if (DOINGSOFTDEP(vp)) {
@@ -914,11 +933,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 +987,12 @@
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);
+ if (error != 0) {
+ brelse(bp);
+ goto fail;
+ }
nbp->b_blkno = fsbtodb(fs, nb);
vfs_bio_clrbuf(nbp);
if (DOINGSOFTDEP(vp)) {
@@ -1054,7 +1076,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 +1115,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 +1127,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 +1158,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 +1176,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 +1188,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 +1224,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));
@@ -1208,3 +1240,39 @@
vn_seqc_write_end(vp);
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);
+ }
+}
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);
/*
@@ -188,9 +171,11 @@
*/
goto loop;
}
- if (DOINGSOFTDEP(vp))
+ if (DOINGSOFTDEP(vp)) {
softdep_update_inodeblock(ip, bp, waitfor);
- else if (ip->i_effnlink != ip->i_nlink)
+ if (!IS_UFS(vp))
+ return (ENOENT);
+ } else if (ip->i_effnlink != ip->i_nlink)
panic("ffs_update: bad link cnt");
if (I_IS_UFS1(ip)) {
*((struct ufs1_dinode *)bp->b_data +
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_softdep.c b/sys/ufs/ffs/ffs_softdep.c
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -762,7 +762,8 @@
static int softdep_process_worklist(struct mount *, int);
static int softdep_waitidle(struct mount *, int);
static void drain_output(struct vnode *);
-static struct buf *getdirtybuf(struct buf *, struct rwlock *, int);
+static struct buf *getdirtybuf(struct inode *, struct buf *,
+ struct rwlock *, int);
static int check_inodedep_free(struct inodedep *);
static void clear_remove(struct mount *);
static void clear_inodedeps(struct mount *);
@@ -774,8 +775,9 @@
static int free_pagedep(struct pagedep *);
static int flush_newblk_dep(struct vnode *, struct mount *, ufs_lbn_t);
static int flush_inodedep_deps(struct vnode *, struct mount *, ino_t);
-static int flush_deplist(struct allocdirectlst *, int, int *);
-static int sync_cgs(struct mount *, int);
+static int flush_deplist(struct vnode *, struct allocdirectlst *,
+ int, int *);
+static int sync_cgs(struct vnode *, struct mount *, int);
static int handle_written_filepage(struct pagedep *, struct buf *, int);
static int handle_written_sbdep(struct sbdep *, struct buf *);
static void initiate_write_sbdep(struct sbdep *);
@@ -1947,7 +1949,7 @@
}
if (cgwait) {
FREE_LOCK(ump);
- sync_cgs(mp, MNT_WAIT);
+ sync_cgs(vp, mp, MNT_WAIT);
ffs_sync_snap(mp, MNT_WAIT);
ACQUIRE_LOCK(ump);
continue;
@@ -6757,7 +6759,12 @@
/* See if the block was discarded. */
if (bp == NULL)
break;
- /* Inline part of getdirtybuf(). We dont want bremfree. */
+
+ /*
+ * Inline part of getdirtybuf(). We dont want
+ * bremfree. There is no vnode locked there, so the
+ * order of snap lock->buffer lock is not possible.
+ */
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL) == 0)
break;
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK,
@@ -7077,6 +7084,10 @@
if (bp->b_bufsize == fs->fs_bsize)
bp->b_flags |= B_CLUSTEROK;
softdep_update_inodeblock(ip, bp, 0);
+ if (!IS_UFS(vp)) {
+ brelse(bp);
+ return;
+ }
if (ump->um_fstype == UFS1) {
*((struct ufs1_dinode *)bp->b_data +
ino_to_fsbo(fs, ip->i_number)) = *ip->i_din1;
@@ -7527,6 +7538,8 @@
TAILQ_FOREACH(bp, &bo->bo_dirty.bv_hd, b_bobufs)
bp->b_vflags &= ~BV_SCANNED;
restart:
+ if (!IS_UFS(vp))
+ return;
TAILQ_FOREACH(bp, &bo->bo_dirty.bv_hd, b_bobufs) {
if (bp->b_vflags & BV_SCANNED)
continue;
@@ -7535,7 +7548,8 @@
continue;
}
KASSERT(bp->b_bufobj == bo, ("Wrong object in buffer"));
- if ((bp = getdirtybuf(bp, BO_LOCKPTR(bo), MNT_WAIT)) == NULL)
+ if ((bp = getdirtybuf(ip, bp, BO_LOCKPTR(bo),
+ MNT_WAIT)) == NULL)
goto restart;
BO_UNLOCK(bo);
if (deallocate_dependencies(bp, freeblks, blkoff))
@@ -12709,9 +12723,11 @@
struct mount *mp;
struct buf *ibp;
struct fs *fs;
+ struct vnode *vp;
int error;
ump = ITOUMP(ip);
+ vp = ITOV(ip);
mp = UFSTOVFS(ump);
KASSERT(MOUNTEDSOFTDEP(mp) != 0,
("softdep_update_inodeblock called on non-softdep filesystem"));
@@ -12810,14 +12826,15 @@
return;
}
ibp = inodedep->id_bmsafemap->sm_buf;
- ibp = getdirtybuf(ibp, LOCK_PTR(ump), MNT_WAIT);
+ ibp = getdirtybuf(ip, ibp, LOCK_PTR(ump), MNT_WAIT);
if (ibp == NULL) {
/*
* If ibp came back as NULL, the dependency could have been
* freed while we slept. Look it up again, and check to see
* that it has completed.
*/
- if (inodedep_lookup(mp, ip->i_number, 0, &inodedep) != 0)
+ if (IS_UFS(vp) && inodedep_lookup(mp, ip->i_number, 0,
+ &inodedep) != 0)
goto retry;
FREE_LOCK(ump);
return;
@@ -13074,7 +13091,8 @@
* indirect block.
*/
static int
-sync_cgs(mp, waitfor)
+sync_cgs(vp, mp, waitfor)
+ struct vnode *vp;
struct mount *mp;
int waitfor;
{
@@ -13104,7 +13122,8 @@
* If we don't get the lock and we're waiting try again, if
* not move on to the next buf and try to sync it.
*/
- bp = getdirtybuf(bmsafemap->sm_buf, LOCK_PTR(ump), waitfor);
+ bp = getdirtybuf(VTOI(vp), bmsafemap->sm_buf, LOCK_PTR(ump),
+ waitfor);
if (bp == NULL && waitfor == MNT_WAIT)
continue;
LIST_REMOVE(sentinel, sm_next);
@@ -13216,7 +13235,12 @@
waitfor == MNT_NOWAIT)
continue;
nbp = newblk->nb_bmsafemap->sm_buf;
- nbp = getdirtybuf(nbp, LOCK_PTR(ump), waitfor);
+ nbp = getdirtybuf(VTOI(vp), nbp, LOCK_PTR(ump),
+ waitfor);
+ if (!IS_UFS(vp)) {
+ error = EBADF;
+ goto out;
+ }
if (nbp == NULL)
goto top;
FREE_LOCK(ump);
@@ -13247,7 +13271,12 @@
if (newblk->nb_state & DEPCOMPLETE)
continue;
nbp = newblk->nb_bmsafemap->sm_buf;
- nbp = getdirtybuf(nbp, LOCK_PTR(ump), waitfor);
+ nbp = getdirtybuf(VTOI(vp), nbp, LOCK_PTR(ump),
+ waitfor);
+ if (!IS_UFS(vp)) {
+ error = EBADF;
+ goto out;
+ }
if (nbp == NULL)
goto restart;
FREE_LOCK(ump);
@@ -13355,11 +13384,30 @@
goto restart;
}
}
- if (flush_deplist(&inodedep->id_inoupdt, waitfor, &error) ||
- flush_deplist(&inodedep->id_newinoupdt, waitfor, &error) ||
- flush_deplist(&inodedep->id_extupdt, waitfor, &error) ||
- flush_deplist(&inodedep->id_newextupdt, waitfor, &error))
+ if (flush_deplist(vp, &inodedep->id_inoupdt, waitfor,
+ &error)) {
+ if (!IS_UFS(vp))
+ return (EBADF);
+ continue;
+ }
+ if (flush_deplist(vp, &inodedep->id_newinoupdt, waitfor,
+ &error)) {
+ if (!IS_UFS(vp))
+ return (EBADF);
+ continue;
+ }
+ if (flush_deplist(vp, &inodedep->id_extupdt, waitfor,
+ &error)) {
+ if (!IS_UFS(vp))
+ return (EBADF);
+ continue;
+ }
+ if (flush_deplist(vp, &inodedep->id_newextupdt, waitfor,
+ &error)) {
+ if (!IS_UFS(vp))
+ return (EBADF);
continue;
+ }
/*
* If pass2, we are done, otherwise do pass 2.
*/
@@ -13379,7 +13427,8 @@
* Flush an inode dependency list.
*/
static int
-flush_deplist(listhead, waitfor, errorp)
+flush_deplist(vp, listhead, waitfor, errorp)
+ struct vnode *vp;
struct allocdirectlst *listhead;
int waitfor;
int *errorp;
@@ -13402,7 +13451,9 @@
if (newblk->nb_state & DEPCOMPLETE)
continue;
bp = newblk->nb_bmsafemap->sm_buf;
- bp = getdirtybuf(bp, LOCK_PTR(ump), waitfor);
+ bp = getdirtybuf(VTOI(vp), bp, LOCK_PTR(ump), waitfor);
+ if (!IS_UFS(vp))
+ return (1);
if (bp == NULL) {
if (waitfor == MNT_NOWAIT)
continue;
@@ -13468,7 +13519,11 @@
*/
if ((newblk->nb_state & DEPCOMPLETE) == 0) {
bp = newblk->nb_bmsafemap->sm_buf;
- bp = getdirtybuf(bp, LOCK_PTR(ump), MNT_WAIT);
+ bp = getdirtybuf(ip, bp, LOCK_PTR(ump), MNT_WAIT);
+ if (!IS_UFS(vp)) {
+ FREE_LOCK(ump);
+ return (EBADF);
+ }
if (bp == NULL)
continue;
FREE_LOCK(ump);
@@ -13639,7 +13694,8 @@
*/
if ((inodedep->id_state & (DEPCOMPLETE | GOINGAWAY)) == 0) {
bp = inodedep->id_bmsafemap->sm_buf;
- bp = getdirtybuf(bp, LOCK_PTR(ump), MNT_WAIT);
+ /* directory cannot be a snapshot */
+ bp = getdirtybuf(NULL, bp, LOCK_PTR(ump), MNT_WAIT);
if (bp == NULL)
goto retry;
FREE_LOCK(ump);
@@ -14710,7 +14766,8 @@
* Return acquired buffer or NULL on failure.
*/
static struct buf *
-getdirtybuf(bp, lock, waitfor)
+getdirtybuf(ip, bp, lock, waitfor)
+ struct inode *ip;
struct buf *bp;
struct rwlock *lock;
int waitfor;
@@ -14720,8 +14777,14 @@
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL) != 0) {
if (waitfor != MNT_WAIT)
return (NULL);
- error = BUF_LOCK(bp,
- LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, lock);
+ if (ip != NULL && IS_SNAPSHOT(ip)) {
+ rw_wunlock(lock);
+ (void)ffs_snap_relock(ITOV(ip));
+ rw_wlock(lock);
+ return (NULL);
+ }
+ error = BUF_LOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL |
+ LK_INTERLOCK, lock);
/*
* Even if we successfully acquire bp here, we have dropped
* lock, which may violates our guarantee.
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

Mime Type
text/plain
Expires
Tue, Feb 4, 10:20 PM (20 h, 30 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16461980
Default Alt Text
D33921.diff (22 KB)

Event Timeline