Index: fscklog/extract.c
===================================================================
--- fscklog/extract.c (nonexistent)
+++ fscklog/extract.c (revision 5)
@@ -0,0 +1,984 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*
+ * COMPONENT_NAME: jfs_fscklog (formerly xchklog)
+ *
+ * The jfs_fscklog tool provides 2 basic functions - fsck.jfs
+ * service log extraction and display. The code here extracts
+ * the log.
+ *
+ */
+#include <config.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include "devices.h"
+#include "diskmap.h"
+#include "fsckwsp.h"
+#include "fsck_message.h"
+#include "jfs_endian.h"
+#include "jfs_fscklog.h"
+#include "super.h"
+#include "utilsubs.h"
+#include "xfsck.h"
+
+#define fsck_READ 1
+#define fsck_WRITE 2
+
+extern char file_name[128];
+
+FILE *outfp;
+
+extern struct fscklog_record fscklog_record;
+extern struct fscklog_record *local_recptr;
+
+ /* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ *
+ * superblock I/O buffer and pointer
+ *
+ */
+struct superblock aggr_superblock;
+struct superblock *sb_ptr;
+
+ /* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ *
+ * input: fsck service log I/O buffer
+ * output: fsck extracted service log I/O buffer
+ *
+ */
+char fscklog_buffer[FSCKLOG_BUFSIZE];
+extern char xchklog_buffer[];
+
+ /* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ *
+ * For message processing
+ *
+ * values are assigned by the main jfs_fscklog routine
+ */
+extern char *Vol_Label;
+
+ /* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ *
+ * Device information.
+ *
+ * values are assigned when (if) the device is opened.
+ */
+FILE *Dev_IOPort;
+unsigned Dev_blksize;
+int Dev_SectorSize;
+
+/* VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
+ *
+ * The following are internal to this file
+ *
+ */
+void extract_service_log(void);
+
+int xchklog_final_processing(void);
+
+int xchklog_fscklog_fill_buffer(void);
+
+int xchklog_initial_processing(struct fscklog_record *);
+
+int open_device_read(const char *);
+
+int open_outfile(void);
+
+int readwrite_device(int64_t, unsigned, unsigned *, void *, int);
+
+void record_msg(char *);
+
+int validate_super(int);
+
+int validate_superblock(void);
+
+/*****************************************************************************
+ * NAME: xchklog
+ *
+ * FUNCTION: Entry point for jfs read aggregate fsck service log
+ *
+ * PARAMETERS:
+ * local_recptr - fscklog record
+ *
+ * RETURNS:
+ * success: 0
+ * failure: something else
+ */
+int xchklog(struct fscklog_record *local_recptr)
+{
+ int rc = 0;
+
+ /*
+ * some basic initializations
+ */
+ sb_ptr = &aggr_superblock;
+
+ rc = xchklog_initial_processing(local_recptr);
+
+ if (rc == 0) {
+ /* we have a buffer and the device is open */
+ extract_service_log();
+ }
+
+ if (rc == 0) {
+ rc = xchklog_final_processing();
+ } else {
+ xchklog_final_processing();
+ }
+
+ return (rc);
+}
+
+/***************************************************************************
+ * NAME: extract_service_log
+ *
+ * FUNCTION:
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS:
+ * success: 0
+ * failure: something else
+ */
+void extract_service_log()
+{
+ char *msg_txt;
+ int dsl_rc = 0;
+ char *log_entry;
+ int log_entry_pos;
+ int bytes_left;
+ struct fscklog_entry_hdr *hdptr;
+
+ local_recptr->fscklog_last_read = 0;
+
+ while ((!local_recptr->fscklog_last_read) && (dsl_rc == 0)) {
+
+ dsl_rc = xchklog_fscklog_fill_buffer();
+ local_recptr->this_buffer_last_message = 0;
+ while ((!local_recptr->this_buffer_last_message)
+ && (dsl_rc == 0)) {
+
+ hdptr = (struct fscklog_entry_hdr *)
+ (local_recptr->infile_buf_ptr +
+ local_recptr->infile_buf_data_len);
+ if (hdptr->entry_length == 0) {
+ /* no more entries in this buffer */
+ local_recptr->this_buffer_last_message = -1;
+ } else {
+ /* this entry_length != 0 */
+
+ /* swap if on big endian machine */
+ ujfs_swap_fscklog_entry_hdr(hdptr);
+
+ log_entry = (char *) hdptr;
+ log_entry_pos =
+ sizeof (struct fscklog_entry_hdr);
+
+ /*
+ * Each FSCKLOG_BUFSIZE boundary starts a new
+ * log record. Otherwise, we depend on a valid
+ * entry_length to locate the next message.
+ */
+ bytes_left = local_recptr->infile_buf_length -
+ local_recptr->infile_buf_data_len;
+ if ((bytes_left < 0)
+ || (hdptr->entry_length < 0)
+ || (hdptr->entry_length > bytes_left)) {
+ /* this isn't a valid log record length */
+ send_msg(fsck_CHKLOGINVALRCD);
+ local_recptr->this_buffer_last_message =
+ -1;
+ } else {
+ /* the log record length looks ok */
+ msg_txt = &log_entry[log_entry_pos];
+
+ /*
+ * record the message in the output file
+ */
+ record_msg(msg_txt);
+
+ /*
+ * set up for the next record
+ */
+ local_recptr->infile_buf_data_len +=
+ hdptr->entry_length;
+ /*if (hdptr->msg_num == fsck_SESSEND) {
+ local_recptr->
+ this_buffer_last_message =
+ -1;
+ }*/
+ if (local_recptr->infile_buf_data_len >=
+ local_recptr->infile_buf_length) {
+ local_recptr->
+ this_buffer_last_message =
+ -1;
+ }
+ }
+ }
+ }
+ }
+
+ return;
+}
+
+/***************************************************************************
+ * NAME: xchklog_final_processing
+ *
+ * FUNCTION: If processing read/write, replicate the superblock and the
+ * aggregate inode structures (i.e., the Aggregate Inode Map
+ * and the Aggregate Inode Table).
+ *
+ * Notify the user about various things.
+ *
+ * PARAMETERS: none
+ *
+ * RETURNS:
+ * success: 0
+ * failure: something else
+ */
+int xchklog_final_processing()
+{
+ int pf_rc = 0;
+
+ /*
+ * Close the device
+ */
+ if (local_recptr->device_is_open) {
+ pf_rc = fclose(Dev_IOPort);
+ }
+
+ /*
+ * Close the output file
+ */
+ if (local_recptr->outfile_is_open) {
+ /*
+ * flush the buffer if necessary
+ */
+ if (local_recptr->outfile_buf_data_len != 0) {
+ fwrite((const void *) (local_recptr->outfile_buf_ptr),
+ sizeof (char), local_recptr->outfile_buf_length,
+ outfp);
+ }
+ fclose(outfp);
+ }
+
+ return (pf_rc);
+}
+
+/*****************************************************************************
+ * NAME: fscklog_fill_buffer
+ *
+ * FUNCTION: If the current fsck session has write access to the aggregate,
+ * and if the in-aggregate fsck log is not full, write the
+ * contents of the current fscklog buffer into the in-aggregate
+ * fsck log.
+ *
+ * PARAMETERS: none
+ *
+ * NOTES: o Unlike most _put_ routines in this module, fscklog_put_buffer
+ * actually writes to the device. This is done because the fsck
+ * log contains information which provides crucial serviceability
+ * should the fsck session be interrupted.
+ *
+ * o Errors here are recorded in the control page of the fsck
+ * in-aggregate workspace but never affect other fsck processing.
+ *
+ * RETURNS:
+ * success: 0
+ * failure: something else
+ */
+int xchklog_fscklog_fill_buffer()
+{
+ int flfb_rc = 0;
+ int io_rc = 0;
+ unsigned bytes_read = 0;
+ unsigned log_bytes_left;
+
+ io_rc = readwrite_device(local_recptr->infile_agg_offset,
+ local_recptr->infile_buf_length,
+ &bytes_read,
+ (void *) local_recptr->infile_buf_ptr,
+ fsck_READ);
+
+ if ((io_rc != 0)
+ || (bytes_read != (unsigned) local_recptr->infile_buf_length)) {
+ /*
+ * write failed or didn't read
+ * correct number of bytes
+ */
+ send_msg(fsck_URCVWRT, fsck_ref_msg(fsck_metadata), Vol_Label);
+
+ send_msg(fsck_ERRONLOG, FSCK_BADREAD_FSCKLOG, io_rc, fsck_READ,
+ (long long) local_recptr->infile_agg_offset,
+ (long int) local_recptr->infile_buf_length,
+ (long int) bytes_read);
+ }
+ /*
+ * We want to reset the buffer no matter what. If is useful
+ * to keep going because the next section may be readable.
+ */
+ local_recptr->infile_agg_offset += local_recptr->infile_buf_length;
+ local_recptr->infile_log_offset += local_recptr->infile_buf_length;
+ local_recptr->infile_buf_data_len = 0;
+
+ log_bytes_left = (local_recptr->ondev_fscklog_byte_length / 2) -
+ local_recptr->infile_log_offset;
+ if (log_bytes_left < local_recptr->infile_buf_length) {
+ /* this is the last one */
+ local_recptr->fscklog_last_read = -1;
+ }
+ return (flfb_rc);
+}
+
+/*****************************************************************************
+ * NAME: xchklog_initial_processing
+ *
+ * FUNCTION: Parse and verify invocation parameters.
+ * Open the device and verify that it contains a JFS file system.
+ * Read the chkdsk workspace control page.
+ * Calculate interesting aggregate offsets.
+ *
+ *
+ * PARAMETERS: as specified to main()
+ *
+ * NOTES:
+ *
+ * RETURNS:
+ * success: 0
+ * failure: something else
+ */
+int xchklog_initial_processing(struct fscklog_record *local_recptr)
+{
+ int pi_rc = 0;
+
+ /*
+ * Initialize the fscklog control block
+ */
+ local_recptr->infile_buf_length = FSCKLOG_BUFSIZE;
+ local_recptr->infile_buf_ptr = fscklog_buffer;
+ local_recptr->outfile_buf_length = XCHKLOG_BUFSIZE;
+ local_recptr->outfile_buf_ptr = xchklog_buffer;
+
+ /*
+ * Open the device and verify that it contains a valid JFS aggregate
+ * If it does, check/repair the superblock.
+ */
+ pi_rc = open_device_read(Vol_Label);
+
+ if (pi_rc != 0) {
+ /*device open failed */
+ send_msg(fsck_CNTRESUPB);
+ } else {
+ /* device is open */
+ local_recptr->device_is_open = 1;
+ pi_rc = validate_superblock();
+ if (pi_rc == 0) {
+ /* a valid superblock */
+
+ /*
+ * add some stuff to the local record which is based on
+ * superblock fields
+ */
+
+ /* length of the on-device fsck service log */
+ local_recptr->ondev_fscklog_byte_length =
+ sb_ptr->s_fsckloglen * sb_ptr->s_bsize;
+ /* length of the on-device fsck service log */
+ local_recptr->ondev_fscklog_fsblk_length =
+ sb_ptr->s_fsckloglen;
+ /* length of the on-device fsck workspace */
+ local_recptr->ondev_wsp_fsblk_length =
+ lengthPXD(&(sb_ptr->s_fsckpxd)) -
+ local_recptr->ondev_fscklog_fsblk_length;
+ /* length of the on-device fsck workspace */
+ local_recptr->ondev_wsp_byte_length =
+ local_recptr->ondev_wsp_fsblk_length *
+ sb_ptr->s_bsize;
+ /* aggregate block offset of the on-device fsck workspace */
+ local_recptr->ondev_wsp_fsblk_offset =
+ addressPXD(&(sb_ptr->s_fsckpxd));
+ /* byte offset of the on-device fsck workspace */
+ local_recptr->ondev_wsp_byte_offset =
+ local_recptr->ondev_wsp_fsblk_offset *
+ sb_ptr->s_bsize;
+ /* aggregate block offset of the on-device fsck workspace */
+ local_recptr->ondev_fscklog_fsblk_offset =
+ local_recptr->ondev_wsp_fsblk_offset +
+ local_recptr->ondev_wsp_fsblk_length;
+ /* byte offset of the on-device fsck workspace */
+ local_recptr->ondev_fscklog_byte_offset =
+ local_recptr->ondev_wsp_byte_offset +
+ local_recptr->ondev_wsp_byte_length;
+ /*
+ * The offsets now assume the most recent log is 1st in the
+ * aggregate fsck service log space. Adjust if needed.
+ */
+ if (local_recptr->which_log == NEWLOG) {
+ /* most recent wanted */
+ if (sb_ptr->s_fscklog == 2) {
+ /* the 2nd is most recent */
+ local_recptr->
+ ondev_fscklog_fsblk_offset +=
+ local_recptr->
+ ondev_fscklog_fsblk_length / 2;
+ local_recptr->
+ ondev_fscklog_byte_offset +=
+ local_recptr->
+ ondev_fscklog_byte_length / 2;
+ }
+ } else {
+ /* previous log wanted */
+ if (sb_ptr->s_fscklog != 2) {
+ /* the 2nd is not most recent */
+ local_recptr->
+ ondev_fscklog_fsblk_offset +=
+ local_recptr->
+ ondev_fscklog_fsblk_length / 2;
+ local_recptr->
+ ondev_fscklog_byte_offset +=
+ local_recptr->
+ ondev_fscklog_byte_length / 2;
+ }
+ }
+ local_recptr->infile_agg_offset =
+ local_recptr->ondev_fscklog_byte_offset;
+
+ pi_rc = open_outfile();
+ }
+ }
+
+ if (local_recptr->which_log == NEWLOG) {
+ send_msg(fsck_CHKLOGNEW);
+ } else {
+ send_msg(fsck_CHKLOGOLD);
+ }
+
+ return (pi_rc);
+}
+
+/*****************************************************************************
+ * NAME: open_device_read
+ *
+ * FUNCTION: Open the specified device for read access.
+ *
+ * PARAMETERS:
+ * Device - input - the device specification
+ *
+ * NOTES:
+ *
+ * RETURNS:
+ * success: 0
+ * failure: something else
+ */
+int open_device_read(const char *Device)
+{
+ Dev_IOPort = fopen(Device, "r");
+ if (Dev_IOPort == NULL) {
+ send_msg(fsck_DEVOPENRDRC, ERROR_FILE_NOT_FOUND);
+ return ERROR_FILE_NOT_FOUND;
+ }
+
+ Dev_blksize = Dev_SectorSize = PBSIZE;
+ return 0;
+}
+
+/*****************************************************************************
+ * NAME: open_outfile
+ *
+ * FUNCTION: Open the output file.
+ *
+ * PARAMETERS:
+ * Device - input - the device specification
+ *
+ * RETURNS:
+ * success: 0
+ * failure: something else
+ */
+int open_outfile()
+{
+ int openof_rc = 0;
+
+ if (!local_recptr->file_name_specified) {
+ /* no output file name given */
+ if (local_recptr->which_log == NEWLOG) {
+ /* most recent wanted */
+ memcpy((void *) file_name, (void *) default_logfile_new,
+ default_logfile_name_len);
+ } else {
+ /* prior log wanted */
+ memcpy((void *) file_name, (void *) default_logfile_old,
+ default_logfile_name_len);
+ }
+ }
+
+ outfp = fopen(file_name, "w");
+ if (outfp == NULL) {
+ /* output file open failed */
+ openof_rc = XCHKLOG_CANTOPENOUTFILE;
+ send_msg(fsck_XCHKLOGOPNFAIL, file_name);
+ } else {
+ /* output file is open */
+ local_recptr->outfile_is_open = -1;
+
+ /*
+ * write the eyecatcher into the output buffer
+ */
+ memcpy((void *) (local_recptr->outfile_buf_ptr),
+ (void *) jfs_chklog_eyecatcher, 16);
+ local_recptr->outfile_buf_data_len = 16;
+
+ /*
+ * announce the output file name
+ */
+ if (local_recptr->which_log == NEWLOG) {
+ /* most recent */
+ send_msg(fsck_XCHKLOGNEW, file_name);
+ } else {
+ /* previous */
+ send_msg(fsck_XCHKLOGOLD, file_name);
+ }
+ }
+ return (openof_rc);
+}
+
+/*****************************************************************************
+ * NAME: readwrite_device
+ *
+ * FUNCTION: Read data from or write data to the device on which the
+ * aggregate resides.
+ *
+ * PARAMETERS:
+ * dev_offset - input - the offset, in bytes, into the aggregate
+ * of the data to read or to which to write
+ * the data.
+ * requested_data_size - input - the number of bytes requested
+ * actual_data_size - input - pointer to a variable in which to return
+ * the number of bytes actually read or
+ * written
+ * data_buffer - input - the address of the buffer in which to
+ * put the data or from which to write
+ * the data
+ * mode - input - { fsck_READ | fsck_WRITE }
+ *
+ * NOTES: This routine also exists in fsck code. When there is time,
+ * examine both copies for differences and put the combined
+ * copy in libfs to eliminate extra code.
+ *
+ * RETURNS:
+ * success: 0
+ * failure: something else
+ */
+int readwrite_device(int64_t dev_offset,
+ unsigned requested_data_size,
+ unsigned *actual_data_size, void *data_buffer, int mode)
+{
+ int rwdb_rc = 0;
+
+ if ((dev_offset % Dev_SectorSize)
+ || (requested_data_size % Dev_SectorSize)) {
+ rwdb_rc = FSCK_FAILED_SEEK;
+ } else {
+ switch (mode) {
+ case fsck_READ:
+ rwdb_rc =
+ ujfs_rw_diskblocks(Dev_IOPort, dev_offset,
+ requested_data_size, data_buffer,
+ GET);
+ break;
+ case fsck_WRITE:
+ rwdb_rc =
+ ujfs_rw_diskblocks(Dev_IOPort, dev_offset,
+ requested_data_size, data_buffer,
+ PUT);
+ break;
+ default:
+ rwdb_rc = FSCK_INTERNAL_ERROR_3;
+ break;
+ }
+ }
+
+ if (rwdb_rc == 0)
+ *actual_data_size = requested_data_size;
+ else
+ *actual_data_size = 0;
+
+ return (rwdb_rc);
+}
+
+/*****************************************************************************
+ * NAME: record_msg
+ *
+ * FUNCTION: Record an fsck service log message in the output file,
+ * formatted for the common fsck service log display tool.
+ *
+ * PARAMETERS:
+ * ? - input -
+ * ? - returned -
+ *
+ * NOTES: Any message designated fsck_debug is english-only, and
+ * is issued in english, even if it is sent to stdout.
+ *
+ * All other messages are local-language (in the nls context)
+ * and, when sent to stdout or stderr, are issued in the
+ * local language.
+ *
+ * Regardless of the language used to send a message to
+ * stdout and stderr, messages are ALWAYS LOGGED IN ENGLISH.
+ *
+ * RETURNS:
+ * nothing
+ */
+void record_msg(char *msg_txt)
+{
+ char *msg;
+ char log_entry[4096];
+ int entry_length = sizeof (struct chklog_entry_hdr);
+ struct chklog_entry_hdr *hdptr;
+ int buffer_bytes_left;
+
+ hdptr = (struct chklog_entry_hdr *) log_entry;
+ msg = &log_entry[entry_length];
+ strcpy(msg, msg_txt);
+ entry_length += strlen(msg_txt);
+ /* add null terminator to string */
+ log_entry[entry_length++] = '\0';
+
+ /*
+ * round the length up so the next entry will
+ * start on a doubleword (4 byte) boundary
+ */
+ entry_length = ((entry_length + 3) / 4) * 4;
+
+ hdptr->entry_length = entry_length;
+
+ buffer_bytes_left =
+ local_recptr->outfile_buf_length -
+ local_recptr->outfile_buf_data_len;
+ if (buffer_bytes_left < entry_length) {
+ /* won't fit */
+ local_recptr->last_msghdr->entry_length += buffer_bytes_left;
+ fwrite((const void *) (local_recptr->outfile_buf_ptr),
+ sizeof (char), local_recptr->outfile_buf_length, outfp);
+ /* clear the buffer */
+ memset((void *) (local_recptr->outfile_buf_ptr), 0,
+ local_recptr->outfile_buf_length);
+ local_recptr->outfile_buf_data_len = 0;
+ }
+ local_recptr->last_msghdr = (struct fscklog_entry_hdr *)
+ (local_recptr->outfile_buf_ptr +
+ local_recptr->outfile_buf_data_len);
+ memcpy((void *) local_recptr->last_msghdr, (void *) hdptr,
+ entry_length);
+
+ local_recptr->outfile_buf_data_len += entry_length;
+
+ return;
+}
+
+/*****************************************************************************
+ * NAME: validate_super
+ *
+ * FUNCTION: This routine validates the JFS superblock currently in the
+ * buffer. If any problem is detected, the which_superblock
+ * input parm is used to tailor the message issued to notify
+ * the user.
+ *
+ * PARAMETERS:
+ * which_super - input - specifies the superblock on which is in the
+ * buffer { fsck_primary | fsck_secondary }
+ *
+ * NOTES: This routine also exists in fsck code. When there is time,
+ * examine both copies for differences and put the combined
+ * copy in libfs to eliminate extra code.
+ *
+ * RETURNS:
+ * success: 0
+ * failure: something else
+ */
+int validate_super(int which_super)
+{
+ int vs_rc = 0; /* assume the superblock is ok */
+ int64_t bytes_on_device;
+ int64_t agg_blks_in_aggreg = 0, agg_blks_on_device =
+ 0, dev_blks_on_device;
+ int64_t fsck_start_from_pxd, fsck_blkmap_start_blks;
+ uint32_t fsck_length_from_pxd, fsck_blkmap_size_blks,
+ fsck_blkmap_size_pages;
+ int64_t jlog_start_from_pxd;
+ uint32_t jlog_length_from_pxd;
+ int agl2size;
+ unsigned expected_flag = JFS_GROUPCOMMIT;
+ unsigned agsize;
+ int bad_bsize = 0;
+
+ if (memcmp(sb_ptr->s_magic, JFS_MAGIC, sizeof (sb_ptr->s_magic)) != 0) {
+ vs_rc = FSCK_BADSBMGC;
+ send_msg(fsck_BADSBMGC, fsck_ref_msg(which_super));
+ } else if (sb_ptr->s_version > JFS_VERSION) {
+ vs_rc = FSCK_BADSBVRSN;
+ send_msg(fsck_BADSBVRSN, fsck_ref_msg(which_super));
+ } else {
+ /* the magic number and version number are correct so it
+ * probably is a JFS superblock with the format we are expecting
+ */
+
+ /* get physical device size */
+ ujfs_get_dev_size(Dev_IOPort, &bytes_on_device);
+
+ dev_blks_on_device = bytes_on_device / Dev_blksize;
+
+ if (sb_ptr->s_pbsize != Dev_blksize) {
+ vs_rc = FSCK_BADSBOTHR1;
+ send_msg(fsck_BADSBOTHR, "1", fsck_ref_msg(which_super));
+ }
+ if (sb_ptr->s_l2pbsize != log2shift(Dev_blksize)) {
+ vs_rc = FSCK_BADSBOTHR2;
+ send_msg(fsck_BADSBOTHR, "2", fsck_ref_msg(which_super));
+ }
+ if (!inrange(sb_ptr->s_bsize, 512, 4096)) {
+ bad_bsize = -1;
+ vs_rc = FSCK_BADSBOTHR3;
+ send_msg(fsck_BADSBBLSIZ, fsck_ref_msg(which_super));
+ } else {
+ /* else the filesystem block size is a legal value */
+ if (sb_ptr->s_l2bsize != log2shift(sb_ptr->s_bsize)) {
+ vs_rc = FSCK_BADSBOTHR4;
+ send_msg(fsck_BADSBOTHR, "4",
+ fsck_ref_msg(which_super));
+ }
+ if (sb_ptr->s_l2bfactor !=
+ log2shift(sb_ptr->s_bsize / Dev_blksize)) {
+ vs_rc = FSCK_BADSBOTHR5;
+ send_msg(fsck_BADSBOTHR, "5",
+ fsck_ref_msg(which_super));
+ }
+ if (sb_ptr->s_bsize < Dev_blksize) {
+ bad_bsize = -1;
+ vs_rc = FSCK_BLSIZLTLVBLSIZ;
+ send_msg(fsck_BLSIZLTLVBLSIZ,
+ fsck_ref_msg(which_super));
+ }
+ }
+
+ if (!bad_bsize) {
+ agg_blks_on_device = bytes_on_device / sb_ptr->s_bsize;
+ }
+
+ if (sb_ptr->s_size > dev_blks_on_device) {
+ vs_rc = FSCK_BADSBFSSIZ;
+ send_msg(fsck_BADSBFSSIZ, fsck_ref_msg(which_super));
+ }
+#ifdef _JFS_DFS_LFS
+ s_size_inbytes = sb_ptr->s_size * Dev_blksize;
+ sum_inbytes = (int64_t) (sb_ptr->totalUsable * 1024) +
+ (int64_t) (sb_ptr->minFree * 1024);
+ if ((sum_inbytes > s_size_inbytes)
+ || ((s_size_inbytes - sum_inbytes) >= 1024)) {
+ /* the sum is greater or the difference is at least 1K */
+ vs_rc = FSCK_BADBLKCTTTL;
+ send_msg(fsck_BADBLKCTTTL, fsck_ref_msg(which_super));
+ }
+#endif
+ /* must have JFS_OS2 or JFS_LINUX */
+ if (!(((sb_ptr->s_flag & JFS_OS2) == JFS_OS2)
+ || ((sb_ptr->s_flag & JFS_LINUX) == JFS_LINUX))) {
+ vs_rc = FSCK_BADSBOTHR6;
+ send_msg(fsck_BADSBOTHR, "6", fsck_ref_msg(which_super));
+ }
+
+ if ((sb_ptr->s_flag & expected_flag) != expected_flag) {
+ vs_rc = FSCK_BADSBOTHR6;
+ send_msg(fsck_BADSBOTHR, "6", fsck_ref_msg(which_super));
+ }
+ if (sb_ptr->s_agsize < (1 << L2BPERDMAP)) {
+ vs_rc = FSCK_BADSBAGSIZ;
+ send_msg(fsck_BADSBAGSIZ, fsck_ref_msg(which_super));
+ } else {
+ /* else the alloc group size is possibly correct */
+ agg_blks_in_aggreg =
+ sb_ptr->s_size * sb_ptr->s_pbsize / sb_ptr->s_bsize;
+ agl2size =
+ ujfs_getagl2size(agg_blks_in_aggreg,
+ sb_ptr->s_bsize);
+ /* get the allocation group size */
+ agsize = (int64_t) 1 << agl2size;
+ if (sb_ptr->s_agsize != agsize) {
+ vs_rc = FSCK_BADAGFSSIZ;
+ send_msg(fsck_BADSBAGSIZ, fsck_ref_msg(which_super));
+ }
+ }
+
+ if (!vs_rc) {
+ /*
+ * check out the fsck in-aggregate workspace
+ */
+ fsck_length_from_pxd = lengthPXD(&(sb_ptr->s_fsckpxd));
+ fsck_start_from_pxd = addressPXD(&(sb_ptr->s_fsckpxd));
+ agg_blks_in_aggreg = fsck_length_from_pxd +
+ (sb_ptr->s_size * sb_ptr->s_pbsize /
+ sb_ptr->s_bsize);
+
+ if (agg_blks_in_aggreg > agg_blks_on_device) {
+ /* wsp length is bad */
+ vs_rc = FSCK_BADSBFWSL1;
+ send_msg(fsck_BADSBFWSL1, fsck_ref_msg(which_super));
+ } else {
+ fsck_blkmap_size_pages =
+ ((agg_blks_in_aggreg +
+ (BITSPERPAGE - 1)) / BITSPERPAGE) + 1 +
+ 50;
+ /* size in aggregate blocks */
+ fsck_blkmap_size_blks =
+ (fsck_blkmap_size_pages << L2PSIZE) /
+ sb_ptr->s_bsize;
+ /*
+ * aggregate block offset of the
+ * fsck workspace in the aggregate.
+ */
+ fsck_blkmap_start_blks =
+ agg_blks_in_aggreg - fsck_blkmap_size_blks;
+ if (fsck_length_from_pxd !=
+ fsck_blkmap_size_blks) {
+ /*
+ * length of fsck in-aggregate
+ * workspace is incorrect
+ */
+ vs_rc = FSCK_BADSBFWSL;
+ send_msg(fsck_BADSBFWSL,
+ fsck_ref_msg(which_super));
+ }
+ if (fsck_start_from_pxd !=
+ fsck_blkmap_start_blks) {
+ /*
+ * address of fsck in-aggregate
+ * workspace is incorrect
+ */
+ vs_rc = FSCK_BADSBFWSA;
+ send_msg(fsck_BADSBFWSA,
+ fsck_ref_msg(which_super));
+ }
+ }
+ }
+ if (!vs_rc) {
+ /*
+ * check out the in-aggregate journal log
+ *
+ * if there is one it starts at the end of the fsck
+ * in-aggregate workspace.
+ */
+ jlog_length_from_pxd = lengthPXD(&(sb_ptr->s_logpxd));
+ jlog_start_from_pxd = addressPXD(&(sb_ptr->s_logpxd));
+
+ if (jlog_start_from_pxd != 0) {
+ /* there's one in there */
+ if (jlog_start_from_pxd != agg_blks_in_aggreg) {
+ /*
+ * address of in-aggregate
+ * journal log is incorrect
+ */
+ vs_rc = FSCK_BADSBFJLA;
+ send_msg(fsck_BADSBFJLA,
+ fsck_ref_msg(which_super));
+ }
+ agg_blks_in_aggreg += jlog_length_from_pxd;
+ if (agg_blks_in_aggreg > agg_blks_on_device) {
+ /* log length is bad */
+ vs_rc = FSCK_BADSBFJLL;
+ send_msg(fsck_BADSBFJLL,
+ fsck_ref_msg(which_super));
+ }
+ }
+ }
+ }
+ return (vs_rc);
+}
+
+/*****************************************************************************
+ * NAME: validate_superblock
+ *
+ * FUNCTION: Verify that the primary superblock is valid.
+ * If not, verify that the secondary superblock is valid.
+ *
+ * PARAMETERS: none
+ *
+ * NOTES: If this routine returns 0 then the superblock
+ * I/O buffer contains a valid superblock.
+ *
+ * This routine also exists in fsck code. When there is time,
+ * examine both copies for differences and put the combined
+ * copy in libfs to eliminate extra code.
+ *
+ * RETURNS:
+ * success: 0
+ * failure: something else
+ */
+int validate_superblock()
+{
+ int vsb_rc = 0;
+ int primary_sb_bad = 1;
+ int secondary_sb_bad = 1;
+ int which_sb = 0;
+
+ /* get primary */
+ vsb_rc = ujfs_get_superblk(Dev_IOPort, sb_ptr, 1);
+
+ if (vsb_rc != 0) {
+ /* if read primary fails */
+ send_msg(fsck_CNTRESUPP);
+ } else {
+ /* got primary superblock */
+ which_sb = fsck_primary;
+ primary_sb_bad = validate_super(fsck_primary);
+ }
+
+ if (primary_sb_bad) {
+ /* can't use the primary superblock */
+ send_msg(fsck_SBBADP);
+
+ /* get 2ndary */
+ vsb_rc = ujfs_get_superblk(Dev_IOPort, sb_ptr, 0);
+
+ if (vsb_rc != 0) {
+ send_msg(fsck_CNTRESUPS);
+ } else {
+ /* got secondary superblock */
+ which_sb = fsck_secondary;
+ secondary_sb_bad = validate_super(fsck_secondary);
+ }
+
+ if (!secondary_sb_bad) {
+ /* secondary is ok */
+ vsb_rc = 0;
+ } else {
+ send_msg(fsck_SBBADS);
+ }
+ }
+ if ((!primary_sb_bad) || (!secondary_sb_bad)) {
+ /* the buffer holds a valid superblock */
+
+ /* aggregate block size */
+ local_recptr->ag_blk_size = sb_ptr->s_bsize;
+
+ send_msg(fsck_XCHKLOGSBOK, fsck_ref_msg(which_sb));
+ }
+
+ return (vsb_rc);
+}
Index: fscklog
===================================================================
--- fscklog (nonexistent)
+++ fscklog (revision 5)
Property changes on: fscklog
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: libfs/devices.c
===================================================================
--- libfs/devices.c (nonexistent)
+++ libfs/devices.c (revision 5)
@@ -0,0 +1,474 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2000-2008
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * autoconf 2.61 causes fseeko to miscompile against glibc-2.3.
+ * Override config.h by defining _LARGEFILE_SOURCE here
+ */
+#define _LARGEFILE_SOURCE
+
+#include <config.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_SYS_MOUNT_H
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#include <sys/mount.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/sysmacros.h>
+#if defined(__DragonFly__)
+#include <machine/param.h>
+#include <sys/diskslice.h>
+#endif
+
+#ifdef HAVE_SYS_DISKLABEL_H
+#include <sys/disklabel.h>
+#endif
+
+#include "jfs_types.h"
+#include "jfs_filsys.h"
+#include "devices.h"
+#include "debug.h"
+
+#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE64)
+#define BLKGETSIZE64 _IOR(0x12, 114, size_t)
+#endif
+#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
+#define BLKGETSIZE _IO(0x12,96) /* return device size (sectors) */
+#endif
+
+/*
+ * NAME: ujfs_device_is_valid
+ *
+ * FUNCTION: Check device validity by examining stat modes.
+ *
+ * PRE CONDITIONS: 'device' must refer to an open device handle.
+ *
+ * PARAMETERS:
+ * device_handle - open device handle to check
+ * st - stat information if device handle not provided
+ *
+ * RETURNS: 0 if successful; anything else indicates failures
+ */
+int ujfs_device_is_valid(FILE *device_handle, struct stat *st)
+{
+ struct stat stat_data;
+ int rc = 0;
+
+ if (device_handle != NULL) {
+ rc = fstat(fileno(device_handle), &stat_data);
+ if (rc)
+ return -1;
+ st = &stat_data;
+ }
+ else if (st == NULL) {
+ return -1;
+ }
+
+ /* Do we have a block special device or regular file? */
+#if defined(__DragonFly__)
+ if (!S_ISCHR(st->st_mode) && !S_ISREG(st->st_mode))
+#else /* __linux__ etc. */
+ if (!S_ISBLK(st->st_mode) && !S_ISREG(st->st_mode))
+#endif
+ return -1;
+
+ return (rc);
+}
+
+/*
+ * NAME: ujfs_get_dev_size
+ *
+ * FUNCTION: Uses the device driver interface to determine the raw capacity of
+ * the specified device.
+ *
+ * PRE CONDITIONS:
+ *
+ * POST CONDITIONS:
+ *
+ * PARAMETERS:
+ * device - device
+ * size - filled in with size of device; not modified if failure occurs
+ *
+ * NOTES:
+ *
+ * DATA STRUCTURES:
+ *
+ * RETURNS: 0 if successful; anything else indicates failures
+ */
+int ujfs_get_dev_size(FILE *device, int64_t *size)
+{
+
+ off_t Starting_Position; /* position within file/device upon
+ * entry to this function. */
+ off_t Current_Position = 16777215; /* position we are attempting
+ * to read from. */
+ off_t Last_Valid_Position = 0; /* Last position we could successfully
+ * read from. */
+ off_t First_Invalid_Position; /* first invalid position we attempted
+ * to read from/seek to. */
+ int Seek_Result; /* value returned by lseek. */
+ size_t Read_Result = 0; /* value returned by read. */
+ int rc;
+ struct stat stat_data;
+ int devfd = fileno(device);
+
+ rc = fstat(devfd, &stat_data);
+ if (!rc && S_ISREG(stat_data.st_mode)) {
+ /* This is a regular file. */
+ *size = (int64_t) ((stat_data.st_size / 1024) * 1024);
+ return NO_ERROR;
+ }
+#ifdef BLKGETSIZE64
+ {
+ uint64_t sz;
+ if (ioctl(devfd, BLKGETSIZE64, &sz) >= 0) {
+ *size = sz;
+ return 0;
+ }
+ }
+#endif
+#ifdef BLKGETSIZE
+ {
+ unsigned long num_sectors = 0;
+
+ if (ioctl(devfd, BLKGETSIZE, &num_sectors) >= 0) {
+ /* for now, keep size as multiple of 1024, *
+ * not 512, so eliminate any odd sector. */
+ *size = PBSIZE * (int64_t) ((num_sectors / 2) * 2);
+ return NO_ERROR;
+ }
+ }
+#endif
+#if defined(__DragonFly__)
+ {
+ struct diskslices dss;
+ struct disklabel dl;
+ struct diskslice *sliceinfo;
+ int slice;
+ dev_t dev = stat_data.st_rdev;
+
+ rc = ioctl(devfd, DIOCGSLICEINFO, &dss);
+ if (rc < 0)
+ return -1;
+
+ slice = dkslice(dev);
+ sliceinfo = &dss.dss_slices[slice];
+
+ DBG_TRACE(("ujfs_get_device_size: slice = %d\n", slice));
+
+ if (sliceinfo) {
+ if (slice == WHOLE_DISK_SLICE || slice == 0) {
+ *size = (int64_t) sliceinfo->ds_size * dss.dss_secsize;
+ DBG_TRACE(("ujfs_get_device_size: slice represents disk\n"));
+ } else {
+ if (sliceinfo->ds_label) {
+ DBG_TRACE(("ujfs_get_device_size: slice has disklabel\n"));
+ rc = ioctl(devfd, DIOCGDINFO, &dl);
+ if (!rc) {
+ *size = (int64_t) dl.d_secperunit * dss.dss_secsize;
+ } else {
+ return (-1);
+ }
+ }
+ }
+ } else {
+ return (-1);
+ }
+
+ DBG_TRACE(("ujfs_get_device_size: size in bytes = %ld\n", *size));
+ DBG_TRACE(("ujfs_get_device_size: size in megabytes = %ld\n",
+ *size / (1024 * 1024)));
+
+ return 0;
+ }
+#endif
+#if defined(HAVE_SYS_DISKLABEL_H) && !defined(__DragonFly__)
+ {
+ struct disklabel dl;
+ struct partition * part;
+ dev_t dev = stat_data.st_rdev;
+
+ rc = ioctl(devfd, DIOCGDINFO, &dl);
+ if (rc < 0)
+ return -1;
+ part = dl.d_partitions + DISKPART(dev);
+
+ *size = (dl.d_secsize * part->p_size);
+
+ DBG_TRACE(("ujfs_get_device_size: size in bytes = %ld\n",
+ *size));
+ DBG_TRACE(("ujfs_get_device_size: size in megabytes = %ld\n",
+ *size / (1024 * 1024)));
+
+ return NO_ERROR;
+ }
+#endif
+
+
+ /*
+ * If the ioctl above fails or is undefined, use a binary search to
+ * find the last byte in the partition. This works because an lseek to
+ * a position within the partition does not return an error while an
+ * lseek to a position beyond the end of the partition does. Note that
+ * some SCSI drivers may log an 'access beyond end of device' error
+ * message.
+ */
+
+ /* Save the starting position so that we can restore it when we are
+ * done! */
+ Starting_Position = ftello(device);
+ if (Starting_Position < 0)
+ return ERROR_SEEK;
+
+ /*
+ * Find a position beyond the end of the partition. We will start by
+ * attempting to seek to and read the 16777216th byte in the partition.
+ * We start here because a JFS partition must be at least this big. If
+ * it is not, then we can not format it as JFS.
+ */
+ do {
+ /* Seek to the location we wish to test. */
+ Seek_Result = fseeko(device, Current_Position, SEEK_SET);
+ if (Seek_Result == 0) {
+ /* Can we read from this location? */
+ Read_Result = fgetc(device);
+ if (Read_Result != EOF) {
+ /* The current test position is valid. Save it
+ * for future reference. */
+ Last_Valid_Position = Current_Position;
+
+ /* Lets calculate the next location to test. */
+ Current_Position = ((Current_Position + 1) * 2)
+ - 1;
+
+ }
+ }
+ } while ((Seek_Result == 0) && (Read_Result == 1));
+
+ /*
+ * We have exited the while loop, which means that Current Position is
+ * beyond the end of the partition or is unreadable due to a hardware
+ * problem (bad block). Since the odds of hitting a bad block are very
+ * low, we will ignore that condition for now. If time becomes
+ * available, then this issue can be revisited.
+ */
+
+ /* Is the drive greater than 16MB? */
+ if (Last_Valid_Position == 0) {
+ /*
+ * Determine if drive is readable at all. If it is, the drive
+ * is too small. If not, it could be a newly created partion,
+ * so we need to issue a different error message
+ */
+ *size = 0; /* Indicates not readable at all */
+ Seek_Result = fseeko(device, Last_Valid_Position, SEEK_SET);
+ if (Seek_Result == 0) {
+ /* Can we read from this location? */
+ Read_Result = fgetc(device);
+ if (Read_Result != EOF)
+ /* non-zero indicates readable, but too small */
+ *size = 1;
+ }
+ goto restore;
+ }
+ /*
+ * The drive is larger than 16MB. Now we must find out exactly how
+ * large.
+ *
+ * We now have a point within the partition and one beyond it. The end
+ * of the partition must lie between the two. We will use a binary
+ * search to find it.
+ */
+
+ /* Setup for the binary search. */
+ First_Invalid_Position = Current_Position;
+ Current_Position = Last_Valid_Position +
+ ((Current_Position - Last_Valid_Position) / 2);
+
+ /*
+ * Iterate until the difference between the last valid position and the
+ * first invalid position is 2 or less.
+ */
+ while ((First_Invalid_Position - Last_Valid_Position) > 2) {
+ /* Seek to the location we wish to test. */
+ Seek_Result = fseeko(device, Current_Position, SEEK_SET);
+ if (Seek_Result == 0) {
+ /* Can we read from this location? */
+ Read_Result = fgetc(device);
+ if (Read_Result != EOF) {
+ /* The current test position is valid.
+ * Save it for future reference. */
+ Last_Valid_Position = Current_Position;
+
+ /*
+ * Lets calculate the next location to test. It
+ * should be half way between the current test
+ * position and the first invalid position that
+ * we know of.
+ */
+ Current_Position = Current_Position +
+ ((First_Invalid_Position -
+ Last_Valid_Position) / 2);
+
+ }
+ } else
+ Read_Result = 0;
+
+ if (Read_Result != 1) {
+ /* Out test position is beyond the end of the partition.
+ * It becomes our first known invalid position. */
+ First_Invalid_Position = Current_Position;
+
+ /* Our new test position should be half way between our
+ * last known valid position and our current test
+ * position. */
+ Current_Position =
+ Last_Valid_Position +
+ ((Current_Position - Last_Valid_Position) / 2);
+ }
+ }
+
+ /*
+ * The size of the drive should be Last_Valid_Position + 1 as
+ * Last_Valid_Position is an offset from the beginning of the partition.
+ */
+ *size = Last_Valid_Position + 1;
+
+
+restore:
+ /* Restore the original position. */
+ if (fseeko(device, Starting_Position, SEEK_SET) != 0)
+ return ERROR_SEEK;
+
+ return NO_ERROR;
+}
+
+/*
+ * NAME: ujfs_rw_diskblocks
+ *
+ * FUNCTION: Read/Write specific number of bytes for an opened device.
+ *
+ * PRE CONDITIONS:
+ *
+ * POST CONDITIONS:
+ *
+ * PARAMETERS:
+ * dev_ptr - file handle of an opened device to read/write
+ * disk_offset - byte offset from beginning of device for start of disk
+ * block read/write
+ * disk_count - number of bytes to read/write
+ * data_buffer - On read this will be filled in with data read from
+ * disk; on write this contains data to be written
+ * mode - GET: read; PUT: write; VRFY: verify
+ *
+ * NOTES: A disk address is formed by {#cylinder, #head, #sector}
+ *
+ * Also the DSK_READTRACK and DSK_WRITETRACK is a track based
+ * function. If it needs to read/write crossing track boundary,
+ * additional calls are used.
+ *
+ * DATA STRUCTURES:
+ *
+ * RETURNS:
+ */
+int ujfs_rw_diskblocks(FILE *dev_ptr,
+ int64_t disk_offset,
+ int32_t disk_count,
+ void *data_buffer,
+ int32_t mode)
+{
+ int Seek_Result;
+ size_t Bytes_Transferred;
+ int error = NO_ERROR;
+
+ Seek_Result = fseeko(dev_ptr, disk_offset, SEEK_SET);
+ if (Seek_Result != 0) {
+ error = ERROR_SEEK;
+ goto finished;
+ }
+
+ if (disk_count == 0) {
+ fprintf(stderr, "ujfs_rw_diskblocks: disk_count is 0\n");
+ error = ERROR_INVALID_PARAMETER;
+ goto finished;
+ }
+
+ switch (mode) {
+ case GET:
+ Bytes_Transferred = fread(data_buffer, 1, disk_count, dev_ptr);
+ break;
+ case PUT:
+ Bytes_Transferred = fwrite(data_buffer, 1, disk_count, dev_ptr);
+ break;
+ default:
+ DBG_ERROR(("Internal error: %s(%d): bad mode: %d\n", __FILE__,
+ __LINE__, mode))
+ error = ERROR_INVALID_HANDLE;
+ goto finished;
+ break; /* Keep the compiler happy. */
+ }
+
+ if (Bytes_Transferred != disk_count) {
+ if (Bytes_Transferred == -1)
+ perror("ujfs_rw_diskblocks");
+ else
+ fprintf(stderr,
+ "ujfs_rw_diskblocks: %s %zd of %d bytes at offset %lld\n",
+ (mode == GET) ? "read" : "wrote",
+ Bytes_Transferred, disk_count, disk_offset);
+
+ if (mode == GET)
+ error = ERROR_READ_FAULT;
+ else
+ error = ERROR_WRITE_FAULT;
+ goto finished;
+ }
+
+finished:
+ if (error)
+ rewind(dev_ptr);
+ return (error);
+}
+
+#define RAMDISK_MAJOR 1
+
+int ujfs_flush_dev(FILE *fp)
+{
+ int fd = fileno(fp);
+ struct stat buf;
+
+ if (fsync(fd) == -1)
+ return errno;
+#ifdef BLKFLSBUF
+ fstat(fd, &buf);
+ if (major(buf.st_rdev) != RAMDISK_MAJOR)
+ return ioctl(fileno(fp), BLKFLSBUF, 0);
+#endif
+ return 0;
+}
Index: libfs/devices.h
===================================================================
--- libfs/devices.h (nonexistent)
+++ libfs/devices.h (revision 5)
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef H_DEVICES
+#define H_DEVICES
+
+#define GET 0
+#define PUT 1
+#define VRFY 2
+
+/* Macros used for determining open mode */
+#define READONLY 0
+#define RDWR_EXCL 1
+
+/* Error codes */
+#define NO_ERROR 0
+#define ERROR_INVALID_FUNCTION 1
+#define ERROR_FILE_NOT_FOUND 2
+#define ERROR_INVALID_HANDLE 6
+#define ERROR_NOT_ENOUGH_MEMORY 8
+#define ERROR_INVALID_ACCESS 12
+#define ERROR_SEEK 25
+#define ERROR_WRITE_FAULT 29
+#define ERROR_READ_FAULT 30
+#define ERROR_GEN_FAILURE 31
+#define ERROR_INVALID_PARAMETER 87
+#define ERROR_DISK_FULL 112
+
+#include <inttypes.h>
+
+struct stat;
+
+int ujfs_get_dev_size(FILE *, int64_t * size);
+int ujfs_rw_diskblocks(FILE *, int64_t, int32_t, void *, int32_t);
+int ujfs_flush_dev(FILE *);
+int ujfs_device_is_valid(FILE *, struct stat *);
+#endif /* H_DEVICES */
Index: libfs/log_dump.c
===================================================================
--- libfs/log_dump.c (nonexistent)
+++ libfs/log_dump.c (revision 5)
@@ -0,0 +1,986 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <config.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "jfs_types.h"
+#include "jfs_endian.h"
+#include "jfs_filsys.h"
+#include "jfs_superblock.h"
+#include "jfs_dinode.h"
+#include "jfs_dtree.h"
+#include "jfs_xtree.h"
+#include "jfs_logmgr.h"
+#include "jfs_dmap.h"
+#include "jfs_imap.h"
+#include "logredo.h"
+#include "devices.h"
+#include "debug.h"
+
+extern int LogOpenMode;
+
+#define LOGDMP_OK 0
+#define LOGDMP_FAILED -1
+
+#define MAKEDEV(__x,__y) (dev_t)(((__x)<<16) | (__y))
+
+#define LOGPNTOB(x) ((x)<<L2LOGPSIZE)
+
+#define LOG2NUM(NUM, L2NUM)\
+{\
+ if ((NUM) <= 0)\
+ L2NUM = -1;\
+ else\
+ if ((NUM) == 1)\
+ L2NUM = 0;\
+ else\
+ {\
+ L2NUM = 0;\
+ while ( (NUM) > 1 )\
+ {\
+ L2NUM++;\
+ (NUM) >>= 1;\
+ }\
+ }\
+}
+
+/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ *
+ * things for the log.
+ */
+int32_t logend; /* address of the end of last log record */
+extern struct logsuper logsup; /* log super block */
+extern int32_t numdoblk; /* number of do blocks used */
+extern int32_t numnodofile; /* number of nodo file blocks used */
+
+/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ *
+ * The output file.
+ *
+ */
+
+FILE *outfp;
+
+#define output_filename "./jfslog.dmp"
+
+int logdmp_outfile_is_open = 0;
+
+/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ *
+ * open file system aggregate/lv array
+ *
+ * logredo() processes a single log.
+ * at the first release, logredo will process a single log
+ * related to one aggregate. But the future release, logredo needs to
+ * to process one single log related to multiple agreegates.
+ * In both cases, the aggregate(logical volume) where the log stays
+ * will be different from the file system aggregate/lv.
+ *
+ * There will be one imap for the aggregate inode allocation map
+ * and a list of imap pointers to multiple fileset inode allocation maps.
+ *
+ * There is one block allocation map per aggregate and shared by all the
+ * filesets within the aggregate.
+ *
+ * the log and related aggregates (logical volumes) are all in
+ * the same volume group, i.e., each logical volume is uniquely specified
+ * by their minor number with the same major number,
+ * the maximum number of lvs in a volume group is NUMMINOR (256).
+ */
+
+/*
+ * We only deal with the log here. No need for vopen array
+ */
+struct vopen volume;
+
+/*
+ * log page buffer cache
+ *
+ * log has its own 4 page buffer pool.
+ */
+extern uint8_t afterdata[]; /* buffer to read in redopage data */
+
+/*
+ * Miscellaneous
+ */
+caddr_t prog; /* Program name */
+int32_t mntcnt, bufsize;
+char *mntinfo;
+int32_t retcode; /* return code from logredo */
+
+/*
+ * external references
+ */
+extern char *optarg;
+extern int optind;
+extern int initMaps(int32_t);
+extern int updateMaps(int);
+extern int findEndOfLog(void);
+extern int logRead(int32_t, struct lrd *, char *);
+extern int logredoInit(void);
+extern int alloc_wrksp(uint32_t, int, int, void **); /* defined in fsckwsp.c */
+
+/*
+ * forward references
+ */
+int open_outfile(void);
+int ldmp_readSuper(FILE *, struct superblock *);
+int ldmp_isLogging(caddr_t, int32_t, char *, int32_t);
+int ldmp_logError(int, int);
+int usage(void);
+
+int disp_updatemap(struct lrd *);
+int disp_redopage(struct lrd *);
+int disp_noredopage(struct lrd *);
+int disp_noredoinoext(struct lrd *);
+
+void ldmp_xdump(char *, int);
+int ldmp_x_scmp(char *, char *);
+void ldmp_x_scpy(char *, char *);
+int prtdesc(struct lrd *);
+
+/* --------------------------------------------------------------------
+ *
+ * NAME: jfs_logdump()
+ *
+ * FUNCTION:
+ *
+ */
+
+int jfs_logdump(caddr_t pathname, FILE *fp, int32_t dump_all)
+{
+ int rc;
+ int32_t logaddr, nextaddr, lastaddr, nlogrecords;
+ struct lrd ld;
+ int32_t lowest_lr_byte = 2 * LOGPSIZE + LOGPHDRSIZE;
+ int32_t highest_lr_byte = 0;
+ int log_has_wrapped = 0;
+ int in_use;
+
+ rc = open_outfile();
+
+ if (rc == 0) { /* output file is open */
+ /*
+ * loop until we get enough memory to read vmount struct
+ */
+ mntinfo = (char *) &bufsize;
+ bufsize = sizeof (int);
+
+ /*
+ * Find and open the log
+ */
+ LogOpenMode = O_RDONLY;
+ rc = findLog(fp, &in_use);
+
+ if (rc != 0) {
+ printf("JFS_LOGDUMP:Error occurred when open/read device\n");
+ fprintf(outfp, "??????????????????????????????????????????????????????\n");
+ fprintf(outfp, "JFS_LOGDUMP:Error occurred when open/read device\n");
+ fprintf(outfp, "??????????????????????????????????????????????????????\n");
+ return (rc);
+ }
+
+ /*
+ * validate log superblock
+ *
+ * aggregate block size is for log file as well.
+ */
+
+ rc = ujfs_rw_diskblocks(Log.fp,
+ (uint64_t) (Log.xaddr + LOGPNTOB(LOGSUPER_B)),
+ (unsigned) sizeof (struct logsuper), (char *) &logsup, GET);
+ if (rc != 0) {
+ printf("JFS_LOGDUMP:couldn't read log superblock:failure in %s\n", prog);
+ fprintf(outfp, "??????????????????????????????????????????????????????\n");
+ fprintf(outfp, "JFS_LOGDUMP:couldn't read log superblock:failure in %s\n",
+ prog);
+ fprintf(outfp, "??????????????????????????????????????????????????????\n");
+ return (LOGSUPER_READ_ERROR);
+ }
+ ujfs_swap_logsuper(&logsup);
+
+ fprintf(outfp, "JOURNAL SUPERBLOCK: \n");
+ fprintf(outfp, "------------------------------------------------------\n");
+ fprintf(outfp, " magic number: x %x \n", logsup.magic);
+ fprintf(outfp, " version : x %x \n", logsup.version);
+ fprintf(outfp, " serial : x %x \n", logsup.serial);
+ fprintf(outfp, " size : t %d pages (4096 bytes/page)\n", logsup.size);
+ fprintf(outfp, " bsize : t %d bytes/block\n", logsup.bsize);
+ fprintf(outfp, " l2bsize : t %d \n", logsup.l2bsize);
+ fprintf(outfp, " flag : x %x \n", logsup.flag);
+ fprintf(outfp, " state : x %x \n", logsup.state);
+ fprintf(outfp, " end : x %x \n", logsup.end);
+ fprintf(outfp, "\n");
+ fprintf(outfp, "======================================================\n");
+ fprintf(outfp, "\n");
+
+ if (logsup.magic != LOGMAGIC) {
+ fprintf(outfp, "\n");
+ fprintf(outfp, "**WARNING** %s: %s is not a log file\n", prog, pathname);
+ fprintf(outfp, "\n");
+ fprintf(outfp, "======================================================\n");
+ fprintf(outfp, "\n");
+ }
+
+ if (logsup.version != LOGVERSION) {
+ fprintf(outfp, "\n");
+ fprintf(outfp, "**WARNING** %s and log file %s version mismatch\n", prog,
+ pathname);
+ fprintf(outfp, "\n");
+ fprintf(outfp, "======================================================\n");
+ fprintf(outfp, "\n");
+ }
+
+ if (logsup.state == LOGREDONE) {
+ fprintf(outfp, "\n");
+ fprintf(outfp, "**WARNING** %s and log file %s state is LOGREDONE\n", prog,
+ pathname);
+ fprintf(outfp, "\n");
+ fprintf(outfp, "======================================================\n");
+ fprintf(outfp, "\n");
+ }
+
+ Log.size = logsup.size;
+ Log.serial = logsup.serial;
+
+ /*
+ * find the end of log
+ */
+ logend = findEndOfLog();
+ if (logend < 0) {
+ printf("logend < 0\n");
+ ldmp_logError(LOGEND, 0);
+ ujfs_swap_logsuper(&logsup);
+ rc = ujfs_rw_diskblocks(Log.fp,
+ (uint64_t) (Log.xaddr + LOGPNTOB(LOGSUPER_B)),
+ (unsigned long) LOGPSIZE, (char *) &logsup, PUT);
+ rc = logend;
+ goto loopexit;
+ }
+
+ highest_lr_byte = logsup.size * LOGPSIZE - LOGRDSIZE;
+
+ if ((logend < lowest_lr_byte) || (logend > highest_lr_byte)) {
+ fprintf(outfp, "\n");
+ fprintf(outfp,
+ "**ERROR** logend address is not valid for a logrec. logend: 0x0%x\n",
+ logend);
+ fprintf(outfp, "\n");
+ fprintf(outfp, "======================================================\n");
+ fprintf(outfp, "\n");
+ return (INVALID_LOGEND);
+ }
+
+ /*
+ * replay log
+ *
+ * read log backwards and process records as we go.
+ * reading stops at place specified by first SYNCPT we
+ * encounter.
+ */
+ nlogrecords = lastaddr = 0;
+ nextaddr = logend;
+ do {
+ logaddr = nextaddr;
+ nextaddr = logRead(logaddr, &ld, afterdata);
+ fprintf(outfp,
+ "logrec d %d Logaddr= x %x Nextaddr= x %x Backchain = x %x\n",
+ nlogrecords, logaddr, nextaddr, ld.backchain);
+ fprintf(outfp, "\n");
+ nlogrecords += 1;
+ /*
+ *
+ * Validate the nextaddr as much as possible
+ *
+ */
+ if (nextaddr < 0) {
+ ldmp_logError(READERR, logaddr);
+ if (nextaddr == REFORMAT_ERROR) {
+ rc = nextaddr;
+ goto loopexit;
+ }
+ break;
+ }
+ /*
+ * Certain errors we'll assume signal the end of the log
+ * since we're just dumping everything from the latest
+ * commit record to the earliest valid record.
+ */
+ if ((nextaddr < lowest_lr_byte) || (nextaddr > highest_lr_byte)) {
+ lastaddr = logaddr;
+ }
+
+ if (nextaddr == logaddr) {
+ lastaddr = logaddr;
+ }
+
+ if (nextaddr > logaddr) {
+ if (log_has_wrapped) {
+ fprintf(outfp, "\n");
+ fprintf(outfp,
+ "**ERROR** log wrapped twice. logaddr:0x0%x nextaddr:0x0%x\n",
+ logaddr, nextaddr);
+ fprintf(outfp, "\n");
+ fprintf(outfp,
+ "======================================================\n");
+ fprintf(outfp, "\n");
+ lastaddr = logaddr;
+ } else {
+ log_has_wrapped = -1;
+ }
+ }
+ /*
+ *
+ * The addresses seem ok. Process the current record.
+ *
+ */
+ if (lastaddr != logaddr) {
+ switch (ld.type) {
+ case LOG_COMMIT:
+ fprintf(outfp,
+ "LOG_COMMIT (type = d %d) logtid = d %d aggregate = d %d\n",
+ ld.type, ld.logtid, ld.aggregate);
+ fprintf(outfp, "\n");
+ fprintf(outfp, "\tdata length = d %d\n", ld.length);
+
+ break;
+
+ case LOG_MOUNT:
+ fprintf(outfp,
+ "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+ fprintf(outfp,
+ "LOG_MOUNT (type = d %d) logtid = d %d aggregate = d %d\n",
+ ld.type, ld.logtid, ld.aggregate);
+ fprintf(outfp, "\n");
+ fprintf(outfp, "\tdata length = d %d\n", ld.length);
+ fprintf(outfp,
+ "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+ break;
+
+ case LOG_SYNCPT:
+ fprintf(outfp,
+ "****************************************************************\n");
+ fprintf(outfp,
+ "LOG_SYNCPT (type = d %d) logtid = d %d aggregate = d %d\n",
+ ld.type, ld.logtid, ld.aggregate);
+ fprintf(outfp, "\n");
+ fprintf(outfp, "\tdata length = d %d\n", ld.length);
+ fprintf(outfp, "\tsync = x %x\n", ld.log.syncpt.sync);
+ fprintf(outfp,
+ "****************************************************************\n");
+
+ rc = 0;
+ if (!dump_all) { /* user just wants from last synch point forward */
+ if (lastaddr == 0) {
+ lastaddr = (ld.log.syncpt.sync == 0)
+ ? logaddr : ld.log.syncpt.sync;
+ }
+ } /* end user just wants from last synch point forward */
+ break;
+
+ case LOG_REDOPAGE:
+ fprintf(outfp,
+ "LOG_REDOPAGE (type = d %d) logtid = d %d aggregate = d %d\n",
+ ld.type, ld.logtid, ld.aggregate);
+ fprintf(outfp, "\n");
+ fprintf(outfp, "\tdata length = d %d ", ld.length);
+ disp_redopage(&ld);
+ break;
+
+ case LOG_NOREDOPAGE:
+ fprintf(outfp,
+ "LOG_NOREDOPAGE (type = d %d) logtid = d %d aggregate = d %d\n",
+ ld.type, ld.logtid, ld.aggregate);
+ fprintf(outfp, "\n");
+ fprintf(outfp, "\tdata length = d %d ", ld.length);
+ disp_noredopage(&ld);
+ break;
+
+ case LOG_NOREDOINOEXT:
+ fprintf(outfp,
+ "LOG_NOREDOINOEXT (type = d %d) logtid = d %d aggregate = d %d\n",
+ ld.type, ld.logtid, ld.aggregate);
+ fprintf(outfp, "\n");
+ fprintf(outfp, "\tdata length = d %d ", ld.length);
+ disp_noredoinoext(&ld);
+ break;
+
+ case LOG_UPDATEMAP:
+ fprintf(outfp,
+ "LOG_UPDATEMAP (type = d %d) logtid = d %d aggregate = d %d\n",
+ ld.type, ld.logtid, ld.aggregate);
+ fprintf(outfp, "\n");
+ fprintf(outfp, "\tdata length = d %d ", ld.length);
+ disp_updatemap(&ld);
+ break;
+
+ default:
+ fprintf(outfp,
+ "*UNRECOGNIZED* (type = d %d) logtid = d %d aggregate = d %d\n",
+ ld.type, ld.logtid, ld.aggregate);
+ fprintf(outfp, "\n");
+ fprintf(outfp, "\tdata length = d %d\n", ld.length);
+ fprintf(outfp, "\n");
+ fprintf(outfp, "**ERROR** unrecognized log record type\n");
+ fprintf(outfp, "\n");
+ fprintf(outfp,
+ "======================================================\n");
+ fprintf(outfp, "\n");
+ return (UNRECOG_LOGRECTYP);
+ }
+
+ if (rc == 0) {
+ fprintf(outfp, "\n");
+ if (ld.length > 0) {
+ ldmp_xdump((char *) afterdata, ld.length);
+ }
+ }
+
+ fprintf(outfp, "\n");
+ fprintf(outfp,
+ "----------------------------------------------------------------------\n");
+ }
+ /* end if( lastaddr != logaddr ) */
+ } while (logaddr != lastaddr);
+
+ loopexit:
+
+ /*
+ * Close the output file
+ */
+ if (logdmp_outfile_is_open) {
+ fclose(outfp);
+ }
+
+ if (rc == 0) { /* log has been dumped successfully */
+ printf
+ ("JFS_LOGDUMP: The current JFS log has been dumped into ./jfslog.dmp\n");
+ } else {
+ printf("JFS_LOGDUMP:Failed in %s\n", prog);
+ fprintf(outfp, "??????????????????????????????????????????????????????\n");
+ fprintf(outfp, "JFS_LOGDUMP:Failed in %s\n", prog);
+ fprintf(outfp, "??????????????????????????????????????????????????????\n");
+ }
+ }
+ /* end output file is open */
+ return (rc < 0) ? (rc) : (0);
+}
+
+/*----------------------------------------------------------------
+ *
+ * NAME: ldmp_readSuper(fp, sb)
+ *
+ * FUNCTION: read the superblock for the file system described
+ * by the file descriptor of the opened aggregate/lv.
+ * if a read of primary superblock fails,
+ * try to read the secondary superblock. report error only
+ * when both reads failed.
+ */
+int ldmp_readSuper(FILE *fp, /* file descriptor */
+ struct superblock * sb)
+{ /* superblock of the opened aggregate/lv */
+ int rc;
+
+ union {
+ struct superblock super;
+ char block[PSIZE];
+ } super;
+
+ /*
+ * seek to the postion of the primary superblock.
+ * since at this time we don't know the aggregate/lv
+ * logical block size yet, we have to use the fixed
+ * byte offset address SUPER1_OFF to seek for.
+ */
+
+ /*
+ * read super block
+ */
+ rc = ujfs_rw_diskblocks(fp, SUPER1_OFF, (unsigned) SIZE_OF_SUPER, super.block, GET);
+ if (rc != 0) {
+ printf
+ ("ldmp_readSuper: read primary agg superblock failed. errno=%d Continuing.\n",
+ errno);
+ fprintf(outfp, "??????????????????????????????????????????????????????\n");
+ fprintf(outfp,
+ "ldmp_readSuper: read primary agg superblock failed. errno=%d Continuing\n",
+ errno);
+ fprintf(outfp, "??????????????????????????????????????????????????????\n");
+ /* read failed for the primary superblock:
+ * try to read the secondary superblock
+ */
+ rc = ujfs_rw_diskblocks(fp, SUPER2_OFF, (unsigned) SIZE_OF_SUPER, super.block, GET);
+ if (rc != 0) {
+ printf
+ ("ldmp_readSuper: read 2ndary agg superblock failed. errno=%d Cannot continue.\n",
+ errno);
+ fprintf(outfp, "??????????????????????????????????????????????????????\n");
+ fprintf(outfp,
+ "ldmp_readSuper: read 2ndary agg superblock failed. errno=%d Cannot continue.\n",
+ errno);
+ fprintf(outfp, "??????????????????????????????????????????????????????\n");
+ return (MAJOR_ERROR);
+ }
+ }
+
+ *sb = super.super;
+
+ ujfs_swap_superblock(sb);
+
+ return (0);
+}
+
+extern void exit(int);
+
+/*----------------------------------------------------------------
+ *
+ * ldmp_logError(type)
+ *
+ * error handling for log read errors.
+ */
+int ldmp_logError(int type, int logaddr)
+{
+ retcode = -1;
+ logsup.state = LOGREADERR;
+
+ switch (type) {
+ case LOGEND:
+ printf("ldmp_logError:find end of log failed \n");
+ fprintf(outfp, "??????????????????????????????????????????????????????\n");
+ fprintf(outfp, "ldmp_logError:find end of log failed \n");
+ fprintf(outfp, "??????????????????????????????????????????????????????\n");
+ break;
+ case READERR:
+ printf("log read failed 0x%x\n", logaddr);
+ fprintf(outfp, "??????????????????????????????????????????????????????\n");
+ fprintf(outfp, "log read failed 0x%x\n", logaddr);
+ fprintf(outfp, "??????????????????????????????????????????????????????\n");
+ break;
+ case UNKNOWNR:
+ printf("unknown log record type \nlog read failed 0x%x\n", logaddr);
+ fprintf(outfp, "??????????????????????????????????????????????????????\n");
+ fprintf(outfp, "unknown log record type \nlog read failed 0x%x\n", logaddr);
+ fprintf(outfp, "??????????????????????????????????????????????????????\n");
+ break;
+ case IOERROR:
+ printf("i/o error log reading page 0x%x\n", logaddr);
+ fprintf(outfp, "??????????????????????????????????????????????????????\n");
+ fprintf(outfp, "i/o error log reading page 0x%x\n", logaddr);
+ fprintf(outfp, "??????????????????????????????????????????????????????\n");
+ break;
+ case LOGWRAP:
+ printf("log wrapped...\n");
+ fprintf(outfp, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
+ fprintf(outfp, "log wrapped...\n");
+ fprintf(outfp, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
+ }
+
+ return (0);
+}
+
+/*----------------------------------------------------------------
+ *
+ * ldmp_xdump()
+ *
+ * hex dump
+ */
+void ldmp_xdump(char *saddr, int count)
+{
+#define LINESZ 60
+#define ASCIISTRT 40
+#define HEXEND 36
+
+ int i, j, k, hexdigit;
+ int c;
+ char *hexchar;
+ char linebuf[LINESZ + 1];
+ char prevbuf[LINESZ + 1];
+ char *linestart;
+ int asciistart;
+ char asterisk = ' ';
+
+ hexchar = "0123456789ABCDEF";
+ prevbuf[0] = '\0';
+ i = (int) saddr % 4;
+ if (i != 0)
+ saddr = saddr - i;
+
+ for (i = 0; i < count;) {
+ for (j = 0; j < LINESZ; j++)
+ linebuf[j] = ' ';
+
+ linestart = saddr;
+ asciistart = ASCIISTRT;
+ for (j = 0; j < HEXEND;) {
+ for (k = 0; k < 4; k++) {
+ c = *(saddr++) & 0xFF;
+ if ((c >= 0x20) && (c <= 0x7e))
+ linebuf[asciistart++] = (char) c;
+ else
+ linebuf[asciistart++] = '.';
+ hexdigit = c >> 4;
+ linebuf[j++] = hexchar[hexdigit];
+ hexdigit = c & 0x0f;
+ linebuf[j++] = hexchar[hexdigit];
+ i++;
+ }
+ if (i >= count)
+ break;
+ linebuf[j++] = ' ';
+ }
+ linebuf[LINESZ] = '\0';
+ if (((j = ldmp_x_scmp(linebuf, prevbuf)) == 0) && (i < count)) {
+ if (asterisk == ' ') {
+ asterisk = '*';
+ fprintf(outfp, " *\n");
+ }
+ } else {
+ fprintf(outfp, " %p %s\n", linestart, linebuf);
+ asterisk = ' ';
+ ldmp_x_scpy(prevbuf, linebuf);
+ }
+ }
+
+ return;
+}
+
+/*----------------------------------------------------------------
+ *
+ * ldmp_x_scmp()
+ *
+ */
+int ldmp_x_scmp(char *s1, char *s2)
+{
+ while ((*s1) && (*s1 == *s2)) {
+ s1++;
+ s2++;
+ }
+ if (*s1 || *s2)
+ return (-1);
+ else
+ return (0);
+}
+
+/*----------------------------------------------------------------
+ *
+ * ldmp_x_scpy()
+ *
+ */
+void ldmp_x_scpy(char *s1, char *s2)
+{
+ while ((*s1 = *s2) != '\0') {
+ s1++;
+ s2++;
+ }
+}
+
+/***************************************************************************
+ *
+ * NAME: disp_noredopage
+ *
+ * FUNCTION:
+ *
+ * PARAMETERS: none
+ *
+ * NOTES:
+ *
+ * RETURNS:
+ * success: LOGDMP_OK
+ * failure: something else
+ */
+int disp_noredopage(struct lrd *lrd_ptr)
+{
+ fprintf(outfp, "fileset = d %d inode = d %d (x %x)\n",
+ lrd_ptr->log.noredopage.fileset,
+ lrd_ptr->log.noredopage.inode, lrd_ptr->log.noredopage.inode);
+
+ switch (lrd_ptr->log.noredopage.type) {
+ case LOG_INODE:
+ fprintf(outfp, "\ttype = d %d NOREDOPAGE:INODE\n", lrd_ptr->log.noredopage.type);
+ break;
+ case LOG_XTREE:
+ fprintf(outfp, "\ttype = d %d NOREDOPAGE:XTREE\n ", lrd_ptr->log.noredopage.type);
+ break;
+ case (LOG_XTREE | LOG_NEW):
+ fprintf(outfp, "\ttype = d %d NOREDOPAGE:XTREE_NEW\n ",
+ lrd_ptr->log.noredopage.type);
+ break;
+ case (LOG_BTROOT | LOG_XTREE):
+ fprintf(outfp, "\ttype = d %d NOREDOPAGE:BTROOT_XTREE\n ",
+ lrd_ptr->log.noredopage.type);
+ break;
+ case LOG_DTREE:
+ fprintf(outfp, "\ttype = d %d NOREDOPAGE:DTREE\n ", lrd_ptr->log.noredopage.type);
+ break;
+ case (LOG_DTREE | LOG_NEW):
+ fprintf(outfp, "\ttype = d %d NOREDOPAGE:DTREE_NEW \n ",
+ lrd_ptr->log.noredopage.type);
+ break;
+ case (LOG_DTREE | LOG_EXTEND):
+ fprintf(outfp, "\ttype = d %d NOREDOPAGE:DTREE_EXTEND\n ",
+ lrd_ptr->log.noredopage.type);
+ break;
+ case (LOG_BTROOT | LOG_DTREE):
+ fprintf(outfp, "\ttype = d %d NOREDOPAGE:BTROOT_DTREE\n ",
+ lrd_ptr->log.noredopage.type);
+ break;
+ case (LOG_BTROOT | LOG_DTREE | LOG_NEW):
+ fprintf(outfp, "\ttype = d %d NOREDOPAGE:BTROOT_DTREE.NEW\n ",
+ lrd_ptr->log.noredopage.type);
+ break;
+ case LOG_EA:
+ fprintf(outfp, "\ttype = d %d NOREDOPAGE:EA\n", lrd_ptr->log.noredopage.type);
+ break;
+ case LOG_ACL:
+ fprintf(outfp, "\ttype = d %d NOREDOPAGE:ACL\n", lrd_ptr->log.noredopage.type);
+ break;
+ case LOG_DATA:
+ fprintf(outfp, "\ttype = d %d NOREDOPAGE:DATA\n", lrd_ptr->log.noredopage.type);
+ break;
+/*
+ case LOG_NOREDOFILE:
+ fprintf( outfp, "\ttype = d %d NOREDOPAGE:NOREDOFILE\n",
+ lrd_ptr->log.noredopage.type );
+ break;
+*/
+ default:
+ fprintf(outfp, "\ttype = d %d ***UNRECOGNIZED***\n", lrd_ptr->log.noredopage.type);
+ break;
+ }
+
+ fprintf(outfp, "\tpxd length = d %d phys offset = x %llx (d %lld)\n",
+ lengthPXD(&(lrd_ptr->log.noredopage.pxd)),
+ (long long) addressPXD(&(lrd_ptr->log.noredopage.pxd)),
+ (long long) addressPXD(&(lrd_ptr->log.noredopage.pxd)));
+
+ return (LOGDMP_OK);
+} /* end of disp_noredopage() */
+
+/***************************************************************************
+ *
+ * NAME: disp_noredoinoext
+ *
+ * FUNCTION:
+ *
+ * PARAMETERS: none
+ *
+ * NOTES:
+ *
+ * RETURNS:
+ * success: LOGDMP_OK
+ * failure: something else
+ */
+int disp_noredoinoext(struct lrd * lrd_ptr)
+{
+ fprintf(outfp, "fileset = d %d \n", lrd_ptr->log.noredoinoext.fileset);
+
+ fprintf(outfp, "\tiag number = d %d extent index = d %d\n",
+ lrd_ptr->log.noredoinoext.iagnum, lrd_ptr->log.noredoinoext.inoext_idx);
+
+ fprintf(outfp, "\tpxd length = d %d phys offset = x %llx (d %lld)\n",
+ lengthPXD(&(lrd_ptr->log.noredoinoext.pxd)),
+ (long long) addressPXD(&(lrd_ptr->log.noredoinoext.pxd)),
+ (long long) addressPXD(&(lrd_ptr->log.noredoinoext.pxd)));
+
+ return (LOGDMP_OK);
+} /* end of disp_noredopage() */
+
+/***************************************************************************
+ *
+ * NAME: disp_redopage
+ *
+ * FUNCTION:
+ *
+ * PARAMETERS: none
+ *
+ * NOTES:
+ *
+ * RETURNS:
+ * success: LOGDMP_OK
+ * failure: something else
+ */
+int disp_redopage(struct lrd * lrd_ptr)
+{
+ fprintf(outfp, "fileset = d %d inode = d %d (x %x)\n",
+ lrd_ptr->log.redopage.fileset, lrd_ptr->log.redopage.inode,
+ lrd_ptr->log.redopage.inode);
+
+ switch (lrd_ptr->log.redopage.type) {
+ case LOG_INODE:
+ fprintf(outfp, "\ttype = d %d REDOPAGE:INODE\n", lrd_ptr->log.redopage.type);
+ break;
+ case LOG_XTREE:
+ fprintf(outfp, "\ttype = d %d REDOPAGE:XTREE\n ", lrd_ptr->log.redopage.type);
+ break;
+ case (LOG_XTREE | LOG_NEW):
+ fprintf(outfp, "\ttype = d %d REDOPAGE:XTREE_NEW\n ", lrd_ptr->log.redopage.type);
+ break;
+ case (LOG_BTROOT | LOG_XTREE):
+ fprintf(outfp, "\ttype = d %d REDOPAGE:BTROOT_XTREE\n ",
+ lrd_ptr->log.redopage.type);
+ break;
+ case LOG_DTREE:
+ fprintf(outfp, "\ttype = d %d REDOPAGE:DTREE\n ", lrd_ptr->log.redopage.type);
+ break;
+ case (LOG_DTREE | LOG_NEW):
+ fprintf(outfp, "\ttype = d %d REDOPAGE:DTREE_NEW \n ", lrd_ptr->log.redopage.type);
+ break;
+ case (LOG_DTREE | LOG_EXTEND):
+ fprintf(outfp, "\ttype = d %d REDOPAGE:DTREE_EXTEND\n ",
+ lrd_ptr->log.redopage.type);
+ break;
+ case (LOG_BTROOT | LOG_DTREE):
+ fprintf(outfp, "\ttype = d %d REDOPAGE:BTROOT_DTREE\n ",
+ lrd_ptr->log.redopage.type);
+ break;
+ case (LOG_BTROOT | LOG_DTREE | LOG_NEW):
+ fprintf(outfp, "\ttype = d %d REDOPAGE:BTROOT_DTREE.NEW\n ",
+ lrd_ptr->log.redopage.type);
+ break;
+ case LOG_EA:
+ fprintf(outfp, "\ttype = d %d REDOPAGE:EA\n", lrd_ptr->log.redopage.type);
+ break;
+ case LOG_ACL:
+ fprintf(outfp, "\ttype = d %d REDOPAGE:ACL\n", lrd_ptr->log.redopage.type);
+ break;
+ case LOG_DATA:
+ fprintf(outfp, "\ttype = d %d REDOPAGE:DATA\n", lrd_ptr->log.redopage.type);
+ break;
+/*
+ case LOG_NOREDOFILE:
+ fprintf( outfp, "\ttype = d %d REDOPAGE:NOREDOFILE\n",
+ lrd_ptr->log.redopage.type );
+ break;
+*/
+ default:
+ fprintf(outfp, "\ttype = d %d ***UNRECOGNIZED***\n", lrd_ptr->log.redopage.type);
+ break;
+ }
+ fprintf(outfp, "\tl2linesize = d %d ", lrd_ptr->log.redopage.l2linesize);
+ fprintf(outfp, "pxd length = d %d phys offset = x %llx (d %lld)\n",
+ lengthPXD(&(lrd_ptr->log.redopage.pxd)),
+ (long long) addressPXD(&(lrd_ptr->log.redopage.pxd)),
+ (long long) addressPXD(&(lrd_ptr->log.redopage.pxd)));
+
+ return (LOGDMP_OK);
+} /* end of disp_redopage() */
+
+/***************************************************************************
+ *
+ * NAME: disp_updatemap
+ *
+ * FUNCTION:
+ *
+ * PARAMETERS: none
+ *
+ * NOTES:
+ *
+ * RETURNS:
+ * success: LOGDMP_OK
+ * failure: something else
+ */
+int disp_updatemap(struct lrd * lrd_ptr)
+{
+ int flag_unrecognized = -1;
+ fprintf(outfp, "fileset = d %d inode = d %d (x %x)\n",
+ lrd_ptr->log.updatemap.fileset, lrd_ptr->log.updatemap.inode,
+ lrd_ptr->log.updatemap.inode);
+
+ fprintf(outfp, "\ttype = x %x UPDATEMAP: ", lrd_ptr->log.updatemap.type);
+
+ if ((lrd_ptr->log.updatemap.type & LOG_ALLOCXADLIST) == LOG_ALLOCXADLIST) {
+ flag_unrecognized = 0;
+ fprintf(outfp, " ALLOCXADLIST");
+ }
+ if ((lrd_ptr->log.updatemap.type & LOG_ALLOCPXDLIST) == LOG_ALLOCPXDLIST) {
+ flag_unrecognized = 0;
+ fprintf(outfp, " ALLOCPXDLIST");
+ }
+ if ((lrd_ptr->log.updatemap.type & LOG_ALLOCXAD) == LOG_ALLOCXAD) {
+ flag_unrecognized = 0;
+ fprintf(outfp, " ALLOCXAD");
+ }
+ if ((lrd_ptr->log.updatemap.type & LOG_ALLOCPXD) == LOG_ALLOCPXD) {
+ flag_unrecognized = 0;
+ fprintf(outfp, " ALLOCPXD");
+ }
+ if ((lrd_ptr->log.updatemap.type & LOG_FREEXADLIST) == LOG_FREEXADLIST) {
+ flag_unrecognized = 0;
+ fprintf(outfp, " FREEXADLIST");
+ }
+ if ((lrd_ptr->log.updatemap.type & LOG_FREEPXDLIST) == LOG_FREEPXDLIST) {
+ flag_unrecognized = 0;
+ fprintf(outfp, " FREEPXDLIST");
+ }
+ if ((lrd_ptr->log.updatemap.type & LOG_FREEXAD) == LOG_FREEXAD) {
+ flag_unrecognized = 0;
+ fprintf(outfp, " FREEXAD");
+ }
+ if ((lrd_ptr->log.updatemap.type & LOG_FREEPXD) == LOG_FREEPXD) {
+ flag_unrecognized = 0;
+ fprintf(outfp, " FREEPXD");
+ }
+ if (flag_unrecognized) {
+ fprintf(outfp, " *** UNRECOGNIZED ***");
+ }
+
+ fprintf(outfp, "\n");
+
+ fprintf(outfp, "\tnxd = d %d (number of extents)\n", lrd_ptr->log.updatemap.nxd);
+ fprintf(outfp, "\tpxd length = d %d phys offset = x %llx (d %lld)\n",
+ lengthPXD(&(lrd_ptr->log.updatemap.pxd)),
+ (long long) addressPXD(&(lrd_ptr->log.updatemap.pxd)),
+ (long long) addressPXD(&(lrd_ptr->log.updatemap.pxd)));
+
+ return (LOGDMP_OK);
+} /* end of disp_updatemap() */
+
+/*****************************************************************************
+ * NAME: open_outfile
+ *
+ * FUNCTION: Open the output file.
+ *
+ * PARAMETERS:
+ * Device - input - the device specification
+ *
+ * NOTES:
+ *
+ * RETURNS:
+ * success: XCHKLOG_OK
+ * failure: something else
+ */
+int open_outfile()
+{
+ int openof_rc = 0;
+
+ outfp = fopen(output_filename, "w");
+
+ if (outfp == NULL) { /* output file open failed */
+ printf("LOG_DUMP: unable to open output file: ./jfslog.dmp\n");
+ openof_rc = -1;
+ } else {
+ logdmp_outfile_is_open = -1;
+ }
+
+ return (openof_rc);
+} /* end of open_outfile ( ) */
Index: libfs/logredo.c
===================================================================
--- libfs/logredo.c (nonexistent)
+++ libfs/logredo.c (revision 5)
@@ -0,0 +1,1931 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2000-2002
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <config.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "jfs_types.h"
+#include "jfs_endian.h"
+#include "jfs_filsys.h"
+#include "jfs_superblock.h"
+#include "jfs_dinode.h"
+#include "jfs_dtree.h"
+#include "jfs_xtree.h"
+#include "jfs_logmgr.h"
+#include "jfs_dmap.h"
+#include "jfs_imap.h"
+#include "logredo.h"
+#include "logform.h"
+#include "devices.h"
+#include "debug.h"
+#include "utilsubs.h"
+#include "fsck_message.h" /* for chkdsk message logging facility */
+
+/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ *
+ * L O C A L M A C R O D E F I N I T I O N S
+ *
+ */
+#define MAKEDEV(__x,__y) (dev_t)(((__x)<<16) | (__y))
+
+#define LOGPNTOB(x) ((x)<<L2LOGPSIZE)
+
+#define LOG2NUM(NUM, L2NUM)\
+{\
+ if ((NUM) <= 0)\
+ L2NUM = -1;\
+ else\
+ if ((NUM) == 1)\
+ L2NUM = 0;\
+ else\
+ {\
+ L2NUM = 0;\
+ while ( (NUM) > 1 )\
+ {\
+ L2NUM++;\
+ (NUM) >>= 1;\
+ }\
+ }\
+}
+
+/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ *
+ * R E M E M B E R M E M O R Y A L L O C F A I L U R E
+ *
+ */
+int32_t Insuff_memory_for_maps = 0;
+char *available_stg_addr = NULL;
+int32_t available_stg_bytes = 0;
+char *bmap_stg_addr = NULL;
+int32_t bmap_stg_bytes = 0;
+
+/* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ *
+ * S T U F F F O R T H E L O G
+ *
+ */
+struct logsuper logsup; /* log super block */
+int32_t numdoblk; /* number of do blocks used */
+int32_t numnodofile; /* number of nodo file blocks used */
+int32_t numExtDtPg = 0; /* number of extended dtpage blocks used */
+
+/*
+ * open file system aggregate/lv array
+ *
+ * logredo() processes a single log.
+ *
+ * In the first release, logredo will process a single log which relates
+ * to the single fileset in a single aggregate. In some future release,
+ * a single log may be used for multiple filesets which may or may not all
+ * reside in the same aggregate.
+ *
+ */
+struct vopen vopen[MAX_ACTIVE];
+struct log_info Log;
+struct {
+ uuid_t uuid;
+ FILE *fp;
+} primary_vol;
+extern int LogOpenMode; /* logdump sets this to O_RDONLY */
+
+/*
+ * if this flag is set then the primary superblock is
+ * corrupt. The secondary superblock is good, but chkdsk
+ * wasn't able to fix the primary version. logredo can
+ * run, but must use the secondary version of the
+ * aggregate superblock
+ */
+int32_t use_2ndary_agg_superblock;
+/*
+ * file system page buffer cache
+ *
+ * for k > 0, bufhdr[k] describes contents of buffer[k-1].
+ * bufhdr[0] is reserved as anchor for free/lru list:
+ * bufhdr[0].next points to the MRU buffer (head),
+ * bufhdr[0].prev points to the LRU buffer (tail);
+ */
+
+/* buffer header table */
+struct bufhdr {
+ int16_t next; /* 2: next on free/lru list */
+ int16_t prev; /* 2: previous on free/lru list */
+ int16_t hnext; /* 2: next on hash chain */
+ int16_t hprev; /* 2: previous on hash chain */
+ char modify; /* 1: buffer was modified */
+ char inuse; /* 1: buffer on hash chain */
+ int16_t reserve; /* 2 */
+ int32_t vol; /* 4: minor of agrregate/lv number */
+ pxd_t pxd; /* 8: on-disk page pxd */
+} bufhdr[NBUFPOOL]; /* (24) */
+
+/* buffer table */
+struct bufpool {
+ char bytes[PSIZE];
+} buffer[NBUFPOOL - 1];
+
+/*
+ * log page buffer cache
+ *
+ * log has its own 4 page buffer pool.
+ */
+uint8_t afterdata[LOGPSIZE * 2]; /* buffer to read in redopage data */
+
+/*
+ * Miscellaneous
+ */
+extern caddr_t prog; /* Program name */
+extern int32_t mntcnt;
+extern int32_t bufsize;
+extern char *mntinfo;
+extern int32_t retcode; /* return code from logredo */
+int end_of_transaction = 0;
+
+/*
+ * external references
+ */
+extern char *optarg;
+extern int optind;
+extern int initMaps(int32_t);
+extern int updateMaps(int);
+extern int findEndOfLog(void);
+extern int logRead(int32_t, struct lrd *, char *);
+extern int logredoInit(void);
+extern int doCommit(struct lrd *);
+extern int doExtDtPg(void);
+extern int doNoRedoFile(struct lrd *, uint32_t);
+extern int doNoRedoPage(struct lrd *);
+extern int doNoRedoInoExt(struct lrd *);
+extern int doAfter(struct lrd *, int32_t);
+extern int doUpdateMap(struct lrd *);
+extern int alloc_wrksp(uint32_t, int, int, void **);
+
+extern FILE * open_by_label(uuid_t, int, int, char *, int *);
+extern char log_device[];
+/*
+ * forward references
+ */
+int doMount(struct lrd *);
+int openVol(int32_t);
+int updateSuper(int vol);
+int rdwrSuper(FILE *, struct superblock *, int32_t);
+int bflush(int32_t, struct bufpool *);
+int logOpen(void);
+int fsError(int, int, int64_t);
+int logError(int, int);
+static int recoverExtendFS(FILE *);
+int alloc_storage(int32_t, void **, int32_t *);
+int alloc_dmap_bitrec(struct dmap_bitmaps **);
+
+/*
+ * debug control
+ */
+#ifdef _JFS_DEBUG
+int32_t dflag = 1;
+time_t *Tp;
+uint32_t tp_start, tp_end;
+int xdump(char *, int);
+int x_scmp(char *, char *);
+void x_scpy(char *, char *);
+int prtdesc(struct lrd *);
+#else
+int32_t dflag = 0;
+#endif
+
+/*
+ * NAME: jfs_logredo()
+ *
+ * FUNCTION: Replay all transactions committed since the most
+ * recent synch point.
+ *
+ * NOTES:
+ * >>>>>> The log replay is accomplished in one pass over the
+ * log, reading backwards from logend to the first synch
+ * point record encountered. This means that the log
+ * entries are read and processed in LIFO (Last-In-First-Out)
+ * order. In other words, the records logged latest in
+ * time are the first records processed during log replay.
+ *
+ * >>>>>> Inodes, index trees, and directory trees
+ *
+ * Inodes, index tree structures, and directory tree
+ * structures are handled by processing committed redopage
+ * records which have not been superceded by noredo records.
+ * This processing copies data from the log record into the
+ * appropriate disk extent page(s).
+ *
+ * To ensure that only the last (in time) updates to any
+ * given disk page are applied during log replay, logredo
+ * maintains a record (union structure summary1/summary2),
+ * for each disk page which it has processed, of which
+ * portions have been updated by log records encountered.
+ *
+ * >>>>>> Inode Allocation Map processing
+
+ * The xtree for the Inode Allocation Map is journaled, and
+ * a careful write is used to update it during commit
+ * processing.
+ * The imap index tree is also duplicated at the known location. (TBD)
+ * So at logredo time, the xtree for imap is always readable and correct.
+ * This is the basic requirement from logredo.
+ *
+ * the inode map control page (struct dinomap) is only flushed to disk at
+ * the umount time. For iag, pmap will go to disk at commit time.
+ * iagnum will not change in run-time.
+ * agstart field will stable without extendfs utility. It is TBD for
+ * how to handle agstart when extendfs utility is available.
+ * Other fields ( wmap. inosmap, extsmap ino free list pointers,
+ * ino ext free list pointers ) are at working status ( i.e they are
+ * updated in run-time. So the following
+ * meta-data of the imap need to be reconstructed at the logredo time:
+ * 1) IAGs, the pmap of imap and inoext array are contained in IAGs.
+ * 2) AG Free inode list
+ * 3) AG Free Inode Extent list
+ * 4) IAG Free list
+ *
+ * There are two imaps need to take care of :
+ * 1) aggregate imap
+ * 2) fileset imap
+ * For the first release, the aggregate imap is stable and we only
+ * need to deal with the fileset imap.
+ *
+ * Block Allocation Map (bmap file) is for an aggregate/lv. There are
+ * three fields related to the size of bmap file.
+ * 1) superblock.s_size: This field indicates aggregate size. It
+ * tells number of sector-size blocks for this
+ * aggregate. The size of aggregate determines
+ * the size of its bmap file.
+ * Since the aggregate's superblock is updated
+ * using sync-write, superblock.s_size is trustable
+ * at logredo time.
+ * note1: mkfs reserves the fsck space. So s_size really
+ * inidcate (size_of_aggregate - fsck_reserve_space)
+ * note2: At the mkfs time, "-s" parameter could be used
+ * to indicate how large the aggregate/filesystem is.
+ * One lv contains at most one aggregate/filesystem.
+ * If "-s" gives the value is smaller than the size
+ * of lv, it is ok. The space is just wasted.
+ *
+ * Without "-s" parameter, mkfs wil use the whole
+ * size of lv to make an aggregate/filesystem.
+ * That is usually the case. So we can also say
+ * an aggregate/lv. "-s" is often used for test.
+ *
+ * 2) dbmap.dn_mapsize: This field also indicates aggregate/lv size.
+ * It tells number of aggre. blocks in the
+ * aggregate/lv. Without extendfs, this field should
+ * be equivalent to superblock.s_size.
+ * With extendfs, this field may not be updated
+ * before a system crash happens. So logredo
+ * need to update it.
+ * 3) dinode.di_size: For an inode of bmap file, this field indicates
+ * the logical size of the file. I.e. it contains
+ * the offset value of the last byte written
+ * in the file plus one.
+ * So di_size will include the bmap control page,
+ * the dmap control pages and dmap pages.
+ * In the JFS, if a file is a sparse file, the logical
+ * size is different from its physical size.
+ * The bmap file is a sparse file if the total of
+ * dmap pages is ( < 1024) or ( < 1024 * 1024).
+ * In that case, physically L1.0, and/or L2 does
+ * not exist, but di_size will include their page
+ * size.
+ *
+ * Note: The di_size does NOT contain the logical
+ * structure of the file, i.e. the space allocated
+ * for the xtree stuff is not indicated in di_size.
+ * It is indicated in di_nblocks.
+ *
+ * In addition, the mkfs always put one more dmap
+ * page into the bmap file for preparing extendfs.
+ * This hidden dmap page cannot be figured out from
+ * superblock.s_size, but di_size includes it. Any
+ * dmapctl pages caused by this hidden dmap page
+ * are also included in di_size.
+ *
+ * The bmap control page, dmap control pages and dmap pages are all
+ * needed to rebuild at logredo time.
+ *
+ * In overall, the following actions are taken at logredo time:
+ * 1) apply log rec data to the specified page.
+ * 2) initialize freelist for dtree page or root.
+ * 3) rebuilt imap
+ * 4) rebuilt bmap
+ * in addition, in order to ensure the log record only applying to a
+ * certain portion of page one time, logredo will start NoRedoFile,
+ * NoRedoExtent/NoRedoPage filter in the process for accuracy and
+ * efficiency.
+ *
+ * The three log rec types: REDOPAGE, NOREDOPAGE, NOREDOINOEXT, and
+ * UPDATEMAP, are the main force to initiate these actions. See
+ * comments on doAfter(), updatePage(), doNoRedoPage(), doNoRedoInoExt,
+ * and doUpdateMap() for detailed information.
+ *
+ * If the aggregate/lv has state of FM_DIRTY, then fsck will run
+ * after the logredo process since logredo could not get 100%
+ * recovery. Currently bmap rebuild is slow ( 1 min per 32 GB),
+ * so logredo will NOT rebuild imap and bmap if fsck will do it
+ * anyway. But logredo still read maps in and mark them for starting
+ * NoRedoExtent/NoRedoPage filter.
+ *
+ * The maps are rebuilt in the following way:
+ * at the init phase, storage is allocated for the whole map file for
+ * both imap and bmap. Reading in the map files from the disk.
+ * The wmap is inited to zero. At the logredo time, the wmap is used
+ * to track the bits in pmap. In the beginning of the logredo process
+ * the allocation status of every block is in doubt. As log records
+ * are processed, the allocation state is determined and the bit of pmap
+ * is updated. This fact is recorded in the corresponding bits in wmap.
+ * So a pmap bit is only updated once at logredo time and only updated
+ * by the latest in time log record.
+ * At the end of logredo, the control information, the freelist, etc.
+ * are built from the value of pmap; then pmap is copied to wmap and
+ * the whole map is written back to disk.
+ *
+ * the status field s_state in the superblock of each file-system is
+ * set to FM_CLEAN provided the initial status was either FM_CLEAN
+ * or FM_MOUNT and logredo processing was successful. If an error
+ * is detected in logredo the status is set to FM_LOGREDO. the status
+ * is not changed if its initial value was FM_MDIRTY. fsck should be
+ * run to clean-up the probable damage if the status after logredo
+ * is either FM_LOGREDO or FM_MDIRTY.
+ *
+ * The log record has the format:
+ * <LogRecordData><LogRecLRD>
+ * At logredo time, the log is read backward. So for every log rec,
+ * we read LogRecLRD, which tells how long the LogRecordData is.
+ * see comments on updatePage() for detailed info of log record format.
+ *
+ *.....................................................................
+ * The logredo handles the log-within-file-system (aka inline log) issue:
+ *.....................................................................
+ * For AIX, we always deal with the outline log, i.e. the log resides
+ * in a separate logical volume. A log is associated with one volume
+ * group and can be shared by many file systems with this volume group.
+ * In AIX, the logredo received a device name. It then determines if
+ * this device is a log name or a filesystem name. If it is a filesustem
+ * name, get the log minor number for this filesystem. If it is a log name,
+ * get its minor number.
+ *
+ * XJFS decided to put log inside the file system
+ *
+ * For supporting the inline log, the above AIX logic should be changed.
+ *
+ * Here is the outline:
+ *
+ * When the logredo received a device name, it first read the SIZE_OF_SUPER
+ * bytes from SUPER1_OFF offset to see if it is a file system superblock.
+ * If yes, check the s_flag to see if it has a inline log or outline log.
+ * for an inline log the s_logdev should match the input device name's
+ * major and minor number. If not, an error is returned and logredo exit.
+ * If no error, the logredo read the log superblock according the log info
+ * in the fs superblock.
+ * If the device name does not represent a filesystem device, then logredo
+ * read the LOGPSIZE bytes from the log page 1 location. If it indicates
+ * a log device, then open the filesystems according to the log superblock's
+ * active list. For each filesystem in the active list, read its superblock
+ * if one of the superblock indicates that it uses an inline log, return
+ * an error. It is a system code bug if some filesystems use inline log
+ * and some use outline log.
+ * If the superblock indicates it used an outline log, check the superblock's
+ * s_logdev to match the input device name's major and minor numbers.
+ * If one of them does not match, return error. -- It is a system code bug,
+ * if some match and some not match; -- It should either match all or non of
+ * them match. The AIX logredo never check s_logdev with the input log device.
+ * We should check here.
+ *
+ * for outline log, logredo will be called once to cover all the file
+ * systems in the log superblock's active list.
+ * For inline log, logredo will be called many times. Each time is for
+ * one file system. The log superblock's active list has nothing. The
+ * logmajor and logminor contains file system's major and minor number.
+ *
+ *.....................................................................
+ * logredo handles support EA:
+ *.....................................................................
+ * There is 16-byte EA descriptor which is located in the section I of
+ * dinode.
+ * The EA can be inline or outline. If it is inlineEA then the data will
+ * occupy the section IV of the dinode. The dxd_t.flag will indicate so.
+ * If it is outlineEA, dxd_t.flag will indicate so and the single extent
+ * is described by EA descriptor.
+ *
+ * The section IV of dinode has 128 byte. It is shared by the xtroot and
+ * inlineEA. The sharing is in FCFS style. If xtree gets the section IV,
+ * xtree will never give it away even if xtree is shrink or split.
+ * If inlineEA gets it, there is a chance that later inlineEA is freed and
+ * so xtree still can get it.
+ *
+ * for outlineEA, the XJFS will syncly write the data portion out so there
+ * is no log rec for the data, but there is still an INODE log rec for EA
+ * descriptor changes and there is a UPDATEMAP log rec for the allocated
+ * pxd. If an outlineEA is freed, there are also two log records for it:
+ * one is INODE with EA descriptor zeroed out, another is the UPDATEMAP
+ * log rec for the freed pxd.
+ * For inlineEA, it has to be recorded in the log rec. It is not in a
+ * separate log rec. Just one additional segment is added into the
+ * INODE log rec. So an INODE log rec can have at most three segments:
+ * when the parent and child inodes are in the same page, then there are
+ * one segment for parent base inode; one segment for child base inode;
+ * and maybe the third one for the child inlineEA data.
+ *....................................................................
+ * 32-bit vs 64-bit
+ * At the first release. assume that a file system will not be larger
+ * than 32-bit.
+ *....................................................................
+ * TBD:
+ * the method for handling crashes in the middle of extending a file
+ * system is as follows. the size of a filesystem is established from
+ * the superblock.s_size field (i.e the sizes in the diskmap
+ * and inodemaps are ignored). in extendfs (jfs_cntl.c) the superblock
+ * is not updated before the maps have been extended and the new inodes
+ * formatted to zeros. no allocations in the new part of the filesystem
+ * occur prior to the change in map sizes. if a crash occurs just
+ * before updating the superblock, the map sizes will be their old
+ * values. in this case the maps as files may be bigger than necessary.
+ * if the crash occurs just after writing the super block, the map sizes
+ * are fixed up here.
+ */
+int jfs_logredo(caddr_t pathname, FILE *fp, int32_t use_2nd_aggSuper)
+{
+ int rc;
+ int k, logaddr, nextaddr, lastaddr, nlogrecords;
+ int syncrecord = 0;
+ struct lrd ld;
+ int lowest_lr_byte = 2 * LOGPSIZE + LOGPHDRSIZE;
+ int highest_lr_byte = 0;
+ int log_has_wrapped = 0;
+ int logend;
+ int in_use;
+
+ /*
+ * store away the indicator of which aggregate superblock
+ * to use
+ */
+ use_2ndary_agg_superblock = use_2nd_aggSuper;
+
+ /*
+ * loop until we get enough memory to read vmount struct
+ */
+ mntinfo = (char *) &bufsize;
+ bufsize = sizeof (int);
+
+ /*
+ * validate that the log is not currently in use;
+ */
+ rc = findLog(fp, &in_use);
+ if (rc < 0) {
+ fsck_send_msg(lrdo_DEVOPNREADERROR);
+ return (rc);
+ }
+
+ /* recover from extendfs() ? */
+ if (Log.location & INLINELOG && (vopen[0].status & FM_EXTENDFS)) {
+ fsck_send_msg(lrdo_REXTNDBEGIN);
+ rc = recoverExtendFS(fp);
+ fsck_send_msg(lrdo_REXTNDDONE);
+ return rc;
+ }
+
+ /*
+ * validate log superblock
+ *
+ * aggregate block size is for log file as well.
+ */
+ rc = ujfs_rw_diskblocks(Log.fp,
+ (uint64_t) (Log.xaddr +
+ LOGPNTOB(LOGSUPER_B)),
+ (unsigned) sizeof (struct logsuper), (char *) &logsup, GET);
+ if (rc != 0) {
+ fsck_send_msg(lrdo_CANTREADLOGSUP);
+ rc = LOGSUPER_READ_ERROR;
+ goto error_out;
+ }
+ ujfs_swap_logsuper(&logsup);
+
+ if (logsup.magic != LOGMAGIC) {
+ fsck_send_msg(lrdo_LOGSUPBADMGC);
+ rc = NOT_LOG_FILE_ERROR;
+ goto error_out;
+ }
+
+ if (logsup.version > LOGVERSION) {
+ fsck_send_msg(lrdo_LOGSUPBADVER);
+ rc = JFS_VERSION_ERROR;
+ goto error_out;
+ }
+
+ if (Log.location & OUTLINELOG) {
+ struct stat st;
+
+ if ((rc = fstat(fileno(Log.fp), &st)))
+ goto error_out;
+
+ Log.devnum = st.st_rdev;
+
+ if (in_use) {
+ fsck_send_msg(lrdo_LOGINUSE);
+ return LOG_IN_USE;
+ }
+ }
+
+ if (logsup.state == LOGREDONE) {
+ fsck_send_msg(lrdo_ALREADYREDONE);
+ if (Log.location & INLINELOG)
+ if ((rc = updateSuper(0)) != 0) {
+ fsck_send_msg(lrdo_CANTUPDLOGSUP);
+ return (rc);
+ }
+ return (0);
+ }
+
+ Log.size = logsup.size;
+ Log.serial = logsup.serial;
+
+ /*
+ * find the end of log
+ */
+ logend = findEndOfLog();
+
+ if (logend < 0) {
+ fsck_send_msg(lrdo_LOGEND, logend);
+
+ fsck_send_msg(lrdo_LOGENDBAD1);
+ logError(LOGEND, 0);
+ ujfs_swap_logsuper(&logsup);
+ rc = ujfs_rw_diskblocks(Log.fp,
+ (Log.xaddr + LOGPNTOB(LOGSUPER_B)),
+ (unsigned long) LOGPSIZE, (char *) &logsup, PUT);
+ rc = logend;
+ goto error_out;
+ }
+
+ /*
+ * allocate/initialize logredo runtime data structures and
+ * initialize each file system associated with the log based on
+ * the contents of its superblock
+ */
+ if ((rc = logredoInit()) != 0) {
+ fsck_send_msg(lrdo_INITFAILED, rc, errno);
+ goto error_out;
+ }
+
+ highest_lr_byte = logsup.size * LOGPSIZE - LOGRDSIZE;
+
+ if ((logend < lowest_lr_byte) || (logend > highest_lr_byte)) {
+ fsck_send_msg(lrdo_LOGEND, logend);
+
+ fsck_send_msg(lrdo_LOGENDBAD2);
+ rc = INVALID_LOGEND;
+ goto error_out;
+ }
+
+ /*
+ * replay log
+ *
+ * read log backwards and process records as we go.
+ * reading stops at place specified by first SYNCPT we
+ * encounter.
+ */
+ nlogrecords = lastaddr = 0;
+ nextaddr = logend;
+
+ do {
+ logaddr = nextaddr;
+ nextaddr = logRead(logaddr, &ld, afterdata);
+ DBG_TRACE(("Logaddr=%x\nNextaddr=%x\n", logaddr, nextaddr))
+ nlogrecords += 1;
+ /*
+ *
+ * Validate the nextaddr as much as possible
+ *
+ */
+ if (nextaddr < 0) {
+ fsck_send_msg(lrdo_NEXTADDRINVALID);
+ rc = nextaddr;
+ goto error_out;
+ }
+
+ if ((nextaddr < lowest_lr_byte)
+ || (nextaddr > highest_lr_byte)) {
+ fsck_send_msg(lrdo_NEXTADDROUTRANGE, nextaddr);
+ rc = INVALID_NEXTADDR;
+ goto error_out;
+ }
+
+ if (nextaddr == logaddr) {
+ fsck_send_msg(lrdo_NEXTADDRSAME, nextaddr);
+ rc = NEXTADDR_SAME;
+ goto error_out;
+ }
+
+ if (nextaddr > logaddr) {
+ if (log_has_wrapped) {
+ fsck_send_msg(lrdo_LOGWRAPPED);
+ rc = LOG_WRAPPED_TWICE;
+ goto error_out;
+ } else {
+ log_has_wrapped = -1;
+ }
+ }
+ /*
+ *
+ * The addresses seem ok. Process the current record.
+ *
+ */
+ switch (ld.type) {
+ case LOG_COMMIT:
+ rc = doCommit(&ld);
+ if (rc) {
+ fsck_send_msg(lrdo_BADCOMMIT, logaddr);
+
+ goto error_out;
+ }
+ break;
+ case LOG_MOUNT:
+ fsck_send_msg(lrdo_MOUNTRECORD, logaddr);
+
+ rc = doMount(&ld);
+ if (rc) {
+ fsck_send_msg(lrdo_BADMOUNT, logaddr);
+
+ goto error_out;
+ }
+ break;
+
+ case LOG_SYNCPT:
+ fsck_send_msg(lrdo_SYNCRECORD, logaddr);
+
+ rc = 0;
+ if (lastaddr == 0) {
+ syncrecord = logaddr;
+ lastaddr = (ld.log.syncpt.sync == 0)
+ ? logaddr : ld.log.syncpt.sync;
+ }
+ break;
+
+ case LOG_REDOPAGE:
+ DBG_TRACE(("jfs_logredo:Case Log_redoPage"))
+ rc = doAfter(&ld, logaddr);
+ if (rc) {
+ fsck_send_msg(lrdo_BADREDOPAGE, logaddr);
+ goto error_out;
+ }
+ break;
+
+ case LOG_NOREDOPAGE:
+ DBG_TRACE(("jfs_logredo:Case Log_noredopage"))
+ rc = doNoRedoPage(&ld);
+ if (rc) {
+ fsck_send_msg(lrdo_BADNOREDOPAGE, logaddr);
+ goto error_out;
+ }
+ break;
+
+ case LOG_NOREDOINOEXT:
+ DBG_TRACE(("jfs_logredo:Case Log_noredoinoext"))
+ rc = doNoRedoInoExt(&ld);
+ if (rc) {
+ fsck_send_msg(lrdo_BADNOREDOINOEXT, logaddr);
+ goto error_out;
+ }
+ break;
+
+ case LOG_UPDATEMAP:
+ rc = doUpdateMap(&ld);
+ if (rc) {
+ fsck_send_msg(lrdo_BADUPDATEMAP, logaddr);
+ goto error_out;
+ }
+ break;
+
+ default:
+ fsck_send_msg(lrdo_UNKNOWNTYPE, logaddr);
+ rc = UNRECOG_LOGRECTYP;
+ goto error_out;
+ break;
+ }
+
+ if (rc < 0) {
+ fsck_send_msg(lrdo_ERRORNEEDREFORMAT);
+ goto error_out;
+ }
+
+ if (rc != 0) {
+ fsck_send_msg(lrdo_ERRORCANTCONTIN);
+ goto error_out;
+ }
+
+ /*
+ * If the transaction just completed was the last
+ * for the current transaction, then flush the
+ * buffers.
+ */
+ if (end_of_transaction != 0) {
+ for (k = 1; k < NBUFPOOL; k++) {
+ if ((rc = bflush(k, &buffer[k - 1])) != 0)
+ goto error_out;
+ }
+ end_of_transaction = 0;
+ }
+
+ } while (logaddr != lastaddr);
+ /*
+ * If any 'dtpage extend' records were processed, then we need
+ * to go back and rebuild their freelists. This cannot be done
+ * when the 'dtpage extend' record is processed, since there may
+ * be records processed later which affect the previous (shorter)
+ * version of the dtpage. Only after all these records are processed
+ * can we safely and accurately rebuild the freelist.
+ */
+ if (numExtDtPg != 0) {
+ rc = doExtDtPg();
+ }
+
+ /*
+ * flush data page buffer cache
+ */
+ for (k = 1; k < NBUFPOOL; k++) {
+ if ((rc = bflush(k, &buffer[k - 1])) != 0)
+ break;
+ }
+
+ /*
+ * finalize file systems
+ *
+ * update allocation map and superblock of file systems
+ * of volumes which are open if they were modified here.
+ * i.e. if they were not previously unmounted cleanly.
+ */
+ for (k = 0; k < MAX_ACTIVE; k++) {
+ if (vopen[k].state != VOPEN_OPEN)
+ continue;
+
+ if ((rc = updateMaps(k)) != 0) {
+ fsck_send_msg(lrdo_ERRORCANTUPDMAPS);
+ goto error_out;
+ }
+
+ /* Make sure all changes are committed to disk before we
+ * mark the superblock clean
+ */
+ ujfs_flush_dev(vopen[k].fp);
+
+ if ((rc = updateSuper(k)) != 0) {
+ fsck_send_msg(lrdo_ERRORCANTUPDFSSUPER);
+ goto error_out;
+ }
+
+ /* sync superblock before journal is finalized */
+ ujfs_flush_dev(vopen[k].fp);
+ }
+
+ /*
+ * finalize log.
+ *
+ * clear active list.
+ * If this is a fully replayed log then it can be moved to earlier
+ * versions of the operating system. Therefore switch the magic
+ * number to the earliest level.
+ */
+ if (logsup.state != LOGREADERR) {
+ for (k = 0; k < MAX_ACTIVE; k++)
+ uuid_clear(logsup.active[k]);
+
+ logsup.end = logend;
+ logsup.state = LOGREDONE;
+ logsup.magic = LOGMAGIC;
+ }
+ ujfs_swap_logsuper(&logsup);
+ rc = ujfs_rw_diskblocks(Log.fp, (Log.xaddr + LOGPNTOB(LOGSUPER_B)),
+ LOGPSIZE, (char *) &logsup, PUT);
+
+ /*
+ * now log some info for the curious
+ */
+ fsck_send_msg(lrdo_LOGEND, logend);
+
+ fsck_send_msg(lrdo_RPTSYNCNUM, syncrecord);
+
+ fsck_send_msg(lrdo_RPTSYNCADDR, lastaddr);
+
+ fsck_send_msg(lrdo_RPTNUMLOGREC, nlogrecords);
+
+ fsck_send_msg(lrdo_RPTNUMDOBLK, numdoblk);
+
+ fsck_send_msg(lrdo_RPTNUMNODOBLK, numnodofile);
+
+ error_out:
+
+ if (rc > 0) {
+ rc = rc * (-1);
+ }
+
+ /*
+ * If everything went ok except that we didn't have
+ * enough memory to deal with the block map, tell chkdsk
+ * to be sure to do a full check and repair, but that a log
+ * format is not necessary
+ */
+ if ((rc == 0) && Insuff_memory_for_maps) {
+ rc = ENOMEM25;
+ }
+
+ return (rc);
+}
+
+/*
+ * NAME: doMount(ld)
+ *
+ * FUNCTION: a log mount record is the first-in-time record which is
+ * put in the log so it is the last we want to process in
+ * logredo. so we mark volume as cleanly unmounted in vopen
+ * array. the mount record is imperative when the volume
+ * is a newly made filesystem.
+ */
+int doMount(struct lrd *ld)
+{ /* pointer to record descriptor */
+ int vol, status;
+
+ vol = ld->aggregate;
+
+ status = vopen[vol].status;
+ DBG_TRACE(("Logredo:domount: status=%d\n", status))
+
+ if (!(status & (FM_LOGREDO | FM_DIRTY)))
+ vopen[vol].status = FM_CLEAN;
+
+ return (0);
+}
+
+/*
+ * NAME: openVol(vol)
+ *
+ * FUNCTION: open the aggregate/volume specified.
+ * check if it was cleanly unmounted. also check log
+ * serial number. initialize disk and inode mpas.
+ */
+int openVol(int vol)
+{ /* device minor number of aggregate/lv */
+ int rc, l2agsize, agsize;
+ int64_t fssize; /* number of aggr blks in the aggregate/lv */
+ struct superblock sb;
+ int aggsb_numpages;
+
+ if (Log.location & OUTLINELOG) {
+ /* First check if this is the already opened volume */
+ if (!uuid_compare(vopen[vol].uuid, primary_vol.uuid))
+ vopen[vol].fp = primary_vol.fp;
+ else {
+ vopen[vol].fp = open_by_label(vopen[vol].uuid, 0, 0,
+ NULL, NULL);
+ if (vopen[vol].fp == NULL)
+ return ENOENT;
+ }
+ }
+
+ /* read superblock of the aggregate/volume */
+ if ((rc = rdwrSuper(vopen[vol].fp, &sb, PB_READ)) != 0) {
+ fsck_send_msg(lrdo_CANTREADFSSUPER);
+
+ fsError(READERR, vol, SUPER1_B);
+ vopen[vol].state = VOPEN_CLOSED;
+ return (FSSUPER_READERROR1);
+ }
+
+ /* check magic number and initialize version specific
+ * values in the vopen struct for this vol.
+ */
+ if (strncmp(sb.s_magic, JFS_MAGIC, (unsigned) strlen(JFS_MAGIC))) {
+ fsck_send_msg(lrdo_FSSUPERBADMAGIC);
+ vopen[vol].state = VOPEN_CLOSED;
+ return (LOGSUPER_BADMAGIC);
+ }
+ if (sb.s_version > JFS_VERSION) {
+ fsck_send_msg(lrdo_FSSUPERBADMAGIC);
+ vopen[vol].state = VOPEN_CLOSED;
+ return (LOGSUPER_BADVERSION);
+ }
+
+ if (Log.location & OUTLINELOG && (sb.s_flag & (JFS_INLINELOG == JFS_INLINELOG))) {
+ fsck_send_msg(lrdo_FSSUPERBADLOGLOC);
+ vopen[vol].state = VOPEN_CLOSED;
+ return (LOGSUPER_BADLOGLOC);
+ }
+ vopen[vol].lblksize = sb.s_bsize;
+ vopen[vol].l2bsize = sb.s_l2bsize;
+ vopen[vol].l2bfactor = sb.s_l2bfactor;
+ fssize = sb.s_size >> sb.s_l2bfactor;
+ vopen[vol].fssize = fssize;
+ vopen[vol].agsize = sb.s_agsize;
+ /* LOG2NUM will alter agsize, so use local var (Then why don't we
+ fix LOG2NUM?) */
+ agsize = vopen[vol].agsize;
+ LOG2NUM(agsize, l2agsize);
+ vopen[vol].numag = fssize >> l2agsize;
+ if (fssize & (vopen[vol].agsize - 1))
+ vopen[vol].numag += 1;
+ vopen[vol].l2agsize = l2agsize;
+
+ if (Log.location & INLINELOG) {
+ /*
+ * Now that the aggregate superblock has been read, do some
+ * more validation of the log superblock
+ */
+ if (logsup.bsize != vopen[vol].lblksize) {
+ fsck_send_msg(lrdo_LOGSUPBADBLKSZ);
+ return JFS_BLKSIZE_ERROR;
+ }
+
+ if (logsup.l2bsize != vopen[vol].l2bsize) {
+ fsck_send_msg(lrdo_LOGSUPBADL2BLKSZ);
+ return JFS_L2BLKSIZE_ERROR;
+ }
+
+ aggsb_numpages = lengthPXD(&sb.s_logpxd) * logsup.bsize / LOGPSIZE;
+ if (logsup.size != aggsb_numpages) {
+ fsck_send_msg(lrdo_LOGSUPBADLOGSZ);
+ return JFS_LOGSIZE_ERROR;
+ }
+ }
+ /*
+ *set lbperpage in vopen.
+ */
+ vopen[vol].lbperpage = PSIZE >> vopen[vol].l2bsize;
+
+ /*
+ * was it cleanly umounted ?
+ */
+ if (sb.s_state == FM_CLEAN) {
+ vopen[vol].status = FM_CLEAN;
+ vopen[vol].state = VOPEN_CLOSED;
+ return (0);
+ }
+
+ /*
+ * get status of volume
+ */
+ vopen[vol].status = sb.s_state;
+ vopen[vol].is_fsdirty = (sb.s_state & FM_DIRTY);
+
+ /*
+ *check log serial number
+ */
+ if (sb.s_logserial != Log.serial) {
+ fsck_send_msg(lrdo_FSSUPERBADLOGSER);
+ vopen[vol].state = VOPEN_CLOSED;
+ fsError(SERIALNO, vol, SUPER1_B);
+ return (LOGSUPER_BADSERIAL);
+ }
+
+ /* initialize the disk and inode maps
+ */
+ if ((rc = initMaps(vol)) != 0) {
+ fsck_send_msg(lrdo_INITMAPSFAIL);
+ fsError(MAPERR, vol, 0);
+ return (rc);
+ }
+ vopen[vol].state = VOPEN_OPEN;
+ return 0;
+}
+
+/*
+ * NAME: updateSuper(vol)
+ *
+ * FUNCTION: updates primary aggregate/lv's superblock status and
+ * writes it out.
+ */
+int updateSuper(int vol)
+{ /* device minor number of aggregate/lv */
+ int rc, status;
+ struct superblock sb;
+
+ /* read in superblock of the volume */
+ if ((rc = rdwrSuper(vopen[vol].fp, &sb, PB_READ)) != 0) {
+ fsck_send_msg(lrdo_READFSSUPERFAIL);
+ return (FSSUPER_READERROR2);
+ }
+
+ /* mark superblock state. write it out */
+ status = vopen[vol].status;
+ if (status & (FM_DIRTY | FM_LOGREDO))
+ sb.s_state = status & ~FM_EXTENDFS;
+ else
+ sb.s_state = FM_CLEAN;
+
+ if ((rc = rdwrSuper(vopen[vol].fp, &sb, PB_UPDATE)) != 0) {
+ fsck_send_msg(lrdo_WRITEFSSUPERFAIL);
+ }
+
+ return (rc);
+}
+
+/*
+ * NAME: rdwrSuper(fp, sb, rwflag)
+ *
+ * FUNCTION: read or write the superblock for the file system described
+ * by the file descriptor of the opened aggregate/lv.
+ * for read, if a read of primary superblock is failed,
+ * try to read the secondary superblock. report error only
+ * when both reads failed.
+ * for write, any write failure should be reported.
+ */
+int rdwrSuper(FILE *fp, struct superblock * sb, int32_t rwflag)
+{
+ int rc;
+ uint64_t super_offset;
+ union {
+ struct superblock super;
+ char block[PSIZE];
+ } super;
+
+ if (use_2ndary_agg_superblock) {
+ super_offset = SUPER2_OFF;
+ } else {
+ super_offset = SUPER1_OFF;
+ }
+ /*
+ * seek to the postion of the primary superblock.
+ * since at this time we don't know the aggregate/lv
+ * logical block size yet, we have to use the fixed
+ * byte offset address super_offset to seek for.
+ */
+
+ /*
+ * read super block
+ */
+ if (rwflag == PB_READ) {
+ rc = ujfs_rw_diskblocks(fp, super_offset,
+ (unsigned) SIZE_OF_SUPER, super.block, GET);
+ if (rc != 0) {
+ if (!use_2ndary_agg_superblock) {
+ fsck_send_msg(lrdo_READFSPRIMSBFAIL);
+ return (CANTREAD_PRIMFSSUPER);
+ } else {
+ fsck_send_msg(lrdo_READFS2NDSBFAIL);
+ return (CANTREAD_2NDFSSUPER);
+ }
+ }
+
+ *sb = super.super;
+
+ ujfs_swap_superblock(sb);
+
+ /*
+ * write superblock
+ */
+ } else { /* PB_UPDATE */
+ /* ? memset(super.block, 0, SIZE_OF_SUPER); */
+ super.super = *sb;
+
+ ujfs_swap_superblock(&super.super);
+
+ /*
+ * write whichever superblock we're working with.
+ * chkdsk will take care of replicating it.
+ */
+ rc = ujfs_rw_diskblocks(fp, super_offset,
+ (unsigned) SIZE_OF_SUPER, super.block, PUT);
+ if (rc != 0) {
+ if (!use_2ndary_agg_superblock) {
+ fsck_send_msg(lrdo_WRITEFSPRIMSBFAIL);
+ return (CANTWRITE_PRIMFSSUPER);
+ } else {
+ fsck_send_msg(lrdo_WRITEFS2NDSBFAIL);
+ return (CANTWRITE_2NDFSSUPER);
+ }
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * NAME: bflush()
+ *
+ * FUNCTION: write out appropriate portion of buffer page if its modified.
+ * Note that a dtree page may not be 4k, depending on the length
+ * field specified in pxd. Write out only length that is needed.
+ */
+int bflush(int32_t k, /* The index in bufhdr that describes buf */
+ struct bufpool *buf)
+{ /* pointer to buffer pool page */
+ FILE *fp = NULL;
+ int rc;
+ int32_t vol;
+ int32_t nbytes;
+ int64_t blkno;
+
+ /* nothing to do ? */
+ if (bufhdr[k].modify == 0)
+ return (0);
+
+ /* write it out */
+ vol = bufhdr[k].vol;
+ fp = vopen[vol].fp;
+ blkno = addressPXD(&bufhdr[k].pxd);
+ nbytes = lengthPXD(&bufhdr[k].pxd) << vopen[vol].l2bsize;
+ rc = ujfs_rw_diskblocks(fp,
+ (uint64_t) (blkno << vopen[vol].l2bsize),
+ (unsigned) nbytes, (char *) buf, PUT);
+ if (rc != 0) {
+ fsck_send_msg(lrdo_BUFFLUSHFAIL);
+ return (BFLUSH_WRITEERROR);
+ }
+
+ bufhdr[k].modify = 0;
+
+ return (0);
+}
+
+/*
+ * NAME: findLog()
+ *
+ * FUNCTION: open the device to see if it's a valid filesystem
+ * or journal. If it is a filesystem, determine whether
+ * the log is inline or external. If external, find
+ * the log device.
+ *
+ */
+int findLog(FILE *fp, int *in_use)
+{
+ struct logsuper logsup;
+ struct superblock sb;
+
+ *in_use = 0;
+ /*
+ * try the LV as file system with in-line log
+ */
+ if (rdwrSuper(fp, &sb, PB_READ)) {
+ fsck_send_msg(lrdo_NOTAFSDEV);
+ return NOT_FSDEV_ERROR;
+ }
+
+ /*
+ * is the LV a file system ?
+ */
+ if (memcmp(sb.s_magic, JFS_MAGIC, sizeof (sb.s_magic)) == 0) {
+ /*
+ * does file system contains its in-line log ?
+ */
+ if ((sb.s_flag & JFS_INLINELOG) == JFS_INLINELOG) {
+ Log.location = INLINELOG;
+ Log.fp = fp;
+ //Log.status = sb.s_state;
+ Log.l2bsize = sb.s_l2bsize;
+ Log.xaddr = addressPXD(&sb.s_logpxd) << sb.s_l2bsize;
+
+ /* vopen[0] represents fs if inline log */
+ vopen[0].status = sb.s_state;
+ vopen[0].fp = fp;
+
+ return 0;
+ }
+ /* Save fp and uuid */
+ primary_vol.fp = fp;
+ uuid_copy(primary_vol.uuid, sb.s_uuid);
+
+ /*
+ * External log
+ *
+ * First check device specified on
+ * command line
+ */
+ Log.xaddr = 0;
+ if (log_device[0]) {
+ Log.fp = NULL;
+ if (LogOpenMode != O_RDONLY) {
+ Log.fp = fopen_excl(log_device, "r+");
+ if (Log.fp == NULL)
+ *in_use = 1;
+ }
+ if (Log.fp == NULL) {
+ Log.fp = fopen(log_device, "r");
+ if (Log.fp == NULL) {
+ printf("Invalid journal specified (%s)\n",
+ log_device);
+ goto by_uuid;
+ }
+ }
+ ujfs_rw_diskblocks(Log.fp, LOGPNTOB(LOGSUPER_B),
+ sizeof (struct logsuper), &logsup, GET);
+ ujfs_swap_logsuper(&logsup);
+ if ((logsup.magic != LOGMAGIC) || (uuid_compare(logsup.uuid, sb.s_loguuid))) {
+ fclose(Log.fp);
+ *in_use = 0;
+ goto by_uuid;
+ }
+ Log.location = OUTLINELOG;
+ return 0;
+ }
+ by_uuid:
+ Log.fp = open_by_label(sb.s_loguuid, 0, 1, NULL, in_use);
+
+ if (Log.fp != NULL) {
+ Log.location |= OUTLINELOG;
+ return 0;
+ }
+
+ return NOT_INLINELOG_ERROR;
+ }
+ /*
+ * is this an external log?
+ */
+ ujfs_rw_diskblocks(fp, LOGPNTOB(LOGSUPER_B), sizeof (struct logsuper), &logsup, GET);
+ ujfs_swap_logsuper(&logsup);
+ if (logsup.magic != LOGMAGIC) {
+ fsck_send_msg(lrdo_NOTAFSDEV);
+ return NOT_FSDEV_ERROR;
+ }
+ Log.fp = fp;
+ Log.location = OUTLINELOG;
+
+ return 0;
+}
+
+extern void exit(int);
+
+/*
+ * NAME: fsError(type,vol,bn)
+ *
+ * FUNCTION: error handling code for the specified
+ * aggregate/lv (filesystem).
+ */
+int fsError(int type, /* error types */
+ int vol, /* the minor number of the aggregate/lv */
+ int64_t bn)
+{ /* aggregate block No. */
+
+ fsck_send_msg(lrdo_ERRORONVOL, vol);
+
+ retcode = -1;
+ vopen[vol].status = FM_LOGREDO;
+
+ switch (type) {
+ case OPENERR:
+ fsck_send_msg(lrdo_OPENFAILED);
+ break;
+ case MAPERR:
+ fsck_send_msg(lrdo_CANTINITMAPS);
+ break;
+ case DBTYPE:
+ fsck_send_msg(lrdo_BADDISKBLKNUM, (long long) bn);
+ break;
+ case INOTYPE:
+ fsck_send_msg(lrdo_BADINODENUM, (long long) bn);
+ break;
+ case READERR:
+ fsck_send_msg(lrdo_CANTREADBLK, (long long) bn);
+ break;
+ case SERIALNO:
+ fsck_send_msg(lrdo_BADLOGSER);
+ break;
+ case IOERROR:
+ fsck_send_msg(lrdo_IOERRREADINGBLK, (long long) bn);
+ break;
+ case LOGRCERR:
+ fsck_send_msg(lrdo_BADUPDMAPREC, (long long) bn);
+ break;
+ }
+ return (0);
+}
+
+/*
+ * logError(type)
+ *
+ * error handling for log read errors.
+ */
+int logError(int type, int logaddr)
+{
+ int k;
+ retcode = -1;
+ logsup.state = LOGREADERR;
+ switch (type) {
+ case LOGEND:
+ fsck_send_msg(lrdo_FINDLOGENDFAIL);
+ break;
+ case READERR:
+ fsck_send_msg(lrdo_LOGREADFAIL, logaddr);
+ break;
+ case UNKNOWNR:
+ fsck_send_msg(lrdo_UNRECOGTYPE, logaddr);
+ break;
+ case IOERROR:
+ fsck_send_msg(lrdo_IOERRONLOG, logaddr);
+ break;
+ case LOGWRAP:
+ fsck_send_msg(lrdo_LOGWRAP);
+ }
+
+ /* mark all open volumes in error
+ */
+ for (k = 0; k < MAX_ACTIVE; k++) {
+ if ((vopen[k].state == VOPEN_OPEN) && vopen[k].status != FM_CLEAN)
+ vopen[k].status = FM_LOGREDO;
+ }
+ return (0);
+}
+
+/*
+ * recoverExtendFS()
+ *
+ * function: recover crash while in extendfs() for inline log;
+ *
+ * note: fs superblock fields remains pre-extendfs state,
+ * while that bmap file, fsck and inline log area may be in
+ * unknown state;
+ *
+ * at entry, only log type/lv has been validated;
+ * for inline log: vopen[0], fs fp = log fp;
+ */
+static int recoverExtendFS(FILE *fp)
+{
+ struct superblock *sbp;
+ struct dinode *dip1, *dip2;
+ struct dbmap *bgcp;
+ xtpage_t *p;
+ int64_t lmchild = 0, xaddr, xoff, barrier, t64, agsize;
+ uint8_t lmxflag;
+ int32_t i;
+ char *dip, *bp;
+ pxd_t temp_pxd;
+
+ /*
+ * read bmap global control page
+ */
+ /* read superblock yet again */
+ sbp = (struct superblock *) &buffer[0];
+ if (rdwrSuper(fp, sbp, PB_READ))
+ goto errout;
+
+ /* read primary block allocation map inode */
+ dip = (char *) &buffer[1];
+ if (ujfs_rw_diskblocks(fp, AITBL_OFF, PSIZE, dip, GET)) {
+ fsck_send_msg(lrdo_EXTFSREADFSSUPERFAIL);
+ goto errout;
+ }
+
+ /* locate the inode in the buffer page */
+ dip1 = (struct dinode *) dip;
+ dip1 += BMAP_I;
+
+ bp = (char *) &buffer[2]; /* utility buffer */
+
+ /* start from root in dinode */
+ p = (xtpage_t *) & dip1->di_btroot;
+ /* is this page leaf ? */
+ if (p->header.flag & BT_LEAF)
+ goto rdbgcp;
+
+ /* traverse down leftmost child node to leftmost leaf of xtree */
+ do {
+ /* read in the leftmost child page */
+ t64 = addressXAD(&p->xad[XTENTRYSTART]) << sbp->s_l2bsize;
+ if (ujfs_rw_diskblocks(fp, t64, PSIZE, bp, GET)) {
+ fsck_send_msg(lrdo_EXTFSREADBLKMAPINOFAIL);
+ goto errout;
+ }
+
+ p = (xtpage_t *) bp;
+ /* is this page leaf ? */
+ if (p->header.flag & BT_LEAF)
+ break;
+ } while (1);
+
+ rdbgcp:
+ t64 = addressXAD(&p->xad[XTENTRYSTART]) << sbp->s_l2bsize;
+ if (ujfs_rw_diskblocks(fp, t64, PSIZE, bp, GET)) {
+ fsck_send_msg(lrdo_EXTFSREADBLKFAIL1, (long long) t64);
+ goto errout;
+ }
+ bgcp = (struct dbmap *) bp;
+
+ /*
+ * recover to pre- or post-extendfs state ?:
+ */
+ if (__le64_to_cpu(bgcp->dn_mapsize) > (sbp->s_size >> sbp->s_l2bfactor)) {
+ agsize = __le64_to_cpu(bgcp->dn_agsize);
+ goto postx;
+ }
+
+ /*
+ * recover pre-extendfs state
+ */
+ /*
+ * reset block allocation map inode (xtree root)
+ */
+ /* read 2ndary block allocation map inode */
+ t64 = addressPXD(&sbp->s_ait2) << sbp->s_l2bsize;
+ if (ujfs_rw_diskblocks(fp, t64, PSIZE, bp, GET)) {
+ fsck_send_msg(lrdo_EXTFSREADBLKFAIL2, (long long) t64);
+ goto errout;
+ }
+ dip2 = (struct dinode *) bp;
+ dip2 += BMAP_I;
+
+ /*
+ * Reset primary bam inode with 2ndary bam inode
+ *
+ * Not forgetting to reset di_ixpxd since they are in different
+ * inode extents.
+ */
+ memcpy((void *) &temp_pxd, (void *) &(dip1->di_ixpxd), sizeof (pxd_t));
+ memcpy(dip1, dip2, DISIZE);
+ memcpy((void *) &(dip1->di_ixpxd), (void *) &temp_pxd, sizeof (pxd_t));
+
+ if (ujfs_rw_diskblocks(fp, AITBL_OFF, PSIZE, dip, PUT)) {
+ fsck_send_msg(lrdo_EXTFSWRITEBLKFAIL1, AITBL_OFF);
+ goto errout;
+ }
+
+ /*
+ * backout bmap file to fs size:
+ *
+ * trim xtree to range specified by i_size:
+ * xtree has been grown in append mode and
+ * written from right to left, bottom-up;
+ */
+ barrier = __le64_to_cpu(dip1->di_size) >> sbp->s_l2bsize;
+
+ /* start with root */
+ xaddr = 0;
+ p = (xtpage_t *) & dip1->di_btroot;
+ lmxflag = p->header.flag;
+ p->header.next = 0;
+ if (lmxflag & BT_INTERNAL) {
+ /* save leftmost child xtpage xaddr */
+ lmchild = addressXAD(&p->xad[XTENTRYSTART]);
+ }
+
+ /*
+ * scan each level of xtree via leftmost descend
+ */
+ while (1) {
+ /*
+ * scan each xtpage of current level of xtree
+ */
+ while (1) {
+ /*
+ * scan each xad in current xtpage
+ */
+ for (i = XTENTRYSTART; i < p->header.nextindex; i++) {
+ /* test if extent is of interest */
+ xoff = offsetXAD(&p->xad[i]);
+ if (xoff < barrier)
+ continue;
+
+ /*
+ * barrier met in current page
+ */
+ assert(i > XTENTRYSTART);
+ /* update current page */
+ p->header.nextindex = i;
+ if (xaddr) {
+ /* discard further right sibling
+ * pages
+ */
+ p->header.next = 0;
+ if (ujfs_rw_diskblocks(fp, t64, PSIZE, p, PUT)) {
+ fsck_send_msg(lrdo_EXTFSWRITEBLKFAIL2, (long long) t64);
+ goto errout;
+ }
+ }
+
+ goto nextLevel;
+ } /* end for current xtpage scan */
+
+ /* barrier was not met in current page */
+
+ /* read in next/right sibling xtpage */
+ xaddr = p->header.next;
+ if (xaddr) {
+ if (xaddr >= barrier) {
+ p->header.next = 0;
+ if (ujfs_rw_diskblocks(fp, t64, PSIZE, p, PUT)) {
+ fsck_send_msg(lrdo_EXTFSWRITEBLKFAIL3, (long long) t64);
+ break;
+ }
+ }
+
+ t64 = xaddr << sbp->s_l2bsize;
+ if (ujfs_rw_diskblocks(fp, t64, PSIZE, bp, GET)) {
+ fsck_send_msg(lrdo_EXTFSREADBLKFAIL3, (long long) t64);
+ goto errout;
+ }
+
+ p = (xtpage_t *) bp;
+ } else
+ break;
+ } /* end while current level scan */
+
+ /*
+ * descend: read leftmost xtpage of next lower level of xtree
+ */
+ nextLevel:
+ if (lmxflag & BT_INTERNAL) {
+ /* get the leftmost child page */
+ xaddr = lmchild;
+ t64 = xaddr << sbp->s_l2bsize;
+ if (ujfs_rw_diskblocks(fp, t64, PSIZE, bp, GET)) {
+ fsck_send_msg(lrdo_EXTFSREADBLKFAIL4, (long long) t64);
+ goto errout;
+ }
+
+ p = (xtpage_t *) bp;
+
+ lmxflag = p->header.flag;
+ if (lmxflag & BT_INTERNAL) {
+ /* save leftmost child xtpage xaddr */
+ lmchild = addressXAD(&p->xad[XTENTRYSTART]);
+ }
+ } else
+ break;
+ } /* end while level scan */
+
+ /*
+ * reconstruct map;
+ *
+ * readBmap() init blocks beyond fs size in the last
+ * partial dmap page as allocated which might have been
+ * marked as free by extendfs();
+ */
+ /* fake log opend/validated */
+ Log.serial = sbp->s_logserial;
+
+ /*
+ * reconstruct maps
+ */
+ /* open LV and initialize maps */
+ if (logredoInit()) {
+ fsck_send_msg(lrdo_EXTFSINITLOGREDOFAIL);
+ goto errout;
+ }
+
+ /* bypass log replay */
+
+ /* update/write maps */
+ updateMaps(0);
+
+ /*
+ * reformat log
+ *
+ * request reformat original log (which might have been
+ * overwritten by extendfs() and set superblock clean
+ */
+ jfs_logform(fp, sbp->s_bsize, sbp->s_l2bsize, sbp->s_flag,
+ addressPXD(&sbp->s_logpxd), lengthPXD(&sbp->s_logpxd), NULL, NULL);
+
+ /* update superblock */
+ updateSuper(0);
+
+ fsck_send_msg(lrdo_REXTNDTOPRE);
+
+ return 0;
+
+ /*
+ * recover post-extendfs state
+ */
+ postx:
+ /*
+ * update 2ndary bam inode
+ */
+ /* read 2ndary block allocation map inode */
+ t64 = addressPXD(&sbp->s_ait2) << sbp->s_l2bsize;
+ if (ujfs_rw_diskblocks(fp, t64, PSIZE, bp, GET)) {
+ fsck_send_msg(lrdo_EXTFSREADBLKFAIL5, (long long) t64);
+ goto errout;
+ }
+ dip2 = (struct dinode *) bp;
+ dip2 += BMAP_I;
+
+ /*
+ * Reset 2ndary bam inode with primary bam inode
+ * Not forgetting to reset di_ixpxd since they are in different
+ * inode extents.
+ */
+ memcpy((void *) &temp_pxd, (void *) &(dip2->di_ixpxd), sizeof (pxd_t));
+ memcpy(dip2, dip1, DISIZE);
+ memcpy((void *) &(dip2->di_ixpxd), (void *) &temp_pxd, sizeof (pxd_t));
+
+ if (ujfs_rw_diskblocks(fp, t64, PSIZE, bp, PUT)) {
+ fsck_send_msg(lrdo_EXTFSWRITEBLKFAIL4, (long long) t64);
+ goto errout;
+ }
+
+ /*
+ * update superblock
+ */
+ if (!(sbp->s_state & (FM_DIRTY | FM_LOGREDO)))
+ sbp->s_state = FM_CLEAN;
+ else
+ sbp->s_state &= ~FM_EXTENDFS;
+ sbp->s_size = sbp->s_xsize;
+ sbp->s_agsize = agsize;
+ sbp->s_fsckpxd = sbp->s_xfsckpxd;
+ sbp->s_fscklog = 0;
+ sbp->s_logpxd = sbp->s_xlogpxd;
+ sbp->s_logserial = 1;
+
+ if (rdwrSuper(fp, sbp, PB_UPDATE)) {
+ fsck_send_msg(lrdo_EXTFSWRITEFSSUPERFAIL);
+ goto errout;
+ }
+
+ /*
+ * finalize log
+ *
+ * note: new log is valid;
+ */
+ /* read log superblock */
+ t64 = (addressPXD(&sbp->s_logpxd) << sbp->s_l2bsize) + LOGPSIZE;
+ if (ujfs_rw_diskblocks(fp, t64, LOGPSIZE, &logsup, GET)) {
+ fsck_send_msg(lrdo_EXTFSREADLOGSUPFAIL);
+ goto errout;
+ }
+
+ logsup.end = findEndOfLog();
+ logsup.state = LOGREDONE;
+
+ if (ujfs_rw_diskblocks(fp, t64, LOGPSIZE, &logsup, PUT)) {
+ fsck_send_msg(lrdo_EXTFSWRITELOGSUPFAIL);
+ goto errout;
+ }
+
+ fsck_send_msg(lrdo_REXTNDTOPOST);
+
+ return 0;
+
+ errout:
+ fsck_send_msg(lrdo_REXTNDFAIL, errno);
+ return (EXTENDFS_FAILRECOV);
+}
+
+/*
+ *
+ * NAME: alloc_dmap_bitrec
+ *
+ * FUNCTION: This routine allocates memory by calling the chkdsk
+ * alloc_wrksp() routine (because that will allocate high
+ * memory during autocheck). If that fails then logredo
+ * cannot continue bmap processing, so it will set a flag
+ * and make the storage aleady allocated to the bmap
+ * available for other uses.
+ * was successfully allocated and there's enough of it left,
+ * this routine will return a piece of it.
+ */
+int alloc_dmap_bitrec(struct dmap_bitmaps ** dmap_bitrec)
+{
+ int adb_rc = 0;
+ int intermed_rc = 0;
+
+ *dmap_bitrec = NULL;
+
+ intermed_rc = alloc_wrksp((uint32_t) (sizeof (struct dmap_bitmaps)), 0, /* not meaningful from logredo */
+ -1, /* I am logredo */
+ (void **) dmap_bitrec);
+
+ if ((intermed_rc != 0) || ((*dmap_bitrec) == NULL)) {
+ Insuff_memory_for_maps = -1;
+ available_stg_addr = bmap_stg_addr;
+ available_stg_bytes = bmap_stg_bytes;
+ /*
+ * initialize the storage for its new use
+ */
+ memset((void *) available_stg_addr, 0, available_stg_bytes);
+ }
+
+ return (adb_rc);
+} /* end alloc_dmap_bitrec() */
+
+/*
+ *
+ * NAME: alloc_storage
+ *
+ * FUNCTION: This routine allocates memory by calling the chkdsk
+ * alloc_wrksp() routine (because that will allocate high
+ * memory during autocheck). If that fails and the bmap
+ * was successfully allocated and there's enough of it left,
+ * this routine will return a piece of it.
+ */
+int alloc_storage(int32_t size_in_bytes, void **addr_stg_ptr, int32_t * bmap_stg_returned)
+{
+ int as_rc = 0;
+ int intermed_rc = 0;
+
+ *bmap_stg_returned = 0; /* assume we'll get it the usual way */
+ *addr_stg_ptr = NULL;
+
+ intermed_rc = alloc_wrksp((uint32_t) size_in_bytes, 0, -1, addr_stg_ptr);
+
+ if ((intermed_rc != 0) || ((*addr_stg_ptr) == NULL)) {
+ if ((!Insuff_memory_for_maps) && (bmap_stg_addr != NULL)) {
+ /*
+ * we did allocate storage for the bmap
+ * and haven't started cannibalizing it yet
+ */
+ Insuff_memory_for_maps = -1;
+ available_stg_addr = bmap_stg_addr;
+ available_stg_bytes = bmap_stg_bytes;
+ /*
+ * initialize the storage for its new use
+ */
+ memset((void *) available_stg_addr, 0, available_stg_bytes);
+ }
+ /* end we did allocate storage for the bmap... */
+ if (Insuff_memory_for_maps & (available_stg_bytes != 0)) {
+ /*
+ * we may be able to go on anyway
+ */
+ if (available_stg_bytes < size_in_bytes) {
+ /*
+ * not enough here
+ */
+ return (ENOMEM0);
+ } else {
+ /* we can scavenge the memory we need */
+ *addr_stg_ptr = available_stg_addr;
+ available_stg_bytes -= size_in_bytes;
+ available_stg_addr = (char *) (available_stg_addr + size_in_bytes);
+ *bmap_stg_returned = -1;
+ }
+ } else {
+ return (ENOMEM1);
+ }
+ }
+
+ return (as_rc);
+}
+
+#ifdef _JFS_WIP
+/*
+ * nfsisloaded()
+ *
+ * check whether nfs is loaded
+ */
+static int nfsisloaded()
+{
+ int sav_errno;
+ int (*entry) ();
+ if (entry = load("/usr/sbin/probe", 0, 0))
+ return (1);
+ if (errno == ENOEXEC) {
+ DBG_TRACE(("%s: nfs is not loaded\n", prog))
+ return (0);
+ }
+ sav_errno = errno;
+ DBG_TRACE(("%s: ", prog))
+ errno = sav_errno;
+ perror("load");
+ return (0);
+}
+#endif /* _JFS_WIP */
+
+#ifdef _JFS_DEBUG
+/*
+ * xdump()
+ *
+ * hex dump
+ */
+xdump(char *saddr, int count)
+{
+#define LINESZ 60
+#define ASCIISTRT 40
+#define HEXEND 36
+ int i, j, k, hexdigit;
+ int c;
+ char *hexchar;
+ char linebuf[LINESZ + 1];
+ char prevbuf[LINESZ + 1];
+ char *linestart;
+ int asciistart;
+ char asterisk = ' ';
+ void x_scpy();
+ int x_scmp();
+ hexchar = "0123456789ABCDEF";
+ prevbuf[0] = '\0';
+ i = (int) saddr % 4;
+ if (i != 0)
+ saddr = saddr - i;
+ for (i = 0; i < count;) {
+ for (j = 0; j < LINESZ; j++)
+ linebuf[j] = ' ';
+ linestart = saddr;
+ asciistart = ASCIISTRT;
+ for (j = 0; j < HEXEND;) {
+ for (k = 0; k < 4; k++) {
+ c = *(saddr++) & 0xFF;
+ if ((c >= 0x20) && (c <= 0x7e))
+ linebuf[asciistart++] = (char) c;
+ else
+ linebuf[asciistart++] = '.';
+ hexdigit = c >> 4;
+ linebuf[j++] = hexchar[hexdigit];
+ hexdigit = c & 0x0f;
+ linebuf[j++] = hexchar[hexdigit];
+ i++;
+ }
+ if (i >= count)
+ break;
+ linebuf[j++] = ' ';
+ }
+ linebuf[LINESZ] = '\0';
+ if (((j = x_scmp(linebuf, prevbuf)) == 0) && (i < count)) {
+ if (asterisk == ' ') {
+ asterisk = '*';
+ DBG_TRACE((" *\n"))
+ }
+ } else {
+ DBG_TRACE((" %x %s\n", linestart, linebuf))
+ asterisk = ' ';
+ x_scpy(prevbuf, linebuf);
+ }
+ }
+ return (0);
+}
+
+int x_scmp(char *s1, char *s2)
+{
+ while ((*s1) && (*s1 == *s2)) {
+ s1++;
+ s2++;
+ }
+ if (*s1 || *s2)
+ return (-1);
+ else
+ return (0);
+}
+
+void x_scpy(char *s1, char *s2)
+{
+ while ((*s1 = *s2) != '\0') {
+ s1++;
+ s2++;
+ }
+}
+
+prtdesc(struct lrd *ld)
+{
+ switch (ld->log.redopage.type) {
+ case LOG_XTREE:
+ DBG_TRACE((" REDOPAGE:XTREE\n "))
+ break;
+ case (LOG_XTREE | LOG_NEW):
+ DBG_TRACE((" REDOPAGE:XTREE_NEW\n "))
+ break;
+ case (LOG_BTROOT | LOG_XTREE):
+ DBG_TRACE((" REDOPAGE:BTROOT_XTREE\n "))
+ break;
+ case LOG_DTREE:
+ DBG_TRACE((" REDOPAGE:DTREE\n "))
+ break;
+ case (LOG_DTREE | LOG_NEW):
+ DBG_TRACE((" REDOPAGE:DTREE_NEW \n "))
+ break;
+ case (LOG_DTREE | LOG_EXTEND):
+ DBG_TRACE((" REDOPAGE:DTREE_EXTEND\n "))
+ break;
+ case (LOG_BTROOT | LOG_DTREE):
+ DBG_TRACE((" REDOPAGE:BTROOT_DTREE\n "))
+ break;
+ case (LOG_BTROOT | LOG_DTREE | LOG_NEW):
+ DBG_TRACE((" REDOPAGE:BTROOT_DTREE.NEW\n "))
+ break;
+ case LOG_INODE:
+ /*
+ * logredo() updates imap for alloc of inode.
+ */
+ DBG_TRACE((" REDOPAGE:INODE\n "))
+ break;
+ case LOG_EA:
+ DBG_TRACE((" REDOPAGE:EA\n "))
+ break;
+ case LOG_DATA:
+ DBG_TRACE((" REDOPAGE:DATA\n "))
+ break;
+ }
+ return (0);
+}
+#endif /* _JFS_DEBUG */
Index: libfs
===================================================================
--- libfs (nonexistent)
+++ libfs (revision 5)
Property changes on: libfs
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: .
===================================================================
--- . (nonexistent)
+++ . (revision 5)
Property changes on: .
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~