blob: 70097bc18488ccdad05a7381d025c4ad309b9d27 [file] [log] [blame]
/*
* Copyright (c) 2015 Red Hat, Inc.
* All Rights Reserved.
*
* 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.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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 the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libxfs.h"
#include "command.h"
#include "init.h"
#include "output.h"
#include "libxlog.h"
#define MAX_LSUNIT 256 * 1024 /* max log buf. size */
static int
logformat_f(int argc, char **argv)
{
xfs_daddr_t head_blk;
xfs_daddr_t tail_blk;
int logversion;
int lsunit = -1;
int cycle = -1;
int error;
int c;
logversion = xfs_sb_version_haslogv2(&mp->m_sb) ? 2 : 1;
while ((c = getopt(argc, argv, "c:s:")) != EOF) {
switch (c) {
case 'c':
cycle = strtol(optarg, NULL, 0);
if (cycle == 0) {
dbprintf("invalid cycle\n");
return -1;
}
break;
case 's':
lsunit = strtol(optarg, NULL, 0);
/*
* The log stripe unit must be block aligned and no
* larger than 256k.
*/
if (lsunit > 1 &&
(lsunit % mp->m_sb.sb_blocksize ||
(logversion == 2 && lsunit > MAX_LSUNIT))) {
dbprintf("invalid log stripe unit\n");
return -1;
}
break;
default:
dbprintf("invalid option\n");
return -1;
}
}
/*
* Check whether the log is dirty. This also determines the current log
* cycle if we have to use it by default below.
*/
memset(mp->m_log, 0, sizeof(struct xlog));
mp->m_log->l_mp = mp;
mp->m_log->l_dev = mp->m_logdev_targp;
mp->m_log->l_logBBsize = XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
mp->m_log->l_logBBstart = XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart);
mp->m_log->l_sectBBsize = BBSIZE;
if (xfs_sb_version_hassector(&mp->m_sb))
mp->m_log->l_sectBBsize <<= (mp->m_sb.sb_logsectlog - BBSHIFT);
mp->m_log->l_sectBBsize = BTOBB(mp->m_log->l_sectBBsize);
error = xlog_find_tail(mp->m_log, &head_blk, &tail_blk);
if (error) {
dbprintf("could not find log head/tail\n");
return -1;
}
if (head_blk != tail_blk) {
dbprintf(_(
"The log is dirty. Please mount to replay the log.\n"));
return -1;
}
/*
* Use the current cycle and/or log stripe unit if either is not
* provided by the user.
*/
if (cycle < 0)
cycle = mp->m_log->l_curr_cycle;
if (lsunit < 0)
lsunit = mp->m_sb.sb_logsunit;
dbprintf("Formatting the log to cycle %d, stripe unit %d bytes.\n",
cycle, lsunit);
error = -libxfs_log_clear(mp->m_logdev_targp, NULL,
mp->m_log->l_logBBstart,
mp->m_log->l_logBBsize,
&mp->m_sb.sb_uuid, logversion, lsunit,
XLOG_FMT, cycle, false);
if (error) {
dbprintf("error formatting log - %d\n", error);
return error;
}
return 0;
}
static void
logformat_help(void)
{
dbprintf(_(
"\n"
" The 'logformat' command reformats (clears) the log to the specified log\n"
" cycle and log stripe unit. If the log cycle is not specified, the log is\n"
" reformatted to the current cycle. If the log stripe unit is not specified,\n"
" the stripe unit from the filesystem superblock is used.\n"
"\n"
));
}
static const struct cmdinfo logformat_cmd = {
.name = "logformat",
.altname = NULL,
.cfunc = logformat_f,
.argmin = 0,
.argmax = 4,
.canpush = 0,
.args = N_("[-c cycle] [-s sunit]"),
.oneline = N_("reformat the log"),
.help = logformat_help,
};
void
logformat_init(void)
{
if (!expert_mode)
return;
add_command(&logformat_cmd);
}