|
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 |
|