|
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/types.h>
|
|
Packit Service |
360c39 |
#include <sys/stat.h>
|
|
Packit Service |
360c39 |
#include <unistd.h>
|
|
Packit Service |
360c39 |
#include <libintl.h>
|
|
Packit Service |
360c39 |
#include <ctype.h>
|
|
Packit Service |
360c39 |
#include <fcntl.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 "afterpass1_common.h"
|
|
Packit Service |
360c39 |
#include "metawalk.h"
|
|
Packit Service |
360c39 |
#include "util.h"
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* find_remove_dup - find out if this is a duplicate ref. If so, remove it.
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Returns: 1 if there are any remaining references to this block, else 0.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int find_remove_dup(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
const char *btype, int *removed_last_meta)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct duptree *dt;
|
|
Packit Service |
360c39 |
struct inode_with_dups *id;
|
|
Packit Service |
360c39 |
int deleted_a_meta_ref = 0;
|
|
Packit Service |
360c39 |
int meta_refs_left = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
dt = dupfind(block);
|
|
Packit Service |
360c39 |
if (!dt)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/* remove the inode reference id structure for this reference. */
|
|
Packit Service |
360c39 |
id = find_dup_ref_inode(dt, ip);
|
|
Packit Service |
360c39 |
if (!id)
|
|
Packit Service |
360c39 |
goto more_refs;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (id->reftypecount[ref_as_meta])
|
|
Packit Service |
360c39 |
deleted_a_meta_ref = 1;
|
|
Packit Service |
360c39 |
dup_listent_delete(dt, id);
|
|
Packit Service |
360c39 |
if (dt->refs == 0) {
|
|
Packit Service |
360c39 |
log_info( _("This was the last reference: it's no longer a "
|
|
Packit Service |
360c39 |
"duplicate.\n"));
|
|
Packit Service |
360c39 |
dup_delete(dt); /* not duplicate now */
|
|
Packit Service |
360c39 |
if (deleted_a_meta_ref) {
|
|
Packit Service |
360c39 |
log_debug("Removed the last reference as metadata.\n");
|
|
Packit Service |
360c39 |
*removed_last_meta = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
} else if (deleted_a_meta_ref) {
|
|
Packit Service |
360c39 |
/* If we deleted a metadata reference, see if there are more
|
|
Packit Service |
360c39 |
references as meta, or if it was the last one. */
|
|
Packit Service |
360c39 |
meta_refs_left = count_dup_meta_refs(dt);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
more_refs:
|
|
Packit Service |
360c39 |
log_info(_("%d block reference(s) remain (%d as metadata).\n"),
|
|
Packit Service |
360c39 |
dt->refs, meta_refs_left);
|
|
Packit Service |
360c39 |
if (deleted_a_meta_ref && meta_refs_left == 0) {
|
|
Packit Service |
360c39 |
log_debug("Removed the last reference as metadata.\n");
|
|
Packit Service |
360c39 |
*removed_last_meta = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return 1; /* references still exist so do not free the block. */
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
/**
|
|
Packit Service |
360c39 |
* delete_block_if_notdup - delete blocks associated with an inode
|
|
Packit Service |
360c39 |
*
|
|
Packit Service |
360c39 |
* Ignore blocks that are already marked free.
|
|
Packit Service |
360c39 |
* If it has been identified as duplicate, remove the duplicate reference.
|
|
Packit Service |
360c39 |
* If all duplicate references have been removed, delete the block.
|
|
Packit Service |
360c39 |
*/
|
|
Packit Service |
360c39 |
static int delete_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh,
|
|
Packit Service |
360c39 |
const char *btype, int *was_duplicate,
|
|
Packit Service |
360c39 |
void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int q;
|
|
Packit Service |
360c39 |
int removed_lastmeta = 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!valid_block_ip(ip, block))
|
|
Packit Service |
360c39 |
return meta_error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
q = bitmap_type(ip->i_sbd, block);
|
|
Packit Service |
360c39 |
if (q == GFS2_BLKST_FREE) {
|
|
Packit Service |
360c39 |
log_info( _("%s block %lld (0x%llx), part of inode "
|
|
Packit Service |
360c39 |
"%lld (0x%llx), was already free.\n"),
|
|
Packit Service |
360c39 |
btype, (unsigned long long)block,
|
|
Packit Service |
360c39 |
(unsigned long long)block,
|
|
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 meta_is_good;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
if (find_remove_dup(ip, block, btype, &removed_lastmeta)) { /* a dup */
|
|
Packit Service |
360c39 |
if (was_duplicate) {
|
|
Packit Service |
360c39 |
if (removed_lastmeta)
|
|
Packit Service |
360c39 |
log_debug("Removed last reference as meta.\n");
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
*was_duplicate = 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
log_err( _("Not clearing duplicate reference in inode "
|
|
Packit Service |
360c39 |
"at block #%llu (0x%llx) to block #%llu (0x%llx) "
|
|
Packit Service |
360c39 |
"because it's referenced by another inode.\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 |
(unsigned long long)block, (unsigned long long)block);
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
check_n_fix_bitmap(ip->i_sbd, ip->i_rgd, block, 0,
|
|
Packit Service |
360c39 |
GFS2_BLKST_FREE);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return meta_is_good;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int remove_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
|
|
Packit Service |
360c39 |
struct gfs2_dirent *prev_de,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *bh,
|
|
Packit Service |
360c39 |
char *filename, uint32_t *count, int *lindex,
|
|
Packit Service |
360c39 |
void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
/* the metawalk_fxn's private field must be set to the dentry
|
|
Packit Service |
360c39 |
* block we want to clear */
|
|
Packit Service |
360c39 |
uint64_t *dentryblock = (uint64_t *) private;
|
|
Packit Service |
360c39 |
struct gfs2_dirent dentry, *de;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
memset(&dentry, 0, sizeof(struct gfs2_dirent));
|
|
Packit Service |
360c39 |
gfs2_dirent_in(&dentry, (char *)dent);
|
|
Packit Service |
360c39 |
de = &dentry;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (de->de_inum.no_addr == *dentryblock)
|
|
Packit Service |
360c39 |
dirent2_del(ip, bh, prev_de, dent);
|
|
Packit Service |
360c39 |
else
|
|
Packit Service |
360c39 |
(*count)++;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int remove_dentry_from_dir(struct gfs2_sbd *sdp, uint64_t dir,
|
|
Packit Service |
360c39 |
uint64_t dentryblock)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct metawalk_fxns remove_dentry_fxns = {0};
|
|
Packit Service |
360c39 |
struct gfs2_inode *ip;
|
|
Packit Service |
360c39 |
int q;
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
log_debug( _("Removing dentry %llu (0x%llx) from directory %llu"
|
|
Packit Service |
360c39 |
" (0x%llx)\n"), (unsigned long long)dentryblock,
|
|
Packit Service |
360c39 |
(unsigned long long)dentryblock,
|
|
Packit Service |
360c39 |
(unsigned long long)dir, (unsigned long long)dir);
|
|
Packit Service |
360c39 |
if (!valid_block(sdp, dir)) {
|
|
Packit Service |
360c39 |
log_err( _("Parent directory is invalid\n"));
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
remove_dentry_fxns.private = &dentryblock;
|
|
Packit Service |
360c39 |
remove_dentry_fxns.check_dentry = remove_dentry;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
q = bitmap_type(sdp, dir);
|
|
Packit Service |
360c39 |
if (q != GFS2_BLKST_DINODE) {
|
|
Packit Service |
360c39 |
log_info( _("Parent block is not an inode...ignoring\n"));
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
ip = fsck_load_inode(sdp, dir);
|
|
Packit Service |
360c39 |
if (ip == NULL) {
|
|
Packit Service |
360c39 |
stack;
|
|
Packit Service |
360c39 |
return -1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* Need to run check_dir with a private var of dentryblock,
|
|
Packit Service |
360c39 |
* and fxns that remove that dentry if found */
|
|
Packit Service |
360c39 |
error = check_dir(sdp, ip, &remove_dentry_fxns);
|
|
Packit Service |
360c39 |
fsck_inode_put(&ip);
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int delete_metadata(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh, int h, int *is_valid,
|
|
Packit Service |
360c39 |
int *was_duplicate, void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
*is_valid = 1;
|
|
Packit Service |
360c39 |
*was_duplicate = 0;
|
|
Packit Service |
360c39 |
return delete_block_if_notdup(ip, block, bh, _("metadata"),
|
|
Packit Service |
360c39 |
was_duplicate, private);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int delete_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return delete_block_if_notdup(ip, block, NULL, _("leaf"), NULL,
|
|
Packit Service |
360c39 |
private);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int delete_data(struct gfs2_inode *ip, uint64_t metablock,
|
|
Packit Service |
360c39 |
uint64_t block, void *private, struct gfs2_buffer_head *bh,
|
|
Packit Service |
360c39 |
uint64_t *ptr)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return delete_block_if_notdup(ip, block, NULL, _("data"), NULL,
|
|
Packit Service |
360c39 |
private);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
static int del_eattr_generic(struct gfs2_inode *ip, uint64_t block,
|
|
Packit Service |
360c39 |
uint64_t parent, struct gfs2_buffer_head **bh,
|
|
Packit Service |
360c39 |
void *private, const char *eatype)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
int ret = 0;
|
|
Packit Service |
360c39 |
int was_free = 0;
|
|
Packit Service |
360c39 |
int q;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (valid_block_ip(ip, block)) {
|
|
Packit Service |
360c39 |
q = bitmap_type(ip->i_sbd, block);
|
|
Packit Service |
360c39 |
if (q == GFS2_BLKST_FREE)
|
|
Packit Service |
360c39 |
was_free = 1;
|
|
Packit Service |
360c39 |
ret = delete_block_if_notdup(ip, block, NULL, eatype,
|
|
Packit Service |
360c39 |
NULL, private);
|
|
Packit Service |
360c39 |
if (!ret) {
|
|
Packit Service |
360c39 |
*bh = bread(ip->i_sbd, block);
|
|
Packit Service |
360c39 |
if (!was_free)
|
|
Packit Service |
360c39 |
ip->i_di.di_blocks--;
|
|
Packit Service |
360c39 |
bmodified(ip->i_bh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
/* Even if it's a duplicate reference, we want to eliminate the
|
|
Packit Service |
360c39 |
reference itself, and adjust di_blocks accordingly. */
|
|
Packit Service |
360c39 |
if (ip->i_di.di_eattr) {
|
|
Packit Service |
360c39 |
if (block == ip->i_di.di_eattr)
|
|
Packit Service |
360c39 |
ip->i_di.di_eattr = 0;
|
|
Packit Service |
360c39 |
bmodified(ip->i_bh);
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return ret;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int delete_eattr_indir(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh, void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return del_eattr_generic(ip, block, parent, bh, private,
|
|
Packit Service |
360c39 |
_("extended attribute"));
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int delete_eattr_leaf(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head **bh, void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
return del_eattr_generic(ip, block, parent, bh, private,
|
|
Packit Service |
360c39 |
_("indirect extended attribute"));
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int delete_eattr_entry(struct gfs2_inode *ip, struct gfs2_buffer_head *leaf_bh,
|
|
Packit Service |
360c39 |
struct gfs2_ea_header *ea_hdr,
|
|
Packit Service |
360c39 |
struct gfs2_ea_header *ea_hdr_prev, void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
struct gfs2_sbd *sdp = ip->i_sbd;
|
|
Packit Service |
360c39 |
char ea_name[256];
|
|
Packit Service |
360c39 |
uint32_t avail_size;
|
|
Packit Service |
360c39 |
int max_ptrs;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!ea_hdr->ea_name_len){
|
|
Packit Service |
360c39 |
/* Skip this entry for now */
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
memset(ea_name, 0, sizeof(ea_name));
|
|
Packit Service |
360c39 |
strncpy(ea_name, (char *)ea_hdr + sizeof(struct gfs2_ea_header),
|
|
Packit Service |
360c39 |
ea_hdr->ea_name_len);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!GFS2_EATYPE_VALID(ea_hdr->ea_type) &&
|
|
Packit Service |
360c39 |
((ea_hdr_prev) || (!ea_hdr_prev && ea_hdr->ea_type))){
|
|
Packit Service |
360c39 |
/* Skip invalid entry */
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (!ea_hdr->ea_num_ptrs)
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
avail_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header);
|
|
Packit Service |
360c39 |
max_ptrs = (be32_to_cpu(ea_hdr->ea_data_len) + avail_size - 1) /
|
|
Packit Service |
360c39 |
avail_size;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
if (max_ptrs > ea_hdr->ea_num_ptrs)
|
|
Packit Service |
360c39 |
return 1;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
log_debug( _(" Pointers Required: %d\n Pointers Reported: %d\n"),
|
|
Packit Service |
360c39 |
max_ptrs, ea_hdr->ea_num_ptrs);
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
return 0;
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
int delete_eattr_extentry(struct gfs2_inode *ip, int i, uint64_t *ea_data_ptr,
|
|
Packit Service |
360c39 |
struct gfs2_buffer_head *leaf_bh, uint32_t tot_ealen,
|
|
Packit Service |
360c39 |
struct gfs2_ea_header *ea_hdr,
|
|
Packit Service |
360c39 |
struct gfs2_ea_header *ea_hdr_prev, void *private)
|
|
Packit Service |
360c39 |
{
|
|
Packit Service |
360c39 |
uint64_t block = be64_to_cpu(*ea_data_ptr);
|
|
Packit Service |
360c39 |
int error;
|
|
Packit Service |
360c39 |
|
|
Packit Service |
360c39 |
error = delete_block_if_notdup(ip, block, NULL,
|
|
Packit Service |
360c39 |
_("extended attribute"), NULL, private);
|
|
Packit Service |
360c39 |
if (error) {
|
|
Packit Service |
360c39 |
log_err(_("Bad extended attribute found at block %lld "
|
|
Packit Service |
360c39 |
"(0x%llx)"),
|
|
Packit Service |
360c39 |
(unsigned long long)be64_to_cpu(*ea_data_ptr),
|
|
Packit Service |
360c39 |
(unsigned long long)be64_to_cpu(*ea_data_ptr));
|
|
Packit Service |
360c39 |
if (query( _("Repair the bad Extended Attribute? (y/n) "))) {
|
|
Packit Service |
360c39 |
ea_hdr->ea_num_ptrs = i;
|
|
Packit Service |
360c39 |
ea_hdr->ea_data_len = cpu_to_be32(tot_ealen);
|
|
Packit Service |
360c39 |
*ea_data_ptr = 0;
|
|
Packit Service |
360c39 |
bmodified(leaf_bh);
|
|
Packit Service |
360c39 |
/* Endianness doesn't matter in this case because it's
|
|
Packit Service |
360c39 |
a single byte. */
|
|
Packit Service |
360c39 |
fsck_bitmap_set(ip, ip->i_di.di_eattr,
|
|
Packit Service |
360c39 |
_("extended attribute"),
|
|
Packit Service |
360c39 |
ip->i_sbd->gfs1 ? GFS2_BLKST_DINODE :
|
|
Packit Service |
360c39 |
GFS2_BLKST_USED);
|
|
Packit Service |
360c39 |
log_err( _("The EA was fixed.\n"));
|
|
Packit Service |
360c39 |
} else {
|
|
Packit Service |
360c39 |
error = 1;
|
|
Packit Service |
360c39 |
log_err( _("The bad EA was not fixed.\n"));
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
}
|
|
Packit Service |
360c39 |
return error;
|
|
Packit Service |
360c39 |
}
|