Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F136349994
D24088.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
31 KB
Referenced Files
None
Subscribers
None
D24088.diff
View Options
Index: sys/geom/geom_vfs.c
===================================================================
--- sys/geom/geom_vfs.c
+++ sys/geom/geom_vfs.c
@@ -55,6 +55,7 @@
struct bufobj *sc_bo;
int sc_active;
int sc_orphaned;
+ int sc_enxio_active;
};
static struct buf_ops __g_vfs_bufops = {
@@ -139,9 +140,14 @@
cp = bip->bio_from;
sc = cp->geom->softc;
- if (bip->bio_error && bip->bio_error != EOPNOTSUPP)
+ if (bip->bio_error != 0 && bip->bio_error != EOPNOTSUPP) {
+ if ((bp->b_xflags & BX_CVTENXIO) != 0)
+ sc->sc_enxio_active = 1;
+ if (sc->sc_enxio_active)
+ bip->bio_error = ENXIO;
g_print_bio("g_vfs_done():", bip, "error = %d",
bip->bio_error);
+ }
bp->b_error = bip->bio_error;
bp->b_ioflags = bip->bio_flags;
if (bip->bio_error)
@@ -172,7 +178,7 @@
* If the provider has orphaned us, just return ENXIO.
*/
mtx_lock(&sc->sc_mtx);
- if (sc->sc_orphaned) {
+ if (sc->sc_orphaned || sc->sc_enxio_active) {
mtx_unlock(&sc->sc_mtx);
bp->b_error = ENXIO;
bp->b_ioflags |= BIO_ERROR;
Index: sys/kern/vfs_bio.c
===================================================================
--- sys/kern/vfs_bio.c
+++ sys/kern/vfs_bio.c
@@ -2176,6 +2176,8 @@
bp->b_flags |= B_CKHASH;
bp->b_ckhashcalc = ckhashfunc;
}
+ if ((flags & GB_CVTENXIO) != 0)
+ bp->b_xflags |= BX_CVTENXIO;
bp->b_ioflags &= ~BIO_ERROR;
if (bp->b_rcred == NOCRED && cred != NOCRED)
bp->b_rcred = crhold(cred);
@@ -2773,6 +2775,7 @@
panic("brelse: not dirty");
bp->b_flags &= ~(B_ASYNC | B_NOCACHE | B_RELBUF | B_DIRECT);
+ bp->b_xflags &= ~(BX_CVTENXIO);
/* binsfree unlocks bp. */
binsfree(bp, qindex);
}
@@ -2804,6 +2807,7 @@
return;
}
bp->b_flags &= ~(B_ASYNC | B_NOCACHE | B_AGE | B_RELBUF);
+ bp->b_xflags &= ~(BX_CVTENXIO);
if (bp->b_flags & B_MANAGED) {
if (bp->b_flags & B_REMFREE)
Index: sys/sys/buf.h
===================================================================
--- sys/sys/buf.h
+++ sys/sys/buf.h
@@ -261,12 +261,14 @@
*/
#define BX_VNDIRTY 0x00000001 /* On vnode dirty list */
#define BX_VNCLEAN 0x00000002 /* On vnode clean list */
+#define BX_CVTENXIO 0x00000004 /* Convert errors to ENXIO */
#define BX_BKGRDWRITE 0x00000010 /* Do writes in background */
#define BX_BKGRDMARKER 0x00000020 /* Mark buffer for splay tree */
#define BX_ALTDATA 0x00000040 /* Holds extended data */
#define BX_FSPRIV 0x00FF0000 /* Filesystem-specific flags mask */
-#define PRINT_BUF_XFLAGS "\20\7altdata\6bkgrdmarker\5bkgrdwrite\2clean\1dirty"
+#define PRINT_BUF_XFLAGS "\20\7altdata\6bkgrdmarker\5bkgrdwrite\3cvtenxio" \
+ "\2clean\1dirty"
#define NOOFFSET (-1LL) /* No buffer offset calculated yet */
@@ -487,6 +489,7 @@
#define GB_KVAALLOC 0x0010 /* But allocate KVA. */
#define GB_CKHASH 0x0020 /* If reading, calc checksum hash */
#define GB_NOSPARSE 0x0040 /* Do not instantiate holes */
+#define GB_CVTENXIO 0x0080 /* Convert errors to ENXIO */
#ifdef _KERNEL
extern int nbuf; /* The number of buffer headers */
Index: sys/ufs/ffs/ffs_alloc.c
===================================================================
--- sys/ufs/ffs/ffs_alloc.c
+++ sys/ufs/ffs/ffs_alloc.c
@@ -222,6 +222,10 @@
softdep_request_cleanup(fs, ITOV(ip), cred, FLUSH_BLOCKS_WAIT);
goto retry;
}
+ if (ffs_fsfail_cleanup_locked(ump, 0)) {
+ UFS_UNLOCK(ump);
+ return (ENXIO);
+ }
if (reclaimed > 0 &&
ppsratecheck(&ump->um_last_fullmsg, &ump->um_secs_fullmsg, 1)) {
UFS_UNLOCK(ump);
@@ -447,6 +451,12 @@
softdep_request_cleanup(fs, vp, cred, FLUSH_BLOCKS_WAIT);
goto retry;
}
+ if (bp)
+ brelse(bp);
+ if (ffs_fsfail_cleanup_locked(ump, 0)) {
+ UFS_UNLOCK(ump);
+ return (ENXIO);
+ }
if (reclaimed > 0 &&
ppsratecheck(&ump->um_last_fullmsg, &ump->um_secs_fullmsg, 1)) {
UFS_UNLOCK(ump);
@@ -456,8 +466,6 @@
} else {
UFS_UNLOCK(ump);
}
- if (bp)
- brelse(bp);
return (ENOSPC);
}
@@ -1102,7 +1110,7 @@
struct ufsmount *ump;
ino_t ino, ipref;
u_int cg;
- int error, error1, reclaimed;
+ int error, reclaimed;
*vpp = NULL;
pip = VTOI(pvp);
@@ -1137,28 +1145,21 @@
(allocfcn_t *)ffs_nodealloccg);
if (ino == 0)
goto noinodes;
-
/*
* Get rid of the cached old vnode, force allocation of a new vnode
- * for this inode.
+ * for this inode. If this fails, release the allocated ino and
+ * return the error.
*/
- error = ffs_vgetf(pvp->v_mount, ino, LK_EXCLUSIVE, vpp, FFSV_REPLACE);
- if (error) {
- error1 = ffs_vgetf(pvp->v_mount, ino, LK_EXCLUSIVE, vpp,
- FFSV_FORCEINSMQ | FFSV_REPLACE);
+ if ((error = ffs_vgetf(pvp->v_mount, ino, LK_EXCLUSIVE, vpp,
+ FFSV_FORCEINSMQ | FFSV_REPLACE)) != 0) {
ffs_vfree(pvp, ino, mode);
- if (error1 == 0) {
- ip = VTOI(*vpp);
- if (ip->i_mode)
- goto dup_alloc;
- UFS_INODE_SET_FLAG(ip, IN_MODIFIED);
- vput(*vpp);
- }
return (error);
}
+ /*
+ * We got an inode, so check mode and panic if it is already allocated.
+ */
ip = VTOI(*vpp);
if (ip->i_mode) {
-dup_alloc:
printf("mode = 0%o, inum = %ju, fs = %s\n",
ip->i_mode, (uintmax_t)ip->i_number, fs->fs_fsmnt);
panic("ffs_valloc: dup alloc");
@@ -1197,6 +1198,10 @@
softdep_request_cleanup(fs, pvp, cred, FLUSH_INODES_WAIT);
goto retry;
}
+ if (ffs_fsfail_cleanup_locked(ump, 0)) {
+ UFS_UNLOCK(ump);
+ return (ENXIO);
+ }
if (ppsratecheck(&ump->um_last_fullmsg, &ump->um_secs_fullmsg, 1)) {
UFS_UNLOCK(ump);
ffs_fserr(fs, pip->i_number, "out of inodes");
@@ -2230,6 +2235,7 @@
struct mount *mp;
struct cg *cgp;
struct buf *bp;
+ daddr_t dbn;
ufs1_daddr_t fragno, cgbno;
int i, blk, frags, bbase, error;
u_int cg;
@@ -2262,8 +2268,23 @@
ffs_fserr(fs, inum, "bad block");
return;
}
- if ((error = ffs_getcg(fs, devvp, cg, 0, &bp, &cgp)) != 0)
+ if ((error = ffs_getcg(fs, devvp, cg, GB_CVTENXIO, &bp, &cgp)) != 0) {
+ if (!ffs_fsfail_cleanup(ump, error) ||
+ !MOUNTEDSOFTDEP(UFSTOVFS(ump)) || devvp->v_type != VCHR)
+ return;
+ if (devvp->v_type == VREG)
+ dbn = fragstoblks(fs, cgtod(fs, cg));
+ else
+ dbn = fsbtodb(fs, cgtod(fs, cg));
+ error = getblkx(devvp, dbn, dbn, fs->fs_cgsize, 0, 0, 0, &bp);
+ KASSERT(error == 0, ("getblkx failed"));
+ softdep_setup_blkfree(UFSTOVFS(ump), bp, bno,
+ numfrags(fs, size), dephd);
+ bp->b_flags |= B_RELBUF | B_NOCACHE;
+ bp->b_flags &= ~B_CACHE;
+ bawrite(bp);
return;
+ }
cgbno = dtogd(fs, bno);
blksfree = cg_blksfree(cgp);
UFS_LOCK(ump);
@@ -2783,6 +2804,7 @@
{
struct cg *cgp;
struct buf *bp;
+ daddr_t dbn;
int error;
u_int cg;
u_int8_t *inosused;
@@ -2804,8 +2826,22 @@
if (ino >= fs->fs_ipg * fs->fs_ncg)
panic("ffs_freefile: range: dev = %s, ino = %ju, fs = %s",
devtoname(dev), (uintmax_t)ino, fs->fs_fsmnt);
- if ((error = ffs_getcg(fs, devvp, cg, 0, &bp, &cgp)) != 0)
+ if ((error = ffs_getcg(fs, devvp, cg, GB_CVTENXIO, &bp, &cgp)) != 0) {
+ if (!ffs_fsfail_cleanup(ump, error) ||
+ !MOUNTEDSOFTDEP(UFSTOVFS(ump)) || devvp->v_type != VCHR)
+ return (error);
+ if (devvp->v_type == VREG)
+ dbn = fragstoblks(fs, cgtod(fs, cg));
+ else
+ dbn = fsbtodb(fs, cgtod(fs, cg));
+ error = getblkx(devvp, dbn, dbn, fs->fs_cgsize, 0, 0, 0, &bp);
+ KASSERT(error == 0, ("getblkx failed"));
+ softdep_setup_inofree(UFSTOVFS(ump), bp, ino, wkhd);
+ bp->b_flags |= B_RELBUF | B_NOCACHE;
+ bp->b_flags &= ~B_CACHE;
+ bawrite(bp);
return (error);
+ }
inosused = cg_inosused(cgp);
cgino = ino % fs->fs_ipg;
if (isclr(inosused, cgino)) {
Index: sys/ufs/ffs/ffs_balloc.c
===================================================================
--- sys/ufs/ffs/ffs_balloc.c
+++ sys/ufs/ffs/ffs_balloc.c
@@ -324,7 +324,8 @@
UFS_UNLOCK(ump);
goto retry;
}
- if (ppsratecheck(&ump->um_last_fullmsg,
+ if (!ffs_fsfail_cleanup_locked(ump, error) &&
+ ppsratecheck(&ump->um_last_fullmsg,
&ump->um_secs_fullmsg, 1)) {
UFS_UNLOCK(ump);
ffs_fserr(fs, ip->i_number, "filesystem full");
@@ -407,7 +408,8 @@
UFS_UNLOCK(ump);
goto retry;
}
- if (ppsratecheck(&ump->um_last_fullmsg,
+ if (!ffs_fsfail_cleanup_locked(ump, error) &&
+ ppsratecheck(&ump->um_last_fullmsg,
&ump->um_secs_fullmsg, 1)) {
UFS_UNLOCK(ump);
ffs_fserr(fs, ip->i_number, "filesystem full");
@@ -919,7 +921,8 @@
UFS_UNLOCK(ump);
goto retry;
}
- if (ppsratecheck(&ump->um_last_fullmsg,
+ if (!ffs_fsfail_cleanup_locked(ump, error) &&
+ ppsratecheck(&ump->um_last_fullmsg,
&ump->um_secs_fullmsg, 1)) {
UFS_UNLOCK(ump);
ffs_fserr(fs, ip->i_number, "filesystem full");
@@ -1003,7 +1006,8 @@
UFS_UNLOCK(ump);
goto retry;
}
- if (ppsratecheck(&ump->um_last_fullmsg,
+ if (!ffs_fsfail_cleanup_locked(ump, error) &&
+ ppsratecheck(&ump->um_last_fullmsg,
&ump->um_secs_fullmsg, 1)) {
UFS_UNLOCK(ump);
ffs_fserr(fs, ip->i_number, "filesystem full");
Index: sys/ufs/ffs/ffs_extern.h
===================================================================
--- sys/ufs/ffs/ffs_extern.h
+++ sys/ufs/ffs/ffs_extern.h
@@ -116,6 +116,11 @@
vfs_vget_t ffs_vget;
int ffs_vgetf(struct mount *, ino_t, int, struct vnode **, int);
void process_deferred_inactive(struct mount *mp);
+int ffs_fsfail_cleanup(struct ufsmount *, int);
+int ffs_fsfail_cleanup_locked(struct ufsmount *, int);
+int ffs_breadz(struct ufsmount *, struct vnode *, daddr_t, daddr_t, int,
+ daddr_t *, int *, int, struct ucred *, int, void (*)(struct buf *),
+ struct buf **);
/*
* Flags to ffs_vgetf
@@ -162,6 +167,7 @@
int softdep_mount(struct vnode *, struct mount *, struct fs *,
struct ucred *);
void softdep_unmount(struct mount *);
+void softdep_handle_error(struct buf *);
int softdep_move_dependencies(struct buf *, struct buf *);
int softdep_flushworklist(struct mount *, int *, struct thread *);
int softdep_flushfiles(struct mount *, int, struct thread *);
Index: sys/ufs/ffs/ffs_inode.c
===================================================================
--- sys/ufs/ffs/ffs_inode.c
+++ sys/ufs/ffs/ffs_inode.c
@@ -86,6 +86,7 @@
struct fs *fs;
struct buf *bp;
struct inode *ip;
+ daddr_t bn;
int flags, error;
ASSERT_VOP_ELOCKED(vp, "ffs_update");
@@ -112,9 +113,9 @@
if (IS_SNAPSHOT(ip))
flags = GB_LOCK_NOWAIT;
loop:
- error = bread_gb(ITODEVVP(ip),
- fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
- (int) fs->fs_bsize, NOCRED, flags, &bp);
+ bn = fsbtodb(fs, ino_to_fsba(fs, ip->i_number));
+ error = ffs_breadz(VFSTOUFS(vp->v_mount), ITODEVVP(ip), bn, bn,
+ (int) fs->fs_bsize, NULL, NULL, 0, NOCRED, flags, NULL, &bp);
if (error != 0) {
if (error != EBUSY)
return (error);
@@ -163,9 +164,11 @@
*/
random_harvest_queue(&(ip->i_din2), sizeof(ip->i_din2), RANDOM_FS_ATIME);
}
- if (waitfor)
+ if (waitfor) {
error = bwrite(bp);
- else if (vm_page_count_severe() || buf_dirty_count_severe()) {
+ if (ffs_fsfail_cleanup(VFSTOUFS(vp->v_mount), error))
+ error = 0;
+ } else if (vm_page_count_severe() || buf_dirty_count_severe()) {
bawrite(bp);
error = 0;
} else {
@@ -684,7 +687,7 @@
* of having bread() attempt to calculate it using VOP_BMAP().
*/
vp = ITOV(ip);
- error = breadn_flags(vp, lbn, dbn, (int)fs->fs_bsize, NULL, NULL, 0,
+ error = ffs_breadz(ump, vp, lbn, dbn, (int)fs->fs_bsize, NULL, NULL, 0,
NOCRED, 0, NULL, &bp);
if (error) {
*countp = 0;
Index: sys/ufs/ffs/ffs_softdep.c
===================================================================
--- sys/ufs/ffs/ffs_softdep.c
+++ sys/ufs/ffs/ffs_softdep.c
@@ -2271,6 +2271,7 @@
inodedep->id_ino = inum;
inodedep->id_state = ALLCOMPLETE;
inodedep->id_nlinkdelta = 0;
+ inodedep->id_nlinkwrote = -1;
inodedep->id_savedino1 = NULL;
inodedep->id_savedsize = -1;
inodedep->id_savedextsize = -1;
@@ -3606,6 +3607,7 @@
jblocks->jb_needseg = 0;
WORKLIST_INSERT(&bp->b_dep, &jseg->js_list);
FREE_LOCK(ump);
+ bp->b_xflags |= BX_CVTENXIO;
pbgetvp(ump->um_devvp, bp);
/*
* We only do the blocking wait once we find the journal
@@ -6334,7 +6336,7 @@
* the on-disk address, so we just pass it to bread() instead of
* having bread() attempt to calculate it using VOP_BMAP().
*/
- error = breadn_flags(ITOV(ip), lbn, blkptrtodb(ump, blkno),
+ error = ffs_breadz(ump, ITOV(ip), lbn, blkptrtodb(ump, blkno),
(int)mp->mnt_stat.f_iosize, NULL, NULL, 0, NOCRED, 0, NULL, &bp);
if (error)
return (error);
@@ -6485,6 +6487,15 @@
else
WORKLIST_INSERT(&indirdep->ir_freeblks->fb_freeworkhd,
&freework->fw_list);
+ if (fwn == NULL) {
+ freework->fw_indir = (void *)0x0000deadbeef0000;
+ bp = indirdep->ir_savebp;
+ indirdep->ir_savebp = NULL;
+ free_indirdep(indirdep);
+ FREE_LOCK(ump);
+ brelse(bp);
+ ACQUIRE_LOCK(ump);
+ }
} else {
/* Complete when the real copy is written. */
WORKLIST_INSERT(&bp->b_dep, &freework->fw_list);
@@ -6589,6 +6600,7 @@
struct buf *bp;
struct vnode *vp;
struct mount *mp;
+ daddr_t dbn;
ufs2_daddr_t extblocks, datablocks;
ufs_lbn_t tmpval, lbn, lastlbn;
int frags, lastoff, iboff, allocblock, needj, error, i;
@@ -6726,8 +6738,9 @@
*/
ufs_itimes(vp);
ip->i_flag &= ~(IN_LAZYACCESS | IN_LAZYMOD | IN_MODIFIED);
- error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
- (int)fs->fs_bsize, cred, &bp);
+ dbn = fsbtodb(fs, ino_to_fsba(fs, ip->i_number));
+ error = ffs_breadz(ump, ump->um_devvp, dbn, dbn, (int)fs->fs_bsize,
+ NULL, NULL, 0, cred, 0, NULL, &bp);
if (error) {
softdep_error("softdep_journal_freeblocks", error);
return;
@@ -6828,13 +6841,13 @@
*/
size = sblksize(fs, length, lastlbn);
error = bread(vp, lastlbn, size, cred, &bp);
- if (error) {
+ if (error == 0) {
+ bzero((char *)bp->b_data + lastoff, size - lastoff);
+ bawrite(bp);
+ } else if (!ffs_fsfail_cleanup(ump, error)) {
softdep_error("softdep_journal_freeblks", error);
return;
}
- bzero((char *)bp->b_data + lastoff, size - lastoff);
- bawrite(bp);
-
}
ACQUIRE_LOCK(ump);
inodedep_lookup(mp, ip->i_number, DEPALLOC, &inodedep);
@@ -6945,8 +6958,8 @@
if ((error = bread(ump->um_devvp,
fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
(int)fs->fs_bsize, NOCRED, &bp)) != 0) {
- brelse(bp);
- softdep_error("softdep_setup_freeblocks", error);
+ if (!ffs_fsfail_cleanup(ump, error))
+ softdep_error("softdep_setup_freeblocks", error);
return;
}
freeblks = newfreeblks(mp, ip);
@@ -8161,7 +8174,7 @@
ufs_lbn_t lbnadd, nlbn;
u_long key;
int nblocks, ufs1fmt, freedblocks;
- int goingaway, freedeps, needj, level, cnt, i;
+ int goingaway, freedeps, needj, level, cnt, i, error;
freeblks = freework->fw_freeblks;
mp = freeblks->fb_list.wk_mp;
@@ -8199,10 +8212,11 @@
if (indirdep == NULL || (indirdep->ir_state & GOINGAWAY) == 0)
panic("indir_trunc: Bad indirdep %p from buf %p",
indirdep, bp);
- } else if (bread(freeblks->fb_devvp, dbn, (int)fs->fs_bsize,
- NOCRED, &bp) != 0) {
- brelse(bp);
- return;
+ } else {
+ error = ffs_breadz(ump, freeblks->fb_devvp, dbn, dbn,
+ (int)fs->fs_bsize, NULL, NULL, 0, NOCRED, 0, NULL, &bp);
+ if (error)
+ return;
}
ACQUIRE_LOCK(ump);
/* Protects against a race with complete_trunc_indir(). */
@@ -9700,6 +9714,7 @@
struct inodedep *idn;
struct fs *fs, *bpfs;
struct buf *bp;
+ daddr_t dbn;
ino_t ino;
ino_t nino;
ino_t pino;
@@ -9753,11 +9768,10 @@
bp = getblk(ump->um_devvp, btodb(fs->fs_sblockloc),
(int)fs->fs_sbsize, 0, 0, 0);
} else {
- error = bread(ump->um_devvp,
- fsbtodb(fs, ino_to_fsba(fs, pino)),
- (int)fs->fs_bsize, NOCRED, &bp);
- if (error)
- brelse(bp);
+ dbn = fsbtodb(fs, ino_to_fsba(fs, pino));
+ error = ffs_breadz(ump, ump->um_devvp, dbn, dbn,
+ (int)fs->fs_bsize, NULL, NULL, 0, NOCRED, 0, NULL,
+ &bp);
}
ACQUIRE_LOCK(ump);
if (error)
@@ -10578,14 +10592,16 @@
if ((adp->ad_state & ATTACHED) == 0)
panic("inodedep %p and adp %p not attached", inodedep, adp);
prevlbn = adp->ad_offset;
- if (adp->ad_offset < UFS_NDADDR &&
+ if (!ffs_fsfail_cleanup(ump, 0) &&
+ adp->ad_offset < UFS_NDADDR &&
dp->di_db[adp->ad_offset] != adp->ad_newblkno)
panic("initiate_write_inodeblock_ufs2: "
"direct pointer #%jd mismatch %jd != %jd",
(intmax_t)adp->ad_offset,
(intmax_t)dp->di_db[adp->ad_offset],
(intmax_t)adp->ad_newblkno);
- if (adp->ad_offset >= UFS_NDADDR &&
+ if (!ffs_fsfail_cleanup(ump, 0) &&
+ adp->ad_offset >= UFS_NDADDR &&
dp->di_ib[adp->ad_offset - UFS_NDADDR] != adp->ad_newblkno)
panic("initiate_write_inodeblock_ufs2: "
"indirect pointer #%jd mismatch %jd != %jd",
@@ -10817,12 +10833,14 @@
("softdep_setup_inofree called on non-softdep filesystem"));
ump = VFSTOUFS(mp);
ACQUIRE_LOCK(ump);
- fs = ump->um_fs;
- cgp = (struct cg *)bp->b_data;
- inosused = cg_inosused(cgp);
- if (isset(inosused, ino % fs->fs_ipg))
- panic("softdep_setup_inofree: inode %ju not freed.",
- (uintmax_t)ino);
+ if (!ffs_fsfail_cleanup(ump, 0)) {
+ fs = ump->um_fs;
+ cgp = (struct cg *)bp->b_data;
+ inosused = cg_inosused(cgp);
+ if (isset(inosused, ino % fs->fs_ipg))
+ panic("softdep_setup_inofree: inode %ju not freed.",
+ (uintmax_t)ino);
+ }
if (inodedep_lookup(mp, ino, 0, &inodedep))
panic("softdep_setup_inofree: ino %ju has existing inodedep %p",
(uintmax_t)ino, inodedep);
@@ -11091,6 +11109,26 @@
wk_list);
}
+void
+softdep_handle_error(struct buf *bp)
+{
+ struct ufsmount *ump;
+
+ ump = softdep_bp_to_mp(bp);
+ if (ump == NULL)
+ return;
+
+ if (ffs_fsfail_cleanup(ump, bp->b_error)) {
+ /*
+ * No future writes will succeed, so the on-disk image is safe.
+ * Pretend that this write succeeded so that the softdep state
+ * will be cleaned up naturally.
+ */
+ bp->b_ioflags &= ~BIO_ERROR;
+ bp->b_error = 0;
+ }
+}
+
/*
* This routine is called during the completion interrupt
* service routine for a disk write (from the procedure called
@@ -11117,6 +11155,8 @@
"with outstanding dependencies for buffer %p", bp));
if (ump == NULL)
return;
+ if ((bp->b_ioflags & BIO_ERROR) != 0)
+ softdep_handle_error(bp);
/*
* If an error occurred while doing the write, then the data
* has not hit the disk and the dependencies cannot be processed.
@@ -12305,6 +12345,13 @@
FREE_LOCK(ump);
return;
}
+ if (ip->i_nlink != inodedep->id_nlinkwrote &&
+ inodedep->id_nlinkwrote != -1) {
+ KASSERT(ip->i_nlink == 0 &&
+ (ump->um_flags & UM_FSFAIL_CLEANUP) != 0,
+ ("read bad i_nlink value"));
+ ip->i_effnlink = ip->i_nlink = inodedep->id_nlinkwrote;
+ }
ip->i_effnlink -= inodedep->id_nlinkdelta;
KASSERT(ip->i_effnlink >= 0,
("softdep_load_inodeblock: negative i_effnlink"));
@@ -12367,6 +12414,11 @@
panic("softdep_update_inodeblock: bad link count");
return;
}
+ KASSERT(ip->i_nlink >= inodedep->id_nlinkdelta,
+ ("softdep_update_inodeblock inconsistent ip %p i_nlink %d "
+ "inodedep %p id_nlinkdelta %jd",
+ ip, ip->i_nlink, inodedep, (intmax_t)inodedep->id_nlinkdelta));
+ inodedep->id_nlinkwrote = ip->i_nlink;
if (inodedep->id_nlinkdelta != ip->i_nlink - ip->i_effnlink)
panic("softdep_update_inodeblock: bad delta");
/*
@@ -12642,7 +12694,7 @@
else
brelse(bp);
vput(pvp);
- if (error != 0)
+ if (!ffs_fsfail_cleanup(ump, error))
return (error);
ACQUIRE_LOCK(ump);
if (inodedep_lookup(mp, ip->i_number, 0, &inodedep) == 0)
Index: sys/ufs/ffs/ffs_subr.c
===================================================================
--- sys/ufs/ffs/ffs_subr.c
+++ sys/ufs/ffs/ffs_subr.c
@@ -67,6 +67,7 @@
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/ucred.h>
+#include <sys/taskqueue.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
@@ -136,7 +137,8 @@
return (0);
}
dip2 = ((struct ufs2_dinode *)bp->b_data + ino_to_fsbo(fs, ino));
- if ((error = ffs_verify_dinode_ckhash(fs, dip2)) != 0) {
+ if ((error = ffs_verify_dinode_ckhash(fs, dip2)) != 0 &&
+ !ffs_fsfail_cleanup(ITOUMP(ip), error)) {
printf("%s: inode %jd: check-hash failed\n", fs->fs_fsmnt,
(intmax_t)ino);
return (error);
@@ -201,6 +203,93 @@
} else if (!havemtx)
UFS_UNLOCK(ump);
return (EINTEGRITY);
+}
+
+/*
+ * Initiate a forcible unmount.
+ * Used to unmount filesystems whose underlying media has gone away.
+ */
+static void
+ffs_fsfail_unmount(void *v, int pending)
+{
+ struct fsfail_task *etp;
+ struct mount *mp;
+
+ etp = v;
+
+ /*
+ * Find our mount and get a ref on it, then try to unmount.
+ */
+ mp = vfs_getvfs(&etp->fsid);
+ if (mp != NULL)
+ dounmount(mp, MNT_FORCE, curthread);
+ free(etp, M_UFSMNT);
+}
+
+/*
+ * On first ENXIO error, start a task that forcibly unmounts the filesystem.
+ *
+ * Return true if a cleanup is in progress.
+ */
+int
+ffs_fsfail_cleanup(struct ufsmount *ump, int error)
+{
+ int retval;
+
+ UFS_LOCK(ump);
+ retval = ffs_fsfail_cleanup_locked(ump, error);
+ UFS_UNLOCK(ump);
+ return (retval);
+}
+
+int
+ffs_fsfail_cleanup_locked(struct ufsmount *ump, int error)
+{
+ struct fsfail_task *etp;
+ struct task *tp;
+
+ mtx_assert(UFS_MTX(ump), MA_OWNED);
+ if (error == ENXIO && (ump->um_flags & UM_FSFAIL_CLEANUP) == 0) {
+ ump->um_flags |= UM_FSFAIL_CLEANUP;
+ /*
+ * Queue an async forced unmount.
+ */
+ etp = ump->um_fsfail_task;
+ ump->um_fsfail_task = NULL;
+ if (etp != NULL) {
+ tp = &etp->task;
+ TASK_INIT(tp, 0, ffs_fsfail_unmount, etp);
+ taskqueue_enqueue(taskqueue_thread, tp);
+ printf("UFS: forcibly unmounting %s from %s\n",
+ ump->um_mountp->mnt_stat.f_mntfromname,
+ ump->um_mountp->mnt_stat.f_mntonname);
+ }
+ }
+ return ((ump->um_flags & UM_FSFAIL_CLEANUP) != 0);
+}
+
+/*
+ * Wrapper used during ENXIO cleanup to allocate empty buffers when
+ * the kernel is unable to read the real one. They are needed so that
+ * the soft updates code can use them to unwind its dependencies.
+ */
+int
+ffs_breadz(struct ufsmount *ump, struct vnode *vp, daddr_t lblkno,
+ daddr_t dblkno, int size, daddr_t *rablkno, int *rabsize, int cnt,
+ struct ucred *cred, int flags, void (*ckhashfunc)(struct buf *),
+ struct buf **bpp)
+{
+ int error;
+
+ flags |= GB_CVTENXIO;
+ error = breadn_flags(vp, lblkno, dblkno, size, rablkno, rabsize, cnt,
+ cred, flags, ckhashfunc, bpp);
+ if (error != 0 && ffs_fsfail_cleanup(ump, error)) {
+ error = getblkx(vp, lblkno, dblkno, size, 0, 0, flags, bpp);
+ KASSERT(error == 0, ("getblkx failed"));
+ vfs_bio_bzero_buf(*bpp, 0, size);
+ }
+ return (error);
}
#endif /* _KERNEL */
Index: sys/ufs/ffs/ffs_vfsops.c
===================================================================
--- sys/ufs/ffs/ffs_vfsops.c
+++ sys/ufs/ffs/ffs_vfsops.c
@@ -58,6 +58,7 @@
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/rwlock.h>
+#include <sys/sysctl.h>
#include <sys/vmmeter.h>
#include <security/mac/mac_framework.h>
@@ -148,6 +149,12 @@
"multilabel", "nfsv4acls", "fsckpid", "snapshot", "nosuid", "suiddir",
"nosymfollow", "sync", "union", "userquota", "untrusted", NULL };
+static int ffs_enxio_enable = 1;
+SYSCTL_DECL(_vfs_ffs);
+SYSCTL_INT(_vfs_ffs, OID_AUTO, enxio_enable, CTLFLAG_RWTUN,
+ &ffs_enxio_enable, 0,
+ "enable mapping of other disk I/O errors to ENXIO");
+
static int
ffs_mount(struct mount *mp)
{
@@ -795,6 +802,7 @@
struct g_consumer *cp;
struct mount *nmp;
struct vnode *devvp;
+ struct fsfail_task *etp;
int candelete, canspeedup;
off_t loc;
@@ -1085,6 +1093,9 @@
(void) ufs_extattr_autostart(mp, td);
#endif /* !UFS_EXTATTR_AUTOSTART */
#endif /* !UFS_EXTATTR */
+ etp = malloc(sizeof *ump->um_fsfail_task, M_UFSMNT, M_WAITOK | M_ZERO);
+ etp->fsid = mp->mnt_stat.f_fsid;
+ ump->um_fsfail_task = etp;
return (0);
out:
if (fs != NULL) {
@@ -1134,7 +1145,6 @@
return (0);
}
-#include <sys/sysctl.h>
static int bigcgs = 0;
SYSCTL_INT(_debug, OID_AUTO, bigcgs, CTLFLAG_RW, &bigcgs, 0, "");
@@ -1271,7 +1281,7 @@
error = softdep_flushfiles(mp, flags, td);
else
error = ffs_flushfiles(mp, flags, td);
- if (error != 0 && error != ENXIO)
+ if (error != 0 && !ffs_fsfail_cleanup(ump, error))
goto fail;
UFS_LOCK(ump);
@@ -1288,7 +1298,9 @@
if (fs->fs_ronly == 0 || ump->um_fsckpid > 0) {
fs->fs_clean = fs->fs_flags & (FS_UNCLEAN|FS_NEEDSFSCK) ? 0 : 1;
error = ffs_sbupdate(ump, MNT_WAIT, 0);
- if (error && error != ENXIO) {
+ if (ffs_fsfail_cleanup(ump, error))
+ error = 0;
+ if (error != 0 && !ffs_fsfail_cleanup(ump, error)) {
fs->fs_clean = 0;
goto fail;
}
@@ -1326,6 +1338,8 @@
}
free(fs->fs_csp, M_UFSMNT);
free(fs, M_UFSMNT);
+ if (ump->um_fsfail_task != NULL)
+ free(ump->um_fsfail_task, M_UFSMNT);
free(ump, M_UFSMNT);
mp->mnt_data = NULL;
MNT_ILOCK(mp);
@@ -1640,6 +1654,8 @@
if (waitfor == MNT_WAIT || rebooting) {
if ((error = softdep_flushworklist(ump->um_mountp, &count, td)))
allerror = error;
+ if (ffs_fsfail_cleanup(ump, allerror))
+ allerror = 0;
/* Flushed work items may create new vnodes to clean */
if (allerror == 0 && count)
goto loop;
@@ -1657,6 +1673,8 @@
error = ffs_sbupdate(ump, waitfor, 0);
if (error != 0)
allerror = error;
+ if (ffs_fsfail_cleanup(ump, allerror))
+ allerror = 0;
if (allerror == 0 && waitfor == MNT_WAIT)
goto loop;
} else if (suspend != 0) {
@@ -1681,6 +1699,8 @@
if (fs->fs_fmod != 0 &&
(error = ffs_sbupdate(ump, waitfor, suspended)) != 0)
allerror = error;
+ if (ffs_fsfail_cleanup(ump, allerror))
+ allerror = 0;
return (allerror);
}
@@ -1707,6 +1727,7 @@
struct ufsmount *ump;
struct buf *bp;
struct vnode *vp;
+ daddr_t dbn;
int error;
MPASS((ffs_flags & FFSV_REPLACE) == 0 || (flags & LK_EXCLUSIVE) != 0);
@@ -1796,9 +1817,10 @@
}
/* Read in the disk contents for the inode, copy into the inode. */
- error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
- (int)fs->fs_bsize, NOCRED, &bp);
- if (error) {
+ dbn = fsbtodb(fs, ino_to_fsba(fs, ino));
+ error = ffs_breadz(ump, ump->um_devvp, dbn, dbn, (int)fs->fs_bsize,
+ NULL, NULL, 0, NOCRED, 0, NULL, &bp);
+ if (error != 0) {
/*
* The inode does not contain anything useful, so it would
* be misleading to leave it on its hash chain. With mode
@@ -1957,6 +1979,7 @@
ret = ufs_uninit(vfsp);
softdep_uninitialize();
ffs_susp_uninitialize();
+ taskqueue_drain_all(taskqueue_thread);
return (ret);
}
@@ -2039,6 +2062,8 @@
* Writing the superblock itself. We need to do special checks for it.
*/
bp = devfdp->sbbp;
+ if (ffs_fsfail_cleanup(ump, devfdp->error))
+ devfdp->error = 0;
if (devfdp->error != 0) {
brelse(bp);
return (devfdp->error);
@@ -2112,6 +2137,11 @@
struct bufobj *bufobj;
struct buf *origbp;
+#ifdef SOFTUPDATES
+ if (!LIST_EMPTY(&bp->b_dep) && (bp->b_ioflags & BIO_ERROR) != 0)
+ softdep_handle_error(bp);
+#endif
+
/*
* Find the original buffer that we are writing.
*/
@@ -2122,7 +2152,7 @@
/*
* We should mark the cylinder group buffer origbp as
- * dirty, to not loose the failed write.
+ * dirty, to not lose the failed write.
*/
if ((bp->b_ioflags & BIO_ERROR) != 0)
origbp->b_vflags |= BV_BKGRDERR;
@@ -2393,6 +2423,8 @@
break;
}
}
+ if (bp->b_iocmd != BIO_READ && ffs_enxio_enable)
+ bp->b_xflags |= BX_CVTENXIO;
g_vfs_strategy(bo, bp);
}
Index: sys/ufs/ffs/ffs_vnops.c
===================================================================
--- sys/ufs/ffs/ffs_vnops.c
+++ sys/ufs/ffs/ffs_vnops.c
@@ -239,6 +239,8 @@
}
BO_UNLOCK(bo);
}
+ if (ffs_fsfail_cleanup(VFSTOUFS(vp->v_mount), 0))
+ return (ENXIO);
return (0);
}
@@ -247,6 +249,7 @@
{
struct inode *ip;
struct bufobj *bo;
+ struct ufsmount *ump;
struct buf *bp, *nbp;
ufs_lbn_t lbn;
int error, passes;
@@ -255,14 +258,18 @@
ip = VTOI(vp);
ip->i_flag &= ~IN_NEEDSYNC;
bo = &vp->v_bufobj;
+ ump = VFSTOUFS(vp->v_mount);
/*
* When doing MNT_WAIT we must first flush all dependencies
* on the inode.
*/
if (DOINGSOFTDEP(vp) && waitfor == MNT_WAIT &&
- (error = softdep_sync_metadata(vp)) != 0)
+ (error = softdep_sync_metadata(vp)) != 0) {
+ if (ffs_fsfail_cleanup(ump, error))
+ error = 0;
return (error);
+ }
/*
* Flush all dirty buffers associated with a vnode.
@@ -332,7 +339,10 @@
}
if (wait) {
bremfree(bp);
- if ((error = bwrite(bp)) != 0)
+ error = bwrite(bp);
+ if (ffs_fsfail_cleanup(ump, error))
+ error = 0;
+ if (error != 0)
return (error);
} else if ((bp->b_flags & B_CLUSTEROK)) {
(void) vfs_bio_awrite(bp);
@@ -901,8 +911,11 @@
uio->uio_offset -= resid - uio->uio_resid;
uio->uio_resid = resid;
}
- } else if (resid > uio->uio_resid && (ioflag & IO_SYNC))
+ } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) {
error = ffs_update(vp, 1);
+ if (ffs_fsfail_cleanup(VFSTOUFS(vp->v_mount), error))
+ error = ENXIO;
+ }
return (error);
}
Index: sys/ufs/ffs/softdep.h
===================================================================
--- sys/ufs/ffs/softdep.h
+++ sys/ufs/ffs/softdep.h
@@ -358,6 +358,7 @@
struct fs *id_fs; /* associated filesystem */
ino_t id_ino; /* dependent inode */
nlink_t id_nlinkdelta; /* saved effective link count */
+ nlink_t id_nlinkwrote; /* i_nlink that we wrote to disk */
nlink_t id_savednlink; /* Link saved during rollback */
LIST_ENTRY(inodedep) id_deps; /* bmsafemap's list of inodedep's */
struct bmsafemap *id_bmsafemap; /* related bmsafemap (if pending) */
Index: sys/ufs/ufs/ufs_vnops.c
===================================================================
--- sys/ufs/ufs/ufs_vnops.c
+++ sys/ufs/ufs/ufs_vnops.c
@@ -1426,6 +1426,7 @@
if (DOINGSOFTDEP(tvp))
softdep_change_linkcnt(tip);
}
+ goto bad;
}
if (doingdirectory && !DOINGSOFTDEP(tvp)) {
/*
@@ -1523,11 +1524,13 @@
if (error == 0 && endoff != 0) {
error = UFS_TRUNCATE(tdvp, endoff, IO_NORMAL |
(DOINGASYNC(tdvp) ? 0 : IO_SYNC), tcnp->cn_cred);
- if (error != 0)
+ if (error != 0 && !ffs_fsfail_cleanup(VFSTOUFS(mp), error))
vn_printf(tdvp,
"ufs_rename: failed to truncate, error %d\n",
error);
#ifdef UFS_DIRHASH
+ if (error != 0)
+ ufsdirhash_free(tdp);
else if (tdp->i_dirhash != NULL)
ufsdirhash_dirtrunc(tdp, endoff);
#endif
Index: sys/ufs/ufs/ufsmount.h
===================================================================
--- sys/ufs/ufs/ufsmount.h
+++ sys/ufs/ufs/ufsmount.h
@@ -45,6 +45,8 @@
#ifdef _KERNEL
+#include <sys/_task.h>
+
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_UFSMNT);
MALLOC_DECLARE(M_TRIM);
@@ -65,6 +67,10 @@
TAILQ_HEAD(inodedeplst, inodedep);
LIST_HEAD(bmsafemaphd, bmsafemap);
LIST_HEAD(trimlist_hashhead, ffs_blkfree_trim_params);
+struct fsfail_task {
+ struct task task;
+ fsid_t fsid;
+};
/*
* This structure describes the UFS specific mount structure data.
@@ -112,6 +118,7 @@
struct taskqueue *um_trim_tq; /* (c) trim request queue */
struct trimlist_hashhead *um_trimhash; /* (i) trimlist hash table */
u_long um_trimlisthashsize; /* (i) trim hash table size-1 */
+ struct fsfail_task *um_fsfail_task; /* (i) task for fsfail cleanup*/
/* (c) - below function ptrs */
int (*um_balloc)(struct vnode *, off_t, int, struct ucred *,
int, struct buf **);
@@ -133,7 +140,8 @@
#define UM_CANDELETE 0x00000001 /* devvp supports TRIM */
#define UM_WRITESUSPENDED 0x00000002 /* suspension in progress */
#define UM_CANSPEEDUP 0x00000004 /* devvp supports SPEEDUP */
-
+#define UM_FSFAIL_CLEANUP 0x00000008 /* need cleanup after
+ unrecoverable error */
/*
* function prototypes
*/
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Nov 18, 8:59 AM (9 h, 2 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25494998
Default Alt Text
D24088.diff (31 KB)
Attached To
Mode
D24088: handle disk I/O errors in FFS with softdep enabled.
Attached
Detach File
Event Timeline
Log In to Comment