]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
add libxlog directory.
authorNathan Scott <nathans@sgi.com>
Wed, 17 Oct 2001 11:00:32 +0000 (11:00 +0000)
committerNathan Scott <nathans@sgi.com>
Wed, 17 Oct 2001 11:00:32 +0000 (11:00 +0000)
18 files changed:
Makefile
VERSION
doc/CHANGES
include/Makefile
include/builddefs.in
include/libxlog.h [new file with mode: 0644]
libxlog/Makefile [new file with mode: 0644]
libxlog/util.c [new file with mode: 0644]
libxlog/xfs_log_recover.c [new file with mode: 0644]
logprint/Makefile
logprint/log_print_trans.c
logprint/logprint.c
logprint/logprint.h
man/man8/xfs_repair.8
repair/Makefile
repair/globals.h
repair/phase2.c
repair/xfs_repair.c

index 55dde91c5225c2de39d35f73b96d4f3ed90e63f6..c877f251e531c5ac62a01b9d770531e297235643 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -43,7 +43,7 @@ LSRCFILES = configure configure.in Makepkgs install-sh README VERSION
 LDIRT = config.log config.status config.cache confdefs.h conftest* \
        Logs/* install.* install-dev.* *.gz
 
-SUBDIRS = include libxfs libhandle libdisk \
+SUBDIRS = include libxfs libxlog libhandle libdisk \
        bmap db freeze fsck growfs imap logprint mkfile mkfs repair rtcp \
        man doc debian build
 
diff --git a/VERSION b/VERSION
index e8de20afd0c0f99e3eb056e97a61732d527c069a..ebaef32ca09351315e2565bb9389bfac58d59a41 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -3,5 +3,5 @@
 #
 PKG_MAJOR=1
 PKG_MINOR=3
-PKG_REVISION=11
+PKG_REVISION=12
 PKG_BUILD=0
index 633774543c0d0a4079375f6d241c3b6269c7e5af..cce19dde7e21ab84533e06ac12f261f24003814d 100644 (file)
@@ -1,3 +1,9 @@
+xfsprogs-1.3.12 (17 October 2001)
+       - implement the -f (file) option to xfs_logprint
+       - rework the xlog code into libxlog for code sharing
+       - xfs_repair now detects a dirty log and, without -L, will
+         no longer blindly zero it (which prevents any recovery)
+
 xfsprogs-1.3.11 (17 October 2001)
        - tidy up some (benign) compiler warnings from libxfs
        - fixed 64-bit pointer alignment issues in xfs_check
index e54a8e3e4250cee8623361b9f77cd9fd6052351d..af4946126da674aa7c64806aa0c51e5617d5dce8 100644 (file)
@@ -33,7 +33,7 @@
 TOPDIR = ..
 include $(TOPDIR)/include/builddefs
 
-HFILES = arch.h handle.h jdm.h libxfs.h xqm.h \
+HFILES = arch.h handle.h jdm.h libxfs.h libxlog.h xqm.h \
        xfs_ag.h xfs_alloc.h xfs_alloc_btree.h xfs_arch.h xfs_attr_leaf.h \
        xfs_attr_sf.h xfs_bit.h xfs_bmap.h xfs_bmap_btree.h xfs_btree.h \
        xfs_buf_item.h xfs_cred.h xfs_da_btree.h xfs_dfrag.h xfs_dinode.h \
index eac435946881400c14504fd90e96d1dad4b5f8b3..0aa78849e14a990acd4ed089cc7256d9a6cc69d0 100644 (file)
@@ -41,6 +41,7 @@ MALLOCLIB = @malloc_lib@
 
 LIBUUID = @libuuid@
 LIBXFS = $(TOPDIR)/libxfs/libxfs.la
+LIBXLOG = $(TOPDIR)/libxlog/libxlog.la
 LIBDISK = $(TOPDIR)/libdisk/libdisk.la
 LIBHANDLE = $(TOPDIR)/libhandle/libhandle.la
 
diff --git a/include/libxlog.h b/include/libxlog.h
new file mode 100644 (file)
index 0000000..4f0c7f2
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef LIBXLOG_H
+#define LIBXLOG_H
+
+#include <libxfs.h>
+
+/*
+ * define the userlevel xlog_t to be the subset of the kernel's
+ * xlog_t that we actually need to get our work done, avoiding
+ * the need to define any exotic kernel types in userland.
+ */
+typedef struct log {
+       xfs_lsn_t       l_tail_lsn;     /* lsn of 1st LR w/ unflush buffers */
+       xfs_lsn_t       l_last_sync_lsn;/* lsn of last LR on disk */
+       xfs_mount_t     *l_mp;          /* mount point */
+       dev_t           l_dev;          /* dev_t of log */
+       xfs_daddr_t     l_logBBstart;   /* start block of log */
+       int             l_logsize;      /* size of log in bytes */
+       int             l_logBBsize;    /* size of log in 512 byte chunks */
+       int             l_curr_cycle;   /* Cycle number of log writes */
+       int             l_prev_cycle;   /* Cycle # b4 last block increment */
+       int             l_curr_block;   /* current logical block of log */
+       int             l_prev_block;   /* previous logical block of log */
+       int             l_iclog_size;    /* size of log in bytes */
+       int             l_iclog_size_log;/* log power size of log */
+       int             l_iclog_bufs;    /* number of iclog buffers */
+       int             l_grant_reserve_cycle;  /* */
+       int             l_grant_reserve_bytes;  /* */
+       int             l_grant_write_cycle;    /* */
+       int             l_grant_write_bytes;    /* */
+} xlog_t;
+
+#include <xfs_log_recover.h>
+#include <xfs_buf_item.h>
+#include <xfs_inode_item.h>
+#include <xfs_extfree_item.h>
+#include <xfs_dquot_item.h>
+
+
+/*
+ * macros mapping kernel code to user code
+ */
+#define STATIC                 static
+#define EFSCORRUPTED            990
+#define XFS_ERROR(e)           (e)
+#define min(a,b)               ((a) < (b) ? (a) : (b))
+
+#if (__GNUC__ < 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ <= 95))
+# define xlog_warn(fmt,args...) \
+       ( fprintf(stderr,fmt,## args), fputc('\n', stderr) )
+# define cmn_err(sev,fmt,args...) \
+       xlog_warn(fmt,## args)
+# define xlog_exit(fmt,args...) \
+       ( xlog_warn(fmt,## args), exit(1) )
+# define xlog_panic(fmt,args...) \
+       xlog_exit(fmt,## args)
+#else
+# define xlog_warn(...) \
+       ( fprintf(stderr,__VA_ARGS__), fputc('\n', stderr) )
+# define cmn_err(sev,...) \
+       xlog_warn(__VA_ARGS__)
+# define xlog_exit(...) \
+       ( xlog_warn(__VA_ARGS__), exit(1) )
+# define xlog_panic(...) \
+       xlog_exit(__VA_ARGS__)
+#endif
+
+#define xlog_get_bp(nbblks, mp)        libxfs_getbuf(x.logdev, 0, (nbblks))
+#define xlog_put_bp(bp)                libxfs_putbuf(bp)
+#define xlog_bread(log,blkno,nbblks,bp)        \
+       (libxfs_readbufr(x.logdev,      \
+                       (log)->l_logBBstart+(blkno), bp, (nbblks), 1), 0)
+                         
+#define kmem_zalloc(size, foo)                 calloc(size,1)
+#define kmem_free(ptr, foo)                    free(ptr)
+#define kmem_realloc(ptr, len, old, foo)       realloc(ptr, len)
+
+/* exports */
+extern int     print_record_header;
+extern int     print_exit;
+
+/* libxfs parameters */
+extern libxfs_init_t   x;
+
+extern void xfs_log_print_trans(xlog_t          *log,
+                               int             print_block_start);
+
+extern void xfs_log_print(      xlog_t          *log,
+                                int             fd,
+                               int             print_block_start);
+
+extern int  xlog_find_zeroed(xlog_t *log, xfs_daddr_t *blk_no);
+extern int  xlog_find_cycle_start(xlog_t *log, xfs_buf_t *bp,
+               xfs_daddr_t first_blk, xfs_daddr_t *last_blk, uint cycle);
+extern int  xlog_find_tail(xlog_t *log, xfs_daddr_t *head_blk,
+               xfs_daddr_t *tail_blk, int readonly);
+
+extern int  xlog_test_footer(xlog_t *log);
+extern int  xlog_recover(xlog_t *log, int readonly);
+extern void xlog_recover_print_data(xfs_caddr_t p, int len);
+extern void xlog_recover_print_logitem(xlog_recover_item_t *item);
+extern void xlog_recover_print_trans_head(xlog_recover_t *tr);
+extern int  xlog_print_find_oldest(xlog_t *log, xfs_daddr_t *last_blk);
+
+extern void print_xlog_op_line(void);
+extern void print_xlog_record_line(void);
+extern void print_stars(void);
+
+/* for transactional view */
+extern void xlog_recover_print_trans_head(xlog_recover_t *tr);
+
+extern void xlog_recover_print_trans(  xlog_recover_t          *trans,
+                                       xlog_recover_item_t     *itemq,
+                                       int                     print);
+
+extern int  xlog_do_recovery_pass(     xlog_t          *log,
+                                       xfs_daddr_t     head_blk,
+                                       xfs_daddr_t     tail_blk,
+                                       int             pass);
+extern int  xlog_recover_do_trans(     xlog_t          *log,
+                                       xlog_recover_t  *trans,
+                                       int             pass);
+extern int  xlog_header_check_recover(  xfs_mount_t         *mp, 
+                                        xlog_rec_header_t   *head);
+extern int  xlog_header_check_mount(    xfs_mount_t         *mp, 
+                                        xlog_rec_header_t   *head);
+
+#endif /* LIBXLOG_H */
diff --git a/libxlog/Makefile b/libxlog/Makefile
new file mode 100644 (file)
index 0000000..85250bf
--- /dev/null
@@ -0,0 +1,50 @@
+#
+# Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
+# 
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+# 
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# 
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like.  Any license provided herein, whether implied or
+# otherwise, applies only to this software file.  Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+# 
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, USA.
+# 
+# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+# Mountain View, CA  94043, or:
+# 
+# http://www.sgi.com 
+# 
+# For further information regarding this notice, see: 
+# 
+# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+#
+
+TOPDIR = ..
+include $(TOPDIR)/include/builddefs
+
+LTLIBRARY = libxlog.la
+LT_CURRENT = 0
+LT_REVISION = 0
+LT_AGE = 0
+
+CFILES = xfs_log_recover.c util.c
+
+default:  $(LTLIBRARY)
+
+include $(BUILDRULES)
+
+install: default
+
+install-dev: default
+       $(INSTALL_LTLIB_STATIC)
diff --git a/libxlog/util.c b/libxlog/util.c
new file mode 100644 (file)
index 0000000..1d0592a
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <libxlog.h>
+
+int print_exit;
+int print_record_header;
+libxfs_init_t x;
+
+static int
+header_check_uuid(xfs_mount_t *mp, xlog_rec_header_t *head)
+{
+    char uu_log[64], uu_sb[64];
+    
+    if (!uuid_compare(mp->m_sb.sb_uuid, head->h_fs_uuid)) return 0;
+
+    uuid_unparse(mp->m_sb.sb_uuid, uu_sb);
+    uuid_unparse(head->h_fs_uuid, uu_log);
+
+    printf("* ERROR: mismatched uuid in log\n"
+           "*            SB : %s\n*            log: %s\n",
+            uu_sb, uu_log);
+    
+    return 1;
+}
+
+int
+xlog_header_check_recover(xfs_mount_t *mp, xlog_rec_header_t *head)
+{
+    if (print_record_header) 
+        printf("\nLOG REC AT LSN cycle %d block %d (0x%x, 0x%x)\n",
+              CYCLE_LSN(head->h_lsn, ARCH_CONVERT), 
+               BLOCK_LSN(head->h_lsn, ARCH_CONVERT),
+              CYCLE_LSN(head->h_lsn, ARCH_CONVERT), 
+               BLOCK_LSN(head->h_lsn, ARCH_CONVERT));
+    
+    if (INT_GET(head->h_magicno, ARCH_CONVERT) != XLOG_HEADER_MAGIC_NUM) {
+        
+        printf("* ERROR: bad magic number in log header: 0x%x\n",
+                INT_GET(head->h_magicno, ARCH_CONVERT));
+        
+    } else if (header_check_uuid(mp, head)) {
+        
+        /* failed - fall through */
+        
+    } else if (INT_GET(head->h_fmt, ARCH_CONVERT) != XLOG_FMT) {
+        
+       printf("* ERROR: log format incompatible (log=%d, ours=%d)\n",
+                INT_GET(head->h_fmt, ARCH_CONVERT), XLOG_FMT);
+        
+    } else {
+        /* everything is ok */
+        return 0;
+    }
+    
+    /* bail out now or just carry on regardless */
+    if (print_exit)
+        xlog_exit("Bad log");
+    return 0;   
+}
+
+int
+xlog_header_check_mount(xfs_mount_t *mp, xlog_rec_header_t *head)
+{
+    if (uuid_is_null(head->h_fs_uuid)) return 0;
+    if (header_check_uuid(mp, head)) {
+        /* bail out now or just carry on regardless */
+        if (print_exit)
+            xlog_exit("Bad log");
+    }
+    return 0;
+}
diff --git a/libxlog/xfs_log_recover.c b/libxlog/xfs_log_recover.c
new file mode 100644 (file)
index 0000000..be7e6c2
--- /dev/null
@@ -0,0 +1,1247 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ * 
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ * 
+ * http://www.sgi.com 
+ * 
+ * For further information regarding this notice, see: 
+ * 
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <libxlog.h>
+
+/*
+ * This routine finds (to an approximation) the first block in the physical
+ * log which contains the given cycle.  It uses a binary search algorithm.
+ * Note that the algorithm can not be perfect because the disk will not
+ * necessarily be perfect.
+ */
+int
+xlog_find_cycle_start(xlog_t   *log,
+                     xfs_buf_t *bp,
+                     xfs_daddr_t       first_blk,
+                     xfs_daddr_t       *last_blk,
+                     uint      cycle)
+{
+       xfs_daddr_t mid_blk;
+       uint    mid_cycle;
+       int     error;
+
+       mid_blk = BLK_AVG(first_blk, *last_blk);
+       while (mid_blk != first_blk && mid_blk != *last_blk) {
+               if ((error = xlog_bread(log, mid_blk, 1, bp)))
+                       return error;
+               mid_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT);
+               if (mid_cycle == cycle) {
+                       *last_blk = mid_blk;
+                       /* last_half_cycle == mid_cycle */
+               } else {
+                       first_blk = mid_blk;
+                       /* first_half_cycle == mid_cycle */
+               }
+               mid_blk = BLK_AVG(first_blk, *last_blk);
+       }
+       ASSERT((mid_blk == first_blk && mid_blk+1 == *last_blk) ||
+              (mid_blk == *last_blk && mid_blk-1 == first_blk));
+
+       return 0;
+}      /* xlog_find_cycle_start */
+
+
+/*
+ * Check that the range of blocks does not contain the cycle number
+ * given.  The scan needs to occur from front to back and the ptr into the
+ * region must be updated since a later routine will need to perform another
+ * test.  If the region is completely good, we end up returning the same
+ * last block number.
+ *
+ * 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( xlog_t                 *log,
+                       xfs_daddr_t     start_blk,
+                       int             nbblks,
+                       uint            stop_on_cycle_no)
+{
+       int                     i, j;
+       uint                    cycle;
+       xfs_buf_t               *bp;
+       char                    *buf        = NULL;
+       int                     error       = 0;
+       xfs_daddr_t             bufblks     = nbblks;
+
+       while (!(bp = xlog_get_bp(bufblks, log->l_mp))) {
+                /* can't get enough memory to do everything in one big buffer */
+               bufblks >>= 1;
+               if (!bufblks)
+                       return -ENOMEM;
+        }
+        
+
+       for (i = start_blk; i < start_blk + nbblks; i += bufblks)  {
+               int bcount = min(bufblks, (start_blk + nbblks - i));
+
+                if ((error = xlog_bread(log, i, bcount, bp)))
+                       goto out;
+
+               buf = XFS_BUF_PTR(bp);
+               for (j = 0; j < bcount; j++) {
+                       cycle = GET_CYCLE(buf, ARCH_CONVERT);
+                       if (cycle == stop_on_cycle_no) {
+                               error = i;
+                               goto out;
+                       }
+                
+                        buf += BBSIZE;
+               }
+       }
+
+       error = -1;
+
+out:
+       xlog_put_bp(bp);
+
+       return error;
+}      /* xlog_find_verify_cycle */
+
+
+/*
+ * Potentially backup over partial log record write.
+ *
+ * In the typical case, last_blk is the number of the block directly after
+ * a good log record.  Therefore, we subtract one to get the block number
+ * of the last block in the given buffer.  extra_bblks contains the number
+ * of blocks we would have read on a previous read.  This happens when the
+ * last log record is split over the end of the physical log.
+ *
+ * extra_bblks is the number of blocks potentially verified on a previous
+ * call to this routine.
+ */
+
+STATIC int
+xlog_find_verify_log_record(xlog_t     *log,
+                           xfs_daddr_t start_blk,
+                           xfs_daddr_t *last_blk,
+                           int         extra_bblks)
+{
+    xfs_daddr_t         i;
+    xfs_buf_t          *bp;
+    char                *buf        = NULL;
+    xlog_rec_header_t  *head       = NULL;
+    int                        error       = 0;
+    int                 smallmem    = 0;
+    int                 num_blks    = *last_blk - start_blk;
+
+    ASSERT(start_blk != 0 || *last_blk != start_blk);
+
+    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: Log inconsistent (didn't find previous header)");
+#ifdef __KERNEL__
+           ASSERT(0);
+#endif
+           error = XFS_ERROR(EIO);
+           goto out;
+       }
+
+       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;
+        
+        if (!smallmem)
+            buf -= BBSIZE;
+    }
+
+    /*
+     * We hit the beginning of the physical log & still no header.  Return
+     * 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) {
+       error = -1;
+       goto out;
+    }
+
+    /* we have the final block of the good log (the first block
+     * of the log record _before_ the head. So we check the uuid.
+     */
+        
+    if ((error = xlog_header_check_mount(log->l_mp, head)))
+        goto out;
+    
+    /*
+     * We may have found a log record header before we expected one.
+     * last_blk will be the 1st block # with a given cycle #.  We may end
+     * up reading an entire log record.  In this case, we don't want to
+     * reset last_blk.  Only when last_blk points in the middle of a log
+     * record do we update last_blk.
+     */
+    if (*last_blk - i + extra_bblks 
+               != BTOBB(INT_GET(head->h_len, ARCH_CONVERT))+1)
+           *last_blk = i;
+
+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
+ * write could go.  This means that incomplete LR writes at the end are
+ * eliminated when calculating the head.  We aren't guaranteed that previous
+ * LR have complete transactions.  We only know that a cycle number of 
+ * current cycle number -1 won't be present in the log if we start writing
+ * from our current block number.
+ *
+ * last_blk contains the block number of the first block with a given
+ * cycle number.
+ *
+ * Also called from xfs_log_print.c
+ *
+ * Return: zero if normal, non-zero if error.
+ */
+int
+xlog_find_head(xlog_t  *log,
+              xfs_daddr_t *return_head_blk)
+{
+    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;
+    int     error, log_bbnum = log->l_logBBsize;
+
+    /* Is the end of the log device zeroed? */
+    if ((error = xlog_find_zeroed(log, &first_blk)) == -1) {
+       *return_head_blk = first_blk;
+        
+        /* is the whole lot zeroed? */
+        if (!first_blk) {
+            /* Linux XFS shouldn't generate totally zeroed logs -
+             * mkfs etc write a dummy unmount record to a fresh
+             * log so we can store the uuid in there
+             */
+            xlog_warn("XFS: totally zeroed log\n");
+        }
+        
+       return 0;
+    } else if (error) {
+        xlog_warn("XFS: empty log check failed");
+       return error;
+    }
+
+    first_blk = 0;                             /* get cycle # of 1st block */
+    bp = xlog_get_bp(1,log->l_mp);
+    if (!bp)
+       return -ENOMEM;
+    if ((error = xlog_bread(log, 0, 1, bp)))
+       goto bp_err;
+    first_half_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT);
+
+    last_blk = head_blk = log_bbnum-1;         /* get cycle # of last block */
+    if ((error = xlog_bread(log, last_blk, 1, bp)))
+       goto bp_err;
+    last_half_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT);
+    ASSERT(last_half_cycle != 0);
+
+    /*
+     * If the 1st half cycle number is equal to the last half cycle number,
+     * then the entire log is stamped with the same cycle number.  In this
+     * case, head_blk can't be set to zero (which makes sense).  The below
+     * math doesn't work out properly with head_blk equal to zero.  Instead,
+     * we set it to log_bbnum which is an illegal block number, but this
+     * value makes the math correct.  If head_blk doesn't changed through
+     * all the tests below, *head_blk is set to zero at the very end rather
+     * than log_bbnum.  In a sense, log_bbnum and zero are the same block
+     * in a circular file.
+     */
+    if (first_half_cycle == last_half_cycle) {
+       /*
+        * In this case we believe that the entire log should have cycle
+        * number last_half_cycle.  We need to scan backwards from the
+        * end verifying that there are no holes still containing
+        * last_half_cycle - 1.  If we find such a hole, then the start
+        * of that hole will be the new head.  The simple case looks like
+        *        x | x ... | x - 1 | x
+        * Another case that fits this picture would be
+        *        x | x + 1 | x ... | x
+        * In this case the head really is somwhere at the end of the
+        * log, as one of the latest writes at the beginning was incomplete.
+        * One more case is
+        *        x | x + 1 | x ... | x - 1 | x
+        * This is really the combination of the above two cases, and the
+        * head has to end up at the start of the x-1 hole at the end of
+        * the log.
+        * 
+        * In the 256k log case, we will read from the beginning to the
+        * end of the log and search for cycle numbers equal to x-1.  We
+        * don't worry about the x+1 blocks that we encounter, because
+        * we know that they cannot be the head since the log started with
+        * x.
+        */
+       head_blk = log_bbnum;
+       stop_on_cycle = last_half_cycle - 1;
+    } else {
+       /*
+        * In this case we want to find the first block with cycle number
+        * matching last_half_cycle.  We expect the log to be some
+        * variation on
+        *        x + 1 ... | x ...
+        * The first block with cycle number x (last_half_cycle) will be
+        * where the new head belongs.  First we do a binary search for
+        * the first occurrence of last_half_cycle.  The binary search
+        * may not be totally accurate, so then we scan back from there
+        * looking for occurrences of last_half_cycle before us.  If
+        * that backwards scan wraps around the beginning of the log,
+        * then we look for occurrences of last_half_cycle - 1 at the
+        * end of the log.  The cases we're looking for look like
+        *        x + 1 ... | x | x + 1 | x ...
+        *                               ^ binary search stopped here
+        * or
+        *        x + 1 ... | x ... | x - 1 | x
+        *        <---------> less than scan distance
+        */
+       stop_on_cycle = last_half_cycle;
+       if ((error = xlog_find_cycle_start(log, bp, first_blk,
+                                         &head_blk, last_half_cycle)))
+           goto bp_err;
+    }
+
+    /*
+     * Now validate the answer.  Scan back some number of maximum possible
+     * blocks and make sure each one has the expected cycle number.  The
+     * maximum is determined by the total possible amount of buffering
+     * in the in-core log.  The following number can be made tighter if
+     * we actually look at the block size of the filesystem.
+     */
+    num_scan_bblks = BTOBB(XLOG_MAX_ICLOGS<<XLOG_MAX_RECORD_BSHIFT);
+    if (head_blk >= num_scan_bblks) {
+       /*
+        * We are guaranteed that the entire check can be performed
+        * in one buffer.
+        */
+       start_blk = head_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;
+    } else {                   /* need to read 2 parts of log */
+        /*
+        * We are going to scan backwards in the log in two parts.  First
+        * we scan the physical end of the log.  In this part of the log,
+        * we are looking for blocks with cycle number last_half_cycle - 1.
+        * If we find one, then we know that the log starts there, as we've
+        * found a hole that didn't get written in going around the end
+        * of the physical log.  The simple case for this is
+        *        x + 1 ... | x ... | x - 1 | x
+        *        <---------> less than scan distance
+        * If all of the blocks at the end of the log have cycle number
+        * last_half_cycle, then we check the blocks at the start of the
+        * log looking for occurrences of last_half_cycle.  If we find one,
+        * then our current estimate for the location of the first
+        * occurrence of last_half_cycle is wrong and we move back to the
+        * hole we've found.  This case looks like
+        *        x + 1 ... | x | x + 1 | x ...
+        *                               ^ binary search stopped here    
+        * Another case we need to handle that only occurs in 256k logs is
+        *        x + 1 ... | x ... | x+1 | x ...
+        *                   ^ binary search stops here
+        * In a 256k log, the scan at the end of the log will see the x+1
+        * blocks.  We need to skip past those since that is certainly not
+        * the head of the log.  By searching for last_half_cycle-1 we
+        * accomplish that.
+        */
+       start_blk = log_bbnum - num_scan_bblks + head_blk;
+       ASSERT(head_blk <= INT_MAX && (xfs_daddr_t) num_scan_bblks-head_blk >= 0);
+       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;
+           goto bad_blk;
+       }
+
+       /*
+        * Scan beginning of log now.  The last part of the physical log
+        * is good.  This scan needs to verify that it doesn't find the
+        * last_half_cycle.
+        */
+       start_blk = 0;
+       ASSERT(head_blk <= INT_MAX);
+       new_blk = xlog_find_verify_cycle(log, start_blk, (int) head_blk,
+                                        stop_on_cycle);
+       if (new_blk != -1)
+           head_blk = new_blk;
+    }
+
+bad_blk:
+    /*
+     * Now we need to make sure head_blk is not pointing to a block in
+     * the middle of a log record.
+     */
+    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 */
+
+       /* start ptr at last block ptr before head_blk */
+       if ((error = xlog_find_verify_log_record(log,
+                                                start_blk,
+                                                &head_blk,
+                                                0)) == -1) {
+           error = XFS_ERROR(EIO);
+           goto bp_err;
+       } else if (error)
+           goto bp_err;
+    } else {
+       start_blk = 0;
+       ASSERT(head_blk <= INT_MAX);
+       if ((error = xlog_find_verify_log_record(log,
+                                                start_blk,
+                                                &head_blk,
+                                                0)) == -1) {
+           /* We hit the beginning of the log during our search */
+           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);
+           ASSERT(head_blk <= INT_MAX);
+           if ((error = xlog_find_verify_log_record(log,
+                                                    start_blk,
+                                                    &new_blk,
+                                                    (int)head_blk)) == -1) {
+               error = XFS_ERROR(EIO);
+               goto bp_err;
+           } else if (error)
+               goto bp_err;
+           if (new_blk != log_bbnum)
+               head_blk = new_blk;
+       } else if (error)
+           goto bp_err;
+    }
+
+    xlog_put_bp(bp);
+    if (head_blk == log_bbnum)
+           *return_head_blk = 0;
+    else
+           *return_head_blk = head_blk;
+    /*
+     * When returning here, we have a good block number.  Bad block
+     * means that during a previous crash, we didn't have a clean break
+     * from cycle number N to cycle number N-1.  In this case, we need
+     * to find the first block with cycle number N-1.
+     */
+    return 0;
+
+bp_err:
+       xlog_put_bp(bp);
+
+        if (error)
+            xlog_warn("XFS: failed to find log head");
+            
+       return error;
+}      /* xlog_find_head */
+
+/*
+ * Find the sync block number or the tail of the log.
+ *
+ * This will be the block number of the last record to have its
+ * associated buffers synced to disk.  Every log record header has
+ * a sync lsn embedded in it.  LSNs hold block numbers, so it is easy
+ * to get a sync block number.  The only concern is to figure out which
+ * log record header to believe.
+ *
+ * The following algorithm uses the log record header with the largest
+ * lsn.  The entire log record does not need to be valid.  We only care
+ * that the header is valid.
+ *
+ * We could speed up search by using current head_blk buffer, but it is not
+ * available.
+ */
+int
+xlog_find_tail(xlog_t  *log,
+              xfs_daddr_t *head_blk,
+              xfs_daddr_t *tail_blk,
+              int readonly)
+{
+       xlog_rec_header_t       *rhead;
+       xlog_op_header_t        *op_head;
+       xfs_buf_t               *bp;
+       int                     error, i, found;
+       xfs_daddr_t             umount_data_blk;
+       xfs_daddr_t             after_umount_blk;
+       xfs_lsn_t               tail_lsn;
+       
+       found = error = 0;
+
+       /*
+        * Find previous log record 
+        */
+       if ((error = xlog_find_head(log, head_blk)))
+               return error;
+
+       bp = xlog_get_bp(1,log->l_mp);
+       if (!bp)
+               return -ENOMEM;
+       if (*head_blk == 0) {                           /* special case */
+               if ((error = xlog_bread(log, 0, 1, bp)))
+                       goto bread_err;
+               if (GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT) == 0) {
+                       *tail_blk = 0;
+                       /* leave all other log inited values alone */
+                       goto exit;
+               }
+       }
+
+       /*
+        * Search backwards looking for log record header block
+        */
+       ASSERT(*head_blk < INT_MAX);
+       for (i=(int)(*head_blk)-1; i>=0; i--) {
+               if ((error = xlog_bread(log, i, 1, bp)))
+                       goto bread_err;
+               if (INT_GET(*(uint *)(XFS_BUF_PTR(bp)), ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM) {
+                       found = 1;
+                       break;
+               }
+       }
+       /*
+        * If we haven't found the log record header block, start looking
+        * again from the end of the physical log.  XXXmiken: There should be
+        * a check here to make sure we didn't search more than N blocks in
+        * the previous code.
+        */
+       if (!found) {
+               for (i=log->l_logBBsize-1; i>=(int)(*head_blk); i--) {
+                       if ((error = xlog_bread(log, i, 1, bp)))
+                               goto bread_err;
+                       if (INT_GET(*(uint*)(XFS_BUF_PTR(bp)), ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM) {
+                               found = 2;
+                               break;
+                       }
+               }
+       }
+       if (!found) {
+               xlog_warn("XFS: xlog_find_tail: couldn't find sync record");
+               ASSERT(0);
+               return XFS_ERROR(EIO);
+       }
+
+       /* find blk_no of tail of log */
+       rhead = (xlog_rec_header_t *)XFS_BUF_PTR(bp);
+       *tail_blk = BLOCK_LSN(rhead->h_tail_lsn, ARCH_CONVERT);
+
+       /*
+        * Reset log values according to the state of the log when we
+        * crashed.  In the case where head_blk == 0, we bump curr_cycle
+        * one because the next write starts a new cycle rather than
+        * continuing the cycle of the last good log record.  At this
+        * point we have guaranteed that all partial log records have been
+        * accounted for.  Therefore, we know that the last good log record
+        * written was complete and ended exactly on the end boundary
+        * of the physical log.
+        */
+       log->l_prev_block = i;
+       log->l_curr_block = (int)*head_blk;
+       log->l_curr_cycle = INT_GET(rhead->h_cycle, ARCH_CONVERT);
+       if (found == 2)
+               log->l_curr_cycle++;
+       log->l_tail_lsn = INT_GET(rhead->h_tail_lsn, ARCH_CONVERT);
+       log->l_last_sync_lsn = INT_GET(rhead->h_lsn, ARCH_CONVERT);
+       log->l_grant_reserve_cycle = log->l_curr_cycle;
+       log->l_grant_reserve_bytes = BBTOB(log->l_curr_block);
+       log->l_grant_write_cycle = log->l_curr_cycle;
+       log->l_grant_write_bytes = BBTOB(log->l_curr_block);
+
+       /*
+        * Look for unmount record.  If we find it, then we know there
+        * was a clean unmount.  Since 'i' could be the last block in
+        * the physical log, we convert to a log block before comparing
+        * to the head_blk.
+        *
+        * Save the current tail lsn to use to pass to
+        * xlog_clear_stale_blocks() below.  We won't want to clear the
+        * unmount record if there is one, so we pass the lsn of the
+        * unmount record rather than the block after it.
+        */
+       after_umount_blk = (i + 2) % log->l_logBBsize;
+       tail_lsn = log->l_tail_lsn;
+       if (*head_blk == after_umount_blk && INT_GET(rhead->h_num_logops, ARCH_CONVERT) == 1) {
+               umount_data_blk = (i + 1) % log->l_logBBsize;
+               if ((error = xlog_bread(log, umount_data_blk, 1, bp))) {
+                       goto bread_err;
+               }
+               op_head = (xlog_op_header_t *)XFS_BUF_PTR(bp);
+               if (op_head->oh_flags & XLOG_UNMOUNT_TRANS) {
+                       /*
+                        * Set tail and last sync so that newly written
+                        * log records will point recovery to after the
+                        * current unmount record.
+                        */
+                       ASSIGN_ANY_LSN(log->l_tail_lsn, log->l_curr_cycle,
+                                       after_umount_blk, ARCH_NOCONVERT);
+                       ASSIGN_ANY_LSN(log->l_last_sync_lsn, log->l_curr_cycle,
+                                       after_umount_blk, ARCH_NOCONVERT);
+                       *tail_blk = after_umount_blk;
+               }
+       }
+
+#ifdef __KERNEL__
+       /*
+        * Make sure that there are no blocks in front of the head
+        * with the same cycle number as the head.  This can happen
+        * because we allow multiple outstanding log writes concurrently,
+        * and the later writes might make it out before earlier ones.
+        *
+        * We use the lsn from before modifying it so that we'll never
+        * overwrite the unmount record after a clean unmount.
+        *
+        * Do this only if we are going to recover the filesystem
+        */
+       if (!readonly)
+               error = xlog_clear_stale_blocks(log, tail_lsn);
+#endif
+
+bread_err:
+exit:
+       xlog_put_bp(bp);
+
+        if (error) 
+                xlog_warn("XFS: failed to locate log tail");
+
+       return error;
+}      /* xlog_find_tail */
+
+
+/*
+ * Is the log zeroed at all?
+ *
+ * The last binary search should be changed to perform an X block read
+ * once X becomes small enough.  You can then search linearly through
+ * the X blocks.  This will cut down on the number of reads we need to do.
+ *
+ * If the log is partially zeroed, this routine will pass back the blkno
+ * of the first block with cycle number 0.  It won't have a complete LR
+ * preceding it.
+ *
+ * Return:
+ *     0  => the log is completely written to
+ *     -1 => use *blk_no as the first block of the log
+ *     >0 => error has occurred
+ */
+int
+xlog_find_zeroed(struct log    *log,
+                xfs_daddr_t    *blk_no)
+{
+       xfs_buf_t       *bp;
+       uint            first_cycle, last_cycle;
+       xfs_daddr_t     new_blk, last_blk, start_blk;
+       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 ((error = xlog_bread(log, 0, 1, bp)))
+               goto bp_err;
+       first_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT);
+       if (first_cycle == 0) {         /* completely zeroed log */
+               *blk_no = 0;
+               xlog_put_bp(bp);
+               return -1;
+       }
+
+       /* check partially zeroed log */
+       if ((error = xlog_bread(log, log_bbnum-1, 1, bp)))
+               goto bp_err;
+       last_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT);
+       if (last_cycle != 0) {          /* log completely written to */
+               xlog_put_bp(bp);
+               return 0;
+       } else if (first_cycle != 1) {
+               /*
+                * 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: Log inconsistent or not a log (last==0, first!=1)");
+               return XFS_ERROR(EINVAL);
+       }
+        
+       /* we have a partially zeroed log */
+       last_blk = log_bbnum-1;
+       if ((error = xlog_find_cycle_start(log, bp, 0, &last_blk, 0)))
+               goto bp_err;
+
+       /*
+        * Validate the answer.  Because there is no way to guarantee that
+        * the entire log is made up of log records which are the same size,
+        * we scan over the defined maximum blocks.  At this point, the maximum
+        * is not chosen to mean anything special.   XXXmiken
+        */
+       num_scan_bblks = BTOBB(XLOG_MAX_ICLOGS<<XLOG_MAX_RECORD_BSHIFT);
+       ASSERT(num_scan_bblks <= INT_MAX);
+        
+       if (last_blk < num_scan_bblks)
+               num_scan_bblks = last_blk;
+       start_blk = last_blk - num_scan_bblks;
+     
+       /*
+        * 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
+        *        1 ... | 0 | 1 | 0...
+        *                       ^ binary search ends here
+        */
+       new_blk = xlog_find_verify_cycle(log, start_blk,
+                                        (int)num_scan_bblks, 0);
+       if (new_blk != -1)
+               last_blk = new_blk;
+
+       /*
+        * 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(log, start_blk, 
+                               &last_blk, 0)))
+           goto bp_err;
+
+       *blk_no = last_blk;
+bp_err:
+       xlog_put_bp(bp);
+       if (error)
+               return error;
+       return -1;
+}      /* xlog_find_zeroed */
+
+/* stuff for transactional view */
+STATIC void
+xlog_unpack_data(xlog_rec_header_t *rhead,
+                xfs_caddr_t       dp,
+                xlog_t            *log)
+{
+       int i;
+#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
+       uint *up = (uint *)dp;
+       uint chksum = 0;
+#endif
+
+       for (i=0; i<BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); i++) {
+               INT_SET(*(uint *)dp, ARCH_CONVERT, INT_GET(*(uint *)&rhead->h_cycle_data[i], ARCH_CONVERT));
+               dp += BBSIZE;
+       }
+#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
+       /* divide length by 4 to get # words */
+       for (i=0; i < INT_GET(rhead->h_len, ARCH_CONVERT) >> 2; i++) {
+               chksum ^= INT_GET(*up, ARCH_CONVERT);
+               up++;
+       }
+       if (chksum != INT_GET(rhead->h_chksum, ARCH_CONVERT)) {
+           if (!INT_ISZERO(rhead->h_chksum, ARCH_CONVERT) ||
+               ((log->l_flags & XLOG_CHKSUM_MISMATCH) == 0)) {
+                   cmn_err(CE_DEBUG,
+                       "XFS: LogR chksum mismatch: was (0x%x) is (0x%x)",
+                           INT_GET(rhead->h_chksum, ARCH_CONVERT), chksum);
+                   cmn_err(CE_DEBUG,
+"XFS: Disregard message if filesystem was created with non-DEBUG kernel");
+                   log->l_flags |= XLOG_CHKSUM_MISMATCH;
+           }
+        }
+#endif /* DEBUG && XFS_LOUD_RECOVERY */
+}      /* xlog_unpack_data */
+
+
+STATIC xlog_recover_t *
+xlog_recover_find_tid(xlog_recover_t *q,
+                     xlog_tid_t     tid)
+{
+       xlog_recover_t *p = q;
+
+       while (p != NULL) {
+               if (p->r_log_tid == tid)
+                   break;
+               p = p->r_next;
+       }
+       return p;
+}      /* xlog_recover_find_tid */
+
+STATIC void
+xlog_recover_put_hashq(xlog_recover_t **q,
+                      xlog_recover_t *trans)
+{
+       trans->r_next = *q;
+       *q = trans;
+}      /* xlog_recover_put_hashq */
+
+STATIC void
+xlog_recover_new_tid(xlog_recover_t    **q,
+                    xlog_tid_t         tid,
+                    xfs_lsn_t          lsn)
+{
+       xlog_recover_t  *trans;
+
+       trans = kmem_zalloc(sizeof(xlog_recover_t), 0);
+       trans->r_log_tid   = tid;
+       trans->r_lsn       = lsn;
+       xlog_recover_put_hashq(q, trans);
+}      /* xlog_recover_new_tid */
+
+
+STATIC int
+xlog_recover_unlink_tid(xlog_recover_t **q,
+                       xlog_recover_t  *trans)
+{
+       xlog_recover_t  *tp;
+       int             found = 0;
+
+       ASSERT(trans != 0);
+       if (trans == *q) {
+               *q = (*q)->r_next;
+       } else {
+               tp = *q;
+               while (tp != 0) {
+                       if (tp->r_next == trans) {
+                               found = 1;
+                               break;
+                       }
+                       tp = tp->r_next;
+               }
+               if (!found) {
+                       xlog_warn(
+                            "XFS: xlog_recover_unlink_tid: trans not found");
+                       ASSERT(0);
+                       return XFS_ERROR(EIO);
+               }
+               tp->r_next = tp->r_next->r_next;
+       }
+       return 0;
+}      /* xlog_recover_unlink_tid */
+
+/*
+ * Free up any resources allocated by the transaction
+ *
+ * Remember that EFIs, EFDs, and IUNLINKs are handled later.
+ */
+STATIC void
+xlog_recover_free_trans(xlog_recover_t      *trans)
+{
+       xlog_recover_item_t *first_item, *item, *free_item;
+       int i;
+
+       item = first_item = trans->r_itemq;
+       do {
+               free_item = item;
+               item = item->ri_next;
+                /* Free the regions in the item. */
+               for (i = 0; i < free_item->ri_cnt; i++) {
+                       kmem_free(free_item->ri_buf[i].i_addr,
+                                 free_item->ri_buf[i].i_len);
+               }
+               /* Free the item itself */
+               kmem_free(free_item->ri_buf,
+                         (free_item->ri_total * sizeof(xfs_log_iovec_t)));
+               kmem_free(free_item, sizeof(xlog_recover_item_t));
+       } while (first_item != item);
+       /* Free the transaction recover structure */
+       kmem_free(trans, sizeof(xlog_recover_t));
+}      /* xlog_recover_free_trans */
+
+
+STATIC int
+xlog_recover_commit_trans(xlog_t        *log,
+                         xlog_recover_t **q,
+                         xlog_recover_t *trans,
+                         int            pass)
+{
+       int error;
+
+       if ((error = xlog_recover_unlink_tid(q, trans)))
+               return error;
+       if ((error = xlog_recover_do_trans(log, trans, pass)))
+               return error;
+       xlog_recover_free_trans(trans);                 /* no error */
+       return 0;
+}      /* xlog_recover_commit_trans */
+
+STATIC void
+xlog_recover_insert_item_backq(xlog_recover_item_t **q,
+                              xlog_recover_item_t *item)
+{
+       if (*q == 0) {
+               item->ri_prev = item->ri_next = item;
+               *q = item;
+       } else {
+               item->ri_next           = *q;
+               item->ri_prev           = (*q)->ri_prev;
+               (*q)->ri_prev           = item;
+               item->ri_prev->ri_next  = item;
+       }
+}      /* xlog_recover_insert_item_backq */
+
+STATIC void
+xlog_recover_add_item(xlog_recover_item_t **itemq)
+{
+       xlog_recover_item_t *item;
+
+       item = kmem_zalloc(sizeof(xlog_recover_item_t), 0);
+       xlog_recover_insert_item_backq(itemq, item);
+}      /* xlog_recover_add_item */
+
+/* The next region to add is the start of a new region.  It could be
+ * a whole region or it could be the first part of a new region.  Because
+ * of this, the assumption here is that the type and size fields of all
+ * format structures fit into the first 32 bits of the structure.
+ *
+ * This works because all regions must be 32 bit aligned.  Therefore, we
+ * either have both fields or we have neither field.  In the case we have
+ * neither field, the data part of the region is zero length.  We only have
+ * a log_op_header and can throw away the header since a new one will appear
+ * later.  If we have at least 4 bytes, then we can determine how many regions
+ * will appear in the current log item.
+ */
+STATIC int
+xlog_recover_add_to_trans(xlog_recover_t       *trans,
+                         xfs_caddr_t           dp,
+                         int                   len)
+{
+       xfs_inode_log_format_t   *in_f;                 /* any will do */
+       xlog_recover_item_t      *item;
+       xfs_caddr_t              ptr;
+
+       if (!len)
+               return 0;
+       ptr = kmem_zalloc(len, 0);
+       bcopy(dp, ptr, len);
+       
+       in_f = (xfs_inode_log_format_t *)ptr;
+       item = trans->r_itemq;
+       if (item == 0) {
+               ASSERT(*(uint *)dp == XFS_TRANS_HEADER_MAGIC);
+               if (len == sizeof(xfs_trans_header_t))
+                       xlog_recover_add_item(&trans->r_itemq);
+               bcopy(dp, &trans->r_theader, len); /* s, d, l */
+               return 0;
+       }
+       if (item->ri_prev->ri_total != 0 &&
+            item->ri_prev->ri_total == item->ri_prev->ri_cnt) {
+               xlog_recover_add_item(&trans->r_itemq);
+       }
+       item = trans->r_itemq;
+       item = item->ri_prev;
+
+       if (item->ri_total == 0) {              /* first region to be added */
+               item->ri_total  = in_f->ilf_size;
+               ASSERT(item->ri_total <= XLOG_MAX_REGIONS_IN_ITEM);
+               item->ri_buf = kmem_zalloc((item->ri_total *
+                                           sizeof(xfs_log_iovec_t)), 0);
+       }
+       ASSERT(item->ri_total > item->ri_cnt);
+       /* Description region is ri_buf[0] */
+       item->ri_buf[item->ri_cnt].i_addr = ptr;
+       item->ri_buf[item->ri_cnt].i_len  = len;
+       item->ri_cnt++;
+       return 0;
+}      /* xlog_recover_add_to_trans */
+
+STATIC int
+xlog_recover_add_to_cont_trans(xlog_recover_t  *trans,
+                              xfs_caddr_t              dp,
+                              int              len)
+{
+       xlog_recover_item_t     *item;
+       xfs_caddr_t                     ptr, old_ptr;
+       int                     old_len;
+       
+       item = trans->r_itemq;
+       if (item == 0) {
+               /* finish copying rest of trans header */
+               xlog_recover_add_item(&trans->r_itemq);
+               ptr = (xfs_caddr_t)&trans->r_theader+sizeof(xfs_trans_header_t)-len;
+               bcopy(dp, ptr, len); /* s, d, l */
+               return 0;
+       }
+       item = item->ri_prev;
+
+       old_ptr = item->ri_buf[item->ri_cnt-1].i_addr;
+       old_len = item->ri_buf[item->ri_cnt-1].i_len;
+
+       ptr = kmem_realloc(old_ptr, len+old_len, old_len, 0); 
+        bcopy(dp , &ptr[old_len], len); /* s, d, l */
+       item->ri_buf[item->ri_cnt-1].i_len += len;
+       item->ri_buf[item->ri_cnt-1].i_addr = ptr;
+       return 0;
+}      /* xlog_recover_add_to_cont_trans */
+
+STATIC int
+xlog_recover_unmount_trans(xlog_recover_t *trans)
+{
+       /* Do nothing now */
+       xlog_warn("XFS: xlog_recover_unmount_trans: Unmount LR");
+       return( 0 );
+}      /* xlog_recover_unmount_trans */
+
+
+STATIC int
+xlog_recover_process_data(xlog_t           *log,
+                         xlog_recover_t    *rhash[],
+                         xlog_rec_header_t *rhead,
+                         xfs_caddr_t       dp,
+                         int               pass)
+{
+    xfs_caddr_t                lp         = dp+INT_GET(rhead->h_len, ARCH_CONVERT);
+    int                        num_logops = INT_GET(rhead->h_num_logops, ARCH_CONVERT);
+    xlog_op_header_t   *ohead;
+    xlog_recover_t     *trans;
+    xlog_tid_t         tid;
+    int                        error;
+    unsigned long      hash;
+    uint               flags;
+    
+    /* check the log format matches our own - else we can't recover */
+    if (xlog_header_check_recover(log->l_mp, rhead))
+           return (XFS_ERROR(EIO));
+    
+    while (dp < lp) {
+       ASSERT(dp + sizeof(xlog_op_header_t) <= lp);
+       ohead = (xlog_op_header_t *)dp;
+       dp += sizeof(xlog_op_header_t);
+       if (ohead->oh_clientid != XFS_TRANSACTION &&
+           ohead->oh_clientid != XFS_LOG) {
+           xlog_warn("XFS: xlog_recover_process_data: bad clientid");
+           ASSERT(0);
+           return (XFS_ERROR(EIO));
+        }
+       tid = INT_GET(ohead->oh_tid, ARCH_CONVERT);
+       hash = XLOG_RHASH(tid);
+       trans = xlog_recover_find_tid(rhash[hash], tid);
+       if (trans == NULL) {                       /* not found; add new tid */
+           if (ohead->oh_flags & XLOG_START_TRANS)
+               xlog_recover_new_tid(&rhash[hash], tid, INT_GET(rhead->h_lsn, ARCH_CONVERT));
+       } else {
+           ASSERT(dp+INT_GET(ohead->oh_len, ARCH_CONVERT) <= lp);
+           flags = ohead->oh_flags & ~XLOG_END_TRANS;
+           if (flags & XLOG_WAS_CONT_TRANS)
+               flags &= ~XLOG_CONTINUE_TRANS;
+           switch (flags) {
+               case XLOG_COMMIT_TRANS: {
+                   error = xlog_recover_commit_trans(log, &rhash[hash],
+                                                     trans, pass);
+                   break;
+               }
+               case XLOG_UNMOUNT_TRANS: {
+                   error = xlog_recover_unmount_trans(trans);
+                   break;
+               }
+               case XLOG_WAS_CONT_TRANS: {
+                   error = xlog_recover_add_to_cont_trans(trans, dp,
+                                 INT_GET(ohead->oh_len, ARCH_CONVERT));
+                   break;
+               }
+               case XLOG_START_TRANS : {
+                   xlog_warn("XFS: xlog_recover_process_data: bad transaction");
+                   ASSERT(0);
+                   error = XFS_ERROR(EIO);
+                   break;
+               }
+               case 0:
+               case XLOG_CONTINUE_TRANS: {
+                   error = xlog_recover_add_to_trans(trans, dp,
+                                  INT_GET(ohead->oh_len, ARCH_CONVERT));
+                   break;
+               }
+               default: {
+                   xlog_warn("XFS: xlog_recover_process_data: bad flag");
+                   ASSERT(0);
+                   error = XFS_ERROR(EIO);
+                   break;
+               }
+           } /* switch */
+           if (error)
+               return error;
+       } /* if */
+       dp += INT_GET(ohead->oh_len, ARCH_CONVERT);
+       num_logops--;
+    }
+    return( 0 );
+}      /* xlog_recover_process_data */
+
+/*
+ * Read the log from tail to head and process the log records found.
+ * Handle the two cases where the tail and head are in the same cycle
+ * and where the active portion of the log wraps around the end of
+ * the physical log separately.  The pass parameter is passed through
+ * to the routines called to process the data and is not looked at
+ * here.
+ */
+int
+xlog_do_recovery_pass(xlog_t   *log,
+                     xfs_daddr_t       head_blk,
+                     xfs_daddr_t       tail_blk,
+                     int       pass)
+{
+    xlog_rec_header_t  *rhead;
+    xfs_daddr_t                blk_no;
+    xfs_caddr_t                bufaddr;
+    xfs_buf_t          *hbp, *dbp;
+    int                        error;
+    int                        bblks, split_bblks;
+    xlog_recover_t     *rhash[XLOG_RHASH_SIZE];
+
+    error = 0;
+    hbp = xlog_get_bp(1,log->l_mp);
+    if (!hbp)
+       return -ENOMEM;
+    dbp = xlog_get_bp(BTOBB(XLOG_MAX_RECORD_BSIZE),log->l_mp);
+    if (!dbp) {
+       xlog_put_bp(hbp);
+       return -ENOMEM;
+    }
+    bzero(rhash, sizeof(rhash));
+    if (tail_blk <= head_blk) {
+       for (blk_no = tail_blk; blk_no < head_blk; ) {
+           if ((error = xlog_bread(log, blk_no, 1, hbp)))
+               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));
+           bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT));   /* blocks in data section */
+           if (bblks > 0) {
+               if ((error = xlog_bread(log, blk_no+1, bblks, dbp)))
+                   goto bread_err;
+               xlog_unpack_data(rhead, XFS_BUF_PTR(dbp), log);
+               if ((error = xlog_recover_process_data(log, rhash,
+                                                     rhead, XFS_BUF_PTR(dbp),
+                                                     pass)))
+                       goto bread_err;
+           }
+           blk_no += (bblks+1);
+       }
+    } else {
+       /*
+        * Perform recovery around the end of the physical log.  When the head
+        * is not on the same cycle number as the tail, we can't do a sequential
+        * recovery as above.
+        */
+       blk_no = tail_blk;
+       while (blk_no < log->l_logBBsize) {
+
+           /* Read header of one block */
+           if ((error = xlog_bread(log, blk_no, 1, hbp)))
+               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));            
+           bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT));
+
+           /* LR body must have data or it wouldn't have been written */
+           ASSERT(bblks > 0);
+           blk_no++;                   /* successfully read header */
+           ASSERT(blk_no <= log->l_logBBsize);
+
+           if ((INT_GET(rhead->h_magicno, ARCH_CONVERT) != XLOG_HEADER_MAGIC_NUM) ||
+               (BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) > INT_MAX)) ||
+               (bblks <= 0) ||
+               (blk_no > log->l_logBBsize)) {
+                   error = EFSCORRUPTED;
+                   goto bread_err;
+           }
+                   
+           /* Read in data for log record */
+           if (blk_no+bblks <= log->l_logBBsize) {
+               if ((error = xlog_bread(log, blk_no, bblks, dbp)))
+                   goto bread_err;
+           } else {
+               /* This log record is split across physical end of log */
+               split_bblks = 0;
+               if (blk_no != log->l_logBBsize) {
+
+                   /* some data is before physical end of log */
+                   ASSERT(blk_no <= INT_MAX);
+                   split_bblks = log->l_logBBsize - (int)blk_no;
+                   ASSERT(split_bblks > 0);
+                   if ((error = xlog_bread(log, blk_no, split_bblks, dbp)))
+                       goto bread_err;
+               }
+               bufaddr = XFS_BUF_PTR(dbp);
+               XFS_BUF_SET_PTR(dbp, bufaddr + BBTOB(split_bblks),
+                       BBTOB(bblks - split_bblks));
+               if ((error = xlog_bread(log, 0, bblks - split_bblks, dbp)))
+                   goto bread_err;
+               XFS_BUF_SET_PTR(dbp, bufaddr, XLOG_MAX_RECORD_BSIZE);
+           }
+           xlog_unpack_data(rhead, XFS_BUF_PTR(dbp), log);
+           if ((error = xlog_recover_process_data(log, rhash,
+                                                 rhead, XFS_BUF_PTR(dbp),
+                                                 pass)))
+               goto bread_err;
+           blk_no += bblks;
+       }
+
+       ASSERT(blk_no >= log->l_logBBsize);
+       blk_no -= log->l_logBBsize;
+
+       /* read first part of physical log */
+       while (blk_no < head_blk) {
+           if ((error = xlog_bread(log, blk_no, 1, hbp)))
+               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));
+           bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT));
+           ASSERT(bblks > 0);
+           if ((error = xlog_bread(log, blk_no+1, bblks, dbp)))
+               goto bread_err;
+           xlog_unpack_data(rhead, XFS_BUF_PTR(dbp), log);
+           if ((error = xlog_recover_process_data(log, rhash,
+                                                 rhead, XFS_BUF_PTR(dbp),
+                                                 pass)))
+               goto bread_err;
+           blk_no += (bblks+1);
+        }
+    }
+
+bread_err:
+    xlog_put_bp(dbp);
+    xlog_put_bp(hbp);
+
+    return error;
+}
index 2867d9f4eed42a40799cc80a5365a48bf85a972d..05c5a8f1da93773eeab976afb7f2fe5bdf711ce1 100644 (file)
@@ -35,11 +35,10 @@ include $(TOPDIR)/include/builddefs
 
 LTCOMMAND = xfs_logprint
 
