Blame gfs2/fsck/lost_n_found.c

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
}