[Ocfs2-commits] mfasheh commits r2590 - in trunk: . fs/ocfs2
fs/ocfs2/cluster
svn-commits at oss.oracle.com
svn-commits at oss.oracle.com
Fri Sep 16 19:34:43 CDT 2005
Author: mfasheh
Signed-off-by: jlbec
Signed-off-by: zab
Date: 2005-09-16 19:34:40 -0500 (Fri, 16 Sep 2005)
New Revision: 2590
Modified:
trunk/README
trunk/fs/ocfs2/alloc.c
trunk/fs/ocfs2/buffer_head_io.c
trunk/fs/ocfs2/cluster/ocfs2_nodemanager.h
trunk/fs/ocfs2/dir.c
trunk/fs/ocfs2/dlmglue.c
trunk/fs/ocfs2/extent_map.c
trunk/fs/ocfs2/file.c
trunk/fs/ocfs2/inode.c
trunk/fs/ocfs2/journal.c
trunk/fs/ocfs2/journal.h
trunk/fs/ocfs2/localalloc.c
trunk/fs/ocfs2/namei.c
trunk/fs/ocfs2/ocfs2.h
trunk/fs/ocfs2/ocfs2_fs.h
trunk/fs/ocfs2/slot_map.c
trunk/fs/ocfs2/suballoc.c
trunk/fs/ocfs2/super.c
trunk/fs/ocfs2/super.h
Log:
* Merged revisions 2562:2589 from readonly-operation branch into trunk.
Signed-off-by: jlbec
Signed-off-by: zab
Modified: trunk/README
===================================================================
--- trunk/README 2005-09-17 00:08:28 UTC (rev 2589)
+++ trunk/README 2005-09-17 00:34:40 UTC (rev 2590)
@@ -48,3 +48,5 @@
barrier=1 This enables/disables barriers. barrier=0 disables it,
barrier=1 enables it.
+errors=remount-ro(*) Remount the filesystem read-only on an error.
+errors=panic Panic and halt the machine if an error occurs.
Modified: trunk/fs/ocfs2/alloc.c
===================================================================
--- trunk/fs/ocfs2/alloc.c 2005-09-17 00:08:28 UTC (rev 2589)
+++ trunk/fs/ocfs2/alloc.c 2005-09-17 00:34:40 UTC (rev 2590)
@@ -115,7 +115,11 @@
mlog_entry_void();
- OCFS2_BUG_ON_INVALID_DINODE(fe);
+ if (!OCFS2_IS_VALID_DINODE(fe)) {
+ OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe);
+ retval = -EIO;
+ goto bail;
+ }
if (fe->i_last_eb_blk) {
retval = ocfs2_read_block(osb, le64_to_cpu(fe->i_last_eb_blk),
@@ -307,7 +311,11 @@
for(i = 0; i < new_blocks; i++) {
bh = new_eb_bhs[i];
eb = (ocfs2_extent_block *) bh->b_data;
- OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+ if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+ OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+ status = -EIO;
+ goto bail;
+ }
eb_el = &eb->h_list;
status = ocfs2_journal_access(handle, inode, bh,
@@ -431,7 +439,12 @@
}
eb = (ocfs2_extent_block *) new_eb_bh->b_data;
- OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+ if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+ OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+ status = -EIO;
+ goto bail;
+ }
+
eb_el = &eb->h_list;
fe = (ocfs2_dinode *) fe_bh->b_data;
fe_el = &fe->id2.i_list;
@@ -549,7 +562,14 @@
i = 0;
while(el->l_tree_depth) {
next_free = le16_to_cpu(el->l_next_free_rec);
- OCFS2_BUG_ON_RO(next_free == 0);
+ if (next_free == 0) {
+ ocfs2_error(inode->i_sb,
+ "Dinode %"MLFu64" has a bad "
+ "extent list",
+ OCFS2_I(inode)->ip_blkno);
+ status = -EIO;
+ goto bail;
+ }
next_blkno = le64_to_cpu(el->l_recs[next_free - 1].e_blkno);
BUG_ON(i >= num_bhs);
@@ -560,7 +580,12 @@
goto bail;
}
eb = (ocfs2_extent_block *) eb_bhs[i]->b_data;
- OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+ if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+ OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb,
+ eb);
+ status = -EIO;
+ goto bail;
+ }
status = ocfs2_journal_access(handle, inode, eb_bhs[i],
OCFS2_JOURNAL_ACCESS_WRITE);
@@ -582,7 +607,14 @@
* bottom-most leaf in order to update it with the
* actual extent data below. */
next_free = le16_to_cpu(el->l_next_free_rec);
- OCFS2_BUG_ON_RO(next_free == 0);
+ if (next_free == 0) {
+ ocfs2_error(inode->i_sb,
+ "Dinode %"MLFu64" has a bad "
+ "extent list",
+ OCFS2_I(inode)->ip_blkno);
+ status = -EIO;
+ goto bail;
+ }
le32_add_cpu(&el->l_recs[next_free - 1].e_clusters,
new_clusters);
/* (num_bhs - 1) to avoid the leaf */
@@ -616,7 +648,15 @@
} else if (le16_to_cpu(el->l_next_free_rec) &&
(le32_to_cpu(el->l_recs[i].e_clusters) == 0)) {
/* having an empty extent at eof is legal. */
- OCFS2_BUG_ON_RO(el->l_recs[i].e_cpos != fe->i_clusters);
+ if (el->l_recs[i].e_cpos != fe->i_clusters) {
+ ocfs2_error(inode->i_sb,
+ "Dinode %"MLFu64" trailing extent is bad: "
+ "cpos (%u) != number of clusters (%u)",
+ le32_to_cpu(el->l_recs[i].e_cpos),
+ le32_to_cpu(fe->i_clusters));
+ status = -EIO;
+ goto bail;
+ }
el->l_recs[i].e_blkno = cpu_to_le64(start_blk);
el->l_recs[i].e_clusters = cpu_to_le32(new_clusters);
} else {
@@ -704,10 +744,23 @@
el = &fe->id2.i_list;
while(le16_to_cpu(el->l_tree_depth) > 1) {
- OCFS2_BUG_ON_RO(le16_to_cpu(el->l_next_free_rec) == 0);
+ if (le16_to_cpu(el->l_next_free_rec) == 0) {
+ ocfs2_error(inode->i_sb, "Dinode %"MLFu64" has empty "
+ "extent list (next_free_rec == 0)",
+ OCFS2_I(inode)->ip_blkno);
+ status = -EIO;
+ goto bail;
+ }
i = le16_to_cpu(el->l_next_free_rec) - 1;
blkno = le64_to_cpu(el->l_recs[i].e_blkno);
- OCFS2_BUG_ON_RO(!blkno);
+ if (!blkno) {
+ ocfs2_error(inode->i_sb, "Dinode %"MLFu64" has extent "
+ "list where extent # %d has no physical "
+ "block start",
+ OCFS2_I(inode)->ip_blkno, i);
+ status = -EIO;
+ goto bail;
+ }
if (bh) {
brelse(bh);
@@ -722,7 +775,11 @@
}
eb = (ocfs2_extent_block *) bh->b_data;
- OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+ if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+ OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+ status = -EIO;
+ goto bail;
+ }
el = &eb->h_list;
if (le16_to_cpu(el->l_next_free_rec) <
@@ -913,7 +970,12 @@
di = (ocfs2_dinode *) tl_bh->b_data;
tl = &di->id2.i_dealloc;
- OCFS2_BUG_ON_INVALID_DINODE(di);
+ if (!OCFS2_IS_VALID_DINODE(di)) {
+ OCFS2_RO_ON_INVALID_DINODE(osb->sb, di);
+ status = -EIO;
+ goto bail;
+ }
+
tl_count = le16_to_cpu(tl->tl_count);
mlog_bug_on_msg(tl_count > ocfs2_truncate_recs_per_inode(osb->sb) ||
tl_count == 0,
@@ -1063,7 +1125,11 @@
di = (ocfs2_dinode *) tl_bh->b_data;
tl = &di->id2.i_dealloc;
- OCFS2_BUG_ON_INVALID_DINODE(di);
+ if (!OCFS2_IS_VALID_DINODE(di)) {
+ OCFS2_RO_ON_INVALID_DINODE(osb->sb, di);
+ status = -EIO;
+ goto bail;
+ }
num_to_flush = le16_to_cpu(tl->tl_used);
mlog(0, "Flush %u records from truncate log #%"MLFu64"\n",
@@ -1097,8 +1163,9 @@
}
handle = ocfs2_start_trans(osb, handle, OCFS2_TRUNCATE_LOG_UPDATE);
- if (!handle) {
- status = -ENOMEM;
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
+ handle = NULL;
mlog_errno(status);
goto bail;
}
@@ -1224,7 +1291,11 @@
di = (ocfs2_dinode *) tl_bh->b_data;
tl = &di->id2.i_dealloc;
- OCFS2_BUG_ON_INVALID_DINODE(di);
+ if (!OCFS2_IS_VALID_DINODE(di)) {
+ OCFS2_RO_ON_INVALID_DINODE(tl_inode->i_sb, di);
+ status = -EIO;
+ goto bail;
+ }
if (le16_to_cpu(tl->tl_used)) {
mlog(0, "We'll have %u logs to recover\n",
@@ -1302,8 +1373,8 @@
handle = ocfs2_start_trans(osb, NULL,
OCFS2_TRUNCATE_LOG_UPDATE);
- if (!handle) {
- status = -ENOMEM;
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
mlog_errno(status);
goto bail_up;
}
@@ -1393,10 +1464,14 @@
ocfs2_extent_list *el;
struct buffer_head *bh = NULL;
- OCFS2_BUG_ON_INVALID_DINODE(fe);
-
*new_last_eb = NULL;
+ if (!OCFS2_IS_VALID_DINODE(fe)) {
+ OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe);
+ status = -EIO;
+ goto bail;
+ }
+
/* we have no tree, so of course, no last_eb. */
if (!fe->id2.i_list.l_tree_depth)
goto bail;
@@ -1443,7 +1518,11 @@
}
eb = (ocfs2_extent_block *) bh->b_data;
el = &eb->h_list;
- OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+ if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+ OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+ status = -EIO;
+ goto bail;
+ }
} while (el->l_tree_depth);
*new_last_eb = bh;
@@ -1574,7 +1653,11 @@
goto bail;
}
eb = (ocfs2_extent_block *)eb_bh->b_data;
- OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+ if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+ OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+ status = -EIO;
+ goto bail;
+ }
el = &(eb->h_list);
status = ocfs2_journal_access(handle, inode, eb_bh,
@@ -1738,7 +1821,11 @@
goto bail;
}
eb = (ocfs2_extent_block *) last_eb_bh->b_data;
- OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+ if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+ OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+ status = -EIO;
+ goto bail;
+ }
el = &(eb->h_list);
}
@@ -1770,8 +1857,9 @@
credits = ocfs2_calc_tree_trunc_credits(osb->sb, clusters_to_del,
fe, el);
handle = ocfs2_start_trans(osb, NULL, credits);
- if (!handle) {
- status = -ENOMEM;
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
+ handle = NULL;
mlog_errno(status);
goto bail;
}
@@ -1857,7 +1945,19 @@
mlog(0, "fe->i_clusters = %u, new_i_clusters = %u, fe->i_size ="
"%"MLFu64"\n", fe->i_clusters, new_i_clusters, fe->i_size);
- BUG_ON(le32_to_cpu(fe->i_clusters) <= new_i_clusters);
+ if (le32_to_cpu(fe->i_clusters) <= new_i_clusters) {
+ ocfs2_error(inode->i_sb, "Dinode %"MLFu64" has cluster count "
+ "%u and size %"MLFu64" whereas struct inode has "
+ "cluster count %u and size %llu which caused an "
+ "invalid truncate to %u clusters.",
+ le64_to_cpu(fe->i_blkno),
+ le32_to_cpu(fe->i_clusters),
+ le64_to_cpu(fe->i_size),
+ OCFS2_I(inode)->ip_clusters, i_size_read(inode),
+ new_i_clusters);
+ status = -EIO;
+ goto bail;
+ }
*tc = kcalloc(1, sizeof(struct ocfs2_truncate_context), GFP_KERNEL);
if (!(*tc)) {
@@ -1878,7 +1978,13 @@
goto bail;
}
eb = (ocfs2_extent_block *) last_eb_bh->b_data;
- OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+ if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+ OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+
+ brelse(last_eb_bh);
+ status = -EIO;
+ goto bail;
+ }
el = &(eb->h_list);
if (le32_to_cpu(el->l_recs[0].e_cpos) >= new_i_clusters)
metadata_delete = 1;
Modified: trunk/fs/ocfs2/buffer_head_io.c
===================================================================
--- trunk/fs/ocfs2/buffer_head_io.c 2005-09-17 00:08:28 UTC (rev 2589)
+++ trunk/fs/ocfs2/buffer_head_io.c 2005-09-17 00:34:40 UTC (rev 2590)
@@ -57,7 +57,6 @@
{
int status = 0;
int i;
- struct super_block *sb;
struct buffer_head *bh;
mlog_entry("(bh[0]->b_blocknr = %llu, nr=%d, inode=%p)\n",
@@ -69,7 +68,13 @@
goto bail;
}
- sb = osb->sb;
+ /* No need to check for a soft readonly file system here. non
+ * journalled writes are only ever done on system files which
+ * can get modified during recovery even if read-only. */
+ if (ocfs2_is_hard_readonly(osb)) {
+ status = -EROFS;
+ goto bail;
+ }
if (inode)
down(&OCFS2_I(inode)->ip_io_sem);
Modified: trunk/fs/ocfs2/cluster/ocfs2_nodemanager.h
===================================================================
--- trunk/fs/ocfs2/cluster/ocfs2_nodemanager.h 2005-09-17 00:08:28 UTC (rev 2589)
+++ trunk/fs/ocfs2/cluster/ocfs2_nodemanager.h 2005-09-17 00:34:40 UTC (rev 2590)
@@ -28,7 +28,7 @@
#ifndef _OCFS2_NODEMANAGER_H
#define _OCFS2_NODEMANAGER_H
-#define O2NM_API_VERSION 4
+#define O2NM_API_VERSION 5
#define O2NM_MAX_NODES 255
#define O2NM_INVALID_NODE_NUM 255
Modified: trunk/fs/ocfs2/dir.c
===================================================================
--- trunk/fs/ocfs2/dir.c 2005-09-17 00:08:28 UTC (rev 2589)
+++ trunk/fs/ocfs2/dir.c 2005-09-17 00:34:40 UTC (rev 2590)
@@ -451,8 +451,9 @@
}
handle = ocfs2_start_trans(osb, handle, credits);
- if (handle == NULL) {
- status = -ENOMEM;
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
+ handle = NULL;
mlog_errno(status);
goto bail;
}
Modified: trunk/fs/ocfs2/dlmglue.c
===================================================================
--- trunk/fs/ocfs2/dlmglue.c 2005-09-17 00:08:28 UTC (rev 2589)
+++ trunk/fs/ocfs2/dlmglue.c 2005-09-17 00:34:40 UTC (rev 2590)
@@ -49,6 +49,7 @@
#include "inode.h"
#include "journal.h"
#include "slot_map.h"
+#include "super.h"
#include "uptodate.h"
#include "vote.h"
@@ -1163,7 +1164,7 @@
int ocfs2_data_lock(struct inode *inode,
int write)
{
- int status, level;
+ int status = 0, level;
struct ocfs2_lock_res *lockres;
BUG_ON(!inode);
@@ -1174,6 +1175,16 @@
OCFS2_I(inode)->ip_blkno,
write ? "EXMODE" : "PRMODE");
+ /* We'll allow faking a readonly data lock for
+ * rodevices. */
+ if (ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb))) {
+ if (write) {
+ status = -EROFS;
+ mlog_errno(status);
+ }
+ goto out;
+ }
+
lockres = &OCFS2_I(inode)->ip_data_lockres;
level = write ? LKM_EXMODE : LKM_PRMODE;
@@ -1183,6 +1194,7 @@
if (status < 0)
mlog_errno(status);
+out:
mlog_exit(status);
return status;
}
@@ -1230,7 +1242,8 @@
OCFS2_I(inode)->ip_blkno,
write ? "EXMODE" : "PRMODE");
- ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level);
+ if (!ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb)))
+ ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level);
mlog_exit_void();
}
@@ -1508,7 +1521,11 @@
* node provides a guarantee that we receive that
* message and can mark the inode before dropping any
* locks associated with it. */
- OCFS2_BUG_ON_INVALID_DINODE(fe);
+ if (!OCFS2_IS_VALID_DINODE(fe)) {
+ OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe);
+ status = -EIO;
+ goto bail_refresh;
+ }
mlog_bug_on_msg(inode->i_generation !=
le32_to_cpu(fe->i_generation),
"Invalid dinode %"MLFu64" disk generation: %u "
@@ -1609,6 +1626,16 @@
OCFS2_I(inode)->ip_blkno,
ex ? "EXMODE" : "PRMODE");
+ status = 0;
+ acquired = 0;
+ /* We'll allow faking a readonly metadata lock for
+ * rodevices. */
+ if (ocfs2_is_hard_readonly(osb)) {
+ if (ex)
+ status = -EROFS;
+ goto bail;
+ }
+
if (!(flags & OCFS2_META_LOCK_RECOVERY))
wait_event(osb->recovery_event,
ocfs2_node_map_is_empty(osb, &osb->recovery_map));
@@ -1694,7 +1721,8 @@
OCFS2_I(inode)->ip_blkno,
ex ? "EXMODE" : "PRMODE");
- ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level);
+ if (!ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb)))
+ ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level);
mlog_exit_void();
}
@@ -1710,6 +1738,9 @@
mlog_entry_void();
+ if (ocfs2_is_hard_readonly(osb))
+ return -EROFS;
+
status = ocfs2_cluster_lock(osb, lockres, level, 0, NULL, 0);
if (status < 0) {
mlog_errno(status);
@@ -1756,6 +1787,9 @@
int status;
struct ocfs2_lock_res *lockres = &osb->osb_rename_lockres;
+ if (ocfs2_is_hard_readonly(osb))
+ return -EROFS;
+
status = ocfs2_cluster_lock(osb, lockres, LKM_EXMODE, 0, NULL, 0);
if (status < 0)
mlog_errno(status);
Modified: trunk/fs/ocfs2/extent_map.c
===================================================================
--- trunk/fs/ocfs2/extent_map.c 2005-09-17 00:08:28 UTC (rev 2589)
+++ trunk/fs/ocfs2/extent_map.c 2005-09-17 00:34:40 UTC (rev 2590)
@@ -36,6 +36,7 @@
#include "extent_map.h"
#include "inode.h"
+#include "super.h"
#include "buffer_head_io.h"
@@ -236,7 +237,11 @@
if (ret)
goto out_free;
eb = (ocfs2_extent_block *)eb_bh->b_data;
- OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+ if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+ OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+ ret = -EIO;
+ goto out_free;
+ }
el = &eb->h_list;
}
@@ -298,7 +303,11 @@
return ret;
}
eb = (ocfs2_extent_block *)bh->b_data;
- OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(eb);
+ if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+ OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+ brelse(bh);
+ return -EIO;
+ }
el = &eb->h_list;
} else {
spin_unlock(&OCFS2_I(inode)->ip_lock);
@@ -312,7 +321,11 @@
return ret;
}
di = (ocfs2_dinode *)bh->b_data;
- OCFS2_BUG_ON_INVALID_DINODE(di);
+ if (!OCFS2_IS_VALID_DINODE(di)) {
+ brelse(bh);
+ OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, di);
+ return -EIO;
+ }
el = &di->id2.i_list;
}
Modified: trunk/fs/ocfs2/file.c
===================================================================
--- trunk/fs/ocfs2/file.c 2005-09-17 00:08:28 UTC (rev 2589)
+++ trunk/fs/ocfs2/file.c 2005-09-17 00:34:40 UTC (rev 2590)
@@ -46,6 +46,7 @@
#include "journal.h"
#include "mmap.h"
#include "suballoc.h"
+#include "super.h"
#include "buffer_head_io.h"
@@ -433,30 +434,28 @@
u64 new_i_size)
{
int status;
- ocfs2_journal_handle *handle = NULL;
+ ocfs2_journal_handle *handle;
mlog_entry_void();
- /* TODO: This needs to actually orphen the inode in this
+ /* TODO: This needs to actually orphan the inode in this
* transaction. */
- handle = ocfs2_start_trans(osb, handle, OCFS2_INODE_UPDATE_CREDITS);
- if (handle == NULL) {
- status = -ENOMEM;
+ handle = ocfs2_start_trans(osb, NULL, OCFS2_INODE_UPDATE_CREDITS);
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
mlog_errno(status);
- goto bail;
+ goto out;
}
ocfs2_set_inode_lock_trans(osb->journal, inode);
status = ocfs2_set_inode_size(handle, inode, fe_bh, new_i_size);
- if (status < 0) {
+ if (status < 0)
mlog_errno(status);
- goto bail;
- }
-bail:
- if (handle)
- ocfs2_commit_trans(handle);
+
+ ocfs2_commit_trans(handle);
+out:
mlog_exit(status);
return status;
}
@@ -484,7 +483,11 @@
}
fe = (ocfs2_dinode *) fe_bh->b_data;
- OCFS2_BUG_ON_INVALID_DINODE(fe);
+ if (!OCFS2_IS_VALID_DINODE(fe)) {
+ OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe);
+ status = -EIO;
+ goto bail;
+ }
mlog_bug_on_msg(le64_to_cpu(fe->i_size) != i_size_read(inode),
"Inode %"MLFu64", inode i_size = %lld != di "
"i_size = %"MLFu64", i_flags = 0x%x\n",
@@ -517,8 +520,9 @@
* this truncate. */
handle = ocfs2_start_trans(osb, NULL,
OCFS2_INODE_UPDATE_CREDITS);
- if (handle == NULL) {
- status = -ENOMEM;
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
+ handle = NULL;
mlog_errno(status);
goto bail;
}
@@ -771,7 +775,11 @@
}
fe = (ocfs2_dinode *) bh->b_data;
- OCFS2_BUG_ON_INVALID_DINODE(fe);
+ if (!OCFS2_IS_VALID_DINODE(fe)) {
+ OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe);
+ status = -EIO;
+ goto leave;
+ }
BUG_ON(i_size_read(inode) !=
(le64_to_cpu(fe->i_size) - *bytes_extended));
BUG_ON(new_i_size < i_size_read(inode));
@@ -830,8 +838,9 @@
do_start_trans:
credits = ocfs2_calc_extend_credits(osb->sb, fe, clusters_to_add);
handle = ocfs2_start_trans(osb, handle, credits);
- if (handle == NULL) {
- status = -ENOMEM;
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
+ handle = NULL;
mlog_errno(status);
goto leave;
}
@@ -1065,7 +1074,8 @@
}
handle = ocfs2_start_trans(osb, NULL, OCFS2_INODE_UPDATE_CREDITS);
- if (handle == NULL) {
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
mlog_errno(status);
goto bail;
}
@@ -1081,18 +1091,16 @@
status = inode_setattr(inode, attr);
if (status < 0) {
mlog_errno(status);
- goto bail;
+ goto bail_commit;
}
status = ocfs2_mark_inode_dirty(handle, inode, bh);
- if (status < 0) {
+ if (status < 0)
mlog_errno(status);
- goto bail;
- }
+bail_commit:
+ ocfs2_commit_trans(handle);
bail:
- if (handle)
- ocfs2_commit_trans(handle);
if (unlock)
ocfs2_meta_unlock(inode, 1);
if (bh)
Modified: trunk/fs/ocfs2/inode.c
===================================================================
--- trunk/fs/ocfs2/inode.c 2005-09-17 00:08:28 UTC (rev 2589)
+++ trunk/fs/ocfs2/inode.c 2005-09-17 00:34:40 UTC (rev 2590)
@@ -428,8 +428,9 @@
goto bail;
handle = ocfs2_start_trans(osb, handle, OCFS2_INODE_UPDATE_CREDITS);
- if (handle == NULL) {
- status = -ENOMEM;
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
+ handle = NULL;
mlog_errno(status);
goto bail;
}
@@ -495,8 +496,8 @@
}
handle = ocfs2_start_trans(osb, NULL, OCFS2_DELETE_INODE_CREDITS);
- if (handle == NULL) {
- status = -ENOMEM;
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
mlog_errno(status);
goto bail_unlock;
}
Modified: trunk/fs/ocfs2/journal.c
===================================================================
--- trunk/fs/ocfs2/journal.c 2005-09-17 00:08:28 UTC (rev 2589)
+++ trunk/fs/ocfs2/journal.c 2005-09-17 00:34:40 UTC (rev 2590)
@@ -137,12 +137,13 @@
}
/* pass it NULL and it will allocate a new handle object for you. If
- * you pass it a handle however, it may still return NULL, in which
+ * you pass it a handle however, it may still return error, in which
* case it has free'd the passed handle for you. */
ocfs2_journal_handle *ocfs2_start_trans(ocfs2_super *osb,
ocfs2_journal_handle *handle,
int max_buffs)
{
+ int ret;
journal_t *journal = osb->journal->j_journal;
mlog_entry("(max_buffs = %d)\n", max_buffs);
@@ -150,6 +151,11 @@
if (!osb || !osb->journal->j_journal)
BUG();
+ if (ocfs2_is_hard_readonly(osb)) {
+ ret = -EROFS;
+ goto done_free;
+ }
+
BUG_ON(osb->journal->j_state == OCFS2_JOURNAL_FREE);
BUG_ON(max_buffs <= 0);
@@ -162,6 +168,7 @@
if (!handle)
handle = ocfs2_alloc_handle(osb);
if (!handle) {
+ ret = -ENOMEM;
mlog(ML_ERROR, "Failed to allocate memory for journal "
"handle!\n");
goto done_free;
@@ -176,9 +183,14 @@
if (IS_ERR(handle->k_handle)) {
up_read(&osb->journal->j_trans_barrier);
- mlog(ML_ERROR, "journal_start() failed!\n");
- mlog_errno((int)PTR_ERR(handle->k_handle));
+ ret = PTR_ERR(handle->k_handle);
handle->k_handle = NULL;
+ mlog_errno(ret);
+
+ if (is_journal_aborted(journal)) {
+ ocfs2_abort(osb->sb, "Detected aborted journal");
+ ret = -EROFS;
+ }
goto done_free;
}
@@ -189,12 +201,11 @@
return handle;
done_free:
-
if (handle)
ocfs2_commit_unstarted_handle(handle); /* will kfree handle */
- mlog_exit(NULL);
- return NULL;
+ mlog_exit(ret);
+ return ERR_PTR(ret);
}
void ocfs2_handle_add_inode(ocfs2_journal_handle *handle,
@@ -485,6 +496,19 @@
#define OCFS2_DEFAULT_COMMIT_INTERVAL (HZ * 5)
+void ocfs2_set_journal_params(ocfs2_super *osb)
+{
+ journal_t *journal = osb->journal->j_journal;
+
+ spin_lock(&journal->j_state_lock);
+ journal->j_commit_interval = OCFS2_DEFAULT_COMMIT_INTERVAL;
+ if (osb->s_mount_opt & OCFS2_MOUNT_BARRIER)
+ journal->j_flags |= JFS_BARRIER;
+ else
+ journal->j_flags &= ~JFS_BARRIER;
+ spin_unlock(&journal->j_state_lock);
+}
+
int ocfs2_journal_init(ocfs2_journal *journal, int *dirty)
{
int status = -1;
@@ -551,15 +575,7 @@
mlog(0, "Returned from journal_init_inode\n");
mlog(0, "j_journal->j_maxlen = %u\n", j_journal->j_maxlen);
- j_journal->j_commit_interval = OCFS2_DEFAULT_COMMIT_INTERVAL;
- spin_lock(&j_journal->j_state_lock);
- if (osb->s_mount_opt & OCFS2_MOUNT_BARRIER)
- j_journal->j_flags |= JFS_BARRIER;
- else
- j_journal->j_flags &= ~JFS_BARRIER;
- spin_unlock(&j_journal->j_state_lock);
-
*dirty = (le32_to_cpu(di->id1.journal1.ij_flags) &
OCFS2_JOURNAL_DIRTY_FL);
@@ -567,6 +583,8 @@
journal->j_inode = inode;
journal->j_bh = bh;
+ ocfs2_set_journal_params(osb);
+
journal->j_state = OCFS2_JOURNAL_LOADED;
status = 0;
@@ -598,7 +616,15 @@
mlog_entry_void();
fe = (ocfs2_dinode *)bh->b_data;
- OCFS2_BUG_ON_INVALID_DINODE(fe);
+ if (!OCFS2_IS_VALID_DINODE(fe)) {
+ /* This is called from startup/shutdown which will
+ * handle the errors in a specific manner, so no need
+ * to call ocfs2_error() here. */
+ mlog(ML_ERROR, "Journal dinode %"MLFu64" has invalid "
+ "signature: %.*s", fe->i_blkno, 7, fe->i_signature);
+ status = -EIO;
+ goto out;
+ }
flags = le32_to_cpu(fe->id1.journal1.ij_flags);
if (dirty)
@@ -611,6 +637,7 @@
if (status < 0)
mlog_errno(status);
+out:
mlog_exit(status);
return status;
}
@@ -692,10 +719,27 @@
mlog_exit_void();
}
+static void ocfs2_clear_journal_error(struct super_block *sb,
+ journal_t *journal,
+ int slot)
+{
+ int olderr;
+
+ olderr = journal_errno(journal);
+ if (olderr) {
+ mlog(ML_ERROR, "File system error %d recorded in "
+ "journal %u.\n", olderr, slot);
+ mlog(ML_ERROR, "File system on device %s needs checking.\n",
+ sb->s_id);
+
+ journal_ack_err(journal);
+ journal_clear_err(journal);
+ }
+}
+
int ocfs2_journal_load(ocfs2_journal *journal)
{
int status = 0;
- int olderr = 0;
ocfs2_super *osb;
mlog_entry_void();
@@ -711,12 +755,7 @@
goto done;
}
- olderr = journal_errno(journal->j_journal);
- if (olderr) {
- mlog(ML_ERROR, "last journal left error code %d\n", olderr);
- journal_ack_err(journal->j_journal);
- journal_clear_err(journal->j_journal);
- }
+ ocfs2_clear_journal_error(osb->sb, journal->j_journal, osb->slot_num);
status = ocfs2_journal_toggle_dirty(osb, 1);
if (status < 0) {
@@ -909,7 +948,6 @@
}
mlog(0, "Recovery completion\n");
-
mlog_exit_void();
}
@@ -962,6 +1000,8 @@
osb->slot_num,
osb->local_alloc_copy,
NULL);
+ ocfs2_schedule_truncate_log_flush(osb, 0);
+
osb->local_alloc_copy = NULL;
osb->dirty = 0;
}
@@ -1147,6 +1187,8 @@
goto done;
}
+ ocfs2_clear_journal_error(osb->sb, journal, slot_num);
+
/* wipe the journal */
mlog(0, "flushing the journal.\n");
journal_lock_updates(journal);
@@ -1182,7 +1224,6 @@
mlog_exit(status);
return status;
-
}
/*
@@ -1372,7 +1413,7 @@
if (!orphan_dir_inode) {
status = -ENOENT;
mlog_errno(status);
- goto bail;
+ goto out;
}
down(&orphan_dir_inode->i_sem);
@@ -1380,7 +1421,7 @@
if (status < 0) {
up(&orphan_dir_inode->i_sem);
mlog_errno(status);
- goto bail;
+ goto out;
}
have_disk_lock = 1;
@@ -1397,7 +1438,7 @@
if (bh)
brelse(bh);
mlog_errno(status);
- goto bail;
+ goto out;
}
local = 0;
@@ -1411,7 +1452,7 @@
status = -EINVAL;
mlog_errno(status);
brelse(bh);
- goto bail;
+ goto out;
}
local += le16_to_cpu(de->rec_len);
@@ -1483,7 +1524,7 @@
inode = iter;
}
-bail:
+out:
if (have_disk_lock)
ocfs2_meta_unlock(orphan_dir_inode, 0);
@@ -1545,3 +1586,50 @@
return 0;
}
+
+/* Look for a dirty journal without taking any cluster locks. Used for
+ * hard readonly access to determine whether the file system journals
+ * require recovery. */
+int ocfs2_check_journals_nolocks(ocfs2_super *osb)
+{
+ int ret = 0;
+ unsigned int slot;
+ struct buffer_head *di_bh;
+ ocfs2_dinode *di;
+ struct inode *journal = NULL;
+
+ for(slot = 0; slot < osb->max_slots; slot++) {
+ journal = ocfs2_get_system_file_inode(osb,
+ JOURNAL_SYSTEM_INODE,
+ slot);
+ if (!journal || is_bad_inode(journal)) {
+ ret = -EACCES;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ di_bh = NULL;
+ ret = ocfs2_read_block(osb, OCFS2_I(journal)->ip_blkno, &di_bh,
+ 0, journal);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ di = (ocfs2_dinode *) di_bh->b_data;
+
+ if (le32_to_cpu(di->id1.journal1.ij_flags) &
+ OCFS2_JOURNAL_DIRTY_FL)
+ ret = -EROFS;
+
+ brelse(di_bh);
+ if (ret)
+ break;
+ }
+
+out:
+ if (journal)
+ iput(journal);
+
+ return ret;
+}
Modified: trunk/fs/ocfs2/journal.h
===================================================================
--- trunk/fs/ocfs2/journal.h 2005-09-17 00:08:28 UTC (rev 2589)
+++ trunk/fs/ocfs2/journal.h 2005-09-17 00:34:40 UTC (rev 2590)
@@ -194,12 +194,14 @@
* event on.
* ocfs2_start_checkpoint - Kick the commit thread to do a checkpoint.
*/
+void ocfs2_set_journal_params(ocfs2_super *osb);
int ocfs2_journal_init(ocfs2_journal *journal,
int *dirty);
void ocfs2_journal_shutdown(struct _ocfs2_super *osb);
int ocfs2_journal_wipe(ocfs2_journal *journal,
int full);
int ocfs2_journal_load(ocfs2_journal *journal);
+int ocfs2_check_journals_nolocks(ocfs2_super *osb);
void ocfs2_recovery_thread(struct _ocfs2_super *osb,
int node_num);
int ocfs2_mark_dead_nodes(ocfs2_super *osb);
Modified: trunk/fs/ocfs2/localalloc.c
===================================================================
--- trunk/fs/ocfs2/localalloc.c 2005-09-17 00:08:28 UTC (rev 2589)
+++ trunk/fs/ocfs2/localalloc.c 2005-09-17 00:34:40 UTC (rev 2590)
@@ -40,6 +40,7 @@
#include "journal.h"
#include "localalloc.h"
#include "suballoc.h"
+#include "super.h"
#include "sysfile.h"
#include "buffer_head_io.h"
@@ -245,8 +246,9 @@
/* WINDOW_MOVE_CREDITS is a bit heavy... */
handle = ocfs2_start_trans(osb, handle, OCFS2_WINDOW_MOVE_CREDITS);
- if (!handle) {
- mlog_errno(-ENOMEM);
+ if (IS_ERR(handle)) {
+ mlog_errno(PTR_ERR(handle));
+ handle = NULL;
goto bail;
}
@@ -413,8 +415,9 @@
}
handle = ocfs2_start_trans(osb, handle, OCFS2_WINDOW_MOVE_CREDITS);
- if (!handle) {
- status = -ENOMEM;
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
+ handle = NULL;
mlog_errno(status);
goto bail;
}
@@ -488,8 +491,16 @@
alloc = (ocfs2_dinode *) osb->local_alloc_bh->b_data;
- OCFS2_BUG_ON_RO(le32_to_cpu(alloc->id1.bitmap1.i_used) !=
- ocfs2_local_alloc_count_bits(alloc));
+ if (le32_to_cpu(alloc->id1.bitmap1.i_used) !=
+ ocfs2_local_alloc_count_bits(alloc)) {
+ ocfs2_error(osb->sb, "local alloc inode %"MLFu64" says it has "
+ "%u free bits, but a count shows %u",
+ le64_to_cpu(alloc->i_blkno),
+ le32_to_cpu(alloc->id1.bitmap1.i_used),
+ ocfs2_local_alloc_count_bits(alloc));
+ status = -EIO;
+ goto bail;
+ }
free_bits = le32_to_cpu(alloc->id1.bitmap1.i_total) -
le32_to_cpu(alloc->id1.bitmap1.i_used);
@@ -895,8 +906,9 @@
}
handle = ocfs2_start_trans(osb, handle, OCFS2_WINDOW_MOVE_CREDITS);
- if (!handle) {
- status = -ENOMEM;
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
+ handle = NULL;
mlog_errno(status);
goto bail;
}
Modified: trunk/fs/ocfs2/namei.c
===================================================================
--- trunk/fs/ocfs2/namei.c 2005-09-17 00:08:28 UTC (rev 2589)
+++ trunk/fs/ocfs2/namei.c 2005-09-17 00:34:40 UTC (rev 2590)
@@ -369,8 +369,9 @@
}
handle = ocfs2_start_trans(osb, handle, OCFS2_MKNOD_CREDITS);
- if (handle == NULL) {
- status = -ENOMEM;
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
+ handle = NULL;
mlog_errno(status);
goto leave;
}
@@ -496,9 +497,9 @@
else
inode->i_nlink = 1;
inode->i_mode = mode;
- spin_lock(&osb->s_next_gen_lock);
+ spin_lock(&osb->osb_lock);
inode->i_generation = osb->s_next_generation++;
- spin_unlock(&osb->s_next_gen_lock);
+ spin_unlock(&osb->osb_lock);
*new_fe_bh = sb_getblk(osb->sb, fe_blkno);
if (!*new_fe_bh) {
@@ -683,8 +684,10 @@
}
handle = ocfs2_start_trans(osb, handle, OCFS2_LINK_CREDITS);
- if (handle == NULL) {
- err = -ENOMEM;
+ if (IS_ERR(handle)) {
+ err = PTR_ERR(handle);
+ handle = NULL;
+ mlog_errno(err);
goto bail;
}
@@ -846,8 +849,9 @@
}
handle = ocfs2_start_trans(osb, handle, OCFS2_UNLINK_CREDITS);
- if (handle == NULL) {
- status = -ENOMEM;
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
+ handle = NULL;
mlog_errno(status);
goto leave;
}
@@ -1243,8 +1247,9 @@
}
handle = ocfs2_start_trans(osb, handle, OCFS2_RENAME_CREDITS);
- if (handle == NULL) {
- status = -ENOMEM;
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
+ handle = NULL;
mlog_errno(status);
goto bail;
}
@@ -1600,8 +1605,9 @@
}
handle = ocfs2_start_trans(osb, handle, credits);
- if (handle == NULL) {
- status = -ENOMEM;
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
+ handle = NULL;
mlog_errno(status);
goto bail;
}
Modified: trunk/fs/ocfs2/ocfs2.h
===================================================================
--- trunk/fs/ocfs2/ocfs2.h 2005-09-17 00:08:28 UTC (rev 2589)
+++ trunk/fs/ocfs2/ocfs2.h 2005-09-17 00:34:40 UTC (rev 2590)
@@ -171,14 +171,19 @@
enum ocfs2_mount_options
{
- OCFS2_MOUNT_HB_OK = 1 << 0, /* Heartbeat started */
+ OCFS2_MOUNT_HB_LOCAL = 1 << 0, /* Heartbeat started in local mode */
OCFS2_MOUNT_BARRIER = 1 << 1, /* Use block barriers */
OCFS2_MOUNT_NOINTR = 1 << 2, /* Don't catch signals */
+ OCFS2_MOUNT_ERRORS_PANIC = 1 << 3, /* Panic on errors */
#ifdef OCFS2_ORACORE_WORKAROUNDS
OCFS2_MOUNT_COMPAT_OCFS = 1 << 30, /* ocfs1 compatibility mode */
#endif
};
+#define OCFS2_OSB_SOFT_RO 0x0001
+#define OCFS2_OSB_HARD_RO 0x0002
+#define OCFS2_OSB_ERROR_FS 0x0004
+
struct _ocfs2_journal;
typedef struct _ocfs2_journal_handle ocfs2_journal_handle;
@@ -213,8 +218,11 @@
u32 s_feature_incompat;
u32 s_feature_ro_compat;
- spinlock_t s_next_gen_lock;
+ /* Protects s_next_generaion, osb_flags. Could protect more on
+ * osb as it's very short lived. */
+ spinlock_t osb_lock;
u32 s_next_generation;
+ unsigned long osb_flags;
unsigned long s_mount_opt;
@@ -292,38 +300,83 @@
#define OCFS2_SB(sb) ((ocfs2_super *)(sb)->s_fs_info)
#define OCFS2_MAX_OSB_ID 65536
-/* Helps document which BUG's should really just force the file system
- * to go readonly */
-#define OCFS2_BUG_ON_RO(x) BUG_ON((x))
+/* set / clear functions because cluster events can make these happen
+ * in parallel so we want the transitions to be atomic. this also
+ * means that any future flags osb_flags must be protected by spinlock
+ * too! */
+static inline void ocfs2_set_osb_flag(ocfs2_super *osb,
+ unsigned long flag)
+{
+ spin_lock(&osb->osb_lock);
+ osb->osb_flags |= flag;
+ spin_unlock(&osb->osb_lock);
+}
+static inline void ocfs2_set_ro_flag(ocfs2_super *osb,
+ int hard)
+{
+ spin_lock(&osb->osb_lock);
+ osb->osb_flags &= ~(OCFS2_OSB_SOFT_RO|OCFS2_OSB_HARD_RO);
+ if (hard)
+ osb->osb_flags |= OCFS2_OSB_HARD_RO;
+ else
+ osb->osb_flags |= OCFS2_OSB_SOFT_RO;
+ spin_unlock(&osb->osb_lock);
+}
+
+static inline int ocfs2_is_hard_readonly(ocfs2_super *osb)
+{
+ int ret;
+
+ spin_lock(&osb->osb_lock);
+ ret = osb->osb_flags & OCFS2_OSB_HARD_RO;
+ spin_unlock(&osb->osb_lock);
+
+ return ret;
+}
+
+static inline int ocfs2_is_soft_readonly(ocfs2_super *osb)
+{
+ int ret;
+
+ spin_lock(&osb->osb_lock);
+ ret = osb->osb_flags & OCFS2_OSB_SOFT_RO;
+ spin_unlock(&osb->osb_lock);
+
+ return ret;
+}
+
#define OCFS2_IS_VALID_DINODE(ptr) \
(!strcmp((ptr)->i_signature, OCFS2_INODE_SIGNATURE))
-#define OCFS2_BUG_ON_INVALID_DINODE(__di) do { \
- mlog_bug_on_msg(!OCFS2_IS_VALID_DINODE((__di)), \
- "Dinode # %"MLFu64" has bad signature %.*s\n", \
- (__di)->i_blkno, 7, \
- (__di)->i_signature); \
+#define OCFS2_RO_ON_INVALID_DINODE(__sb, __di) do { \
+ typeof(__di) ____di = (__di); \
+ ocfs2_error((__sb), \
+ "Dinode # %"MLFu64" has bad signature %.*s", \
+ (____di)->i_blkno, 7, \
+ (____di)->i_signature); \
} while (0);
#define OCFS2_IS_VALID_EXTENT_BLOCK(ptr) \
(!strcmp((ptr)->h_signature, OCFS2_EXTENT_BLOCK_SIGNATURE))
-#define OCFS2_BUG_ON_INVALID_EXTENT_BLOCK(__eb) do { \
- mlog_bug_on_msg(!OCFS2_IS_VALID_EXTENT_BLOCK((__eb)), \
- "Extent Block # %"MLFu64" has bad signature %.*s\n", \
- (__eb)->h_blkno, 7, \
- (__eb)->h_signature); \
+#define OCFS2_RO_ON_INVALID_EXTENT_BLOCK(__sb, __eb) do { \
+ typeof(__eb) ____eb = (__eb); \
+ ocfs2_error((__sb), \
+ "Extent Block # %"MLFu64" has bad signature %.*s", \
+ (____eb)->h_blkno, 7, \
+ (____eb)->h_signature); \
} while (0);
#define OCFS2_IS_VALID_GROUP_DESC(ptr) \
(!strcmp((ptr)->bg_signature, OCFS2_GROUP_DESC_SIGNATURE))
-#define OCFS2_BUG_ON_INVALID_GROUP_DESC(__gd) do { \
- mlog_bug_on_msg(!OCFS2_IS_VALID_GROUP_DESC((__gd)), \
- "Group Descriptor # %"MLFu64" has bad signature %.*s\n",\
- (__gd)->bg_blkno, 7, \
- (__gd)->bg_signature); \
+#define OCFS2_RO_ON_INVALID_GROUP_DESC(__sb, __gd) do { \
+ typeof(__gd) ____gd = (__gd); \
+ ocfs2_error((__sb), \
+ "Group Descriptor # %"MLFu64" has bad signature %.*s", \
+ (____gd)->bg_blkno, 7, \
+ (____gd)->bg_signature); \
} while (0);
static inline unsigned long ino_from_blkno(struct super_block *sb,
Modified: trunk/fs/ocfs2/ocfs2_fs.h
===================================================================
--- trunk/fs/ocfs2/ocfs2_fs.h 2005-09-17 00:08:28 UTC (rev 2589)
+++ trunk/fs/ocfs2/ocfs2_fs.h 2005-09-17 00:34:40 UTC (rev 2590)
@@ -185,7 +185,8 @@
};
/* Parameter passed from mount.ocfs2 to module */
-#define OCFS2_HB_OK "hbok"
+#define OCFS2_HB_NONE "heartbeat=none"
+#define OCFS2_HB_LOCAL "heartbeat=local"
/*
* OCFS2 directory file types. Only the low 3 bits are used. The
Modified: trunk/fs/ocfs2/slot_map.c
===================================================================
--- trunk/fs/ocfs2/slot_map.c 2005-09-17 00:08:28 UTC (rev 2589)
+++ trunk/fs/ocfs2/slot_map.c 2005-09-17 00:34:40 UTC (rev 2590)
@@ -38,6 +38,7 @@
#include "heartbeat.h"
#include "inode.h"
#include "slot_map.h"
+#include "super.h"
#include "sysfile.h"
#include "buffer_head_io.h"
Modified: trunk/fs/ocfs2/suballoc.c
===================================================================
--- trunk/fs/ocfs2/suballoc.c 2005-09-17 00:08:28 UTC (rev 2589)
+++ trunk/fs/ocfs2/suballoc.c 2005-09-17 00:34:40 UTC (rev 2590)
@@ -40,6 +40,7 @@
#include "journal.h"
#include "localalloc.h"
#include "suballoc.h"
+#include "super.h"
#include "sysfile.h"
#include "uptodate.h"
@@ -155,7 +156,13 @@
mlog_entry_void();
- OCFS2_BUG_ON_RO(((unsigned long long) bg_bh->b_blocknr) != group_blkno);
+ if (((unsigned long long) bg_bh->b_blocknr) != group_blkno) {
+ ocfs2_error(alloc_inode->i_sb, "group block (%"MLFu64") "
+ "!= b_blocknr (%llu)", group_blkno,
+ (unsigned long long) bg_bh->b_blocknr);
+ status = -EIO;
+ goto bail;
+ }
status = ocfs2_journal_access(handle,
alloc_inode,
@@ -250,8 +257,9 @@
credits = ocfs2_calc_group_alloc_credits(osb->sb,
le16_to_cpu(cl->cl_cpg));
handle = ocfs2_start_trans(osb, handle, credits);
- if (!handle) {
- status = -ENOMEM;
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
+ handle = NULL;
mlog_errno(status);
goto bail;
}
@@ -368,8 +376,17 @@
}
fe = (ocfs2_dinode *) bh->b_data;
- OCFS2_BUG_ON_INVALID_DINODE(fe);
- OCFS2_BUG_ON_RO(!(fe->i_flags & cpu_to_le32(OCFS2_CHAIN_FL)));
+ if (!OCFS2_IS_VALID_DINODE(fe)) {
+ OCFS2_RO_ON_INVALID_DINODE(alloc_inode->i_sb, fe);
+ status = -EIO;
+ goto bail;
+ }
+ if (!(fe->i_flags & cpu_to_le32(OCFS2_CHAIN_FL))) {
+ ocfs2_error(alloc_inode->i_sb, "Invalid chain allocator "
+ "# %"MLFu64, le64_to_cpu(fe->i_blkno));
+ status = -EIO;
+ goto bail;
+ }
free_bits = le32_to_cpu(fe->id1.bitmap1.i_total) -
le32_to_cpu(fe->id1.bitmap1.i_used);
@@ -653,7 +670,10 @@
int offset, start, found, status = 0;
ocfs2_group_desc *bg = (ocfs2_group_desc *) bg_bh->b_data;
- OCFS2_BUG_ON_INVALID_GROUP_DESC(bg);
+ if (!OCFS2_IS_VALID_GROUP_DESC(bg)) {
+ OCFS2_RO_ON_INVALID_GROUP_DESC(osb->sb, bg);
+ return -EIO;
+ }
found = start = best_offset = best_size = 0;
bitmap = bg->bg_bitmap;
@@ -720,7 +740,11 @@
mlog_entry_void();
- OCFS2_BUG_ON_INVALID_GROUP_DESC(bg);
+ if (!OCFS2_IS_VALID_GROUP_DESC(bg)) {
+ OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, bg);
+ status = -EIO;
+ goto bail;
+ }
BUG_ON(le16_to_cpu(bg->bg_free_bits_count) < num_bits);
mlog(0, "block_group_set_bits: off = %u, num = %u\n", bit_off,
@@ -789,9 +813,21 @@
ocfs2_group_desc *bg = (ocfs2_group_desc *) bg_bh->b_data;
ocfs2_group_desc *prev_bg = (ocfs2_group_desc *) prev_bg_bh->b_data;
- OCFS2_BUG_ON_INVALID_DINODE(fe);
- OCFS2_BUG_ON_INVALID_GROUP_DESC(bg);
- OCFS2_BUG_ON_INVALID_GROUP_DESC(prev_bg);
+ if (!OCFS2_IS_VALID_DINODE(fe)) {
+ OCFS2_RO_ON_INVALID_DINODE(alloc_inode->i_sb, fe);
+ status = -EIO;
+ goto out;
+ }
+ if (!OCFS2_IS_VALID_GROUP_DESC(bg)) {
+ OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, bg);
+ status = -EIO;
+ goto out;
+ }
+ if (!OCFS2_IS_VALID_GROUP_DESC(prev_bg)) {
+ OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, prev_bg);
+ status = -EIO;
+ goto out;
+ }
mlog(0, "In suballoc %"MLFu64", chain %u, move group %"MLFu64" to "
"top, prev = %"MLFu64"\n",
@@ -805,7 +841,7 @@
OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) {
mlog_errno(status);
- goto bail;
+ goto out_rollback;
}
prev_bg->bg_next_group = bg->bg_next_group;
@@ -813,14 +849,14 @@
status = ocfs2_journal_dirty(handle, prev_bg_bh);
if (status < 0) {
mlog_errno(status);
- goto bail;
+ goto out_rollback;
}
status = ocfs2_journal_access(handle, alloc_inode, bg_bh,
OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) {
mlog_errno(status);
- goto bail;
+ goto out_rollback;
}
bg->bg_next_group = fe->id2.i_chain.cl_recs[chain].c_blkno;
@@ -828,14 +864,14 @@
status = ocfs2_journal_dirty(handle, bg_bh);
if (status < 0) {
mlog_errno(status);
- goto bail;
+ goto out_rollback;
}
status = ocfs2_journal_access(handle, alloc_inode, fe_bh,
OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) {
mlog_errno(status);
- goto bail;
+ goto out_rollback;
}
fe->id2.i_chain.cl_recs[chain].c_blkno = bg->bg_blkno;
@@ -843,17 +879,17 @@
status = ocfs2_journal_dirty(handle, fe_bh);
if (status < 0) {
mlog_errno(status);
- goto bail;
+ goto out_rollback;
}
status = 0;
-bail:
+out_rollback:
if (status < 0) {
fe->id2.i_chain.cl_recs[chain].c_blkno = cpu_to_le64(fe_ptr);
bg->bg_next_group = cpu_to_le64(bg_ptr);
prev_bg->bg_next_group = cpu_to_le64(prev_bg_ptr);
}
-
+out:
mlog_exit(status);
return status;
}
@@ -882,12 +918,17 @@
ret = ocfs2_block_group_find_clear_bits(OCFS2_SB(inode->i_sb),
group_bh, bits_wanted,
&tmp_off, &tmp_found);
- if (!ret) {
- if (min_bits <= tmp_found) {
- *bit_off = tmp_off;
- *bits_found = tmp_found;
- search = 0; /* success */
- }
+ if (ret)
+ return ret;
+
+ /* ocfs2_block_group_find_clear_bits() might
+ * return success, but we still want to return
+ * -ENOSPC unless it found the minimum number
+ * of bits. */
+ if (min_bits <= tmp_found) {
+ *bit_off = tmp_off;
+ *bits_found = tmp_found;
+ search = 0; /* success */
}
}
@@ -944,7 +985,11 @@
goto bail;
}
bg = (ocfs2_group_desc *) group_bh->b_data;
- OCFS2_BUG_ON_INVALID_GROUP_DESC(bg);
+ if (!OCFS2_IS_VALID_GROUP_DESC(bg)) {
+ OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, bg);
+ status = -EIO;
+ goto bail;
+ }
status = -ENOSPC;
/* for now, the chain search is a bit simplistic. We just use
@@ -970,7 +1015,11 @@
goto bail;
}
bg = (ocfs2_group_desc *) group_bh->b_data;
- OCFS2_BUG_ON_INVALID_GROUP_DESC(bg);
+ if (!OCFS2_IS_VALID_GROUP_DESC(bg)) {
+ OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, bg);
+ status = -EIO;
+ goto bail;
+ }
}
if (status < 0) {
if (status != -ENOSPC)
@@ -1078,9 +1127,21 @@
BUG_ON(!ac->ac_bh);
fe = (ocfs2_dinode *) ac->ac_bh->b_data;
- OCFS2_BUG_ON_INVALID_DINODE(fe);
- OCFS2_BUG_ON_RO(le32_to_cpu(fe->id1.bitmap1.i_used) >=
- le32_to_cpu(fe->id1.bitmap1.i_total));
+ if (!OCFS2_IS_VALID_DINODE(fe)) {
+ OCFS2_RO_ON_INVALID_DINODE(osb->sb, fe);
+ status = -EIO;
+ goto bail;
+ }
+ if (le32_to_cpu(fe->id1.bitmap1.i_used) >=
+ le32_to_cpu(fe->id1.bitmap1.i_total)) {
+ ocfs2_error(osb->sb, "Chain allocator dinode %"MLFu64" has %u"
+ "used bits but only %u total.",
+ le64_to_cpu(fe->i_blkno),
+ le32_to_cpu(fe->id1.bitmap1.i_used),
+ le32_to_cpu(fe->id1.bitmap1.i_total));
+ status = -EIO;
+ goto bail;
+ }
cl = (ocfs2_chain_list *) &fe->id2.i_chain;
@@ -1353,7 +1414,11 @@
mlog_entry_void();
- OCFS2_BUG_ON_INVALID_GROUP_DESC(bg);
+ if (!OCFS2_IS_VALID_GROUP_DESC(bg)) {
+ OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, bg);
+ status = -EIO;
+ goto bail;
+ }
mlog(0, "off = %u, num = %u\n", bit_off, num_bits);
@@ -1407,11 +1472,15 @@
mlog_entry_void();
- OCFS2_BUG_ON_INVALID_DINODE(fe);
+ if (!OCFS2_IS_VALID_DINODE(fe)) {
+ OCFS2_RO_ON_INVALID_DINODE(alloc_inode->i_sb, fe);
+ status = -EIO;
+ goto bail;
+ }
BUG_ON((count + start_bit) > ocfs2_bits_per_group(cl));
mlog(0, "suballocator %"MLFu64": freeing %u bits from group %"MLFu64
- ", starting at %u\n",
+ ", starting at %u\n",
OCFS2_I(alloc_inode)->ip_blkno, count, bg_blkno,
start_bit);
@@ -1423,7 +1492,11 @@
}
group = (ocfs2_group_desc *) group_bh->b_data;
- OCFS2_BUG_ON_INVALID_GROUP_DESC(group);
+ if (!OCFS2_IS_VALID_GROUP_DESC(group)) {
+ OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, group);
+ status = -EIO;
+ goto bail;
+ }
BUG_ON((count + start_bit) > le16_to_cpu(group->bg_bits));
status = ocfs2_block_group_clear_bits(handle, alloc_inode,
Modified: trunk/fs/ocfs2/super.c
===================================================================
--- trunk/fs/ocfs2/super.c 2005-09-17 00:08:28 UTC (rev 2589)
+++ trunk/fs/ocfs2/super.c 2005-09-17 00:34:40 UTC (rev 2590)
@@ -89,9 +89,11 @@
MODULE_AUTHOR("Oracle");
MODULE_LICENSE("GPL");
-static int ocfs2_parse_options(char *options, unsigned long *mount_opt);
+static int ocfs2_parse_options(struct super_block *sb, char *options,
+ unsigned long *mount_opt, int is_remount);
static void ocfs2_put_super(struct super_block *sb);
-static int ocfs2_mount_volume(struct super_block *sb, unsigned long mount_opt);
+static int ocfs2_mount_volume(struct super_block *sb);
+static int ocfs2_remount(struct super_block *sb, int *flags, char *data);
static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err);
static int ocfs2_initialize_mem_caches(void);
static void ocfs2_free_mem_caches(void);
@@ -109,7 +111,9 @@
static int ocfs2_verify_volume(ocfs2_dinode *di,
struct buffer_head *bh,
u32 sectsize);
-static int ocfs2_initialize_osb(ocfs2_super *osb, struct buffer_head *bh);
+static int ocfs2_initialize_super(struct super_block *sb,
+ struct buffer_head *bh,
+ int sector_size);
static int ocfs2_get_sector(struct super_block *sb,
struct buffer_head **bh,
int block,
@@ -130,6 +134,7 @@
.sync_fs = ocfs2_sync_fs,
.write_super = ocfs2_write_super,
.put_super = ocfs2_put_super,
+ .remount_fs = ocfs2_remount,
};
#ifdef OCFS2_ORACORE_WORKAROUNDS
@@ -137,24 +142,30 @@
#endif
enum {
- Opt_hbok,
Opt_barrier,
+ Opt_err_panic,
+ Opt_err_ro,
#ifdef OCFS2_ORACORE_WORKAROUNDS
Opt_datavolume,
#endif
Opt_intr,
Opt_nointr,
+ Opt_hb_none,
+ Opt_hb_local,
Opt_err,
};
static match_table_t tokens = {
- {Opt_hbok, OCFS2_HB_OK},
{Opt_barrier, "barrier=%u"},
+ {Opt_err_panic, "errors=panic"},
+ {Opt_err_ro, "errors=remount-ro"},
#ifdef OCFS2_ORACORE_WORKAROUNDS
{Opt_datavolume, "datavolume"},
#endif
{Opt_intr, "intr"},
{Opt_nointr, "nointr"},
+ {Opt_hb_none, OCFS2_HB_NONE},
+ {Opt_hb_local, OCFS2_HB_LOCAL},
{Opt_err, NULL}
};
@@ -176,6 +187,9 @@
sb->s_dirt = 0;
+ if (ocfs2_is_hard_readonly(osb))
+ return -EROFS;
+
if (wait) {
status = ocfs2_flush_truncate_log(osb);
if (status < 0)
@@ -348,13 +362,158 @@
return (((unsigned long long)pagefactor) << bitshift) - 1;
}
+static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
+{
+ int incompat_features;
+ int ret = 0;
+ unsigned long parsed_options;
+ ocfs2_super *osb = OCFS2_SB(sb);
+
+ if (!ocfs2_parse_options(sb, data, &parsed_options, 1)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* We're going to/from readonly mode. */
+ if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
+ /* Lock here so the check of HARD_RO and the potential
+ * setting of SOFT_RO is atomic. */
+ spin_lock(&osb->osb_lock);
+ if (osb->osb_flags & OCFS2_OSB_HARD_RO) {
+ mlog(ML_ERROR, "Remount on readonly device is forbidden.\n");
+ ret = -EROFS;
+ goto unlock_osb;
+ }
+
+ if (*flags & MS_RDONLY) {
+ mlog(0, "Going to ro mode.\n");
+ sb->s_flags |= MS_RDONLY;
+ osb->osb_flags |= OCFS2_OSB_SOFT_RO;
+ } else {
+ mlog(0, "Making ro filesystem writeable.\n");
+
+ if (osb->osb_flags & OCFS2_OSB_ERROR_FS) {
+ mlog(ML_ERROR, "Cannot remount RDWR "
+ "filesystem due to previous errors.\n");
+ ret = -EROFS;
+ goto unlock_osb;
+ }
+ incompat_features = OCFS2_HAS_RO_COMPAT_FEATURE(sb, ~OCFS2_FEATURE_RO_COMPAT_SUPP);
+ if (incompat_features) {
+ mlog(ML_ERROR, "Cannot remount RDWR because "
+ "of unsupported optional features "
+ "(%x).\n", incompat_features);
+ ret = -EINVAL;
+ goto unlock_osb;
+ }
+ sb->s_flags &= ~MS_RDONLY;
+ osb->osb_flags &= ~OCFS2_OSB_SOFT_RO;
+ }
+unlock_osb:
+ spin_unlock(&osb->osb_lock);
+ }
+
+ if (!ret) {
+ if (!ocfs2_is_hard_readonly(osb))
+ ocfs2_set_journal_params(osb);
+
+ /* Only save off the new mount options in case of a successful
+ * remount. */
+ osb->s_mount_opt = parsed_options;
+ }
+out:
+ return ret;
+}
+
+static int ocfs2_sb_probe(struct super_block *sb,
+ struct buffer_head **bh,
+ int *sector_size)
+{
+ int status = 0, tmpstat;
+ ocfs1_vol_disk_hdr *hdr;
+ ocfs2_dinode *di;
+ int blksize;
+
+ *bh = NULL;
+
+ /* may be > 512 */
+ *sector_size = bdev_hardsect_size(sb->s_bdev);
+ if (*sector_size > OCFS2_MAX_BLOCKSIZE) {
+ mlog(ML_ERROR, "Hardware sector size too large: %d (max=%d)\n",
+ *sector_size, OCFS2_MAX_BLOCKSIZE);
+ status = -EINVAL;
+ goto bail;
+ }
+
+ /* Can this really happen? */
+ if (*sector_size < OCFS2_MIN_BLOCKSIZE)
+ *sector_size = OCFS2_MIN_BLOCKSIZE;
+
+ /* check block zero for old format */
+ status = ocfs2_get_sector(sb, bh, 0, *sector_size);
+ if (status < 0) {
+ mlog_errno(status);
+ goto bail;
+ }
+ hdr = (ocfs1_vol_disk_hdr *) (*bh)->b_data;
+ if (hdr->major_version == OCFS1_MAJOR_VERSION) {
+ mlog(ML_ERROR, "incompatible version: %u.%u\n",
+ hdr->major_version, hdr->minor_version);
+ status = -EINVAL;
+ }
+ if (memcmp(hdr->signature, OCFS1_VOLUME_SIGNATURE,
+ strlen(OCFS1_VOLUME_SIGNATURE)) == 0) {
+ mlog(ML_ERROR, "incompatible volume signature: %8s\n",
+ hdr->signature);
+ status = -EINVAL;
+ }
+ brelse(*bh);
+ *bh = NULL;
+ if (status < 0) {
+ mlog(ML_ERROR, "This is an ocfs v1 filesystem which must be "
+ "upgraded before mounting with ocfs v2\n");
+ goto bail;
+ }
+
+ /*
+ * Now check at magic offset for 512, 1024, 2048, 4096
+ * blocksizes. 4096 is the maximum blocksize because it is
+ * the minimum clustersize.
+ */
+ status = -EINVAL;
+ for (blksize = *sector_size;
+ blksize <= OCFS2_MAX_BLOCKSIZE;
+ blksize <<= 1) {
+ tmpstat = ocfs2_get_sector(sb, bh,
+ OCFS2_SUPER_BLOCK_BLKNO,
+ blksize);
+ if (tmpstat < 0) {
+ status = tmpstat;
+ mlog_errno(status);
+ goto bail;
+ }
+ di = (ocfs2_dinode *) (*bh)->b_data;
+ status = ocfs2_verify_volume(di, *bh, blksize);
+ if (status >= 0)
+ goto bail;
+ brelse(*bh);
+ *bh = NULL;
+ if (status != -EAGAIN)
+ break;
+ }
+
+bail:
+ return status;
+}
+
static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
{
struct dentry *root;
- int status;
+ int status, sector_size;
+ unsigned long parsed_opt;
struct inode *inode = NULL;
ocfs2_super *osb = NULL;
- unsigned long mount_opt = 0;
+ struct buffer_head *bh = NULL;
mlog_entry("%p, %p, %i", sb, data, silent);
@@ -365,47 +524,95 @@
goto read_super_error;
}
- if (!ocfs2_parse_options(data, &mount_opt)) {
- status = -EINVAL;
+ /* probe for superblock */
+ status = ocfs2_sb_probe(sb, &bh, §or_size);
+ if (status < 0) {
+ mlog(ML_ERROR, "superblock probe failed!\n");
goto read_super_error;
}
- /* Stopgap check to ensure that mount.ocfs2 mounted the volume */
- if (!(mount_opt & OCFS2_MOUNT_HB_OK)) {
- mlog(ML_ERROR, "No heartbeat for device (%s)\n", sb->s_id);
- status = -EINVAL;
- goto read_super_error;
+ status = ocfs2_initialize_super(sb, bh, sector_size);
+ osb = OCFS2_SB(sb);
+ if (status < 0) {
+ mlog_errno(status);
+ goto read_super_error;
}
+ brelse(bh);
+ bh = NULL;
+ if (!ocfs2_parse_options(sb, data, &parsed_opt, 0)) {
+ status = -EINVAL;
+ goto read_super_error;
+ }
+ osb->s_mount_opt = parsed_opt;
+
#ifdef OCFS2_ORACORE_WORKAROUNDS
- if (mount_opt & OCFS2_MOUNT_COMPAT_OCFS)
+ if (osb->s_mount_opt & OCFS2_MOUNT_COMPAT_OCFS)
sb->s_magic = OCFS_SUPER_MAGIC;
else
#endif
sb->s_magic = OCFS2_SUPER_MAGIC;
- sb->s_op = &ocfs2_sops;
- sb->s_export_op = &ocfs2_export_ops;
- sb->s_flags |= MS_NOATIME;
- sb->s_fs_info = NULL;
- status = ocfs2_mount_volume(sb, mount_opt);
- /* ocfs2_mount_volume may set osb even on error so we want to
- * pull it off for proper cleanup. */
- osb = OCFS2_SB(sb);
- if (osb && osb->root_inode)
+ /* Hard readonly mode only if: bdev_read_only, MS_RDONLY,
+ * heartbeat=none */
+ if (bdev_read_only(sb->s_bdev)) {
+ if (!(sb->s_flags & MS_RDONLY)) {
+ status = -EACCES;
+ mlog(ML_ERROR, "Readonly device detected but readonly "
+ "mount was not specified.\n");
+ goto read_super_error;
+ }
+
+ /* You should not be able to start a local heartbeat
+ * on a readonly device. */
+ if (osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL) {
+ status = -EROFS;
+ mlog(ML_ERROR, "Local heartbeat specified on readonly "
+ "device.\n");
+ goto read_super_error;
+ }
+
+ status = ocfs2_check_journals_nolocks(osb);
+ if (status < 0) {
+ if (status == -EROFS)
+ mlog(ML_ERROR, "Recovery required on readonly "
+ "file system, but write access is "
+ "unavailable.\n");
+ else
+ mlog_errno(status);
+ goto read_super_error;
+ }
+
+ ocfs2_set_ro_flag(osb, 1);
+
+ printk(KERN_NOTICE "Readonly device detected. No cluster "
+ "services will be utilized for this mount. Recovery "
+ "will be skipped.\n");
+ }
+
+ if (!ocfs2_is_hard_readonly(osb)) {
+ /* If this isn't a hard readonly mount, then we need
+ * to make sure that heartbeat is in a valid state,
+ * and that we mark ourselves soft readonly is -oro
+ * was specified. */
+ if (!(osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL)) {
+ mlog(ML_ERROR, "No heartbeat for device (%s)\n",
+ sb->s_id);
+ status = -EINVAL;
+ goto read_super_error;
+ }
+
+ if (sb->s_flags & MS_RDONLY)
+ ocfs2_set_ro_flag(osb, 0);
+ }
+
+ status = ocfs2_mount_volume(sb);
+ if (osb->root_inode)
inode = igrab(osb->root_inode);
if (status < 0)
goto read_super_error;
- /* this is needed to support O_LARGEFILE */
- sb->s_maxbytes = ocfs2_max_file_offset(sb->s_blocksize_bits);
-
- if (!osb) {
- status = -EINVAL;
- goto read_super_error;
- }
-
if (!inode) {
status = -EIO;
mlog_errno(status);
@@ -434,6 +641,9 @@
return status;
read_super_error:
+ if (bh != NULL)
+ brelse(bh);
+
if (inode)
iput(inode);
@@ -467,13 +677,19 @@
.next = NULL
};
-static int ocfs2_parse_options(char *options, unsigned long *mount_opt)
+static int ocfs2_parse_options(struct super_block *sb,
+ char *options,
+ unsigned long *mount_opt,
+ int is_remount)
{
int status;
char *p;
- mlog_entry("options: \"%s\"\n", options ? options : "(none)");
+ mlog_entry("remount: %d, options: \"%s\"\n", is_remount,
+ options ? options : "(none)");
+ *mount_opt = 0;
+
if (!options) {
status = 1;
goto bail;
@@ -488,9 +704,12 @@
token = match_token(p, tokens, args);
switch (token) {
- case Opt_hbok:
- *mount_opt |= OCFS2_MOUNT_HB_OK;
+ case Opt_hb_local:
+ *mount_opt |= OCFS2_MOUNT_HB_LOCAL;
break;
+ case Opt_hb_none:
+ *mount_opt &= ~OCFS2_MOUNT_HB_LOCAL;
+ break;
case Opt_barrier:
if (match_int(&args[0], &option)) {
status = 0;
@@ -507,8 +726,20 @@
case Opt_nointr:
*mount_opt |= OCFS2_MOUNT_NOINTR;
break;
+ case Opt_err_panic:
+ *mount_opt |= OCFS2_MOUNT_ERRORS_PANIC;
+ break;
+ case Opt_err_ro:
+ *mount_opt &= ~OCFS2_MOUNT_ERRORS_PANIC;
+ break;
#ifdef OCFS2_ORACORE_WORKAROUNDS
case Opt_datavolume:
+ if (is_remount) {
+ mlog(ML_ERROR, "Cannot specifiy datavolume "
+ "on remount.\n");
+ status = 0;
+ goto bail;
+ }
*mount_opt |= OCFS2_MOUNT_COMPAT_OCFS;
break;
#endif
@@ -739,87 +970,6 @@
ocfs2_lock_cache = NULL;
}
-static int ocfs2_sb_probe(struct super_block *sb,
- struct buffer_head **bh,
- int *sector_size)
-{
- int status = 0, tmpstat;
- ocfs1_vol_disk_hdr *hdr;
- ocfs2_dinode *di;
- int blksize;
-
- *bh = NULL;
-
- /* may be > 512 */
- *sector_size = bdev_hardsect_size(sb->s_bdev);
- if (*sector_size > OCFS2_MAX_BLOCKSIZE) {
- mlog(ML_ERROR, "Hardware sector size too large: %d (max=%d)\n",
- *sector_size, OCFS2_MAX_BLOCKSIZE);
- status = -EINVAL;
- goto bail;
- }
-
- /* Can this really happen? */
- if (*sector_size < OCFS2_MIN_BLOCKSIZE)
- *sector_size = OCFS2_MIN_BLOCKSIZE;
-
- /* check block zero for old format */
- status = ocfs2_get_sector(sb, bh, 0, *sector_size);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- hdr = (ocfs1_vol_disk_hdr *) (*bh)->b_data;
- if (hdr->major_version == OCFS1_MAJOR_VERSION) {
- mlog(ML_ERROR, "incompatible version: %u.%u\n",
- hdr->major_version, hdr->minor_version);
- status = -EINVAL;
- }
- if (memcmp(hdr->signature, OCFS1_VOLUME_SIGNATURE,
- strlen(OCFS1_VOLUME_SIGNATURE)) == 0) {
- mlog(ML_ERROR, "incompatible volume signature: %8s\n",
- hdr->signature);
- status = -EINVAL;
- }
- brelse(*bh);
- *bh = NULL;
- if (status < 0) {
- mlog(ML_ERROR, "This is an ocfs v1 filesystem which must be "
- "upgraded before mounting with ocfs v2\n");
- goto bail;
- }
-
- /*
- * Now check at magic offset for 512, 1024, 2048, 4096
- * blocksizes. 4096 is the maximum blocksize because it is
- * the minimum clustersize.
- */
- status = -EINVAL;
- for (blksize = *sector_size;
- blksize <= OCFS2_MAX_BLOCKSIZE;
- blksize <<= 1) {
- tmpstat = ocfs2_get_sector(sb, bh,
- OCFS2_SUPER_BLOCK_BLKNO,
- blksize);
- if (tmpstat < 0) {
- status = tmpstat;
- mlog_errno(status);
- goto bail;
- }
- di = (ocfs2_dinode *) (*bh)->b_data;
- status = ocfs2_verify_volume(di, *bh, blksize);
- if (status >= 0)
- goto bail;
- brelse(*bh);
- *bh = NULL;
- if (status != -EAGAIN)
- break;
- }
-
-bail:
- return status;
-}
-
static int ocfs2_get_sector(struct super_block *sb,
struct buffer_head **bh,
int block,
@@ -865,46 +1015,17 @@
return status;
}
-static int ocfs2_mount_volume(struct super_block *sb, unsigned long mount_opt)
+static int ocfs2_mount_volume(struct super_block *sb)
{
- int status, sector_size;
+ int status = 0;
int unlock_super = 0;
- ocfs2_super *osb = NULL;
- struct buffer_head *bh = NULL;
+ ocfs2_super *osb = OCFS2_SB(sb);
mlog_entry_void();
- /* probe for superblock */
- status = ocfs2_sb_probe(sb, &bh, §or_size);
- if (status < 0) {
- mlog(ML_ERROR, "superblock probe failed!\n");
- goto leave;
- }
+ if (ocfs2_is_hard_readonly(osb))
+ goto out_add_proc;
- osb = kcalloc(1, sizeof(ocfs2_super), GFP_KERNEL);
- if (!osb) {
- status = -ENOMEM;
- mlog_errno(status);
- goto leave;
- }
-
- sb->s_fs_info = osb;
- osb->sb = sb;
-
- osb->s_mount_opt = mount_opt;
-
- /* Save off for ocfs2_rw_direct */
- osb->s_sectsize_bits = blksize_bits(sector_size);
- if (!osb->s_sectsize_bits)
- BUG();
-
- /* s_blocksize was set in the probe */
- status = ocfs2_initialize_osb(osb, bh);
- if (status < 0) {
- mlog_errno(status);
- goto leave;
- }
-
status = ocfs2_fill_local_node_info(osb);
if (status < 0) {
mlog_errno(status);
@@ -953,10 +1074,6 @@
goto leave;
}
- /* Add proc entry for this volume */
- ocfs2_proc_add_volume(osb);
-
- mlog(0, "ocfs2_check_volume...\n");
status = ocfs2_check_volume(osb);
if (status < 0) {
mlog_errno(status);
@@ -978,12 +1095,14 @@
if (status < 0)
mlog_errno(status);
+out_add_proc:
+ /* Add proc entry for this volume */
+ ocfs2_proc_add_volume(osb);
+
leave:
if (unlock_super)
ocfs2_super_unlock(osb, 1);
- if (bh != NULL)
- brelse(bh);
mlog_exit(status);
return status;
}
@@ -1102,7 +1221,9 @@
return 0;
}
-static int ocfs2_initialize_osb(ocfs2_super *osb, struct buffer_head *bh)
+static int ocfs2_initialize_super(struct super_block *sb,
+ struct buffer_head *bh,
+ int sector_size)
{
int status = 0;
int i;
@@ -1111,9 +1232,30 @@
struct buffer_head *bitmap_bh = NULL;
ocfs2_journal *journal;
__le32 uuid_net_key;
+ ocfs2_super *osb;
mlog_entry_void();
+ osb = kcalloc(1, sizeof(ocfs2_super), GFP_KERNEL);
+ if (!osb) {
+ status = -ENOMEM;
+ mlog_errno(status);
+ goto bail;
+ }
+
+ sb->s_fs_info = osb;
+ sb->s_op = &ocfs2_sops;
+ sb->s_export_op = &ocfs2_export_ops;
+ sb->s_flags |= MS_NOATIME;
+ /* this is needed to support O_LARGEFILE */
+ sb->s_maxbytes = ocfs2_max_file_offset(sb->s_blocksize_bits);
+
+ osb->sb = sb;
+ /* Save off for ocfs2_rw_direct */
+ osb->s_sectsize_bits = blksize_bits(sector_size);
+ if (!osb->s_sectsize_bits)
+ BUG();
+
osb->net_response_ids = 0;
spin_lock_init(&osb->net_response_lock);
INIT_LIST_HEAD(&osb->net_response_list);
@@ -1127,7 +1269,7 @@
INIT_LIST_HEAD(&osb->blocked_lock_list);
osb->blocked_lock_count = 0;
INIT_LIST_HEAD(&osb->vote_list);
- spin_lock_init(&osb->s_next_gen_lock);
+ spin_lock_init(&osb->osb_lock);
osb->osb_okp_teardown_next = NULL;
atomic_set(&osb->osb_okp_pending, 0);
@@ -1479,7 +1621,6 @@
return status;
}
-
/*
* The routine gets called from dismount or close whenever a dismount on
* volume is requested and the osb open count becomes 1.
@@ -1509,5 +1650,80 @@
mlog_exit_void();
}
+/* Put OCFS2 into a readonly state, or (if the user specifies it),
+ * panic(). We do not support continue-on-error operation. */
+static void ocfs2_handle_error(struct super_block *sb)
+{
+ ocfs2_super *osb = OCFS2_SB(sb);
+
+ if (osb->s_mount_opt & OCFS2_MOUNT_ERRORS_PANIC)
+ panic("OCFS2: (device %s): panic forced after error\n",
+ sb->s_id);
+
+ ocfs2_set_osb_flag(osb, OCFS2_OSB_ERROR_FS);
+
+ if (sb->s_flags & MS_RDONLY &&
+ (ocfs2_is_soft_readonly(osb) ||
+ ocfs2_is_hard_readonly(osb)))
+ return;
+
+ printk(KERN_CRIT "File system is now read-only due to the potential "
+ "of on-disk corruption. Please run fsck.ocfs2 once the file "
+ "system is unmounted.\n");
+ sb->s_flags |= MS_RDONLY;
+ ocfs2_set_ro_flag(osb, 0);
+}
+
+static char error_buf[1024];
+
+void __ocfs2_error(struct super_block *sb,
+ const char *function,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vsprintf(error_buf, fmt, args);
+ va_end(args);
+
+ /* Not using mlog here because we want to show the actual
+ * function the error came from. */
+ printk(KERN_CRIT "OCFS2: ERROR (device %s): %s: %s\n",
+ sb->s_id, function, error_buf);
+
+ ocfs2_handle_error(sb);
+}
+
+/* Handle critical errors. This is intentionally more drastic than
+ * ocfs2_handle_error, so we only use for things like journal errors,
+ * etc. */
+void __ocfs2_abort(struct super_block* sb,
+ const char *function,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vsprintf(error_buf, fmt, args);
+ va_end(args);
+
+ printk(KERN_CRIT "OCFS2: abort (device %s): %s: %s\n",
+ sb->s_id, function, error_buf);
+
+ /* We don't have the cluster support yet to go straight to
+ * hard readonly in here. Until then, we want to keep
+ * ocfs2_abort() so that we can at least mark critical
+ * errors.
+ *
+ * TODO: This should abort the journal and alert other nodes
+ * that our slot needs recovery. */
+
+ /* Force a panic(). This stinks, but it's better than letting
+ * things continue without having a proper hard readonly
+ * here. */
+ OCFS2_SB(sb)->s_mount_opt |= OCFS2_MOUNT_ERRORS_PANIC;
+ ocfs2_handle_error(sb);
+}
+
module_init(ocfs2_init);
module_exit(ocfs2_exit);
Modified: trunk/fs/ocfs2/super.h
===================================================================
--- trunk/fs/ocfs2/super.h 2005-09-17 00:08:28 UTC (rev 2589)
+++ trunk/fs/ocfs2/super.h 2005-09-17 00:34:40 UTC (rev 2590)
@@ -31,4 +31,14 @@
int ocfs2_publish_get_mount_state(ocfs2_super *osb,
int node_num);
+void __ocfs2_error(struct super_block *sb,
+ const char *function,
+ const char *fmt, ...);
+#define ocfs2_error(sb, fmt, args...) __ocfs2_error(sb, __PRETTY_FUNCTION__, fmt, ##args)
+
+void __ocfs2_abort(struct super_block *sb,
+ const char *function,
+ const char *fmt, ...);
+#define ocfs2_abort(sb, fmt, args...) __ocfs2_abort(sb, __PRETTY_FUNCTION__, fmt, ##args)
+
#endif /* OCFS2_SUPER_H */
More information about the Ocfs2-commits
mailing list