Blame gfs2/fsck/link.c

Packit 6ef888
#include "clusterautoconfig.h"
Packit 6ef888
Packit 6ef888
#include <inttypes.h>
Packit 6ef888
#include <stdlib.h>
Packit 6ef888
#include <stdint.h>
Packit 6ef888
#include <string.h>
Packit 6ef888
#include <unistd.h>
Packit 6ef888
#include <libintl.h>
Packit 6ef888
#define _(String) gettext(String)
Packit 6ef888
Packit 6ef888
#include <logging.h>
Packit 6ef888
#include "libgfs2.h"
Packit 6ef888
#include "fsck.h"
Packit 6ef888
#include "inode_hash.h"
Packit 6ef888
#include "link.h"
Packit 6ef888
#include "util.h"
Packit 6ef888
Packit 6ef888
struct gfs2_bmap nlink1map = { 0 }; /* map of dinodes with nlink == 1 */
Packit 6ef888
struct gfs2_bmap clink1map = { 0 }; /* map of dinodes w/counted links == 1 */
Packit 6ef888
Packit 6ef888
int link1_set(struct gfs2_bmap *bmap, uint64_t bblock, int mark)
Packit 6ef888
{
Packit 6ef888
	static unsigned char *byte;
Packit 6ef888
	static uint64_t b;
Packit 6ef888
Packit 6ef888
	if (!bmap)
Packit 6ef888
		return 0;
Packit 6ef888
	if (bblock > bmap->size)
Packit 6ef888
		return -1;
Packit 6ef888
Packit 6ef888
	byte = bmap->map + BLOCKMAP_SIZE1(bblock);
Packit 6ef888
	b = BLOCKMAP_BYTE_OFFSET1(bblock);
Packit 6ef888
	*byte &= ~(BLOCKMAP_MASK1 << b);
Packit 6ef888
	*byte |= (mark & BLOCKMAP_MASK1) << b;
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
int set_di_nlink(struct gfs2_inode *ip)
Packit 6ef888
{
Packit 6ef888
	struct inode_info *ii;
Packit 6ef888
	struct dir_info *di;
Packit 6ef888
Packit 6ef888
	if (is_dir(&ip->i_di, ip->i_sbd->gfs1)) {
Packit 6ef888
		di = dirtree_find(ip->i_di.di_num.no_addr);
Packit 6ef888
		if (di == NULL) {
Packit 6ef888
			log_err(_("Error: directory %lld (0x%llx) is not "
Packit 6ef888
				  "in the dir_tree (set).\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
			return -1;
Packit 6ef888
		}
Packit 6ef888
		di->di_nlink = ip->i_di.di_nlink;
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
	if (ip->i_di.di_nlink == 1) {
Packit 6ef888
		link1_set(&nlink1map, ip->i_di.di_num.no_addr, 1);
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
	/*log_debug( _("Setting link count to %u for %" PRIu64
Packit 6ef888
	  " (0x%" PRIx64 ")\n"), count, inode_no, inode_no);*/
Packit 6ef888
	/* If the list has entries, look for one that matches inode_no */
Packit 6ef888
	ii = inodetree_find(ip->i_di.di_num.no_addr);
Packit 6ef888
	if (!ii)
Packit 6ef888
		ii = inodetree_insert(ip->i_di.di_num);
Packit 6ef888
	if (ii)
Packit 6ef888
		ii->di_nlink = ip->i_di.di_nlink;
Packit 6ef888
	else
Packit 6ef888
		return -1;
Packit 6ef888
	return 0;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
/* I'm making whyincr a macro rather than function so that the debug output
Packit 6ef888
 * matches older versions. */
Packit 6ef888
#define whyincr(no_addr, why, referenced_from, counted_links)		\
Packit 6ef888
	log_debug(_("Dir (0x%llx) incremented counted links to %u "	\
Packit 6ef888
		    "for (0x%llx) via %s\n"),				\
Packit 6ef888
		  (unsigned long long)referenced_from, counted_links,	\
Packit 6ef888
		  (unsigned long long)no_addr, why);
Packit 6ef888
Packit 6ef888
int incr_link_count(struct gfs2_inum no, struct gfs2_inode *ip,
Packit 6ef888
		    const char *why)
Packit 6ef888
{
Packit 6ef888
	struct inode_info *ii = NULL;
Packit 6ef888
	uint64_t referenced_from = ip ? ip->i_di.di_num.no_addr : 0;
Packit 6ef888
	struct dir_info *di;
Packit 6ef888
	struct gfs2_inode *link_ip;
Packit 6ef888
Packit 6ef888
	di = dirtree_find(no.no_addr);
Packit 6ef888
	if (di) {
Packit 6ef888
		if (di->dinode.no_formal_ino != no.no_formal_ino)
Packit 6ef888
			return incr_link_ino_mismatch;
Packit 6ef888
Packit 6ef888
		di->counted_links++;
Packit 6ef888
		whyincr(no.no_addr, why, referenced_from, di->counted_links);
Packit 6ef888
		return incr_link_good;
Packit 6ef888
	}
Packit 6ef888
	ii = inodetree_find(no.no_addr);
Packit 6ef888
	/* If the list has entries, look for one that matches inode_no */
Packit 6ef888
	if (ii) {
Packit 6ef888
		if (ii->di_num.no_formal_ino != no.no_formal_ino)
Packit 6ef888
			return incr_link_ino_mismatch;
Packit 6ef888
Packit 6ef888
		ii->counted_links++;
Packit 6ef888
		whyincr(no.no_addr, why, referenced_from, ii->counted_links);
Packit 6ef888
		return incr_link_good;
Packit 6ef888
	}
Packit 6ef888
	if (link1_type(&clink1map, no.no_addr) != 1) {
Packit 6ef888
		link1_set(&clink1map, no.no_addr, 1);
Packit 6ef888
		whyincr(no.no_addr, why, referenced_from, 1);
Packit 6ef888
		return incr_link_good;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	link_ip = fsck_load_inode(ip->i_sbd, no.no_addr);
Packit 6ef888
	/* Check formal ino against dinode before adding to inode tree. */
Packit 6ef888
	if (no.no_formal_ino != link_ip->i_di.di_num.no_formal_ino) {
Packit 6ef888
		fsck_inode_put(&link_ip);
Packit 6ef888
		return incr_link_ino_mismatch; /* inode mismatch */
Packit 6ef888
	}
Packit 6ef888
	/* Move it from the link1 maps to a real inode tree entry */
Packit 6ef888
	link1_set(&nlink1map, no.no_addr, 0);
Packit 6ef888
	link1_set(&clink1map, no.no_addr, 0);
Packit 6ef888
Packit 6ef888
	/* If no match was found, it must be a hard link. In theory, it can't
Packit 6ef888
	   be a duplicate because those were resolved in pass1b. Add a new
Packit 6ef888
	   inodetree entry and set its counted links to 2 */
Packit 6ef888
	ii = inodetree_insert(no);
Packit 6ef888
	if (!ii) {
Packit 6ef888
		log_debug( _("Ref: (0x%llx) Error incrementing link for "
Packit 6ef888
			     "(0x%llx)!\n"),
Packit 6ef888
			   (unsigned long long)referenced_from,
Packit 6ef888
			   (unsigned long long)no.no_addr);
Packit 6ef888
		fsck_inode_put(&link_ip);
Packit 6ef888
		return incr_link_bad;
Packit 6ef888
	}
Packit 6ef888
	ii->di_num = link_ip->i_di.di_num;
Packit 6ef888
	fsck_inode_put(&link_ip);
Packit 6ef888
	ii->di_nlink = 1; /* Must be 1 or it wouldn't have gotten into the
Packit 6ef888
			     nlink1map */
Packit 6ef888
	ii->counted_links = 2;
Packit 6ef888
	whyincr(no.no_addr, why, referenced_from, ii->counted_links);
Packit 6ef888
	/* We transitioned a dentry link count from 1 to 2, and we know it's
Packit 6ef888
	   not a directory. But the new reference has the correct formal
Packit 6ef888
	   inode number, so the first reference is suspect: we need to
Packit 6ef888
	   check it in case it's a bad reference, and not just a hard link. */
Packit 6ef888
	return incr_link_check_orig;
Packit 6ef888
}
Packit 6ef888
Packit 6ef888
#define whydecr(no_addr, why, referenced_from, counted_links)		\
Packit 6ef888
	log_debug(_("Dir (0x%llx) decremented counted links to %u "	\
Packit 6ef888
		    "for (0x%llx) via %s\n"),				\
Packit 6ef888
		  (unsigned long long)referenced_from, counted_links,	\
Packit 6ef888
		  (unsigned long long)no_addr, why);
Packit 6ef888
Packit 6ef888
int decr_link_count(uint64_t inode_no, uint64_t referenced_from, int gfs1,
Packit 6ef888
		    const char *why)
Packit 6ef888
{
Packit 6ef888
	struct inode_info *ii = NULL;
Packit 6ef888
	struct dir_info *di;
Packit 6ef888
Packit 6ef888
	di = dirtree_find(inode_no);
Packit 6ef888
	if (di) {
Packit 6ef888
		if (!di->counted_links) {
Packit 6ef888
			log_debug( _("Dir (0x%llx)'s link to "
Packit 6ef888
				     "(0x%llx) via %s is zero!\n"),
Packit 6ef888
				   (unsigned long long)referenced_from,
Packit 6ef888
				   (unsigned long long)inode_no, why);
Packit 6ef888
			return 0;
Packit 6ef888
		}
Packit 6ef888
		di->counted_links--;
Packit 6ef888
		whydecr(inode_no, why, referenced_from, di->counted_links);
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	ii = inodetree_find(inode_no);
Packit 6ef888
	/* If the list has entries, look for one that matches
Packit 6ef888
	 * inode_no */
Packit 6ef888
	if (ii) {
Packit 6ef888
		if (!ii->counted_links) {
Packit 6ef888
			log_debug( _("Dir (0x%llx)'s link to "
Packit 6ef888
			     "(0x%llx) via %s is zero!\n"),
Packit 6ef888
			   (unsigned long long)referenced_from,
Packit 6ef888
			   (unsigned long long)inode_no, why);
Packit 6ef888
			return 0;
Packit 6ef888
		}
Packit 6ef888
		ii->counted_links--;
Packit 6ef888
		whydecr(inode_no, why, referenced_from, ii->counted_links);
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
	if (link1_type(&clink1map, inode_no) == 1) { /* 1 -> 0 */
Packit 6ef888
		link1_set(&clink1map, inode_no, 0);
Packit 6ef888
		whydecr(inode_no, why, referenced_from, 0);
Packit 6ef888
		return 0;
Packit 6ef888
	}
Packit 6ef888
Packit 6ef888
	log_debug( _("No match found when decrementing link for (0x%llx)!\n"),
Packit 6ef888
		   (unsigned long long)inode_no);
Packit 6ef888
	return -1;
Packit 6ef888
Packit 6ef888
}
Packit 6ef888
Packit 6ef888