From 6349fc5a17092c0fa53e93f940d4757e9ebe9770 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 8 Oct 2003 01:07:50 -0500 Subject: [PATCH] JFS: Improved error handing This patch replaces many assert statements, which caused a BUG(), with improved code to mark the superblock dirty and then proceed as specified by the errors= mount flag (as ext2 and ext3 do). JFS's default for the errors option is "remount-ro" in order to prevent addition data corruption when a problem is found. These asserts are usually triggered by on-disk data corruption. By marking the superblock dirty, fsck will perform a complete check on the file system and correct the problems, rather than simply replaying the journal, inviting later trouble. Submitted by Karl Rister & Dave Kleikamp --- Documentation/filesystems/jfs.txt | 4 + fs/jfs/jfs_dmap.c | 169 ++++++++++++++---------- fs/jfs/jfs_dtree.c | 19 ++- fs/jfs/jfs_extent.c | 9 +- fs/jfs/jfs_filsys.h | 7 +- fs/jfs/jfs_imap.c | 205 +++++++++++++++++++++--------- fs/jfs/jfs_metapage.c | 22 +++- fs/jfs/jfs_superblock.h | 3 +- fs/jfs/jfs_txnmgr.c | 9 +- fs/jfs/jfs_xtree.c | 102 +++++++++------ fs/jfs/namei.c | 17 ++- fs/jfs/resize.c | 4 +- fs/jfs/super.c | 72 ++++++++++- fs/jfs/xattr.c | 15 ++- 14 files changed, 454 insertions(+), 203 deletions(-) diff --git a/Documentation/filesystems/jfs.txt b/Documentation/filesystems/jfs.txt index cbece1f31006a..a96fb5c6b98ff 100644 --- a/Documentation/filesystems/jfs.txt +++ b/Documentation/filesystems/jfs.txt @@ -32,6 +32,10 @@ integrity Default. Commit metadata changes to the journal. Use this option to remount a volume where the nointegrity option was previously specified in order to restore normal behavior. +errors=continue Keep going on a filesystem error. +errors=remount-ro Default. Remount the filesystem read-only on an error. +errors=panic Panic and halt the machine if an error occurs. + JFS TODO list: Plans for our near term development items diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index 3edd2320d4d86..dd036ace1f215 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2002 + * Copyright (C) International Business Machines Corp., 2000-2003 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,6 +18,7 @@ #include #include "jfs_incore.h" +#include "jfs_superblock.h" #include "jfs_dmap.h" #include "jfs_imap.h" #include "jfs_lock.h" @@ -134,7 +135,6 @@ static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno, static int dbMaxBud(u8 * cp); s64 dbMapFileSizeToMapSize(struct inode *ipbmap); int blkstol2(s64 nb); -void fsDirty(void); int cntlz(u32 value); int cnttz(u32 word); @@ -382,7 +382,15 @@ int dbFree(struct inode *ip, s64 blkno, s64 nblocks) IREAD_LOCK(ipbmap); /* block to be freed better be within the mapsize. */ - assert(blkno + nblocks <= bmp->db_mapsize); + if (blkno + nblocks > bmp->db_mapsize) { + IREAD_UNLOCK(ipbmap); + printk(KERN_ERR "blkno = %Lx, nblocks = %Lx\n", + (unsigned long long) blkno, + (unsigned long long) nblocks); + jfs_error(ip->i_sb, + "dbFree: block to be freed is outside the map"); + return -EIO; + } /* * free the blocks a dmap at a time. @@ -465,7 +473,14 @@ dbUpdatePMap(struct inode *ipbmap, int lsn, difft, diffp; /* the blocks better be within the mapsize. */ - assert(blkno + nblocks <= bmp->db_mapsize); + if (blkno + nblocks > bmp->db_mapsize) { + printk(KERN_ERR "blkno = %Lx, nblocks = %Lx\n", + (unsigned long long) blkno, + (unsigned long long) nblocks); + jfs_error(ipbmap->i_sb, + "dbUpdatePMap: blocks are outside the map"); + return -EIO; + } /* compute delta of transaction lsn from log syncpt */ lsn = tblk->lsn; @@ -757,7 +772,10 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results) mapSize = bmp->db_mapsize; /* the hint should be within the map */ - assert(hint < mapSize); + if (hint >= mapSize) { + jfs_error(ip->i_sb, "dbAlloc: the hint is outside the map"); + return -EIO; + } /* if the number of blocks to be allocated is greater than the * allocation group size, try to allocate anywhere. @@ -1104,7 +1122,12 @@ int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks) /* better be within the file system */ bmp = sbi->bmap; - assert(lastblkno >= 0 && lastblkno < bmp->db_mapsize); + if (lastblkno < 0 || lastblkno >= bmp->db_mapsize) { + IREAD_UNLOCK(ipbmap); + jfs_error(ip->i_sb, + "dbExtend: the block is outside the filesystem"); + return -EIO; + } /* we'll attempt to extend the current allocation in place by * allocating the additional blocks as the blocks immediately @@ -1145,11 +1168,10 @@ int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks) DBALLOC(bmp->db_DBmap, bmp->db_mapsize, extblkno, addnblocks); write_metapage(mp); - } else { + } else /* we were not successful */ release_metapage(mp); - assert(rc == -ENOSPC || rc == -EIO); - } + return (rc); } @@ -1414,7 +1436,12 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) /* allocation request should not be for more than the * allocation group size. */ - assert(l2nb <= bmp->db_agl2size); + if (l2nb > bmp->db_agl2size) { + jfs_error(bmp->db_ipbmap->i_sb, + "dbAllocAG: allocation request is larger than the " + "allocation group size"); + return -EIO; + } /* determine the starting block number of the allocation * group. @@ -1441,13 +1468,13 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) if (bmp->db_agsize == BPERDMAP || bmp->db_agfree[agno] == bmp->db_agsize) { rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results); - /* assert(!(rc == -ENOSPC && bmp->db_agfree[agno] == bmp->db_agsize)); */ if ((rc == -ENOSPC) && (bmp->db_agfree[agno] == bmp->db_agsize)) { - jfs_err("dbAllocAG: removed assert, but still need to " - "debug here\nblkno = 0x%Lx, nblocks = 0x%Lx", - (unsigned long long) blkno, - (unsigned long long) nblocks); + printk(KERN_ERR "blkno = %Lx, blocks = %Lx\n", + (unsigned long long) blkno, + (unsigned long long) nblocks); + jfs_error(bmp->db_ipbmap->i_sb, + "dbAllocAG: dbAllocCtl failed in free AG"); } return (rc); } @@ -1496,7 +1523,11 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) break; } } - assert(n < 4); + if (n == 4) { + jfs_error(bmp->db_ipbmap->i_sb, + "dbAllocAG: failed descending stree"); + return -EIO; + } } /* determine the block number within the file system @@ -1531,7 +1562,12 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) if ((rc = dbFindCtl(bmp, l2nb, bmp->db_aglevel - 1, &blkno))) { - assert(rc != -ENOSPC); + if (rc == -ENOSPC) { + jfs_error(bmp->db_ipbmap->i_sb, + "dbAllocAG: control page " + "inconsistent"); + return -EIO; + } return (rc); } } @@ -1539,7 +1575,11 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) /* allocate the blocks. */ rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results); - assert(rc != -ENOSPC); + if (rc == -ENOSPC) { + jfs_error(bmp->db_ipbmap->i_sb, + "dbAllocAG: unable to allocate blocks"); + rc = -EIO; + } return (rc); } @@ -1595,7 +1635,11 @@ static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results) /* allocate the blocks. */ rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results); - assert(rc != -ENOSPC); + if (rc == -ENOSPC) { + jfs_error(bmp->db_ipbmap->i_sb, + "dbAllocAny: unable to allocate blocks"); + return -EIO; + } return (rc); } @@ -1666,7 +1710,11 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno) /* space found ? */ if (rc) { - assert(lev == level); + if (lev != level) { + jfs_error(bmp->db_ipbmap->i_sb, + "dbFindCtl: dmap inconsistent"); + return -EIO; + } return -ENOSPC; } @@ -1785,7 +1833,13 @@ dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results) /* the dmap better be all free. */ - assert(dp->tree.stree[ROOT] == L2BPERDMAP); + if (dp->tree.stree[ROOT] != L2BPERDMAP) { + release_metapage(mp); + jfs_error(bmp->db_ipbmap->i_sb, + "dbAllocCtl: the dmap is not all free"); + rc = -EIO; + goto backout; + } /* determine how many blocks to allocate from this dmap. */ @@ -1828,8 +1882,8 @@ dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results) /* could not back out. mark the file system * to indicate that we have leaked blocks. */ - fsDirty(); /* !!! */ - jfs_err("dbAllocCtl: I/O Error: Block Leakage."); + jfs_error(bmp->db_ipbmap->i_sb, + "dbAllocCtl: I/O Error: Block Leakage."); continue; } dp = (struct dmap *) mp->data; @@ -1841,8 +1895,8 @@ dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results) * to indicate that we have leaked blocks. */ release_metapage(mp); - fsDirty(); /* !!! */ - jfs_err("dbAllocCtl: Block Leakage."); + jfs_error(bmp->db_ipbmap->i_sb, + "dbAllocCtl: Block Leakage."); continue; } @@ -2137,7 +2191,12 @@ static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno, * the allocated words. */ for (; nwords > 0; nwords -= nw) { - assert(leaf[word] >= BUDMIN); + if (leaf[word] < BUDMIN) { + jfs_error(bmp->db_ipbmap->i_sb, + "dbAllocBits: leaf page " + "corrupt"); + break; + } /* determine what the leaf value should be * updated to as the minimum of the l2 number @@ -2489,7 +2548,11 @@ dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc, int level) * of the maximum free buddy system. */ assert(level == bmp->db_maxlevel); - assert(bmp->db_maxfreebud == oldroot); + if (bmp->db_maxfreebud != oldroot) { + jfs_error(bmp->db_ipbmap->i_sb, + "dbAdjCtl: the maximum free buddy is " + "not the old root"); + } bmp->db_maxfreebud = dcp->stree[ROOT]; } } @@ -3039,24 +3102,6 @@ int blkstol2(s64 nb) } -/* - * NAME: fsDirty() - * - * FUNCTION: xxx - * - * PARAMETERS: - * ipmnt - mount inode - * - * RETURN VALUES: - * none - */ -void fsDirty(void) -{ - printk("fsDirty(): bye-bye\n"); - assert(0); -} - - /* * NAME: dbAllocBottomUp() * @@ -3343,7 +3388,10 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) /* get L2 page */ p = BMAPBLKNO + nbperpage; /* L2 page */ l2mp = read_metapage(ipbmap, p, PSIZE, 0); - assert(l2mp); + if (!l2mp) { + jfs_error(ipbmap->i_sb, "dbExtendFS: L2 page could not be read"); + return -EIO; + } l2dcp = (struct dmapctl *) l2mp->data; /* compute start L1 */ @@ -3504,7 +3552,9 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks) } } /* for each L1 in a L2 */ - assert(0); + jfs_error(ipbmap->i_sb, + "dbExtendFS: function has not returned as expected"); + return -EIO; /* * finalize bmap control page @@ -3568,7 +3618,10 @@ void dbFinalizeBmap(struct inode *ipbmap) if (bmp->db_agfree[bmp->db_agpref] >= avgfree) break; } - assert(bmp->db_agpref < bmp->db_numag); + if (bmp->db_agpref >= bmp->db_numag) { + jfs_error(ipbmap->i_sb, + "cannot find ag with average freespace"); + } } /* @@ -3589,10 +3642,6 @@ void dbFinalizeBmap(struct inode *ipbmap) n <<= 2; } -/* -printk("bmap: agpref:%d aglevel:%d agheigth:%d agwidth:%d\n", - bmp->db_agpref, bmp->db_aglevel, bmp->db_agheigth, bmp->db_agwidth); -*/ } @@ -3616,9 +3665,6 @@ printk("bmap: agpref:%d aglevel:%d agheigth:%d agwidth:%d\n", static int dbInitDmap(struct dmap * dp, s64 Blkno, int nblocks) { int blkno, w, b, r, nw, nb, i; -/* -printk("sbh_dmap: in dbInitDmap blkno:%Ld nblocks:%ld\n", Blkno, nblocks); -*/ /* starting block number within the dmap */ blkno = Blkno & (BPERDMAP - 1); @@ -3678,10 +3724,6 @@ printk("sbh_dmap: in dbInitDmap blkno:%Ld nblocks:%ld\n", Blkno, nblocks); * mark bits following the range to be freed (non-existing * blocks) as allocated (ONES) */ -/* -printk("sbh_dmap: in dbInitDmap, preparing to mark unbacked, blkno:%ld nblocks:%ld\n", - blkno, nblocks); -*/ if (blkno == BPERDMAP) goto initTree; @@ -3691,9 +3733,6 @@ printk("sbh_dmap: in dbInitDmap, preparing to mark unbacked, blkno:%ld nblocks: /* does nblocks fall on a 32-bit boundary ? */ b = blkno & (DBWORD - 1); -/* -printk("sbh_dmap: in dbInitDmap, b:%ld w:%ld mask: %lx\n", b, w, (ONES>>b)); -*/ if (b) { /* mark a partial word allocated */ dp->wmap[w] = dp->pmap[w] = cpu_to_le32(ONES >> b); @@ -3990,7 +4029,7 @@ static void DBinitmap(s64 size, struct inode *ipbmap, u32 ** results) dbmap = (u32 *) xmalloc(npages * 4096, L2PSIZE, kernel_heap); if (dbmap == NULL) - assert(0); + BUG(); /* Not robust since this is only unused debug code */ for (n = 0, d = dbmap; n < npages; n++, d += 1024) bzero(d, 4096); @@ -4004,7 +4043,9 @@ static void DBinitmap(s64 size, struct inode *ipbmap, u32 ** results) db_l2nbperpage); mp = read_metapage(ipbmap, lblkno, PSIZE, 0); if (mp == NULL) { - assert(0); + jfs_error(ipbmap->i_sb, + "DBinitmap: could not read disk map page"); + continue; } dp = (struct dmap *) mp->data; diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c index 162bbae2053a7..4c4a6b5ccda21 100644 --- a/fs/jfs/jfs_dtree.c +++ b/fs/jfs/jfs_dtree.c @@ -1,5 +1,5 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2002 + * Copyright (C) International Business Machines Corp., 2000-2003 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -130,9 +130,8 @@ struct dtsplit { if (((P)->header.nextindex > (((BN)==0)?DTROOTMAXSLOT:(P)->header.maxslot)) ||\ ((BN) && ((P)->header.maxslot > DTPAGEMAXSLOT)))\ {\ - jfs_err("DT_GETPAGE: dtree page corrupt");\ BT_PUTPAGE(MP);\ - updateSuper((IP)->i_sb, FM_DIRTY);\ + jfs_error((IP)->i_sb, "DT_GETPAGE: dtree page corrupt");\ MP = NULL;\ RC = -EIO;\ }\ @@ -768,8 +767,7 @@ int dtSearch(struct inode *ip, struct component_name * key, ino_t * data, /* Something's corrupted, mark filesytem dirty so * chkdsk will fix it. */ - jfs_err("stack overrun in dtSearch!"); - updateSuper(sb, FM_DIRTY); + jfs_error(sb, "stack overrun in dtSearch!"); rc = -EIO; goto out; } @@ -3204,11 +3202,12 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) d_namleft -= len; /* Sanity Check */ if (d_namleft == 0) { - jfs_err("JFS:Dtree error: ino = " - "%ld, bn=%Ld, index = %d", - (long)ip->i_ino,(long long)bn, - i); - updateSuper(ip->i_sb, FM_DIRTY); + jfs_error(ip->i_sb, + "JFS:Dtree error: ino = " + "%ld, bn=%Ld, index = %d", + (long)ip->i_ino, + (long long)bn, + i); goto skip_one; } len = min(d_namleft, DTSLOTDATALEN); diff --git a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c index 2281f0aa6de8d..4371b6489a5ca 100644 --- a/fs/jfs/jfs_extent.c +++ b/fs/jfs/jfs_extent.c @@ -1,5 +1,5 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2002 + * Copyright (C) International Business Machines Corp., 2000-2003 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,6 +18,7 @@ #include #include "jfs_incore.h" +#include "jfs_superblock.h" #include "jfs_dmap.h" #include "jfs_extent.h" #include "jfs_debug.h" @@ -403,8 +404,10 @@ int extHint(struct inode *ip, s64 offset, xad_t * xp) */ xp->flag &= XAD_NOTRECORDED; - assert(xadl.nxad == 1); - assert(lengthXAD(xp) == nbperpage); + if(xadl.nxad != 1 || lengthXAD(xp) != nbperpage) { + jfs_error(ip->i_sb, "extHint: corrupt xtree"); + return -EIO; + } return (0); } diff --git a/fs/jfs/jfs_filsys.h b/fs/jfs/jfs_filsys.h index 3bf500cf838a4..86ccac80f0abc 100644 --- a/fs/jfs/jfs_filsys.h +++ b/fs/jfs/jfs_filsys.h @@ -1,5 +1,5 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2003 + * Copyright (C) International Business Machines Corp., 2000-2003 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,6 +32,11 @@ /* mount time flag to disable journaling to disk */ #define JFS_NOINTEGRITY 0x00000010 +/* mount time flags for error handling */ +#define JFS_ERR_REMOUNT_RO 0x00000002 /* remount read-only */ +#define JFS_ERR_CONTINUE 0x00000004 /* continue */ +#define JFS_ERR_PANIC 0x00000008 /* panic */ + /* platform option (conditional compilation) */ #define JFS_AIX 0x80000000 /* AIX support */ /* POSIX name/directory support */ diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c index e2378e681027c..74185890b615a 100644 --- a/fs/jfs/jfs_imap.c +++ b/fs/jfs/jfs_imap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2002 + * Copyright (C) International Business Machines Corp., 2000-2003 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -410,8 +410,7 @@ int diRead(struct inode *ip) dp += rel_inode; if (ip->i_ino != le32_to_cpu(dp->di_number)) { - jfs_err("diRead: i_ino != di_number"); - updateSuper(ip->i_sb, FM_DIRTY); + jfs_error(ip->i_sb, "diRead: i_ino != di_number"); rc = -EIO; } else if (le32_to_cpu(dp->di_nlink) == 0) rc = -ESTALE; @@ -641,9 +640,12 @@ int diWrite(tid_t tid, struct inode *ip) ino = ip->i_ino & (INOSPERIAG - 1); - assert(lengthPXD(&(jfs_ip->ixpxd)) == - JFS_IP(ipimap)->i_imap->im_nbperiext); - assert(addressPXD(&(jfs_ip->ixpxd))); + if (!addressPXD(&(jfs_ip->ixpxd)) || + (lengthPXD(&(jfs_ip->ixpxd)) != + JFS_IP(ipimap)->i_imap->im_nbperiext)) { + jfs_error(ip->i_sb, "diWrite: ixpxd invalid"); + return -EIO; + } /* * read the page of disk inode containing the specified inode: @@ -918,12 +920,11 @@ int diFree(struct inode *ip) /* make sure that the iag is contained within * the map. */ - //assert(iagno < imap->im_nextiag); if (iagno >= imap->im_nextiag) { - jfs_err("diFree: inum = %d, iagno = %d, nextiag = %d", - (uint) inum, iagno, imap->im_nextiag); dump_mem("imap", imap, 32); - updateSuper(ip->i_sb, FM_DIRTY); + jfs_error(ip->i_sb, + "diFree: inum = %d, iagno = %d, nextiag = %d", + (uint) inum, iagno, imap->im_nextiag); return -EIO; } @@ -957,22 +958,28 @@ int diFree(struct inode *ip) bitno = ino & (INOSPEREXT - 1); mask = HIGHORDER >> bitno; - assert(le32_to_cpu(iagp->wmap[extno]) & mask); -#ifdef _STILL_TO_PORT - assert((le32_to_cpu(iagp->pmap[extno]) & mask) == 0); -#endif /* _STILL_TO_PORT */ - assert(addressPXD(&iagp->inoext[extno])); + if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) { + jfs_error(ip->i_sb, + "diFree: wmap shows inode already free"); + } + + if (!addressPXD(&iagp->inoext[extno])) { + release_metapage(mp); + IREAD_UNLOCK(ipimap); + AG_UNLOCK(imap, agno); + jfs_error(ip->i_sb, "diFree: invalid inoext"); + return -EIO; + } /* compute the bitmap for the extent reflecting the freed inode. */ bitmap = le32_to_cpu(iagp->wmap[extno]) & ~mask; if (imap->im_agctl[agno].numfree > imap->im_agctl[agno].numinos) { - jfs_err("diFree: numfree > numinos"); release_metapage(mp); IREAD_UNLOCK(ipimap); AG_UNLOCK(imap, agno); - updateSuper(ip->i_sb, FM_DIRTY); + jfs_error(ip->i_sb, "diFree: numfree > numinos"); return -EIO; } /* @@ -1136,7 +1143,6 @@ int diFree(struct inode *ip) if ((rc = diIAGRead(imap, inofreefwd, &cmp))) goto error_out; - assert(cmp != NULL); ciagp = (struct iag *) cmp->data; } assert(ciagp != NULL); @@ -1151,7 +1157,6 @@ int diFree(struct inode *ip) if ((rc = diIAGRead(imap, inofreeback, &dmp))) goto error_out; - assert(dmp != NULL); diagp = (struct iag *) dmp->data; } assert(diagp != NULL); @@ -1224,7 +1229,9 @@ int diFree(struct inode *ip) * the permanent map should have been updated already * for the inode being freed. */ - assert(iagp->pmap[extno] == 0); + if (iagp->pmap[extno] != 0) { + jfs_error(ip->i_sb, "diFree: the pmap does not show inode free"); + } iagp->wmap[extno] = 0; DBG_DIFREE(imap, inum); PXDlength(&iagp->inoext[extno], 0); @@ -1304,7 +1311,7 @@ int diFree(struct inode *ip) iplist[1] = (struct inode *) (size_t)iagno; iplist[2] = (struct inode *) (size_t)extno; - rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE); // D233382 + rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE); txEnd(tid); @@ -1434,6 +1441,7 @@ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip) iagno = INOTOIAG(inum); if ((rc = diIAGRead(imap, iagno, &mp))) { IREAD_UNLOCK(ipimap); + AG_UNLOCK(imap, agno); return (rc); } iagp = (struct iag *) mp->data; @@ -1536,10 +1544,16 @@ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip) */ rem = diFindFree(inosmap, 0); extno = (sword << L2EXTSPERSUM) + rem; - rem = - diFindFree(le32_to_cpu - (iagp->wmap[extno]), 0); - assert(rem < INOSPEREXT); + rem = diFindFree(le32_to_cpu(iagp->wmap[extno]), + 0); + if (rem >= INOSPEREXT) { + IREAD_UNLOCK(ipimap); + AG_UNLOCK(imap, agno); + jfs_error(ip->i_sb, + "diAlloc: can't find free bit " + "in wmap"); + return EIO; + } /* determine the inode number within the * iag and allocate the inode from the @@ -1548,9 +1562,9 @@ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip) ino = (extno << L2INOSPEREXT) + rem; rc = diAllocBit(imap, iagp, ino); IREAD_UNLOCK(ipimap); - if (rc) { + if (rc) assert(rc == -EIO); - } else { + else { /* set the results of the allocation * and write the iag. */ @@ -1678,8 +1692,7 @@ diAllocAG(struct inomap * imap, int agno, boolean_t dir, struct inode *ip) numinos = imap->im_agctl[agno].numinos; if (numfree > numinos) { - jfs_err("diAllocAG: numfree > numinos"); - updateSuper(ip->i_sb, FM_DIRTY); + jfs_error(ip->i_sb, "diAllocAG: numfree > numinos"); return -EIO; } @@ -1827,12 +1840,10 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip) /* better be free inodes in this iag if it is on the * list. */ - //assert(iagp->nfreeinos); if (!iagp->nfreeinos) { - jfs_err("diAllocIno: nfreeinos = 0, but iag on freelist"); - jfs_err(" agno = %d, iagno = %d", agno, iagno); - dump_mem("iag", iagp, 64); - updateSuper(ip->i_sb, FM_DIRTY); + IREAD_UNLOCK(imap->im_ipimap); + jfs_error(ip->i_sb, + "diAllocIno: nfreeinos = 0, but iag on freelist"); return -EIO; } @@ -1840,7 +1851,12 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip) * with free inodes. */ for (sword = 0;; sword++) { - assert(sword < SMAPSZ); + if (sword >= SMAPSZ) { + IREAD_UNLOCK(imap->im_ipimap); + jfs_error(ip->i_sb, + "diAllocIno: free inode not found in summary map"); + return -EIO; + } if (~iagp->inosmap[sword]) break; @@ -1850,13 +1866,21 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip) * the extent number. */ rem = diFindFree(le32_to_cpu(iagp->inosmap[sword]), 0); - assert(rem < EXTSPERSUM); + if (rem >= EXTSPERSUM) { + IREAD_UNLOCK(imap->im_ipimap); + jfs_error(ip->i_sb, "diAllocIno: no free extent found"); + return -EIO; + } extno = (sword << L2EXTSPERSUM) + rem; /* find the first free inode in the extent. */ rem = diFindFree(le32_to_cpu(iagp->wmap[extno]), 0); - assert(rem < INOSPEREXT); + if (rem >= INOSPEREXT) { + IREAD_UNLOCK(imap->im_ipimap); + jfs_error(ip->i_sb, "diAllocIno: free inode not found"); + return -EIO; + } /* compute the inode number within the iag. */ @@ -1939,7 +1963,9 @@ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip) */ IREAD_LOCK(imap->im_ipimap); if ((rc = diIAGRead(imap, iagno, &mp))) { - assert(0); + IREAD_UNLOCK(imap->im_ipimap); + jfs_error(ip->i_sb, "diAllocExt: error reading iag"); + return rc; } iagp = (struct iag *) mp->data; } @@ -1947,7 +1973,13 @@ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip) /* using the free extent summary map, find a free extent. */ for (sword = 0;; sword++) { - assert(sword < SMAPSZ); + if (sword >= SMAPSZ) { + release_metapage(mp); + IREAD_UNLOCK(imap->im_ipimap); + jfs_error(ip->i_sb, + "diAllocExt: free ext summary map not found"); + return -EIO; + } if (~iagp->extsmap[sword]) break; } @@ -1955,7 +1987,12 @@ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip) /* determine the extent number of the free extent. */ rem = diFindFree(le32_to_cpu(iagp->extsmap[sword]), 0); - assert(rem < EXTSPERSUM); + if (rem >= EXTSPERSUM) { + release_metapage(mp); + IREAD_UNLOCK(imap->im_ipimap); + jfs_error(ip->i_sb, "diAllocExt: free extent not found"); + return -EIO; + } extno = (sword << L2EXTSPERSUM) + rem; /* initialize the new extent. @@ -2066,9 +2103,18 @@ static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino) /* the inode should be free and backed. */ - assert((le32_to_cpu(iagp->pmap[extno]) & mask) == 0); - assert((le32_to_cpu(iagp->wmap[extno]) & mask) == 0); - assert(addressPXD(&iagp->inoext[extno]) != 0); + if (((le32_to_cpu(iagp->pmap[extno]) & mask) != 0) || + ((le32_to_cpu(iagp->wmap[extno]) & mask) != 0) || + (addressPXD(&iagp->inoext[extno]) == 0)) { + if (amp) + release_metapage(amp); + if (bmp) + release_metapage(bmp); + + jfs_error(imap->im_ipimap->i_sb, + "diAllocBit: iag inconsistent"); + return -EIO; + } /* mark the inode as allocated in the working map. */ @@ -2172,7 +2218,10 @@ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno) /* better have free extents. */ - assert(iagp->nfreeexts); + if (!iagp->nfreeexts) { + jfs_error(imap->im_ipimap->i_sb, "diNewExt: no free extents"); + return -EIO; + } /* get the inode map inode. */ @@ -2240,7 +2289,12 @@ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno) goto error_out; ciagp = (struct iag *) cmp->data; } - assert(ciagp != NULL); + if (ciagp == NULL) { + jfs_error(imap->im_ipimap->i_sb, + "diNewExt: ciagp == NULL"); + rc = -EIO; + goto error_out; + } } } @@ -2474,7 +2528,14 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp) /* acquire inode map lock */ IWRITE_LOCK(ipimap); - assert(ipimap->i_size >> L2PSIZE == imap->im_nextiag + 1); + if (ipimap->i_size >> L2PSIZE != imap->im_nextiag + 1) { + IWRITE_UNLOCK(ipimap); + IAGFREE_UNLOCK(imap); + jfs_error(imap->im_ipimap->i_sb, + "diNewIAG: ipimap->i_size is wrong"); + return -EIO; + } + /* get the next avaliable iag number */ iagno = imap->im_nextiag; @@ -2507,7 +2568,6 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp) /* assign a buffer for the page */ mp = get_metapage(ipimap, xaddr, PSIZE, 1); - //bp = bmAssign(ipimap, blkno, xaddr, PSIZE, bmREAD_PAGE); if (!mp) { /* Free the blocks allocated for the iag since it was * not successfully added to the inode map @@ -2734,7 +2794,11 @@ diUpdatePMap(struct inode *ipimap, /* get the iag number containing the inode */ iagno = INOTOIAG(inum); /* make sure that the iag is contained within the map */ - assert(iagno < imap->im_nextiag); + if (iagno >= imap->im_nextiag) { + jfs_error(ipimap->i_sb, + "diUpdatePMap: the iag is outside the map"); + return -EIO; + } /* read the iag */ IREAD_LOCK(ipimap); rc = diIAGRead(imap, iagno, &mp); @@ -2759,14 +2823,14 @@ diUpdatePMap(struct inode *ipimap, * of last reference release; */ if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) { - jfs_err("diUpdatePMap: inode %ld not marked as " - "allocated in wmap!", inum); - updateSuper(ipimap->i_sb, FM_DIRTY); + jfs_error(ipimap->i_sb, + "diUpdatePMap: inode %ld not marked as " + "allocated in wmap!", inum); } if (!(le32_to_cpu(iagp->pmap[extno]) & mask)) { - jfs_err("diUpdatePMap: inode %ld not marked as " - "allocated in pmap!", inum); - updateSuper(ipimap->i_sb, FM_DIRTY); + jfs_error(ipimap->i_sb, + "diUpdatePMap: inode %ld not marked as " + "allocated in pmap!", inum); } /* update the bitmap for the extent of the freed inode */ iagp->pmap[extno] &= cpu_to_le32(~mask); @@ -2778,8 +2842,18 @@ diUpdatePMap(struct inode *ipimap, /* The inode should be already allocated in the working map * and should be free in persistent map; */ - assert(le32_to_cpu(iagp->wmap[extno]) & mask); - assert((le32_to_cpu(iagp->pmap[extno]) & mask) == 0); + if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) { + jfs_error(ipimap->i_sb, + "diUpdatePMap: the inode is not allocated in " + "the working map"); + return -EIO; + } + if ((le32_to_cpu(iagp->pmap[extno]) & mask) != 0) { + jfs_error(ipimap->i_sb, + "diUpdatePMap: the inode is not free in the " + "persistent map"); + return -EIO; + } /* update the bitmap for the extent of the allocated inode */ iagp->pmap[extno] |= cpu_to_le32(mask); } @@ -2817,7 +2891,6 @@ diUpdatePMap(struct inode *ipimap, mp->clsn = tblk->clsn; LOGSYNC_UNLOCK(log); } -// bmLazyWrite(mp, log->flag & JFS_COMMIT); write_metapage(mp); return (0); } @@ -2872,7 +2945,12 @@ int diExtendFS(struct inode *ipimap, struct inode *ipbmap) continue; } iagp = (struct iag *) bp->data; - assert(le32_to_cpu(iagp->iagnum) == i); + if (le32_to_cpu(iagp->iagnum) != i) { + release_metapage(bp); + jfs_error(ipimap->i_sb, + "diExtendFs: unexpected value of iagnum"); + return -EIO; + } /* leave free iag in the free iag list */ if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) { @@ -2884,9 +2962,6 @@ int diExtendFS(struct inode *ipimap, struct inode *ipbmap) agstart = le64_to_cpu(iagp->agstart); /* iagp->agstart = agstart & ~(mp->db_agsize - 1); */ n = agstart >> mp->db_agl2size; -/* -printf("diExtendFS: iag:%d agstart:%Ld agno:%d\n", i, agstart, n); -*/ /* compute backed inodes */ numinos = (EXTSPERIAG - le32_to_cpu(iagp->nfreeexts)) @@ -2947,8 +3022,12 @@ printf("diExtendFS: iag:%d agstart:%Ld agno:%d\n", i, agstart, n); write_metapage(bp); } - ASSERT(xnuminos == atomic_read(&imap->im_numinos) && - xnumfree == atomic_read(&imap->im_numfree)); + if (xnuminos != atomic_read(&imap->im_numinos) || + xnumfree != atomic_read(&imap->im_numfree)) { + jfs_error(ipimap->i_sb, + "diExtendFs: numinos or numfree incorrect"); + return -EIO; + } return rcx; } diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index a2109dba90d05..a8100967e1963 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -1,6 +1,6 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2002 - * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * Copyright (C) International Business Machines Corp., 2000-2003 + * Portions Copyright (C) Christoph Hellwig, 2001-2002 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +22,7 @@ #include #include #include "jfs_incore.h" +#include "jfs_superblock.h" #include "jfs_filsys.h" #include "jfs_metapage.h" #include "jfs_txnmgr.h" @@ -233,14 +234,23 @@ struct metapage *__get_metapage(struct inode *inode, unsigned long lblock, if (mp) { page_found: if (test_bit(META_discard, &mp->flag)) { - assert(new); /* It's okay to reuse a discarded - * if we expect it to be empty - */ + if (!new) { + spin_unlock(&meta_lock); + jfs_error(inode->i_sb, + "__get_metapage: using a " + "discarded metapage"); + return NULL; + } clear_bit(META_discard, &mp->flag); } mp->count++; jfs_info("__get_metapage: found 0x%p, in hash", mp); - assert(mp->logical_size == size); + if (mp->logical_size != size) { + spin_unlock(&meta_lock); + jfs_error(inode->i_sb, + "__get_metapage: mp->logical_size != size"); + return NULL; + } lock_metapage(mp); spin_unlock(&meta_lock); } else { diff --git a/fs/jfs/jfs_superblock.h b/fs/jfs/jfs_superblock.h index 01905bbb4552f..5a558ce3e81d1 100644 --- a/fs/jfs/jfs_superblock.h +++ b/fs/jfs/jfs_superblock.h @@ -1,5 +1,5 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2002 + * Copyright (C) International Business Machines Corp., 2000-2003 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -108,5 +108,6 @@ struct jfs_superblock { extern int readSuper(struct super_block *, struct buffer_head **); extern int updateSuper(struct super_block *, uint); +extern void jfs_error(struct super_block *, const char *, ...); #endif /*_H_JFS_SUPERBLOCK */ diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index 3604174b8c6af..c4a4a26c8dc15 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -1,6 +1,6 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2003 - * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * Copyright (C) International Business Machines Corp., 2000-2003 + * Portions Copyright (C) Christoph Hellwig, 2001-2002 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1442,7 +1442,6 @@ int diLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, * page is not itself logged, to prevent pageout of the map * page before the log; */ - assert(tlck->type & tlckFREE); /* log LOG_NOREDOINOEXT of the freed inode extent for * logredo() to start NoRedoPage filters, and to update @@ -2655,7 +2654,7 @@ void txAbort(tid_t tid, int dirty) * mark filesystem dirty */ if (dirty) - updateSuper(tblk->sb, FM_DIRTY); + jfs_error(tblk->sb, "txAbort"); return; } @@ -2714,7 +2713,7 @@ static void txAbortCommit(struct commit * cd) /* * mark filesystem dirty */ - updateSuper(cd->sb, FM_DIRTY); + jfs_error(cd->sb, "txAbortCommit"); } diff --git a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c index 7fb43461cdddd..3ff1672531bed 100644 --- a/fs/jfs/jfs_xtree.c +++ b/fs/jfs/jfs_xtree.c @@ -1,5 +1,5 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2002 + * Copyright (C) International Business Machines Corp., 2000-2003 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -60,21 +60,21 @@ #define XT_PAGE(IP, MP) BT_PAGE(IP, MP, xtpage_t, i_xtroot) /* get page buffer for specified block address */ +/* ToDo: Replace this ugly macro with a function */ #define XT_GETPAGE(IP, BN, MP, SIZE, P, RC)\ {\ - BT_GETPAGE(IP, BN, MP, xtpage_t, SIZE, P, RC, i_xtroot)\ - if (!(RC))\ - {\ - if ((le16_to_cpu((P)->header.nextindex) < XTENTRYSTART) ||\ - (le16_to_cpu((P)->header.nextindex) > le16_to_cpu((P)->header.maxentry)) ||\ - (le16_to_cpu((P)->header.maxentry) > (((BN)==0)?XTROOTMAXSLOT:PSIZE>>L2XTSLOTSIZE)))\ - {\ - jfs_err("XT_GETPAGE: xtree page corrupt");\ + BT_GETPAGE(IP, BN, MP, xtpage_t, SIZE, P, RC, i_xtroot)\ + if (!(RC))\ + {\ + if ((le16_to_cpu((P)->header.nextindex) < XTENTRYSTART) ||\ + (le16_to_cpu((P)->header.nextindex) > le16_to_cpu((P)->header.maxentry)) ||\ + (le16_to_cpu((P)->header.maxentry) > (((BN)==0)?XTROOTMAXSLOT:PSIZE>>L2XTSLOTSIZE)))\ + {\ + jfs_error((IP)->i_sb, "XT_GETPAGE: xtree page corrupt");\ BT_PUTPAGE(MP);\ - updateSuper((IP)->i_sb, FM_DIRTY);\ MP = NULL;\ - RC = -EIO;\ - }\ + RC = -EIO;\ + }\ }\ } @@ -1611,14 +1611,21 @@ int xtExtend(tid_t tid, /* transaction id */ /* there must exist extent to be extended */ if ((rc = xtSearch(ip, xoff - 1, &cmp, &btstack, XT_INSERT))) return rc; - assert(cmp == 0); + if (cmp != 0) { + jfs_error(ip->i_sb, "xtExtend: xtSearch did not find extent"); + return -EIO; + } /* retrieve search result */ XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); /* extension must be contiguous */ xad = &p->xad[index]; - assert((offsetXAD(xad) + lengthXAD(xad)) == xoff); + if ((offsetXAD(xad) + lengthXAD(xad)) != xoff) { + XT_PUTPAGE(mp); + jfs_error(ip->i_sb, "xtExtend: extension is not contiguous"); + return -EIO; + } /* * acquire a transaction lock on the leaf page; @@ -1771,14 +1778,22 @@ printf("xtTailgate: nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n", /* there must exist extent to be tailgated */ if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT))) return rc; - assert(cmp == 0); + if (cmp != 0) { + jfs_error(ip->i_sb, "xtTailgate: couldn't find extent"); + return -EIO; + } /* retrieve search result */ XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); /* entry found must be last entry */ nextindex = le16_to_cpu(p->header.nextindex); - assert(index == nextindex - 1); + if (index != nextindex - 1) { + XT_PUTPAGE(mp); + jfs_error(ip->i_sb, + "xtTailgate: the entry found is not the last entry"); + return -EIO; + } BT_MARK_DIRTY(mp, ip); /* @@ -1941,13 +1956,14 @@ int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad) nxoff = offsetXAD(nxad); nxlen = lengthXAD(nxad); nxaddr = addressXAD(nxad); -/* -printf("xtUpdate: nxflag:0x%x nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n", - nxad->flag, (ulong)nxoff, nxlen, (ulong)nxaddr); -*/ + if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT))) return rc; - assert(cmp == 0); + + if (cmp != 0) { + jfs_error(ip->i_sb, "xtUpdate: Could not find extent"); + return -EIO; + } /* retrieve search result */ XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0); @@ -1966,14 +1982,15 @@ printf("xtUpdate: nxflag:0x%x nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n", xoff = offsetXAD(xad); xlen = lengthXAD(xad); xaddr = addressXAD(xad); -/* -printf("xtUpdate: xflag:0x%x xoff:0x%lx xlen:0x%x xaddr:0x%lx\n", - xflag, (ulong)xoff, xlen, (ulong)xaddr); -*/ /* nXAD must be completely contained within XAD */ - assert(xoff <= nxoff); - assert(nxoff + nxlen <= xoff + xlen); + if ((xoff > nxoff) || + (nxoff + nxlen > xoff + xlen)) { + XT_PUTPAGE(mp); + jfs_error(ip->i_sb, + "xtUpdate: nXAD in not completely contained within XAD"); + return -EIO; + } index = index0; newindex = index + 1; @@ -2118,7 +2135,11 @@ printf("xtUpdate: xflag:0x%x xoff:0x%lx xlen:0x%x xaddr:0x%lx\n", } else if (xoff == nxoff) goto out; - assert(xoff < nxoff); + if (xoff >= nxoff) { + XT_PUTPAGE(mp); + jfs_error(ip->i_sb, "xtUpdate: xoff >= nxoff"); + return -EIO; + } /* #endif _JFS_WIP_COALESCE */ /* @@ -2135,9 +2156,6 @@ printf("xtUpdate: xflag:0x%x xoff:0x%lx xlen:0x%x xaddr:0x%lx\n", /* insert nXAD:recorded */ if (nextindex == le16_to_cpu(p->header.maxentry)) { -/* -printf("xtUpdate.updateRight.split p:0x%p\n", p); -*/ rootsplit = p->header.flag & BT_ROOT; /* xtSpliUp() unpins leaf pages */ @@ -2248,18 +2266,23 @@ printf("xtUpdate.updateRight.split p:0x%p\n", p); /* recompute split pages */ if (nextindex == le16_to_cpu(p->header.maxentry)) { -/* -printf("xtUpdate: updateRight+Left recompute split pages: p:0x%p\n", p); -*/ XT_PUTPAGE(mp); if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT))) return rc; - assert(cmp == 0); + if (cmp != 0) { + jfs_error(ip->i_sb, "xtUpdate: xtSearch failed"); + return -EIO; + } /* retrieve search result */ XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0); - assert(index0 == index); + if (index0 != index) { + XT_PUTPAGE(mp); + jfs_error(ip->i_sb, + "xtUpdate: unexpected value of index"); + return -EIO; + } } /* @@ -2755,6 +2778,7 @@ xtDeleteUp(tid_t tid, struct inode *ip, * txCommit() to commit all the allocation before call * this routine. */ +int xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad, /* old XAD */ s64 nxaddr, /* new xaddr */ int xtype) @@ -3925,7 +3949,11 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size) rc = xtSearch(ip, xoff, &cmp, &btstack, 0); if (rc) return rc; - assert(cmp == 0); + if (cmp != 0) { + jfs_error(ip->i_sb, + "xtTruncate_pmap: did not find extent"); + return -EIO; + } XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); } else { /* diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index f544943a7ebf2..c41d213e418b5 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -1,6 +1,6 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2002 - * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * Copyright (C) International Business Machines Corp., 2000-2003 + * Portions Copyright (C) Christoph Hellwig, 2001-2002 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ #include #include "jfs_incore.h" +#include "jfs_superblock.h" #include "jfs_inode.h" #include "jfs_dinode.h" #include "jfs_dmap.h" @@ -1138,7 +1139,17 @@ int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, new_ip->i_nlink--; if (S_ISDIR(new_ip->i_mode)) { new_ip->i_nlink--; - assert(new_ip->i_nlink == 0); + if (new_ip->i_nlink) { + up(&JFS_IP(new_dir)->commit_sem); + up(&JFS_IP(old_ip)->commit_sem); + if (old_dir != new_dir) + up(&JFS_IP(old_dir)->commit_sem); + if (!S_ISDIR(old_ip->i_mode) && new_ip) + IWRITE_UNLOCK(new_ip); + jfs_error(new_ip->i_sb, + "jfs_rename: new_ip->i_nlink != 0"); + return -EIO; + } tblk = tid_to_tblock(tid); tblk->xflag |= COMMIT_DELETE; tblk->ip = new_ip; diff --git a/fs/jfs/resize.c b/fs/jfs/resize.c index ba7cb585f545d..71f675356758f 100644 --- a/fs/jfs/resize.c +++ b/fs/jfs/resize.c @@ -1,5 +1,5 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2003 + * Copyright (C) International Business Machines Corp., 2000-2003 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -523,7 +523,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize) goto resume; error_out: - updateSuper(sb, FM_DIRTY); + jfs_error(sb, "jfs_extendfs"); resume: /* diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 9efcf7137290a..578a67b981554 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -1,6 +1,6 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2003 - * Portions Copyright (c) Christoph Hellwig, 2001-2002 + * Copyright (C) International Business Machines Corp., 2000-2003 + * Portions Copyright (C) Christoph Hellwig, 2001-2002 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -85,6 +85,42 @@ extern wait_queue_head_t jfs_IO_thread_wait; extern wait_queue_head_t jfs_commit_thread_wait; extern wait_queue_head_t jfs_sync_thread_wait; +static void jfs_handle_error(struct super_block *sb) +{ + struct jfs_sb_info *sbi = JFS_SBI(sb); + + if (sb->s_flags & MS_RDONLY) + return; + + updateSuper(sb, FM_DIRTY); + + if (sbi->flag & JFS_ERR_PANIC) + panic("JFS (device %s): panic forced after error\n", + sb->s_id); + else if (sbi->flag & JFS_ERR_REMOUNT_RO) { + jfs_err("ERROR: (device %s): remounting filesystem " + "as read-only\n", + sb->s_id); + sb->s_flags |= MS_RDONLY; + } + + /* nothing is done for continue beyond marking the superblock dirty */ +} + +void jfs_error(struct super_block *sb, const char * function, ...) +{ + static char error_buf[256]; + va_list args; + + va_start(args, function); + vsprintf(error_buf, function, args); + va_end(args); + + printk(KERN_ERR "ERROR: (device %s): %s\n", sb->s_id, error_buf); + + jfs_handle_error(sb); +} + static struct inode *jfs_alloc_inode(struct super_block *sb) { struct jfs_inode_info *jfs_inode; @@ -167,7 +203,7 @@ static void jfs_put_super(struct super_block *sb) enum { Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize, - Opt_ignore, Opt_err, + Opt_errors, Opt_ignore, Opt_err, }; static match_table_t tokens = { @@ -175,6 +211,7 @@ static match_table_t tokens = { {Opt_nointegrity, "nointegrity"}, {Opt_iocharset, "iocharset=%s"}, {Opt_resize, "resize=%u"}, + {Opt_errors, "errors=%s"}, {Opt_ignore, "noquota"}, {Opt_ignore, "quota"}, {Opt_ignore, "usrquota"}, @@ -234,6 +271,31 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, *newLVSize = simple_strtoull(resize, &resize, 0); break; } + case Opt_errors: + { + char *errors = args[0].from; + if (!errors || !*errors) + goto cleanup; + if (!strcmp(errors, "continue")) { + *flag &= ~JFS_ERR_REMOUNT_RO; + *flag &= ~JFS_ERR_PANIC; + *flag |= JFS_ERR_CONTINUE; + } else if (!strcmp(errors, "remount-ro")) { + *flag &= ~JFS_ERR_CONTINUE; + *flag &= ~JFS_ERR_PANIC; + *flag |= JFS_ERR_REMOUNT_RO; + } else if (!strcmp(errors, "panic")) { + *flag &= ~JFS_ERR_CONTINUE; + *flag &= ~JFS_ERR_REMOUNT_RO; + *flag |= JFS_ERR_PANIC; + } else { + printk(KERN_ERR + "JFS: %s is an invalid error handler\n", + errors); + goto cleanup; + } + break; + } default: printk("jfs: Unrecognized mount option \"%s\" " " or missing value\n", p); @@ -316,7 +378,9 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) memset(sbi, 0, sizeof (struct jfs_sb_info)); sb->s_fs_info = sbi; - flag = 0; + /* initialize the mount flag and determine the default error handler */ + flag = JFS_ERR_REMOUNT_RO; + if (!parse_options((char *) data, sb, &newLVSize, &flag)) { kfree(sbi); return -EINVAL; diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index ddcb7f7215cd8..7c4a6ecf39a68 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c @@ -1,6 +1,6 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2002 - * Copyright (c) Christoph Hellwig, 2002 + * Copyright (C) International Business Machines Corp., 2000-2003 + * Copyright (C) Christoph Hellwig, 2002 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +20,7 @@ #include #include #include "jfs_incore.h" +#include "jfs_superblock.h" #include "jfs_dmap.h" #include "jfs_debug.h" #include "jfs_dinode.h" @@ -381,7 +382,10 @@ static int ea_read(struct inode *ip, struct jfs_ea_list *ealist) return ea_read_inline(ip, ealist); nbytes = sizeDXD(&ji->ea); - assert(nbytes); + if (!nbytes) { + jfs_error(sb, "ea_read: nbytes is 0"); + return -EIO; + } /* * Figure out how many blocks were allocated when this EA list was @@ -477,7 +481,10 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size) } current_blocks = 0; } else { - assert(ji->ea.flag & DXD_EXTENT); + if (!(ji->ea.flag & DXD_EXTENT)) { + jfs_error(sb, "ea_get: invalid ea.flag)"); + return -EIO; + } current_blocks = (ea_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; } -- 2.53.0