Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F109351097
D33921.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
22 KB
Referenced Files
None
Subscribers
None
D33921.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
@@ -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
Details
Attached
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)
Attached To
Mode
D33921: ufs: handle LoR between snap lock and buffer lock
Attached
Detach File
Event Timeline
Log In to Comment