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
......
This diff is collapsed.
/*
* 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);
......
/*
* 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 */
......
This diff is collapsed.
/*
* 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,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 {
/*
......
/*
* 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