Submitter : dxm *Status : closed
Assigned Engineer : dxm *Fixed By : lord
*Fixed By Domain : sgi.com *Closed Date : 10/12/00
Priority : 3 *Modified Date : 10/12/00
*Modified User : lord *Modified User Domain : sgi.com
*Fix Description :
==========================
ADDITIONAL INFORMATION (CLOSE)
From: dxm@engr (BugWorks)
Date: Sep 25 2000 05:59:42PM
==========================
Modid: 2.4.x-xfs:slinx:75004a
Date: Mon Sep 25 17:59:23 PDT 2000
Workarea: snort:/build1/people/dxm/isms/slinx-xfs-tot
Author: dxm
.....
==========================
ADDITIONAL INFORMATION (TAKE)
From: steve lord <lord@xxxxxxx>
Date: Oct 12 2000 07:50:03AM
[pvnews version: 1.71]
==========================
This should allow the beta release to work well on low memory machines.
Date: Thu Oct 12 07:45:02 PDT 2000
Workarea: jen.americas.sgi.com:/src/lord/xfs-beta
The following file(s) were checked into:
bonnie.engr.sgi.com:/isms/slinx/2.4.x-xfs-beta
Modid: 2.4.x-xfs-beta:slinx:76107a
linux/fs/xfs/xfs_log_recover.c - 1.190
- Backport of fixes for low memory xfs log recovery and mount from PV
802017
Description :
I haven't seen this problem for ages on my 64Mb crash box,
but the problem is still there.
I installed XFS on my home machine last night and was very
happy with its performance (P100, 32Mb RAM, 32Gb disk) until
I tried to cleanly remount my XFS partition and tripped an
ASSERT in xlog_get_bp.
My home machine is very tight on memory, but I don't think
it's an unreasonable machine to try to run XFS on. Unfortunately,
.....
==========================
ADDITIONAL INFORMATION (UPDATE)
From: dxm@engr (BugWorks)
Date: Oct 11 2000 05:37:41PM
==========================
I've attached the patch to push this fix into the beta.
QA passes ok.
--- /usr/tmp/p_rdiff_a0sZoC/xfs_log_recover.c Thu Oct 12 11:11:44 2000
+++ /build1/people/dxm/isms/slinx-xfs/linux/fs/xfs/xfs_log_recover.c Wed Oct
11 14:12:05 2000
@@ -149,6 +149,7 @@
xfs_buf_t *bp;
ASSERT(num_bblks > 0);
+
bp = XFS_ngetrbuf(BBTOB(num_bblks),mp);
return bp;
} /* xlog_get_bp */
@@ -294,24 +295,52 @@
* Return -1 if we encounter no errors. This is an invalid block number
* since we don't ever expect logs to get this large.
*/
+
STATIC xfs_daddr_t
-xlog_find_verify_cycle(xfs_caddr_t *bap, /* update ptr as we go
*/
- xfs_daddr_t start_blk,
- int nbblks,
- uint stop_on_cycle_no)
+xlog_find_verify_cycle( xlog_t *log,
+ xfs_daddr_t start_blk,
+ int nbblks,
+ uint stop_on_cycle_no)
{
- int i;
- uint cycle;
+ int i;
+ uint cycle;
+ xfs_buf_t *bp;
+ char *buf = NULL;
+ int error = 0;
+ int smallmem = 0;
+
+ if (!(bp = xlog_get_bp(nbblks, log->l_mp))) {
+ /* can't get enough memory to do everything in one big buffer
*/
+ if (!(bp = xlog_get_bp(1, log->l_mp)))
+ return -ENOMEM;
+ smallmem = 1;
+ } else {
+ if ((error = xlog_bread(log, start_blk, nbblks, bp)))
+ goto out;
+ }
+
+ buf = XFS_BUF_PTR(bp);
- for (i=0; i<nbblks; i++) {
- cycle = GET_CYCLE(*bap, ARCH_CONVERT);
- if (cycle != stop_on_cycle_no) {
- (*bap) += BBSIZE;
- } else {
- return (start_blk+i);
+ for (i=start_blk; i< start_blk + nbblks; i++) {
+ if (smallmem && (error = xlog_bread(log, i, 1, bp)))
+ goto out;
+
+ cycle = GET_CYCLE(buf, ARCH_CONVERT);
+ if (cycle == stop_on_cycle_no) {
+ error = i;
+ goto out;
}
+
+ if (!smallmem)
+ buf += BBSIZE;
}
- return -1;
+
+ error = -1;
+
+out:
+ xlog_put_bp(bp);
+
+ return error;
} /* xlog_find_verify_cycle */
@@ -327,29 +356,55 @@
* extra_bblks is the number of blocks potentially verified on a previous
* call to this routine.
*/
+
STATIC int
-xlog_find_verify_log_record(xfs_caddr_t ba, /* update ptr as
we go */
+xlog_find_verify_log_record(xlog_t *log,
xfs_daddr_t start_blk,
xfs_daddr_t *last_blk,
int extra_bblks)
{
- xlog_rec_header_t *rhead;
- xfs_daddr_t i;
+ xfs_daddr_t i;
+ xfs_buf_t *bp;
+ char *buf = NULL;
+ xlog_rec_header_t *head;
+ int error = 0;
+ int smallmem = 0;
+ int num_blks = *last_blk - start_blk;
ASSERT(start_blk != 0 || *last_blk != start_blk);
- ba -= BBSIZE;
+ if (!(bp = xlog_get_bp(num_blks, log->l_mp))) {
+ if (!(bp = xlog_get_bp(1, log->l_mp)))
+ return -ENOMEM;
+ smallmem = 1;
+ buf = XFS_BUF_PTR(bp);
+ } else {
+ if ((error = xlog_bread(log, start_blk, num_blks, bp)))
+ goto out;
+ buf = XFS_BUF_PTR(bp) + (num_blks - 1) * BBSIZE;
+ }
+
+
for (i=(*last_blk)-1; i>=0; i--) {
if (i < start_blk) {
/* legal log record not found */
- xlog_warn("XFS: xlog_find_verify_log_record: need to back-up");
+ xlog_warn("XFS: Log inconsistent (didn't find previous header)");
+#ifdef __KERNEL__
ASSERT(0);
- return XFS_ERROR(EIO);
+#endif
+ error = XFS_ERROR(EIO);
+ goto out;
}
- if (INT_GET(*(uint *)ba, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM) {
+
+ if (smallmem && (error = xlog_bread(log, i, 1, bp)))
+ goto out;
+ head = (xlog_rec_header_t*)buf;
+
+ if (INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM)
break;
- }
- ba -= BBSIZE;
+
+ if (!smallmem)
+ buf -= BBSIZE;
}
/*
@@ -357,8 +412,10 @@
* to caller. If caller can handle a return of -1, then this routine
* will be called again for the end of the physical log.
*/
- if (i == -1)
- return -1;
+ if (i == -1) {
+ error = -1;
+ goto out;
+ }
/*
* We may have found a log record header before we expected one.
@@ -367,12 +424,15 @@
* reset last_blk. Only when last_blk points in the middle of a log
* record do we update last_blk.
*/
- rhead = (xlog_rec_header_t *)ba;
- if (*last_blk - i + extra_bblks != BTOBB(INT_GET(rhead->h_len,
ARCH_CONVERT))+1)
+ if (*last_blk - i + extra_bblks
+ != BTOBB(INT_GET(head->h_len, ARCH_CONVERT))+1)
*last_blk = i;
- return 0;
-} /* xlog_find_verify_log_record */
+
+out:
+ xlog_put_bp(bp);
+ return error;
+} /* xlog_find_verify_log_record */
/*
* Head is defined to be the point of the log where the next log write
@@ -393,15 +453,14 @@
xlog_find_head(xlog_t *log,
xfs_daddr_t *return_head_blk)
{
- xfs_buf_t *bp, *big_bp;
+ xfs_buf_t *bp;
xfs_daddr_t new_blk, first_blk, start_blk, last_blk, head_blk;
int num_scan_bblks;
uint first_half_cycle, last_half_cycle;
uint stop_on_cycle;
- xfs_caddr_t ba;
int error, log_bbnum = log->l_logBBsize;
- /* special case freshly mkfs'ed filesystem; return immediately */
+ /* Is the end of the log device zeroed? */
if ((error = xlog_find_zeroed(log, &first_blk)) == -1) {
*return_head_blk = first_blk;
return 0;
@@ -413,7 +472,7 @@
first_blk = 0; /* get cycle # of 1st block */
bp = xlog_get_bp(1,log->l_mp);
if (!bp)
- return -ENOMEM;
+ return -ENOMEM;
if (error = xlog_bread(log, 0, 1, bp))
goto bp_err;
first_half_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT);
@@ -495,12 +554,6 @@
* we actually look at the block size of the filesystem.
*/
num_scan_bblks = BTOBB(XLOG_MAX_ICLOGS<<XLOG_MAX_RECORD_BSHIFT);
- big_bp = xlog_get_bp(num_scan_bblks,log->l_mp);
- if (!big_bp) {
- error = -ENOMEM;
- goto bp_err;
- }
-
if (head_blk >= num_scan_bblks) {
/*
* We are guaranteed that the entire check can be performed
@@ -507,10 +560,7 @@
* in one buffer.
*/
start_blk = head_blk - num_scan_bblks;
- if (error = xlog_bread(log, start_blk, num_scan_bblks, big_bp))
- goto big_bp_err;
- ba = XFS_BUF_PTR(big_bp);
- new_blk = xlog_find_verify_cycle(&ba, start_blk, num_scan_bblks,
+ new_blk = xlog_find_verify_cycle(log, start_blk, num_scan_bblks,
stop_on_cycle);
if (new_blk != -1)
head_blk = new_blk;
@@ -542,11 +592,7 @@
*/
start_blk = log_bbnum - num_scan_bblks + head_blk;
ASSERT(head_blk <= INT_MAX && (xfs_daddr_t) num_scan_bblks-head_blk >=
0);
- if (error = xlog_bread(log, start_blk,
- num_scan_bblks-(int)head_blk, big_bp))
- goto big_bp_err;
- ba = XFS_BUF_PTR(big_bp);
- new_blk= xlog_find_verify_cycle(&ba, start_blk,
+ new_blk= xlog_find_verify_cycle(log, start_blk,
num_scan_bblks-(int)head_blk, (stop_on_cycle - 1));
if (new_blk != -1) {
head_blk = new_blk;
@@ -560,10 +606,7 @@
*/
start_blk = 0;
ASSERT(head_blk <= INT_MAX);
- if (error = xlog_bread(log, start_blk, (int) head_blk, big_bp))
- goto big_bp_err;
- ba = XFS_BUF_PTR(big_bp);
- new_blk = xlog_find_verify_cycle(&ba, start_blk, (int) head_blk,
+ new_blk = xlog_find_verify_cycle(log, start_blk, (int) head_blk,
stop_on_cycle);
if (new_blk != -1)
head_blk = new_blk;
@@ -577,26 +620,20 @@
num_scan_bblks = BTOBB(XLOG_MAX_RECORD_BSIZE);
if (head_blk >= num_scan_bblks) {
start_blk = head_blk - num_scan_bblks; /* don't read head_blk */
- if (error = xlog_bread(log, start_blk, num_scan_bblks, big_bp))
- goto big_bp_err;
/* start ptr at last block ptr before head_blk */
- ba = XFS_BUF_PTR(big_bp) + XLOG_MAX_RECORD_BSIZE;
- if ((error = xlog_find_verify_log_record(ba,
+ if ((error = xlog_find_verify_log_record(log,
start_blk,
&head_blk,
0)) == -1) {
error = XFS_ERROR(EIO);
- goto big_bp_err;
+ goto bp_err;
} else if (error)
- goto big_bp_err;
+ goto bp_err;
} else {
start_blk = 0;
ASSERT(head_blk <= INT_MAX);
- if (error = xlog_bread(log, start_blk, (int)head_blk, big_bp))
- goto big_bp_err;
- ba = XFS_BUF_PTR(big_bp) + BBTOB(head_blk);
- if ((error = xlog_find_verify_log_record(ba,
+ if ((error = xlog_find_verify_log_record(log,
start_blk,
&head_blk,
0)) == -1) {
@@ -604,26 +641,21 @@
start_blk = log_bbnum - num_scan_bblks + head_blk;
new_blk = log_bbnum;
ASSERT(start_blk <= INT_MAX && (xfs_daddr_t) log_bbnum-start_blk >=
0);
- if (error = xlog_bread(log, start_blk, log_bbnum - (int)start_blk,
- big_bp))
- goto big_bp_err;
- ba = XFS_BUF_PTR(big_bp) + BBTOB(log_bbnum - start_blk);
ASSERT(head_blk <= INT_MAX);
- if ((error = xlog_find_verify_log_record(ba,
+ if ((error = xlog_find_verify_log_record(log,
start_blk,
&new_blk,
(int)head_blk)) == -1) {
error = XFS_ERROR(EIO);
- goto big_bp_err;
+ goto bp_err;
} else if (error)
- goto big_bp_err;
+ goto bp_err;
if (new_blk != log_bbnum)
head_blk = new_blk;
} else if (error)
- goto big_bp_err;
+ goto bp_err;
}
- xlog_put_bp(big_bp);
xlog_put_bp(bp);
if (head_blk == log_bbnum)
*return_head_blk = 0;
@@ -637,8 +669,6 @@
*/
return 0;
-big_bp_err:
- xlog_put_bp(big_bp);
bp_err:
xlog_put_bp(bp);
@@ -755,8 +785,8 @@
return error;
bp = xlog_get_bp(1,log->l_mp);
- if (!bp)
- return -ENOMEM;
+ if (!bp)
+ return -ENOMEM;
if (*head_blk == 0) { /* special case */
if (error = xlog_bread(log, 0, 1, bp))
goto bread_err;
@@ -907,18 +937,17 @@
xlog_find_zeroed(struct log *log,
xfs_daddr_t *blk_no)
{
- xfs_buf_t *bp, *big_bp;
- uint first_cycle, last_cycle;
+ xfs_buf_t *bp;
+ uint first_cycle, last_cycle;
xfs_daddr_t new_blk, last_blk, start_blk;
- xfs_daddr_t num_scan_bblks;
- xfs_caddr_t ba;
- int error, log_bbnum = log->l_logBBsize;
+ xfs_daddr_t num_scan_bblks;
+ int error, log_bbnum = log->l_logBBsize;
error = 0;
/* check totally zeroed log */
bp = xlog_get_bp(1,log->l_mp);
- if (!bp)
- return -ENOMEM;
+ if (!bp)
+ return -ENOMEM;
if (error = xlog_bread(log, 0, 1, bp))
goto bp_err;
first_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT);
@@ -937,11 +966,11 @@
return 0;
} else if (first_cycle != 1) {
/*
- * Hopefully, this will catch the case where someone mkfs's
- * over a log partition.
+ * If the cycle of the last block is zero, the cycle of
+ * the first block must be 1. If it's not, maybe we're
+ * not looking at a log... Bail out.
*/
- xlog_warn("XFS: (xlog_find_zeroed): last cycle = 0; first cycle != 1");
- ASSERT(first_cycle == 1);
+ xlog_warn("XFS: Log inconsistent or not a log (last==0,
first!=1)");
return XFS_ERROR(EINVAL);
}
@@ -958,21 +987,11 @@
*/
num_scan_bblks = BTOBB(XLOG_MAX_ICLOGS<<XLOG_MAX_RECORD_BSHIFT);
ASSERT(num_scan_bblks <= INT_MAX);
- big_bp = xlog_get_bp((int)num_scan_bblks,log->l_mp);
- if (!big_bp) {
- error = -ENOMEM;
- goto bp_err;
- }
- ASSERT(big_bp);
if (last_blk < num_scan_bblks)
num_scan_bblks = last_blk;
start_blk = last_blk - num_scan_bblks;
-
- if (error = xlog_bread(log, start_blk, (int)num_scan_bblks, big_bp))
- goto big_bp_err;
- ba = XFS_BUF_PTR(big_bp);
-
+
/*
* We search for any instances of cycle number 0 that occur before
* our current estimate of the head. What we're trying to detect is
@@ -979,8 +998,7 @@
* 1 ... | 0 | 1 | 0...
* ^ binary search ends here
*/
- new_blk = xlog_find_verify_cycle(&ba, start_blk,
- (int)num_scan_bblks, 0);
+ new_blk = xlog_find_verify_cycle(log, start_blk, (int)num_scan_bblks,0);
if (new_blk != -1)
last_blk = new_blk;
@@ -988,12 +1006,11 @@
* Potentially backup over partial log record write. We don't need
* to search the end of the log because we know it is zero.
*/
- if (error = xlog_find_verify_log_record(ba, start_blk, &last_blk, 0))
- goto big_bp_err;
+ if (error = xlog_find_verify_log_record(log, start_blk,
+ &last_blk, 0))
+ goto bp_err;
*blk_no = last_blk;
-big_bp_err:
- xlog_put_bp(big_bp);
bp_err:
xlog_put_bp(bp);
if (error)
@@ -1014,32 +1031,56 @@
int start_block,
int blocks,
int tail_cycle,
- int tail_block,
- xfs_buf_t *bp)
+ int tail_block)
{
xlog_rec_header_t *recp;
int i;
- int curr_block;
- int error;
+ int error = 0;
+ xfs_buf_t *bp;
+ char *buf;
+ int smallmem = 0;
- recp = (xlog_rec_header_t*)(XFS_BUF_PTR(bp));
- curr_block = start_block;
- for (i = 0; i < blocks; i++) {
- INT_SET(recp->h_magicno, ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM);
- INT_SET(recp->h_cycle, ARCH_CONVERT, cycle);
- INT_SET(recp->h_version, ARCH_CONVERT, 1);
- INT_ZERO(recp->h_len, ARCH_CONVERT);
- ASSIGN_ANY_LSN(recp->h_lsn, cycle, curr_block, ARCH_CONVERT);
- ASSIGN_ANY_LSN(recp->h_tail_lsn, tail_cycle, tail_block,
ARCH_CONVERT);
- INT_ZERO(recp->h_chksum, ARCH_CONVERT);
- INT_ZERO(recp->h_prev_block, ARCH_CONVERT); /* unused */
- INT_ZERO(recp->h_num_logops, ARCH_CONVERT);
-
- curr_block++;
- recp = (xlog_rec_header_t*)(((char *)recp) + BBSIZE);
- }
+ if (!(bp = xlog_get_bp(blocks, log->l_mp))) {
+ if (!(bp = xlog_get_bp(1, log->l_mp)))
+ return -ENOMEM;
+ smallmem = 1;
+ }
+
+ buf = XFS_BUF_PTR(bp);
+ recp = (xlog_rec_header_t*)buf;
- error = xlog_bwrite(log, start_block, blocks, bp);
+ memset(buf, 0, BBSIZE);
+ INT_SET(recp->h_magicno, ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM);
+ INT_SET(recp->h_cycle, ARCH_CONVERT, cycle);
+ INT_SET(recp->h_version, ARCH_CONVERT, 1);
+ INT_ZERO(recp->h_len, ARCH_CONVERT);
+ ASSIGN_ANY_LSN(recp->h_tail_lsn, tail_cycle, tail_block, ARCH_CONVERT);
+ INT_ZERO(recp->h_chksum, ARCH_CONVERT);
+ INT_ZERO(recp->h_prev_block, ARCH_CONVERT); /* unused */
+ INT_ZERO(recp->h_num_logops, ARCH_CONVERT);
+
+ if (smallmem) {
+ /* for small mem, we keep modifying the block and writing */
+ for (i = start_block; i < start_block + blocks; i++) {
+ ASSIGN_ANY_LSN(recp->h_lsn, cycle, i, ARCH_CONVERT);
+ if ((error = xlog_bwrite(log, i, 1, bp)))
+ break;
+ }
+ } else {
+ ASSIGN_ANY_LSN(recp->h_lsn, cycle, start_block, ARCH_CONVERT);
+ for (i = start_block+1; i < start_block + blocks; i++) {
+ /* with plenty of memory, we duplicate the block
+ * right through the buffer and modify each entry
+ */
+ buf += BBSIZE;
+ recp = (xlog_rec_header_t*)buf;
+ memcpy(buf, XFS_BUF_PTR(bp), BBSIZE);
+ ASSIGN_ANY_LSN(recp->h_lsn, cycle, i, ARCH_CONVERT);
+ }
+ /* then write the whole lot out at once */
+ error = xlog_bwrite(log, start_block, blocks, bp);
+ }
+ xlog_put_bp(bp);
return error;
}
@@ -1072,7 +1113,6 @@
int tail_distance;
int max_distance;
int distance;
- xfs_buf_t *bp;
int error;
tail_cycle = CYCLE_LSN(tail_lsn, ARCH_NOCONVERT);
@@ -1127,9 +1167,6 @@
* for no reason.
*/
max_distance = MIN(max_distance, tail_distance);
- bp = xlog_get_bp(max_distance,log->l_mp);
- if (!bp)
- return -ENOMEM;
if ((head_block + max_distance) <= log->l_logBBsize) {
/*
@@ -1141,11 +1178,7 @@
*/
error = xlog_write_log_records(log, (head_cycle - 1),
head_block, max_distance, tail_cycle,
- tail_block, bp);
- if (error) {
- xlog_put_bp(bp);
- return error;
- }
+ tail_block);
} else {
/*
* We need to wrap around the end of the physical log in
@@ -1157,11 +1190,10 @@
distance = log->l_logBBsize - head_block;
error = xlog_write_log_records(log, (head_cycle - 1),
head_block, distance, tail_cycle,
- tail_block, bp);
- if (error) {
- xlog_put_bp(bp);
+ tail_block);
+
+ if (error)
return error;
- }
/*
* Now write the blocks at the start of the physical log.
@@ -1173,15 +1205,9 @@
*/
distance = max_distance - (log->l_logBBsize - head_block);
error = xlog_write_log_records(log, head_cycle, 0, distance,
- tail_cycle, tail_block, bp);
- if (error) {
- xlog_put_bp(bp);
- return error;
- }
+ tail_cycle, tail_block);
}
- xlog_put_bp(bp);
-
return 0;
}
#endif /* SIM */
@@ -3135,11 +3161,11 @@
error = 0;
hbp = xlog_get_bp(1,log->l_mp);
if (!hbp)
- return -ENOMEM;
+ return -ENOMEM;
dbp = xlog_get_bp(BTOBB(XLOG_MAX_RECORD_BSIZE),log->l_mp);
if (!dbp) {
- xlog_put_bp(hbp);
- return -ENOMEM;
+ xlog_put_bp(hbp);
+ return -ENOMEM;
}
bzero(rhash, sizeof(rhash));
if (tail_blk <= head_blk) {
@@ -3175,7 +3201,7 @@
goto bread_err;
rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp);
ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) ==
XLOG_HEADER_MAGIC_NUM);
- ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <= INT_MAX));
+ ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <= INT_MAX));
bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT));
/* LR body must have data or it wouldn't have been written */
|