Blame gfs2/fsck/lost_n_found.c

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