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 ...@@ -32,6 +32,10 @@ integrity Default. Commit metadata changes to the journal. Use this
option to remount a volume where the nointegrity option was option to remount a volume where the nointegrity option was
previously specified in order to restore normal behavior. 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: JFS TODO list:
Plans for our near term development items 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 * 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 * it under the terms of the GNU General Public License as published by
...@@ -130,9 +130,8 @@ struct dtsplit { ...@@ -130,9 +130,8 @@ struct dtsplit {
if (((P)->header.nextindex > (((BN)==0)?DTROOTMAXSLOT:(P)->header.maxslot)) ||\ if (((P)->header.nextindex > (((BN)==0)?DTROOTMAXSLOT:(P)->header.maxslot)) ||\
((BN) && ((P)->header.maxslot > DTPAGEMAXSLOT)))\ ((BN) && ((P)->header.maxslot > DTPAGEMAXSLOT)))\
{\ {\
jfs_err("DT_GETPAGE: dtree page corrupt");\
BT_PUTPAGE(MP);\ BT_PUTPAGE(MP);\
updateSuper((IP)->i_sb, FM_DIRTY);\ jfs_error((IP)->i_sb, "DT_GETPAGE: dtree page corrupt");\
MP = NULL;\ MP = NULL;\
RC = -EIO;\ RC = -EIO;\
}\ }\
...@@ -768,8 +767,7 @@ int dtSearch(struct inode *ip, struct component_name * key, ino_t * data, ...@@ -768,8 +767,7 @@ int dtSearch(struct inode *ip, struct component_name * key, ino_t * data,
/* Something's corrupted, mark filesytem dirty so /* Something's corrupted, mark filesytem dirty so
* chkdsk will fix it. * chkdsk will fix it.
*/ */
jfs_err("stack overrun in dtSearch!"); jfs_error(sb, "stack overrun in dtSearch!");
updateSuper(sb, FM_DIRTY);
rc = -EIO; rc = -EIO;
goto out; goto out;
} }
...@@ -3204,11 +3202,12 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -3204,11 +3202,12 @@ int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
d_namleft -= len; d_namleft -= len;
/* Sanity Check */ /* Sanity Check */
if (d_namleft == 0) { if (d_namleft == 0) {
jfs_err("JFS:Dtree error: ino = " jfs_error(ip->i_sb,
"JFS:Dtree error: ino = "
"%ld, bn=%Ld, index = %d", "%ld, bn=%Ld, index = %d",
(long)ip->i_ino,(long long)bn, (long)ip->i_ino,
(long long)bn,
i); i);
updateSuper(ip->i_sb, FM_DIRTY);
goto skip_one; goto skip_one;
} }
len = min(d_namleft, DTSLOTDATALEN); 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 * 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 * it under the terms of the GNU General Public License as published by
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include "jfs_incore.h" #include "jfs_incore.h"
#include "jfs_superblock.h"
#include "jfs_dmap.h" #include "jfs_dmap.h"
#include "jfs_extent.h" #include "jfs_extent.h"
#include "jfs_debug.h" #include "jfs_debug.h"
...@@ -403,8 +404,10 @@ int extHint(struct inode *ip, s64 offset, xad_t * xp) ...@@ -403,8 +404,10 @@ int extHint(struct inode *ip, s64 offset, xad_t * xp)
*/ */
xp->flag &= XAD_NOTRECORDED; xp->flag &= XAD_NOTRECORDED;
assert(xadl.nxad == 1); if(xadl.nxad != 1 || lengthXAD(xp) != nbperpage) {
assert(lengthXAD(xp) == nbperpage); jfs_error(ip->i_sb, "extHint: corrupt xtree");
return -EIO;
}
return (0); 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 * 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 * it under the terms of the GNU General Public License as published by
...@@ -32,6 +32,11 @@ ...@@ -32,6 +32,11 @@
/* mount time flag to disable journaling to disk */ /* mount time flag to disable journaling to disk */
#define JFS_NOINTEGRITY 0x00000010 #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) */ /* platform option (conditional compilation) */
#define JFS_AIX 0x80000000 /* AIX support */ #define JFS_AIX 0x80000000 /* AIX support */
/* POSIX name/directory support */ /* POSIX name/directory support */
......
This diff is collapsed.
/* /*
* Copyright (c) International Business Machines Corp., 2000-2002 * Copyright (C) International Business Machines Corp., 2000-2003
* Portions Copyright (c) Christoph Hellwig, 2001-2002 * Portions Copyright (C) Christoph Hellwig, 2001-2002
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/mempool.h> #include <linux/mempool.h>
#include "jfs_incore.h" #include "jfs_incore.h"
#include "jfs_superblock.h"
#include "jfs_filsys.h" #include "jfs_filsys.h"
#include "jfs_metapage.h" #include "jfs_metapage.h"
#include "jfs_txnmgr.h" #include "jfs_txnmgr.h"
...@@ -233,14 +234,23 @@ struct metapage *__get_metapage(struct inode *inode, unsigned long lblock, ...@@ -233,14 +234,23 @@ struct metapage *__get_metapage(struct inode *inode, unsigned long lblock,
if (mp) { if (mp) {
page_found: page_found:
if (test_bit(META_discard, &mp->flag)) { if (test_bit(META_discard, &mp->flag)) {
assert(new); /* It's okay to reuse a discarded if (!new) {
* if we expect it to be empty spin_unlock(&meta_lock);
*/ jfs_error(inode->i_sb,
"__get_metapage: using a "
"discarded metapage");
return NULL;
}
clear_bit(META_discard, &mp->flag); clear_bit(META_discard, &mp->flag);
} }
mp->count++; mp->count++;
jfs_info("__get_metapage: found 0x%p, in hash", mp); 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); lock_metapage(mp);
spin_unlock(&meta_lock); spin_unlock(&meta_lock);
} else { } 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 * 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 * it under the terms of the GNU General Public License as published by
...@@ -108,5 +108,6 @@ struct jfs_superblock { ...@@ -108,5 +108,6 @@ struct jfs_superblock {
extern int readSuper(struct super_block *, struct buffer_head **); extern int readSuper(struct super_block *, struct buffer_head **);
extern int updateSuper(struct super_block *, uint); extern int updateSuper(struct super_block *, uint);
extern void jfs_error(struct super_block *, const char *, ...);
#endif /*_H_JFS_SUPERBLOCK */ #endif /*_H_JFS_SUPERBLOCK */
/* /*
* Copyright (c) International Business Machines Corp., 2000-2003 * Copyright (C) International Business Machines Corp., 2000-2003
* Portions Copyright (c) Christoph Hellwig, 2001-2002 * Portions Copyright (C) Christoph Hellwig, 2001-2002
* *
* This program is free software; you can redistribute it and/or modify * 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 * 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, ...@@ -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 is not itself logged, to prevent pageout of the map
* page before the log; * page before the log;
*/ */
assert(tlck->type & tlckFREE);
/* log LOG_NOREDOINOEXT of the freed inode extent for /* log LOG_NOREDOINOEXT of the freed inode extent for
* logredo() to start NoRedoPage filters, and to update * logredo() to start NoRedoPage filters, and to update
...@@ -2655,7 +2654,7 @@ void txAbort(tid_t tid, int dirty) ...@@ -2655,7 +2654,7 @@ void txAbort(tid_t tid, int dirty)
* mark filesystem dirty * mark filesystem dirty
*/ */
if (dirty) if (dirty)
updateSuper(tblk->sb, FM_DIRTY); jfs_error(tblk->sb, "txAbort");
return; return;
} }
...@@ -2714,7 +2713,7 @@ static void txAbortCommit(struct commit * cd) ...@@ -2714,7 +2713,7 @@ static void txAbortCommit(struct commit * cd)
/* /*
* mark filesystem dirty * 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 * 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 * it under the terms of the GNU General Public License as published by
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
#define XT_PAGE(IP, MP) BT_PAGE(IP, MP, xtpage_t, i_xtroot) #define XT_PAGE(IP, MP) BT_PAGE(IP, MP, xtpage_t, i_xtroot)
/* get page buffer for specified block address */ /* get page buffer for specified block address */
/* ToDo: Replace this ugly macro with a function */
#define XT_GETPAGE(IP, BN, MP, SIZE, P, RC)\ #define XT_GETPAGE(IP, BN, MP, SIZE, P, RC)\
{\ {\
BT_GETPAGE(IP, BN, MP, xtpage_t, SIZE, P, RC, i_xtroot)\ BT_GETPAGE(IP, BN, MP, xtpage_t, SIZE, P, RC, i_xtroot)\
...@@ -69,9 +70,8 @@ ...@@ -69,9 +70,8 @@
(le16_to_cpu((P)->header.nextindex) > le16_to_cpu((P)->header.maxentry)) ||\ (le16_to_cpu((P)->header.nextindex) > le16_to_cpu((P)->header.maxentry)) ||\
(le16_to_cpu((P)->header.maxentry) > (((BN)==0)?XTROOTMAXSLOT:PSIZE>>L2XTSLOTSIZE)))\ (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);\ BT_PUTPAGE(MP);\
updateSuper((IP)->i_sb, FM_DIRTY);\
MP = NULL;\ MP = NULL;\
RC = -EIO;\ RC = -EIO;\
}\ }\
...@@ -1611,14 +1611,21 @@ int xtExtend(tid_t tid, /* transaction id */ ...@@ -1611,14 +1611,21 @@ int xtExtend(tid_t tid, /* transaction id */
/* there must exist extent to be extended */ /* there must exist extent to be extended */
if ((rc = xtSearch(ip, xoff - 1, &cmp, &btstack, XT_INSERT))) if ((rc = xtSearch(ip, xoff - 1, &cmp, &btstack, XT_INSERT)))
return rc; return rc;
assert(cmp == 0); if (cmp != 0) {
jfs_error(ip->i_sb, "xtExtend: xtSearch did not find extent");
return -EIO;
}
/* retrieve search result */ /* retrieve search result */
XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
/* extension must be contiguous */ /* extension must be contiguous */
xad = &p->xad[index]; 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; * acquire a transaction lock on the leaf page;
...@@ -1771,14 +1778,22 @@ printf("xtTailgate: nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n", ...@@ -1771,14 +1778,22 @@ printf("xtTailgate: nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n",
/* there must exist extent to be tailgated */ /* there must exist extent to be tailgated */
if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT))) if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT)))
return rc; return rc;
assert(cmp == 0); if (cmp != 0) {
jfs_error(ip->i_sb, "xtTailgate: couldn't find extent");
return -EIO;
}
/* retrieve search result */ /* retrieve search result */
XT_GETSEARCH(ip, btstack.top, bn, mp, p, index); XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
/* entry found must be last entry */ /* entry found must be last entry */
nextindex = le16_to_cpu(p->header.nextindex); 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); BT_MARK_DIRTY(mp, ip);
/* /*
...@@ -1941,13 +1956,14 @@ int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad) ...@@ -1941,13 +1956,14 @@ int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad)
nxoff = offsetXAD(nxad); nxoff = offsetXAD(nxad);
nxlen = lengthXAD(nxad); nxlen = lengthXAD(nxad);
nxaddr = addressXAD(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))) if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT)))
return rc; return rc;
assert(cmp == 0);
if (cmp != 0) {
jfs_error(ip->i_sb, "xtUpdate: Could not find extent");
return -EIO;
}
/* retrieve search result */ /* retrieve search result */
XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0); 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", ...@@ -1966,14 +1982,15 @@ printf("xtUpdate: nxflag:0x%x nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n",
xoff = offsetXAD(xad); xoff = offsetXAD(xad);
xlen = lengthXAD(xad); xlen = lengthXAD(xad);
xaddr = addressXAD(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 */ /* nXAD must be completely contained within XAD */
assert(xoff <= nxoff); if ((xoff > nxoff) ||
assert(nxoff + nxlen <= xoff + xlen); (nxoff + nxlen > xoff + xlen)) {
XT_PUTPAGE(mp);
jfs_error(ip->i_sb,
"xtUpdate: nXAD in not completely contained within XAD");
return -EIO;
}
index = index0; index = index0;
newindex = index + 1; newindex = index + 1;
...@@ -2118,7 +2135,11 @@ printf("xtUpdate: xflag:0x%x xoff:0x%lx xlen:0x%x xaddr:0x%lx\n", ...@@ -2118,7 +2135,11 @@ printf("xtUpdate: xflag:0x%x xoff:0x%lx xlen:0x%x xaddr:0x%lx\n",
} else if (xoff == nxoff) } else if (xoff == nxoff)
goto out; 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 */ /* #endif _JFS_WIP_COALESCE */
/* /*
...@@ -2135,9 +2156,6 @@ printf("xtUpdate: xflag:0x%x xoff:0x%lx xlen:0x%x xaddr:0x%lx\n", ...@@ -2135,9 +2156,6 @@ printf("xtUpdate: xflag:0x%x xoff:0x%lx xlen:0x%x xaddr:0x%lx\n",
/* insert nXAD:recorded */ /* insert nXAD:recorded */
if (nextindex == le16_to_cpu(p->header.maxentry)) { if (nextindex == le16_to_cpu(p->header.maxentry)) {
/*
printf("xtUpdate.updateRight.split p:0x%p\n", p);
*/
rootsplit = p->header.flag & BT_ROOT; rootsplit = p->header.flag & BT_ROOT;
/* xtSpliUp() unpins leaf pages */ /* xtSpliUp() unpins leaf pages */
...@@ -2248,18 +2266,23 @@ printf("xtUpdate.updateRight.split p:0x%p\n", p); ...@@ -2248,18 +2266,23 @@ printf("xtUpdate.updateRight.split p:0x%p\n", p);
/* recompute split pages */ /* recompute split pages */
if (nextindex == le16_to_cpu(p->header.maxentry)) { if (nextindex == le16_to_cpu(p->header.maxentry)) {
/*
printf("xtUpdate: updateRight+Left recompute split pages: p:0x%p\n", p);
*/
XT_PUTPAGE(mp); XT_PUTPAGE(mp);
if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT))) if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT)))
return rc; return rc;
assert(cmp == 0); if (cmp != 0) {
jfs_error(ip->i_sb, "xtUpdate: xtSearch failed");
return -EIO;
}
/* retrieve search result */ /* retrieve search result */
XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0); 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, ...@@ -2755,6 +2778,7 @@ xtDeleteUp(tid_t tid, struct inode *ip,
* txCommit() to commit all the allocation before call * txCommit() to commit all the allocation before call
* this routine. * this routine.
*/ */
int
xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad, /* old XAD */ xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad, /* old XAD */
s64 nxaddr, /* new xaddr */ s64 nxaddr, /* new xaddr */
int xtype) int xtype)
...@@ -3925,7 +3949,11 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size) ...@@ -3925,7 +3949,11 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
rc = xtSearch(ip, xoff, &cmp, &btstack, 0); rc = xtSearch(ip, xoff, &cmp, &btstack, 0);
if (rc) if (rc)
return 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); XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
} else { } else {
/* /*
......
/* /*
* Copyright (c) International Business Machines Corp., 2000-2002 * Copyright (C) International Business Machines Corp., 2000-2003
* Portions Copyright (c) Christoph Hellwig, 2001-2002 * Portions Copyright (C) Christoph Hellwig, 2001-2002
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include "jfs_incore.h" #include "jfs_incore.h"
#include "jfs_superblock.h"
#include "jfs_inode.h" #include "jfs_inode.h"
#include "jfs_dinode.h" #include "jfs_dinode.h"
#include "jfs_dmap.h" #include "jfs_dmap.h"
...@@ -1138,7 +1139,17 @@ int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1138,7 +1139,17 @@ int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
new_ip->i_nlink--; new_ip->i_nlink--;
if (S_ISDIR(new_ip->i_mode)) { if (S_ISDIR(new_ip->i_mode)) {
new_ip->i_nlink--; 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 = tid_to_tblock(tid);
tblk->xflag |= COMMIT_DELETE; tblk->xflag |= COMMIT_DELETE;
tblk->ip = new_ip; 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 * 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 * 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) ...@@ -523,7 +523,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
goto resume; goto resume;
error_out: error_out:
updateSuper(sb, FM_DIRTY); jfs_error(sb, "jfs_extendfs");
resume: resume:
/* /*
......
/* /*
* Copyright (c) International Business Machines Corp., 2000-2003 * Copyright (C) International Business Machines Corp., 2000-2003
* Portions Copyright (c) Christoph Hellwig, 2001-2002 * Portions Copyright (C) Christoph Hellwig, 2001-2002
* *
* This program is free software; you can redistribute it and/or modify * 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 * 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; ...@@ -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_commit_thread_wait;
extern wait_queue_head_t jfs_sync_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) static struct inode *jfs_alloc_inode(struct super_block *sb)
{ {
struct jfs_inode_info *jfs_inode; struct jfs_inode_info *jfs_inode;
...@@ -167,7 +203,7 @@ static void jfs_put_super(struct super_block *sb) ...@@ -167,7 +203,7 @@ static void jfs_put_super(struct super_block *sb)
enum { enum {
Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize, Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize,
Opt_ignore, Opt_err, Opt_errors, Opt_ignore, Opt_err,
}; };
static match_table_t tokens = { static match_table_t tokens = {
...@@ -175,6 +211,7 @@ static match_table_t tokens = { ...@@ -175,6 +211,7 @@ static match_table_t tokens = {
{Opt_nointegrity, "nointegrity"}, {Opt_nointegrity, "nointegrity"},
{Opt_iocharset, "iocharset=%s"}, {Opt_iocharset, "iocharset=%s"},
{Opt_resize, "resize=%u"}, {Opt_resize, "resize=%u"},
{Opt_errors, "errors=%s"},
{Opt_ignore, "noquota"}, {Opt_ignore, "noquota"},
{Opt_ignore, "quota"}, {Opt_ignore, "quota"},
{Opt_ignore, "usrquota"}, {Opt_ignore, "usrquota"},
...@@ -234,6 +271,31 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, ...@@ -234,6 +271,31 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
*newLVSize = simple_strtoull(resize, &resize, 0); *newLVSize = simple_strtoull(resize, &resize, 0);
break; 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: default:
printk("jfs: Unrecognized mount option \"%s\" " printk("jfs: Unrecognized mount option \"%s\" "
" or missing value\n", p); " or missing value\n", p);
...@@ -316,7 +378,9 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -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)); memset(sbi, 0, sizeof (struct jfs_sb_info));
sb->s_fs_info = sbi; 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)) { if (!parse_options((char *) data, sb, &newLVSize, &flag)) {
kfree(sbi); kfree(sbi);
return -EINVAL; return -EINVAL;
......
/* /*
* Copyright (c) International Business Machines Corp., 2000-2002 * Copyright (C) International Business Machines Corp., 2000-2003
* Copyright (c) Christoph Hellwig, 2002 * Copyright (C) Christoph Hellwig, 2002
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/xattr.h> #include <linux/xattr.h>
#include "jfs_incore.h" #include "jfs_incore.h"
#include "jfs_superblock.h"
#include "jfs_dmap.h" #include "jfs_dmap.h"
#include "jfs_debug.h" #include "jfs_debug.h"
#include "jfs_dinode.h" #include "jfs_dinode.h"
...@@ -381,7 +382,10 @@ static int ea_read(struct inode *ip, struct jfs_ea_list *ealist) ...@@ -381,7 +382,10 @@ static int ea_read(struct inode *ip, struct jfs_ea_list *ealist)
return ea_read_inline(ip, ealist); return ea_read_inline(ip, ealist);
nbytes = sizeDXD(&ji->ea); 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 * 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) ...@@ -477,7 +481,10 @@ static int ea_get(struct inode *inode, struct ea_buffer *ea_buf, int min_size)
} }
current_blocks = 0; current_blocks = 0;
} else { } 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) >> current_blocks = (ea_size + sb->s_blocksize - 1) >>
sb->s_blocksize_bits; 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