-CFILES = log_print_trans.c log_print_all.c log_misc.c logprint.c \
-       xfs_log_recover.c
 HFILES = logprint.h
-LLDLIBS        = $(LIBXFS) $(LIBUUID)
-LTDEPENDENCIES = $(LIBXFS)
+CFILES = log_print_trans.c log_print_all.c log_misc.c logprint.c
+LLDLIBS        = $(LIBXFS) $(LIBXLOG) $(LIBUUID)
+LTDEPENDENCIES = $(LIBXFS) $(LIBXLOG)
 LLDFLAGS = -static
 
 default: $(LTCOMMAND)
index 02baefccd529e202e060c449dd523f88b5e0d0f6..625896e2b91cbe8466f3c3535e73c52a30b49f5d 100644 (file)
@@ -51,7 +51,6 @@ xlog_recover_do_trans(xlog_t       *log,
        return 0;
 }      /* xlog_recover_do_trans */
 
-static int print_record_header=0;
 
 void
 xfs_log_print_trans(xlog_t      *log,
@@ -79,68 +78,3 @@ xfs_log_print_trans(xlog_t      *log,
             exit(1);
 
 }      /* xfs_log_print_trans */
-
-static int
-header_check_uuid(xfs_mount_t *mp, xlog_rec_header_t *head)
-{
-    char uu_log[64], uu_sb[64];
-    
-    if (!uuid_compare(mp->m_sb.sb_uuid, head->h_fs_uuid)) return 0;
-
-    uuid_unparse(mp->m_sb.sb_uuid, uu_sb);
-    uuid_unparse(head->h_fs_uuid, uu_log);
-
-    printf("* ERROR: mismatched uuid in log\n"
-           "*            SB : %s\n*            log: %s\n",
-            uu_sb, uu_log);
-    
-    return 1;
-}
-
-int
-xlog_header_check_recover(xfs_mount_t *mp, xlog_rec_header_t *head)
-{
-    if (print_record_header) 
-        printf("\nLOG REC AT LSN cycle %d block %d (0x%x, 0x%x)\n",
-              CYCLE_LSN(head->h_lsn, ARCH_CONVERT), 
-               BLOCK_LSN(head->h_lsn, ARCH_CONVERT),
-              CYCLE_LSN(head->h_lsn, ARCH_CONVERT), 
-               BLOCK_LSN(head->h_lsn, ARCH_CONVERT));
-    
-    if (INT_GET(head->h_magicno, ARCH_CONVERT) != XLOG_HEADER_MAGIC_NUM) {
-        
-        printf("* ERROR: bad magic number in log header: 0x%x\n",
-                INT_GET(head->h_magicno, ARCH_CONVERT));
-        
-    } else if (header_check_uuid(mp, head)) {
-        
-        /* failed - fall through */
-        
-    } else if (INT_GET(head->h_fmt, ARCH_CONVERT) != XLOG_FMT) {
-        
-       printf("* ERROR: log format incompatible (log=%d, ours=%d)\n",
-                INT_GET(head->h_fmt, ARCH_CONVERT), XLOG_FMT);
-        
-    } else {
-        /* everything is ok */
-        return 0;
-    }
-    
-    /* bail out now or just carry on regardless */
-    if (print_exit)
-        xlog_exit("Bad log");
-    return 0;   
-}
-
-int
-xlog_header_check_mount(xfs_mount_t *mp, xlog_rec_header_t *head)
-{
-    if (uuid_is_null(head->h_fs_uuid)) return 0;
-    if (header_check_uuid(mp, head)) {
-        /* bail out now or just carry on regardless */
-        if (print_exit)
-            xlog_exit("Bad log");
-    }
-    return 0;
-}
index 18aad49bd43839d7165960a649908180ff4d44f2..a6a381925f9654c6e84a5cd884d3b3591d18f978 100644 (file)
@@ -43,7 +43,6 @@ int     print_no_data;
 int     print_no_print;
 int     print_exit = 1; /* -e is now default. specify -c to override */
 
-libxfs_init_t  x;
 xfs_mount_t    mp;
 
 void
index ba267506029e645d7f12f6321fb9332b6ee6bc37..8a750b9deaca3b1bc38268cb9c5bdda3c2c4a2bf 100644 (file)
  *
  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
  */
-#ifndef XFS_LOGPRINT_H
-#define XFS_LOGPRINT_H
+#ifndef LOGPRINT_H
+#define LOGPRINT_H
 
-#include <libxfs.h>
-
-/*
- * define the userlevel xlog_t to be the subset of the kernel's
- * xlog_t that we actually need to get our work done, avoiding
- * the need to define any exotic kernel types in userland.
- */
-typedef struct log {
-       xfs_lsn_t       l_tail_lsn;     /* lsn of 1st LR w/ unflush buffers */
-       xfs_lsn_t       l_last_sync_lsn;/* lsn of last LR on disk */
-       xfs_mount_t     *l_mp;          /* mount point */
-       dev_t           l_dev;          /* dev_t of log */
-       xfs_daddr_t     l_logBBstart;   /* start block of log */
-       int             l_logsize;      /* size of log in bytes */
-       int             l_logBBsize;    /* size of log in 512 byte chunks */
-       int             l_roundoff;     /* round off error of all iclogs */
-       int             l_curr_cycle;   /* Cycle number of log writes */
-       int             l_prev_cycle;   /* Cycle # b4 last block increment */
-       int             l_curr_block;   /* current logical block of log */
-       int             l_prev_block;   /* previous logical block of log */
-       int             l_iclog_size;    /* size of log in bytes */
-       int             l_iclog_size_log;/* log power size of log */
-       int             l_iclog_bufs;    /* number of iclog buffers */
-       int             l_grant_reserve_cycle;  /* */
-       int             l_grant_reserve_bytes;  /* */
-       int             l_grant_write_cycle;    /* */
-       int             l_grant_write_bytes;    /* */
-} xlog_t;
-
-#include <xfs_log_recover.h>
-#include <xfs_buf_item.h>
-#include <xfs_inode_item.h>
-#include <xfs_extfree_item.h>
-#include <xfs_dquot_item.h>
-
-
-/*
- * macros mapping kernel code to user code
- */
-#define STATIC                 static
-#define EFSCORRUPTED            990
-#define XFS_ERROR(e)           (e)
-#define min(a,b)               ((a) < (b) ? (a) : (b))
-
-#if (__GNUC__ < 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ <= 95))
-# define xlog_warn(fmt,args...) \
-       ( fprintf(stderr,fmt,## args), fputc('\n', stderr) )
-# define cmn_err(sev,fmt,args...) \
-       xlog_warn(fmt,## args)
-# define xlog_exit(fmt,args...) \
-       ( xlog_warn(fmt,## args), exit(1) )
-# define xlog_panic(fmt,args...) \
-       xlog_exit(fmt,## args)
-#else
-# define xlog_warn(...) \
-       ( fprintf(stderr,__VA_ARGS__), fputc('\n', stderr) )
-# define cmn_err(sev,...) \
-       xlog_warn(__VA_ARGS__)
-# define xlog_exit(...) \
-       ( xlog_warn(__VA_ARGS__), exit(1) )
-# define xlog_panic(...) \
-       xlog_exit(__VA_ARGS__)
-#endif
-
-#define xlog_get_bp(nbblks, mp)        libxfs_getbuf(x.logdev, 0, (nbblks))
-#define xlog_put_bp(bp)                libxfs_putbuf(bp)
-#define xlog_bread(log,blkno,nbblks,bp)        \
-       (libxfs_readbufr(x.logdev,      \
-                       (log)->l_logBBstart+(blkno), bp, (nbblks), 1), 0)
-                         
-#define kmem_zalloc(size, foo)                 calloc(size,1)
-#define kmem_free(ptr, foo)                    free(ptr)
-#define kmem_realloc(ptr, len, old, foo)       realloc(ptr, len)
+#include <libxlog.h>
 
 /* command line flags */
 extern int     print_data;
@@ -114,59 +42,10 @@ extern int print_quota;
 extern int     print_buffer;
 extern int     print_transactions;
 extern int     print_overwrite;
-
-extern int     print_exit;
 extern int     print_no_data;
 extern int     print_no_print;
 
 /* exports */
-
 extern char *trans_type[];
 
-/* libxfs parameters */
-extern libxfs_init_t   x;
-
-extern void xfs_log_print_trans(xlog_t          *log,
-                               int             print_block_start);
-
-extern void xfs_log_print(      xlog_t          *log,
-                                int             fd,
-                               int             print_block_start);
-
-extern int  xlog_find_zeroed(xlog_t *log, xfs_daddr_t *blk_no);
-extern int  xlog_find_cycle_start(xlog_t *log, xfs_buf_t *bp,
-               xfs_daddr_t first_blk, xfs_daddr_t *last_blk, uint cycle);
-extern int  xlog_find_tail(xlog_t *log, xfs_daddr_t *head_blk,
-               xfs_daddr_t *tail_blk, int readonly);
-
-extern int  xlog_test_footer(xlog_t *log);
-extern int  xlog_recover(xlog_t *log, int readonly);
-extern void xlog_recover_print_data(xfs_caddr_t p, int len);
-extern void xlog_recover_print_logitem(xlog_recover_item_t *item);
-extern void xlog_recover_print_trans_head(xlog_recover_t *tr);
-extern int  xlog_print_find_oldest(xlog_t *log, xfs_daddr_t *last_blk);
-
-extern void print_xlog_op_line(void);
-extern void print_xlog_record_line(void);
-extern void print_stars(void);
-
-/* for transactional view */
-extern void xlog_recover_print_trans_head(xlog_recover_t *tr);
-
-extern void xlog_recover_print_trans(  xlog_recover_t          *trans,
-                                       xlog_recover_item_t     *itemq,
-                                       int                     print);
-
-extern int  xlog_do_recovery_pass(     xlog_t          *log,
-                                       xfs_daddr_t     head_blk,
-                                       xfs_daddr_t     tail_blk,
-                                       int             pass);
-extern int  xlog_recover_do_trans(     xlog_t          *log,
-                                       xlog_recover_t  *trans,
-                                       int             pass);
-extern int  xlog_header_check_recover(  xfs_mount_t         *mp, 
-                                        xlog_rec_header_t   *head);
-extern int  xlog_header_check_mount(    xfs_mount_t         *mp, 
-                                        xlog_rec_header_t   *head);
-
-#endif /* XFS_LOGPRINT_H */
+#endif /* LOGPRINT_H */
index 14a286cba72f9eb309c5617ccc765f4a466c7211..c671c761c68b1aaa86f0eda6b4051e961729810d 100644 (file)
@@ -3,9 +3,9 @@
 xfs_repair \- repair an XFS filesystem
 .SH SYNOPSIS
 .nf
-\f3xfs_repair\f1 [ \f3\-n\f1 ] [ \f3\-o\f1 subopt[=value] ] xfs_special
+\f3xfs_repair\f1 [ \f3\-nL\f1 ] [ \f3\-o\f1 subopt[=value] ] xfs_special
 .sp .8v
-\f3xfs_repair\f1 \f3\-f\f1 [ \f3\-n\f1 ] [ \f3\-o\f1 subopt[=value] ] ... file
+\f3xfs_repair\f1 \f3\-f\f1 [ \f3\-nL\f1 ] [ \f3\-o\f1 subopt[=value] ] ... file
 .fi
 .SH DESCRIPTION
 .I xfs_repair
@@ -35,6 +35,14 @@ Specifies that the special device is actually a file (see the
 This might happen if an image copy
 of a filesystem has been copied or written into an ordinary file.
 .TP
+.B \-L
+Force Log Zeroing.
+Forces
+.I xfs_repair
+to zero the log even if it is dirty (contains metadata changes).
+When using this option the filesystem will likely appear to be corrupt,
+and can cause the loss of user files and/or data.
+.TP
 .B \-l
 Specifies the device special file where the filesystems external
 log resides.
@@ -340,6 +348,15 @@ will return a status of 1 if filesystem corruption was detected and
 .I xfs_repair
 run without the -n option will always return a status code of 0.
 .SH BUGS
+The filesystem to be checked and repaired must have been
+unmounted cleanly using normal system administration procedures
+(the
+.IR umount (8)
+command or system shutdown), not as a result of a crash or system reset.
+If the filesystem has not been unmounted cleanly, mount it and unmount
+it cleanly before running
+.IR xfs_repair .
+.PP
 .I xfs_repair
 does not do a thorough job on XFS extended attributes.
 The structure of the attribute fork will be consistent,
@@ -358,5 +375,6 @@ are encountered.
 .SH SEE ALSO
 dd(1),
 mkfs.xfs(8),
+umount(8),
 xfs_check(8),
 xfs(5).
index 6537f299f49c6ed079bafb44de4d969d2b2ad449..b6d4feb719ba4eedc306143ac0e0b1e170088064 100644 (file)
@@ -45,8 +45,8 @@ CFILES = agheader.c attr_repair.c avl.c avl64.c bmap.c dino_chunks.c \
        phase2.c phase3.c phase4.c phase5.c phase6.c phase7.c rt.c sb.c \
        scan.c versions.c xfs_repair.c
 
-LLDLIBS = $(LIBXFS) $(LIBUUID)
-LTDEPENDENCIES = $(LIBXFS)
+LLDLIBS = $(LIBXFS) $(LIBXLOG) $(LIBUUID)
+LTDEPENDENCIES = $(LIBXFS) $(LIBXLOG)
 LLDFLAGS = -static
 
 default: $(LTCOMMAND)
index 708c69ec5e44d8e4495382cdbfccd220788b5c1e..71548d3c59475b51b4e40ca32a04df0df0be1f3e 100644 (file)
@@ -121,6 +121,7 @@ EXTERN int  fs_fd;                  /* filesystem fd */
 EXTERN int     verbose;
 EXTERN int     no_modify;
 EXTERN int     isa_file;
+EXTERN int     zap_log;
 EXTERN int     dumpcore;               /* abort, not exit on fatal errs */
 EXTERN int     delete_attr_ok;         /* can clear attrs w/o clearing files */
 EXTERN int     force_geo;              /* can set geo on low confidence info */
index a906892b1747914f41ba5da9c32e0e799e5e12d8..eda5806c9deec36dee9d08aeec8457cb3adb2442 100644 (file)
@@ -30,7 +30,7 @@
  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
  */
 
-#include <libxfs.h>
+#include <libxlog.h>
 #include "avl.h"
 #include "globals.h"
 #include "agheader.h"
 void   set_mp(xfs_mount_t *mpp);
 void   scan_ag(xfs_agnumber_t agno);
 
+/* workaround craziness in the xlog routines */
+int xlog_recover_do_trans(xlog_t *log, xlog_recover_t *t, int p) { return 0; }
+
 static void
-zero_log(xfs_mount_t *mp, libxfs_init_t *args)
+zero_log(xfs_mount_t *mp)
 {
-        int logdev = (mp->m_sb.sb_logstart == 0) ? args->logdev : args->ddev;
-        
+       int error;
+       xlog_t  log;
+       xfs_daddr_t head_blk, tail_blk;
+       dev_t logdev = (mp->m_sb.sb_logstart == 0) ? x.logdev : x.ddev;
+
+       memset(&log, 0, sizeof(log));
+       if (!x.logdev)
+               x.logdev = x.ddev;
+       x.logBBsize = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
+       x.logBBstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart);
+
+       log.l_dev = logdev;
+       log.l_logsize = BBTOB(x.logBBsize);
+       log.l_logBBsize = x.logBBsize;
+       log.l_logBBstart = x.logBBstart;
+       log.l_mp = mp;
+
+       if ((error = xlog_find_tail(&log, &head_blk, &tail_blk, 0))) {
+               do_error("xlog_find_tail returned error %d\n", error);
+               return;
+       } else {
+               if (verbose) {
+                       do_warn("zero_log: head block %lld tail block %lld\n",
+                               head_blk, tail_blk);
+               }
+               if (head_blk != tail_blk) {
+                       if (zap_log) {
+                               do_warn(
+"ALERT: The filesystem has valuable metadata changes in a log which is being\n"
+"destroyed because the -L option was used.\n");
+                       } else {
+                               do_warn(
+"ERROR: The filesystem has valuable metadata changes in a log which needs to\n"
+"be replayed.  Mount the filesystem to replay the log, and unmount it before\n"
+"re-running xfs_repair.  If you are unable to mount the filesystem, then use\n"
+"the -L option to destroy the log and attempt a repair.\n"
+"Note that destroying the log may cause corruption -- please attempt a mount\n"
+"of the filesystem before doing this.\n");
+                               exit(2);
+                       }
+               }
+       }
+
        libxfs_log_clear(logdev, 
                XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
                (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks),
-                &mp->m_sb.sb_uuid,
-                XLOG_FMT);
+               &mp->m_sb.sb_uuid,
+               XLOG_FMT);
 }
 
 /*
@@ -63,7 +107,7 @@ zero_log(xfs_mount_t *mp, libxfs_init_t *args)
  */
 
 void
-phase2(xfs_mount_t *mp, libxfs_init_t *args)
+phase2(xfs_mount_t *mp)
 {
        xfs_agnumber_t          i;
        xfs_agblock_t           b;
@@ -75,7 +119,7 @@ phase2(xfs_mount_t *mp, libxfs_init_t *args)
 
        /* Check whether this fs has internal or external log */
        if (mp->m_sb.sb_logstart == 0) {
-               if (!args->logname) {
+               if (!x.logname) {
                        fprintf (stderr,
                                "This filesystem has an external log.  "
                                "Specify log device with the -l option.\n");
@@ -83,14 +127,14 @@ phase2(xfs_mount_t *mp, libxfs_init_t *args)
                }
                
                fprintf (stderr, "Phase 2 - using external log on %s\n", 
-                        args->logname);
+                        x.logname);
        } else
                fprintf (stderr, "Phase 2 - using internal log\n");
 
        /* Zero log if applicable */
        if (!no_modify)  {
                do_log("        - zero log...\n");
-               zero_log(mp, args);
+               zero_log(mp);
        }
 
        do_log("        - scan filesystem freespace and inode maps...\n");
index 951e3b9308cd2bf8163209abb428d19ab60326aa..a93da1be71362691cbe9d6b8863cefe466814508 100644 (file)
@@ -30,7 +30,7 @@
  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
  */
 
-#include <libxfs.h>
+#include <libxlog.h>
 #include "avl.h"
 #include "avl64.h"
 #include "globals.h"
@@ -43,7 +43,7 @@
 #define        rounddown(x, y) (((x)/(y))*(y))
 
 extern void    phase1(xfs_mount_t *);
-extern void    phase2(xfs_mount_t *, libxfs_init_t *);
+extern void    phase2(xfs_mount_t *);
 extern void    phase3(xfs_mount_t *);
 extern void    phase4(xfs_mount_t *);
 extern void    phase5(xfs_mount_t *);
@@ -147,6 +147,7 @@ process_args(int argc, char **argv)
        verbose = 0;
        no_modify = 0;
        isa_file = 0;
+       zap_log = 0;
        dumpcore = 0;
        full_backptrs = 0;
        delete_attr_ok = 1;
@@ -169,7 +170,7 @@ process_args(int argc, char **argv)
         * XXX have to add suboption processing here
         * attributes, quotas, nlinks, aligned_inos, sb_fbits
         */
-       while ((c = getopt(argc, argv, "o:fnDvVl:")) != EOF)  {
+       while ((c = getopt(argc, argv, "o:flLnDvV:")) != EOF)  {
                switch (c) {
                case 'D':
                        dumpcore = 1;
@@ -208,6 +209,9 @@ process_args(int argc, char **argv)
                case 'f':
                        isa_file = 1;
                        break;
+               case 'L':
+                       zap_log = 1;
+                       break;
                case 'n':
                        no_modify = 1;
                        break;
@@ -401,7 +405,6 @@ calc_mkfs(xfs_mount_t *mp)
 int
 main(int argc, char **argv)
 {
-       libxfs_init_t   args;
        xfs_mount_t     *temp_mp;
        xfs_mount_t     *mp;
        xfs_sb_t        *sb;
@@ -414,7 +417,7 @@ main(int argc, char **argv)
        setbuf(stdout, NULL);
 
        process_args(argc, argv);
-       xfs_init(&args);
+       xfs_init(&x);
 
        /* do phase1 to make sure we have a superblock */
        phase1(temp_mp);
@@ -427,12 +430,12 @@ main(int argc, char **argv)
        }
 
        /* prepare the mount structure */
-       sbp = libxfs_readbuf(args.ddev, XFS_SB_DADDR, 1, 0);
+       sbp = libxfs_readbuf(x.ddev, XFS_SB_DADDR, 1, 0);
        memset(&xfs_m, 0, sizeof(xfs_mount_t));
        sb = &xfs_m.m_sb;
        libxfs_xlate_sb(XFS_BUF_PTR(sbp), sb, 1, ARCH_CONVERT, XFS_SB_ALL_BITS);
 
-       mp = libxfs_mount(&xfs_m, sb, args.ddev, args.logdev, args.rtdev, 0);
+       mp = libxfs_mount(&xfs_m, sb, x.ddev, x.logdev, x.rtdev, 0);
 
        if (!mp)  {
                fprintf(stderr, "%s: cannot repair this filesystem.  Sorry.\n",
@@ -468,7 +471,7 @@ main(int argc, char **argv)
 
        /* make sure the per-ag freespace maps are ok so we can mount the fs */
 
-       phase2(mp, &args);
+       phase2(mp);
 
        phase3(mp);
 
@@ -570,11 +573,11 @@ main(int argc, char **argv)
        libxfs_writebuf(sbp, 0);
 
        libxfs_umount(mp);
-       if (args.rtdev)
-               libxfs_device_close(args.rtdev);
-       if (args.logdev)
-               libxfs_device_close(args.logdev);
-       libxfs_device_close(args.ddev);
+       if (x.rtdev)
+               libxfs_device_close(x.rtdev);
+       if (x.logdev && x.logdev != x.ddev)
+               libxfs_device_close(x.logdev);
+       libxfs_device_close(x.ddev);
 
        do_log("done\n");