Blame gfs2/fsck/link.c

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