From 70a15e1eaa6d10f7c04e5c7ef4b9b50b30eb1159 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sun, 12 Nov 2017 21:08:25 +0000 Subject: [PATCH] kernel: propogate I/O errors properly --- Kernel/devio.c | 4 ++-- Kernel/filesys.c | 58 +++++++++++++++++++++++++++++++++++++----------- Kernel/inode.c | 27 ++++++++++++++++------ 3 files changed, 67 insertions(+), 22 deletions(-) diff --git a/Kernel/devio.c b/Kernel/devio.c index 8ea1ce89..24476064 100644 --- a/Kernel/devio.c +++ b/Kernel/devio.c @@ -59,7 +59,7 @@ bufptr bread(uint16_t dev, blkno_t blk, bool rewrite) /* If rewrite is set, we are about to write over the entire block, so we don't need the previous contents */ if (!rewrite) { - if (bdread(bp) == -1) { + if (bdread(bp) != BLKSIZE) { udata.u_error = EIO; bp->bf_busy = BF_FREE; return (NULL); @@ -93,7 +93,7 @@ int bfree(bufptr bp, uint8_t dirty) bp->bf_busy = BF_FREE; if (dirty > 1) { /* immediate writeback */ - if (bdwrite(bp) == -1) + if (bdwrite(bp) != BLKSIZE) udata.u_error = EIO; bp->bf_dirty = false; return -1; diff --git a/Kernel/filesys.c b/Kernel/filesys.c index 888bda90..fe3838cf 100644 --- a/Kernel/filesys.c +++ b/Kernel/filesys.c @@ -159,6 +159,8 @@ inoptr srch_dir(inoptr wd, char *compname) for(curblock=0; curblock < nblocks; ++curblock) { buf = bread(wd->c_dev, bmap(wd, curblock, 1), 0); + if (buf == NULL) + break; for(curentry = 0; curentry < (512 / DIR_LEN); ++curentry) { d = blkptr(buf, curentry * DIR_LEN, DIR_LEN); if(namecomp(compname, d->d_name)) { @@ -245,6 +247,9 @@ inoptr i_open(uint16_t dev, uint16_t ino) } buf = bread(dev,(ino >> 3) + 2, 0); + if (buf == NULL) + return NULLINODE; + blktok(&(nindex->c_node), buf, 64 * (ino & 7), 64); brelse(buf); @@ -543,6 +548,8 @@ tryagain: k = 0; for(blk = 2; blk < dev->s_isize; blk++) { buf = bread(devno, blk, 0); + if (buf == NULL) + goto corrupt; for(j=0; j < 8; j++) { /* Optimisation: add offsetof and use that to reduce blkptr range */ di = blkptr(buf, sizeof(struct dinode) * j, sizeof(struct dinode)); @@ -626,6 +633,8 @@ blkno_t blk_alloc(uint16_t devno) if(!dev->s_nfree) { buf = bread(devno, newno, 0); + if (buf == NULL) + goto corrupt; blktok(&dev->s_nfree, buf, 0, sizeof(int) + FILESYS_TABSIZE * sizeof(blkno_t)); /* This assumes no padding: this is an UZI era assumption */ @@ -640,6 +649,8 @@ blkno_t blk_alloc(uint16_t devno) /* Zero out the new block */ buf = bread(devno, newno, 2); + if (buf == NULL) + goto corrupt; blkzero(buf); bawrite(buf); return newno; @@ -672,11 +683,14 @@ void blk_free(uint16_t devno, blkno_t blk) if(dev->s_nfree == FILESYS_TABSIZE) { buf = bread(devno, blk, 1); - /* nfree must directly preced the blocks and without padding. That's - the assumption UZI always had */ - blkfromk(&dev->s_nfree, buf, 0, sizeof(int) + 50 * sizeof(blkno_t)); - bawrite(buf); - dev->s_nfree = 0; + if (buf) { + /* nfree must directly preced the blocks and without padding. That's + the assumption UZI always had */ + blkfromk(&dev->s_nfree, buf, 0, sizeof(int) + 50 * sizeof(blkno_t)); + bawrite(buf); + dev->s_nfree = 0; + } else + dev->s_mounted = 1; } ++dev->s_tfree; @@ -803,7 +817,12 @@ void i_deref(inoptr ino) } } - +static void corrupt_fs(uint16_t devno) +{ + struct mount *mnt = fs_tab_get(devno); + mnt->m_fs.s_mounted = 1; + kputs("filesystem corrupt.\n"); +} /* Wr_inode writes out the given inode in the inode table out to disk, * and resets its dirty bit. */ @@ -817,10 +836,13 @@ void wr_inode(inoptr ino) blkno =(ino->c_num >> 3) + 2; buf = bread(ino->c_dev, blkno,0); - blkfromk(&ino->c_node, buf, - sizeof(struct dinode) * (ino->c_num & 0x07), sizeof(struct dinode)); - bfree(buf, 2); - ino->c_flags &= ~CDIRTY; + if (buf) { + blkfromk(&ino->c_node, buf, + sizeof(struct dinode) * (ino->c_num & 0x07), sizeof(struct dinode)); + bfree(buf, 2); + ino->c_flags &= ~CDIRTY; + } else + corrupt_fs(ino->c_dev); } @@ -889,6 +911,10 @@ void freeblk(uint16_t dev, blkno_t blk, uint8_t level) if(level){ buf = bread(dev, blk, 0); + if (buf == NULL) { + corrupt_fs(dev); + return: + } for(j=255; j >= 0; --j) blktok(&bn, buf, j * sizeof(blkno_t), sizeof(blkno_t)); freeblk(dev, bn[j], level-1); @@ -911,6 +937,10 @@ void freeblk(uint16_t dev, blkno_t blk, uint8_t level) if(level){ buf = bread(dev, blk, 0); + if (buf == NULL) { + corrupt_fs(dev); + return; + } bn = blkptr(buf, 0, BLKSIZE); for(j=255; j >= 0; --j) freeblk(dev, bn[j], level-1); @@ -980,6 +1010,10 @@ blkno_t bmap(inoptr ip, blkno_t bn, int rwflg) */ for(; j<=2; j++) { bp = bread(dev, nb, 0); + if (bp == NULL) { + corrupt_fs(ip->c_dev); + return 0; + } /****** if(bp->bf_error) { brelse(bp); @@ -1159,10 +1193,8 @@ bool fmount(uint16_t dev, inoptr ino, uint16_t flags) /* Get the buffer with the superblock (block 1) */ buf = bread(dev, 1, 0); - if (buf == NULL) { - udata.u_error = EIO; + if (buf == NULL) return true; - } blktok(fp, buf, 0, sizeof(struct filesys)); brelse(buf); diff --git a/Kernel/inode.c b/Kernel/inode.c index a22f7bc1..c39e6e45 100644 --- a/Kernel/inode.c +++ b/Kernel/inode.c @@ -95,7 +95,8 @@ void readi(inoptr ino, uint8_t flag) bp = zerobuf(); else bp = bread(dev, pblk, 0); - + if (bp == NULL) + break; uputblk(bp, BLKOFF(udata.u_offset), amount); brelse(bp); @@ -114,6 +115,10 @@ void readi(inoptr ino, uint8_t flag) wakeup(ino); } } + /* Compute return value */ + udata.u_count -= toread; + if (udata.u_count == 0 && udata.u_error) + udata.u_count = (usize_t) -1; break; case MODE_R(F_CDEV): @@ -173,9 +178,9 @@ void writei(inoptr ino, uint8_t flag) return; } /* Sleep if empty pipe */ - goto loop; loop: + flag = flag & O_SYNC ? 2 : 1; while (towrite) { amount = min(towrite, BLKSIZE - BLKOFF(udata.u_offset)); @@ -195,11 +200,14 @@ void writei(inoptr ino, uint8_t flag) * about its previous contents */ bp = bread(dev, pblk, (amount == BLKSIZE)); + if (bp == NULL) + break; ugetblk(bp, BLKOFF(udata.u_offset), amount); - /* FIXME: O_SYNC */ - bawrite(bp); + /* O_SYNC */ + if (bfree(bp, flag)) + break; udata.u_base += amount; udata.u_offset += amount; @@ -220,6 +228,10 @@ void writei(inoptr ino, uint8_t flag) ino->c_flags |= CDIRTY; } } + /* Compute return value */ + udata.u_count -= towrite; + if (udata.u_count == 0 && udata.u_error) + udata.u_count = (usize_t) -1; break; case MODE_R(F_CDEV): @@ -358,10 +370,11 @@ void sync(void) /* GO_CLEAN means write a CLEAN to the media */ if (m->m_fs.s_fmod == FMOD_GO_CLEAN) m->m_fs.s_fmod = FMOD_CLEAN; - /* FIXME: I/O error handling */ buf = bread(m->m_dev, 1, 1); - blkfromk(&m->m_fs, buf, 0, sizeof(struct filesys)); - bfree(buf, 2); + if (buf) { + blkfromk(&m->m_fs, buf, 0, sizeof(struct filesys)); + bfree(buf, 2); + } } } /* WRS: also call d_flush(dev) here for each dirty dev ? */ -- 2.34.1