Commit 6349fc5a authored by Dave Kleikamp's avatar Dave Kleikamp

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
parent 902df8e1
......@@ -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
......
/*
* 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 <linux/fs.h>
#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",
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;
......
/*
* 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 = "
jfs_error(ip->i_sb,
"JFS:Dtree error: ino = "
"%ld, bn=%Ld, index = %d",
(long)ip->i_ino,(long long)bn,
(long)ip->i_ino,
(long long)bn,
i);
updateSuper(ip->i_sb, FM_DIRTY);
goto skip_one;
}
len = min(d_namleft, DTSLOTDATALEN);
......
/*
* 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 <linux/fs.h>
#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);
}
......
/*
* 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 */
......
/*
* 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 "
jfs_error(ipimap->i_sb,
"diUpdatePMap: inode %ld not marked as "
"allocated in wmap!", inum);
updateSuper(ipimap->i_sb, FM_DIRTY);
}
if (!(le32_to_cpu(iagp->pmap[extno]) & mask)) {
jfs_err("diUpdatePMap: inode %ld not marked as "
jfs_error(ipimap->i_sb,
"diUpdatePMap: inode %ld not marked as "
"allocated in pmap!", inum);
updateSuper(ipimap->i_sb, FM_DIRTY);
}
/* 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;
}
......
/*
* 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 <linux/buffer_head.h>
#include <linux/mempool.h>
#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 {
......
/*
* 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 */
/*
* 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");
}
......
/*
* 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,6 +60,7 @@
#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)\
......@@ -69,9 +70,8 @@
(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");\
jfs_error((IP)->i_sb, "XT_GETPAGE: xtree page corrupt");\
BT_PUTPAGE(MP);\
updateSuper((IP)->i_sb, FM_DIRTY);\
MP = NULL;\
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 {
/*
......
/*
* 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 <linux/fs.h>
#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;
......
/*
* 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:
/*
......
/*
* 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;
......
/*
* 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 <linux/fs.h>
#include <linux/xattr.h>
#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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment