|
Packit |
6ef888 |
#include "clusterautoconfig.h"
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
#include <inttypes.h>
|
|
Packit |
6ef888 |
#include <stdio.h>
|
|
Packit |
6ef888 |
#include <stdlib.h>
|
|
Packit |
6ef888 |
#include <string.h>
|
|
Packit |
6ef888 |
#include <sys/stat.h>
|
|
Packit |
6ef888 |
#include <unistd.h>
|
|
Packit |
6ef888 |
#include <dirent.h>
|
|
Packit |
6ef888 |
#include <libintl.h>
|
|
Packit |
6ef888 |
#define _(String) gettext(String)
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
#include <logging.h>
|
|
Packit |
6ef888 |
#include "fsck.h"
|
|
Packit |
6ef888 |
#include "libgfs2.h"
|
|
Packit |
6ef888 |
#include "lost_n_found.h"
|
|
Packit |
6ef888 |
#include "link.h"
|
|
Packit |
6ef888 |
#include "metawalk.h"
|
|
Packit |
6ef888 |
#include "util.h"
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
static void add_dotdot(struct gfs2_inode *ip)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct dir_info *di;
|
|
Packit |
6ef888 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit |
6ef888 |
int err;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
log_info( _("Adding .. entry to directory %llu (0x%llx) pointing back "
|
|
Packit |
6ef888 |
"to lost+found\n"),
|
|
Packit |
6ef888 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit |
6ef888 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* If there's a pre-existing .. directory entry, we have to
|
|
Packit |
6ef888 |
back out the links. */
|
|
Packit |
6ef888 |
di = dirtree_find(ip->i_di.di_num.no_addr);
|
|
Packit |
6ef888 |
if (di && valid_block(sdp, di->dotdot_parent.no_addr)) {
|
|
Packit |
6ef888 |
struct gfs2_inode *dip;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
log_debug(_("Directory (0x%llx) already had a "
|
|
Packit |
6ef888 |
"\"..\" link to (0x%llx).\n"),
|
|
Packit |
6ef888 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit |
6ef888 |
(unsigned long long)di->dotdot_parent.no_addr);
|
|
Packit |
6ef888 |
dip = fsck_load_inode(sdp, di->dotdot_parent.no_addr);
|
|
Packit |
6ef888 |
if (dip->i_di.di_num.no_formal_ino ==
|
|
Packit |
6ef888 |
di->dotdot_parent.no_formal_ino) {
|
|
Packit |
6ef888 |
decr_link_count(di->dotdot_parent.no_addr,
|
|
Packit |
6ef888 |
ip->i_di.di_num.no_addr, sdp->gfs1,
|
|
Packit |
6ef888 |
_(".. unlinked, moving to lost+found"));
|
|
Packit |
6ef888 |
if (dip->i_di.di_nlink > 0) {
|
|
Packit |
6ef888 |
dip->i_di.di_nlink--;
|
|
Packit |
6ef888 |
set_di_nlink(dip); /* keep inode tree in sync */
|
|
Packit |
6ef888 |
log_debug(_("Decrementing its links to %d\n"),
|
|
Packit |
6ef888 |
dip->i_di.di_nlink);
|
|
Packit |
6ef888 |
bmodified(dip->i_bh);
|
|
Packit |
6ef888 |
} else if (!dip->i_di.di_nlink) {
|
|
Packit |
6ef888 |
log_debug(_("Its link count is zero.\n"));
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
log_debug(_("Its link count is %d! Changing "
|
|
Packit |
6ef888 |
"it to 0.\n"), dip->i_di.di_nlink);
|
|
Packit |
6ef888 |
dip->i_di.di_nlink = 0;
|
|
Packit |
6ef888 |
set_di_nlink(dip); /* keep inode tree in sync */
|
|
Packit |
6ef888 |
bmodified(dip->i_bh);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
log_debug(_("Directory (0x%llx)'s link to parent "
|
|
Packit |
6ef888 |
"(0x%llx) had a formal inode discrepancy: "
|
|
Packit |
6ef888 |
"was 0x%llx, expected 0x%llx\n"),
|
|
Packit |
6ef888 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit |
6ef888 |
(unsigned long long)di->dotdot_parent.no_addr,
|
|
Packit |
6ef888 |
di->dotdot_parent.no_formal_ino,
|
|
Packit |
6ef888 |
dip->i_di.di_num.no_formal_ino);
|
|
Packit |
6ef888 |
log_debug(_("The parent directory was not changed.\n"));
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
fsck_inode_put(&dip;;
|
|
Packit |
6ef888 |
di = NULL;
|
|
Packit |
6ef888 |
} else {
|
|
Packit |
6ef888 |
if (di)
|
|
Packit |
6ef888 |
log_debug(_("Couldn't find a valid \"..\" entry "
|
|
Packit |
6ef888 |
"for orphan directory (0x%llx): "
|
|
Packit |
6ef888 |
"'..' = 0x%llx\n"),
|
|
Packit |
6ef888 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit |
6ef888 |
(unsigned long long)di->dotdot_parent.no_addr);
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
log_debug(_("Couldn't find directory (0x%llx) "
|
|
Packit |
6ef888 |
"in directory tree.\n"),
|
|
Packit |
6ef888 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
if (gfs2_dirent_del(ip, "..", 2))
|
|
Packit |
6ef888 |
log_warn( _("add_inode_to_lf: Unable to remove "
|
|
Packit |
6ef888 |
"\"..\" directory entry.\n"));
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
err = dir_add(ip, "..", 2, &(lf_dip->i_di.di_num),
|
|
Packit |
6ef888 |
(sdp->gfs1 ? GFS_FILE_DIR : DT_DIR));
|
|
Packit |
6ef888 |
if (err) {
|
|
Packit |
6ef888 |
log_crit(_("Error adding .. directory: %s\n"),
|
|
Packit |
6ef888 |
strerror(errno));
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
void make_sure_lf_exists(struct gfs2_inode *ip)
|
|
Packit |
6ef888 |
{
|
|
Packit |
6ef888 |
struct dir_info *di;
|
|
Packit |
6ef888 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit |
6ef888 |
uint32_t mode;
|
|
Packit |
6ef888 |
int root_entries;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (lf_dip)
|
|
Packit |
6ef888 |
return;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
root_entries = sdp->md.rooti->i_di.di_entries;
|
|
Packit |
6ef888 |
log_info( _("Locating/Creating lost+found directory\n"));
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* if this is gfs1, we have to trick createi into using
|
|
Packit |
6ef888 |
no_formal_ino = no_addr, so we set next_inum to the
|
|
Packit |
6ef888 |
free block we're about to allocate. */
|
|
Packit |
6ef888 |
if (sdp->gfs1)
|
|
Packit |
6ef888 |
sdp->md.next_inum = find_free_blk(sdp);
|
|
Packit |
6ef888 |
mode = (sdp->gfs1 ? DT2IF(GFS_FILE_DIR) : S_IFDIR) | 0700;
|
|
Packit |
6ef888 |
if (sdp->gfs1)
|
|
Packit |
6ef888 |
lf_dip = gfs_createi(sdp->md.rooti, "lost+found", mode, 0);
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
lf_dip = createi(sdp->md.rooti, "lost+found",
|
|
Packit |
6ef888 |
S_IFDIR | 0700, 0);
|
|
Packit |
6ef888 |
if (lf_dip == NULL) {
|
|
Packit |
6ef888 |
log_crit(_("Error creating lost+found: %s\n"),
|
|
Packit |
6ef888 |
strerror(errno));
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* createi will have incremented the di_nlink link count for the root
|
|
Packit |
6ef888 |
directory. We must set the nlink value in the hash table to keep
|
|
Packit |
6ef888 |
them in sync so that pass4 can detect and fix any descrepancies. */
|
|
Packit |
6ef888 |
set_di_nlink(sdp->md.rooti);
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (sdp->md.rooti->i_di.di_entries > root_entries) {
|
|
Packit |
6ef888 |
lf_was_created = 1;
|
|
Packit |
6ef888 |
/* This is a new lost+found directory, so set its block type
|
|
Packit |
6ef888 |
and increment link counts for the directories */
|
|
Packit |
6ef888 |
/* FIXME: i'd feel better about this if fs_mkdir returned
|
|
Packit |
6ef888 |
whether it created a new directory or just found an old one,
|
|
Packit |
6ef888 |
and we used that instead of the bitmap_type to run this */
|
|
Packit |
6ef888 |
dirtree_insert(lf_dip->i_di.di_num);
|
|
Packit |
6ef888 |
/* Set the bitmap AFTER the dirtree insert so that function
|
|
Packit |
6ef888 |
check_n_fix_bitmap will realize it's a dinode and adjust
|
|
Packit |
6ef888 |
the rgrp counts properly. */
|
|
Packit |
6ef888 |
fsck_bitmap_set(ip, lf_dip->i_di.di_num.no_addr,
|
|
Packit |
6ef888 |
_("lost+found dinode"), GFS2_BLKST_DINODE);
|
|
Packit |
6ef888 |
/* root inode links to lost+found */
|
|
Packit |
6ef888 |
incr_link_count(sdp->md.rooti->i_di.di_num, lf_dip, _("root"));
|
|
Packit |
6ef888 |
/* lost+found link for '.' from itself */
|
|
Packit |
6ef888 |
incr_link_count(lf_dip->i_di.di_num, lf_dip, "\".\"");
|
|
Packit |
6ef888 |
/* lost+found link for '..' back to root */
|
|
Packit |
6ef888 |
incr_link_count(lf_dip->i_di.di_num, sdp->md.rooti, "\"..\"");
|
|
Packit |
6ef888 |
if (sdp->gfs1)
|
|
Packit |
6ef888 |
lf_dip->i_di.__pad1 = GFS_FILE_DIR;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
log_info( _("lost+found directory is dinode %lld (0x%llx)\n"),
|
|
Packit |
6ef888 |
(unsigned long long)lf_dip->i_di.di_num.no_addr,
|
|
Packit |
6ef888 |
(unsigned long long)lf_dip->i_di.di_num.no_addr);
|
|
Packit |
6ef888 |
di = dirtree_find(lf_dip->i_di.di_num.no_addr);
|
|
Packit |
6ef888 |
if (di) {
|
|
Packit |
6ef888 |
log_info( _("Marking lost+found inode connected\n"));
|
|
Packit |
6ef888 |
di->checked = 1;
|
|
Packit |
6ef888 |
di = NULL;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* add_inode_to_lf - Add dir entry to lost+found for the inode
|
|
Packit |
6ef888 |
* @ip: inode to add to lost + found
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* This function adds an entry into the lost and found dir
|
|
Packit |
6ef888 |
* for the given inode. The name of the entry will be
|
|
Packit |
6ef888 |
* "lost_<ip->i_num.no_addr>".
|
|
Packit |
6ef888 |
*
|
|
Packit |
6ef888 |
* Returns: 0 on success, -1 on failure.
|
|
Packit |
6ef888 |
*/
|
|
Packit |
6ef888 |
int add_inode_to_lf(struct gfs2_inode *ip){
|
|
Packit |
6ef888 |
char tmp_name[256];
|
|
Packit |
6ef888 |
__be32 inode_type;
|
|
Packit |
6ef888 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit |
6ef888 |
int err = 0;
|
|
Packit |
6ef888 |
uint32_t mode;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
make_sure_lf_exists(ip);
|
|
Packit |
6ef888 |
if (ip->i_di.di_num.no_addr == lf_dip->i_di.di_num.no_addr) {
|
|
Packit |
6ef888 |
log_err( _("Trying to add lost+found to itself...skipping"));
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
if (sdp->gfs1)
|
|
Packit |
6ef888 |
mode = gfs_to_gfs2_mode(ip);
|
|
Packit |
6ef888 |
else
|
|
Packit |
6ef888 |
mode = ip->i_di.di_mode & S_IFMT;
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
switch (mode) {
|
|
Packit |
6ef888 |
case S_IFDIR:
|
|
Packit |
6ef888 |
add_dotdot(ip);
|
|
Packit |
6ef888 |
sprintf(tmp_name, "lost_dir_%llu",
|
|
Packit |
6ef888 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit |
6ef888 |
inode_type = (sdp->gfs1 ? GFS_FILE_DIR : DT_DIR);
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
case S_IFREG:
|
|
Packit |
6ef888 |
sprintf(tmp_name, "lost_file_%llu",
|
|
Packit |
6ef888 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit |
6ef888 |
inode_type = (sdp->gfs1 ? GFS_FILE_REG : DT_REG);
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
case S_IFLNK:
|
|
Packit |
6ef888 |
sprintf(tmp_name, "lost_link_%llu",
|
|
Packit |
6ef888 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit |
6ef888 |
inode_type = (sdp->gfs1 ? GFS_FILE_LNK : DT_LNK);
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
case S_IFBLK:
|
|
Packit |
6ef888 |
sprintf(tmp_name, "lost_blkdev_%llu",
|
|
Packit |
6ef888 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit |
6ef888 |
inode_type = (sdp->gfs1 ? GFS_FILE_BLK : DT_BLK);
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
case S_IFCHR:
|
|
Packit |
6ef888 |
sprintf(tmp_name, "lost_chrdev_%llu",
|
|
Packit |
6ef888 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit |
6ef888 |
inode_type = (sdp->gfs1 ? GFS_FILE_CHR : DT_CHR);
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
case S_IFIFO:
|
|
Packit |
6ef888 |
sprintf(tmp_name, "lost_fifo_%llu",
|
|
Packit |
6ef888 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit |
6ef888 |
inode_type = (sdp->gfs1 ? GFS_FILE_FIFO : DT_FIFO);
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
case S_IFSOCK:
|
|
Packit |
6ef888 |
sprintf(tmp_name, "lost_socket_%llu",
|
|
Packit |
6ef888 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit |
6ef888 |
inode_type = (sdp->gfs1 ? GFS_FILE_SOCK : DT_SOCK);
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
default:
|
|
Packit |
6ef888 |
sprintf(tmp_name, "lost_%llu",
|
|
Packit |
6ef888 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit |
6ef888 |
inode_type = (sdp->gfs1 ? GFS_FILE_REG : DT_REG);
|
|
Packit |
6ef888 |
break;
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
err = dir_add(lf_dip, tmp_name, strlen(tmp_name), &(ip->i_di.di_num),
|
|
Packit |
6ef888 |
inode_type);
|
|
Packit |
6ef888 |
if (err) {
|
|
Packit |
6ef888 |
log_crit(_("Error adding directory %s: %s\n"),
|
|
Packit |
6ef888 |
tmp_name, strerror(errno));
|
|
Packit |
6ef888 |
exit(FSCK_ERROR);
|
|
Packit |
6ef888 |
}
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
/* This inode is linked from lost+found */
|
|
Packit |
6ef888 |
incr_link_count(ip->i_di.di_num, lf_dip, _("from lost+found"));
|
|
Packit |
6ef888 |
/* If it's a directory, lost+found is back-linked to it via .. */
|
|
Packit |
6ef888 |
if (mode == S_IFDIR)
|
|
Packit |
6ef888 |
incr_link_count(lf_dip->i_di.di_num, ip, _("to lost+found"));
|
|
Packit |
6ef888 |
|
|
Packit |
6ef888 |
log_notice( _("Added inode #%llu (0x%llx) to lost+found\n"),
|
|
Packit |
6ef888 |
(unsigned long long)ip->i_di.di_num.no_addr,
|
|
Packit |
6ef888 |
(unsigned long long)ip->i_di.di_num.no_addr);
|
|
Packit |
6ef888 |
gfs2_dinode_out(&lf_dip->i_di, lf_dip->i_bh->b_data);
|
|
Packit |
6ef888 |
bwrite(lf_dip->i_bh);
|
|
Packit |
6ef888 |
return 0;
|
|
Packit |
6ef888 |
}
|