|
Packit Service |
360c39 |
#include "clusterautoconfig.h"
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#include <stdio.h>
|
|
Packit Service |
360c39 |
#include <stdlib.h>
|
|
Packit Service |
360c39 |
#include <inttypes.h>
|
|
Packit Service |
360c39 |
#include <string.h>
|
|
Packit Service |
360c39 |
#include <dirent.h>
|
|
Packit Service |
360c39 |
#include <libintl.h>
|
|
Packit Service |
360c39 |
#define _(String) gettext(String)
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
#include <logging.h>
|
|
Packit Service |
360c39 |
#include "libgfs2.h"
|
|
Packit Service |
360c39 |
#include "osi_list.h"
|
|
Packit Service |
360c39 |
#include "fsck.h"
|
|
Packit Service |
360c39 |
#include "lost_n_found.h"
|
|
Packit Service |
360c39 |
#include "link.h"
|
|
Packit Service |
360c39 |
#include "metawalk.h"
|
|
Packit Service |
360c39 |
#include "util.h"
|
|
Packit Service |
360c39 |
#include "afterpass1_common.h"
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int attach_dotdot_to(struct gfs2_sbd *sdp, uint64_t newdotdot,
|
|
Packit Service |
360c39 |
uint64_t olddotdot, uint64_t block)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
const char *filename = "..";
|
|
Packit Service |
360c39 |
int filename_len = 2;
|
|
Packit Service |
360c39 |
int err;
|
|
Packit Service |
360c39 |
struct gfs2_inode *ip, *pip;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
ip = fsck_load_inode(sdp, block);
|
|
Packit Service |
360c39 |
pip = fsck_load_inode(sdp, newdotdot);
|
|
Packit Service |
360c39 |
/* FIXME: Need to add some interactive
|
|
Packit Service |
360c39 |
* options here and come up with a
|
|
Packit Service |
360c39 |
* good default for non-interactive */
|
|
Packit Service |
360c39 |
/* FIXME: do i need to correct the
|
|
Packit Service |
360c39 |
* '..' entry for this directory in
|
|
Packit Service |
360c39 |
* this case? */
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (gfs2_dirent_del(ip, filename, filename_len))
|
|
Packit Service |
360c39 |
log_warn( _("Unable to remove \"..\" directory entry.\n"));
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
decr_link_count(olddotdot, block, sdp->gfs1, _("old \"..\""));
|
|
Packit Service |
360c39 |
err = dir_add(ip, filename, filename_len, &pip->i_di.di_num,
|
|
Packit Service |
360c39 |
(sdp->gfs1 ? GFS_FILE_DIR : DT_DIR));
|
|
Packit Service |
360c39 |
if (err) {
|
|
Packit Service |
360c39 |
log_err(_("Error adding directory %s: %s\n"),
|
|
Packit Service |
360c39 |
filename, strerror(errno));
|
|
Packit Service |
360c39 |
exit(FSCK_ERROR);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
incr_link_count(pip->i_di.di_num, ip, _("new \"..\""));
|
|
Packit Service |
360c39 |
fsck_inode_put(&ip);
|
|
Packit Service |
360c39 |
fsck_inode_put(&pip;;
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static struct dir_info *mark_and_return_parent(struct gfs2_sbd *sdp,
|
|
Packit Service |
360c39 |
struct dir_info *di)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct dir_info *pdi;
|
|
Packit Service |
360c39 |
int q_dotdot, q_treewalk;
|
|
Packit Service |
360c39 |
int error = 0;
|
|
Packit Service |
360c39 |
struct dir_info *dt_dotdot, *dt_treewalk;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
di->checked = 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!di->treewalk_parent)
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (di->dotdot_parent.no_addr == di->treewalk_parent) {
|
|
Packit Service |
360c39 |
q_dotdot = bitmap_type(sdp, di->dotdot_parent.no_addr);
|
|
Packit Service |
360c39 |
if (q_dotdot != GFS2_BLKST_DINODE) {
|
|
Packit Service |
360c39 |
log_err( _("Orphaned directory at block %llu (0x%llx) "
|
|
Packit Service |
360c39 |
"moved to lost+found\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)di->dinode.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)di->dinode.no_addr);
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
log_warn( _("Directory '..' and treewalk connections disagree for "
|
|
Packit Service |
360c39 |
"inode %llu (0x%llx)\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)di->dinode.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)di->dinode.no_addr);
|
|
Packit Service |
360c39 |
log_notice( _("'..' has %llu (0x%llx), treewalk has %llu (0x%llx)\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)di->dotdot_parent.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)di->dotdot_parent.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)di->treewalk_parent,
|
|
Packit Service |
360c39 |
(unsigned long long)di->treewalk_parent);
|
|
Packit Service |
360c39 |
q_dotdot = bitmap_type(sdp, di->dotdot_parent.no_addr);
|
|
Packit Service |
360c39 |
dt_dotdot = dirtree_find(di->dotdot_parent.no_addr);
|
|
Packit Service |
360c39 |
q_treewalk = bitmap_type(sdp, di->treewalk_parent);
|
|
Packit Service |
360c39 |
dt_treewalk = dirtree_find(di->treewalk_parent);
|
|
Packit Service |
360c39 |
/* if the dotdot entry isn't a directory, but the
|
|
Packit Service |
360c39 |
* treewalk is, treewalk is correct - if the treewalk
|
|
Packit Service |
360c39 |
* entry isn't a directory, but the dotdot is, dotdot
|
|
Packit Service |
360c39 |
* is correct - if both are directories, which do we
|
|
Packit Service |
360c39 |
* choose? if neither are directories, we have a
|
|
Packit Service |
360c39 |
* problem - need to move this directory into lost+found
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
if (q_dotdot != GFS2_BLKST_DINODE || dt_dotdot == NULL) {
|
|
Packit Service |
360c39 |
if (q_treewalk != GFS2_BLKST_DINODE) {
|
|
Packit Service |
360c39 |
log_err( _("Orphaned directory, move to "
|
|
Packit Service |
360c39 |
"lost+found\n"));
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
log_warn( _("Treewalk parent is correct, fixing "
|
|
Packit Service |
360c39 |
"dotdot -> %llu (0x%llx)\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)di->treewalk_parent,
|
|
Packit Service |
360c39 |
(unsigned long long)di->treewalk_parent);
|
|
Packit Service |
360c39 |
attach_dotdot_to(sdp, di->treewalk_parent,
|
|
Packit Service |
360c39 |
di->dotdot_parent.no_addr,
|
|
Packit Service |
360c39 |
di->dinode.no_addr);
|
|
Packit Service |
360c39 |
di->dotdot_parent.no_addr = di->treewalk_parent;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (dt_treewalk) {
|
|
Packit Service |
360c39 |
log_err( _("Both .. and treewalk parents are directories, "
|
|
Packit Service |
360c39 |
"going with treewalk...\n"));
|
|
Packit Service |
360c39 |
attach_dotdot_to(sdp, di->treewalk_parent,
|
|
Packit Service |
360c39 |
di->dotdot_parent.no_addr,
|
|
Packit Service |
360c39 |
di->dinode.no_addr);
|
|
Packit Service |
360c39 |
di->dotdot_parent.no_addr = di->treewalk_parent;
|
|
Packit Service |
360c39 |
goto out;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
log_warn( _(".. parent is valid, but treewalk is bad - reattaching to "
|
|
Packit Service |
360c39 |
"lost+found"));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* FIXME: add a dinode for this entry instead? */
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!query( _("Remove directory entry for bad inode %llu (0x%llx) in "
|
|
Packit Service |
360c39 |
"%llu (0x%llx)? (y/n)"),
|
|
Packit Service |
360c39 |
(unsigned long long)di->dinode.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)di->dinode.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)di->treewalk_parent,
|
|
Packit Service |
360c39 |
(unsigned long long)di->treewalk_parent)) {
|
|
Packit Service |
360c39 |
log_err( _("Directory entry to invalid inode remains\n"));
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
error = remove_dentry_from_dir(sdp, di->treewalk_parent,
|
|
Packit Service |
360c39 |
di->dinode.no_addr);
|
|
Packit Service |
360c39 |
if (error < 0) {
|
|
Packit Service |
360c39 |
stack;
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (error > 0)
|
|
Packit Service |
360c39 |
log_warn( _("Unable to find dentry for block %llu"
|
|
Packit Service |
360c39 |
" (0x%llx) in %llu (0x%llx)\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)di->dinode.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)di->dinode.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)di->treewalk_parent,
|
|
Packit Service |
360c39 |
(unsigned long long)di->treewalk_parent);
|
|
Packit Service |
360c39 |
log_warn( _("Directory entry removed\n"));
|
|
Packit Service |
360c39 |
log_info( _("Marking directory unlinked\n"));
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return NULL;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
out:
|
|
Packit Service |
360c39 |
pdi = dirtree_find(di->dotdot_parent.no_addr);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return pdi;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* pass3 - check connectivity of directories
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* handle disconnected directories
|
|
Packit Service |
360c39 |
* handle lost+found directory errors (missing, not a directory, no space)
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
int pass3(struct gfs2_sbd *sdp)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct osi_node *tmp, *next = NULL;
|
|
Packit Service |
360c39 |
struct dir_info *di, *tdi;
|
|
Packit Service |
360c39 |
struct gfs2_inode *ip;
|
|
Packit Service |
360c39 |
int q;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
di = dirtree_find(sdp->md.rooti->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
if (di) {
|
|
Packit Service |
360c39 |
log_info( _("Marking root inode connected\n"));
|
|
Packit Service |
360c39 |
di->checked = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (sdp->gfs1) {
|
|
Packit Service |
360c39 |
di = dirtree_find(sdp->md.statfs->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
if (di) {
|
|
Packit Service |
360c39 |
log_info( _("Marking GFS1 statfs file inode "
|
|
Packit Service |
360c39 |
"connected\n"));
|
|
Packit Service |
360c39 |
di->checked = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
di = dirtree_find(sdp->md.jiinode->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
if (di) {
|
|
Packit Service |
360c39 |
log_info( _("Marking GFS1 jindex file inode "
|
|
Packit Service |
360c39 |
"connected\n"));
|
|
Packit Service |
360c39 |
di->checked = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
di = dirtree_find(sdp->md.riinode->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
if (di) {
|
|
Packit Service |
360c39 |
log_info( _("Marking GFS1 rindex file inode "
|
|
Packit Service |
360c39 |
"connected\n"));
|
|
Packit Service |
360c39 |
di->checked = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
di = dirtree_find(sdp->md.qinode->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
if (di) {
|
|
Packit Service |
360c39 |
log_info( _("Marking GFS1 quota file inode "
|
|
Packit Service |
360c39 |
"connected\n"));
|
|
Packit Service |
360c39 |
di->checked = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
di = dirtree_find(sdp->master_dir->i_di.di_num.no_addr);
|
|
Packit Service |
360c39 |
if (di) {
|
|
Packit Service |
360c39 |
log_info( _("Marking master directory inode "
|
|
Packit Service |
360c39 |
"connected\n"));
|
|
Packit Service |
360c39 |
di->checked = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* Go through the directory list, working up through the parents
|
|
Packit Service |
360c39 |
* until we find one that's been checked already. If we don't
|
|
Packit Service |
360c39 |
* find a parent, put in lost+found.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
log_info( _("Checking directory linkage.\n"));
|
|
Packit Service |
360c39 |
for (tmp = osi_first(&dirtree); tmp; tmp = next) {
|
|
Packit Service |
360c39 |
next = osi_next(tmp);
|
|
Packit Service |
360c39 |
di = (struct dir_info *)tmp;
|
|
Packit Service |
360c39 |
while (!di->checked) {
|
|
Packit Service |
360c39 |
/* FIXME: Change this so it returns success or
|
|
Packit Service |
360c39 |
* failure and put the parent inode in a
|
|
Packit Service |
360c39 |
* param */
|
|
Packit Service |
360c39 |
if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
|
|
Packit Service |
360c39 |
return FSCK_OK;
|
|
Packit Service |
360c39 |
tdi = mark_and_return_parent(sdp, di);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (tdi) {
|
|
Packit Service |
360c39 |
log_debug( _("Directory at block %llu "
|
|
Packit Service |
360c39 |
"(0x%llx) connected\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)di->dinode.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)di->dinode.no_addr);
|
|
Packit Service |
360c39 |
di = tdi;
|
|
Packit Service |
360c39 |
continue;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
q = bitmap_type(sdp, di->dinode.no_addr);
|
|
Packit Service |
360c39 |
ip = fsck_load_inode(sdp, di->dinode.no_addr);
|
|
Packit Service |
360c39 |
if (q == GFS2_BLKST_FREE) {
|
|
Packit Service |
360c39 |
log_err( _("Found unlinked directory "
|
|
Packit Service |
360c39 |
"containing bad block at block %llu"
|
|
Packit Service |
360c39 |
" (0x%llx)\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)di->dinode.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)di->dinode.no_addr);
|
|
Packit Service |
360c39 |
if (query(_("Clear unlinked directory "
|
|
Packit Service |
360c39 |
"with bad blocks? (y/n) "))) {
|
|
Packit Service |
360c39 |
log_warn( _("inode %lld (0x%llx) is "
|
|
Packit Service |
360c39 |
"now marked as free\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)
|
|
Packit Service |
360c39 |
di->dinode.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)
|
|
Packit Service |
360c39 |
di->dinode.no_addr);
|
|
Packit Service |
360c39 |
check_n_fix_bitmap(sdp, ip->i_rgd,
|
|
Packit Service |
360c39 |
di->dinode.no_addr,
|
|
Packit Service |
360c39 |
0, GFS2_BLKST_FREE);
|
|
Packit Service |
360c39 |
fsck_inode_put(&ip);
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
} else
|
|
Packit Service |
360c39 |
log_err( _("Unlinked directory with bad block remains\n"));
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (q != GFS2_BLKST_DINODE) {
|
|
Packit Service |
360c39 |
log_err( _("Unlinked block marked as an inode "
|
|
Packit Service |
360c39 |
"is not an inode\n"));
|
|
Packit Service |
360c39 |
if (!query(_("Clear the unlinked block?"
|
|
Packit Service |
360c39 |
" (y/n) "))) {
|
|
Packit Service |
360c39 |
log_err( _("The block was not "
|
|
Packit Service |
360c39 |
"cleared\n"));
|
|
Packit Service |
360c39 |
fsck_inode_put(&ip);
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
log_warn( _("inode %lld (0x%llx) is now "
|
|
Packit Service |
360c39 |
"marked as free\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)di->dinode.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)di->dinode.no_addr);
|
|
Packit Service |
360c39 |
check_n_fix_bitmap(sdp, ip->i_rgd,
|
|
Packit Service |
360c39 |
di->dinode.no_addr, 0,
|
|
Packit Service |
360c39 |
GFS2_BLKST_FREE);
|
|
Packit Service |
360c39 |
log_err( _("The block was cleared\n"));
|
|
Packit Service |
360c39 |
fsck_inode_put(&ip);
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
log_err( _("Found unlinked directory at block %llu"
|
|
Packit Service |
360c39 |
" (0x%llx)\n"),
|
|
Packit Service |
360c39 |
(unsigned long long)di->dinode.no_addr,
|
|
Packit Service |
360c39 |
(unsigned long long)di->dinode.no_addr);
|
|
Packit Service |
360c39 |
/* Don't skip zero size directories with eattrs */
|
|
Packit Service |
360c39 |
if (!ip->i_di.di_size && !ip->i_di.di_eattr){
|
|
Packit Service |
360c39 |
log_err( _("Unlinked directory has zero "
|
|
Packit Service |
360c39 |
"size.\n"));
|
|
Packit Service |
360c39 |
if (query( _("Remove zero-size unlinked "
|
|
Packit Service |
360c39 |
"directory? (y/n) "))) {
|
|
Packit Service |
360c39 |
fsck_bitmap_set(ip, di->dinode.no_addr,
|
|
Packit Service |
360c39 |
_("zero-sized unlinked inode"),
|
|
Packit Service |
360c39 |
GFS2_BLKST_FREE);
|
|
Packit Service |
360c39 |
fsck_inode_put(&ip);
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
log_err( _("Zero-size unlinked "
|
|
Packit Service |
360c39 |
"directory remains\n"));
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (query( _("Add unlinked directory to "
|
|
Packit Service |
360c39 |
"lost+found? (y/n) "))) {
|
|
Packit Service |
360c39 |
if (add_inode_to_lf(ip)) {
|
|
Packit Service |
360c39 |
fsck_inode_put(&ip);
|
|
Packit Service |
360c39 |
stack;
|
|
Packit Service |
360c39 |
return FSCK_ERROR;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
log_warn( _("Directory relinked to lost+found\n"));
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
log_err( _("Unlinked directory remains unlinked\n"));
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
fsck_inode_put(&ip);
|
|
Packit Service |
360c39 |
break;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (lf_dip) {
|
|
Packit Service |
360c39 |
log_debug( _("At end of pass3, lost+found entries is %u\n"),
|
|
Packit Service |
360c39 |
lf_dip->i_di.di_entries);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return FSCK_OK;
|
|
Packit Service |
360c39 |
}
|