From mboxrd@z Thu Jan 1 00:00:00 1970 From: Bob Peterson Date: Thu, 5 Sep 2013 11:25:36 -0400 (EDT) Subject: [Cluster-devel] [gfs2-utils PATCH] fsck.gfs2: Check and repair per_node contents such as quota_changeX In-Reply-To: <1437915058.9265143.1378394433338.JavaMail.root@redhat.com> Message-ID: <1543446674.9269193.1378394736712.JavaMail.root@redhat.com> List-Id: To: cluster-devel.redhat.com MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Hi, This patch gives fsck.gfs2 the ability to check the system files that are in the per_node directory: All the inum_rangeX, statfs_changeX and quota_changeX files. If they're found to be corrupt, they are deleted and rebuilt. Regards, Bob Peterson Red Hat File Systems Signed-off-by: Bob Peterson --- diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c index 727cc18..26f7d48 100644 --- a/gfs2/fsck/pass2.c +++ b/gfs2/fsck/pass2.c @@ -1595,6 +1595,116 @@ struct metawalk_fxns pass2_fxns = { .repair_leaf = pass2_repair_leaf, }; +static int check_metalist_qc(struct gfs2_inode *ip, uint64_t block, + struct gfs2_buffer_head **bh, int h, + int *is_valid, int *was_duplicate, void *private) +{ + *was_duplicate = 0; + *is_valid = 1; + *bh = bread(ip->i_sbd, block); + return meta_is_good; +} + +static int check_data_qc(struct gfs2_inode *ip, uint64_t metablock, + uint64_t block, void *private) +{ + struct gfs2_buffer_head *bh; + + /* At this point, basic data block checks have already been done, + so we only need to make sure they're QC blocks. */ + if (!valid_block(ip->i_sbd, block)) + return -1; + + bh = bread(ip->i_sbd, block); + if (gfs2_check_meta(bh, GFS2_METATYPE_QC) != 0) { + log_crit(_("Error: quota_change block at %lld (0x%llx) is " + "the wrong metadata type.\n"), + (unsigned long long)block, (unsigned long long)block); + brelse(bh); + return -1; + } + brelse(bh); + return 0; +} + +struct metawalk_fxns quota_change_fxns = { + .check_metalist = check_metalist_qc, + .check_data = check_data_qc, +}; + +/* check_pernode_for - verify a file within the system per_node directory + * @x - index number X + * @per_node - pointer to the per_node inode + * @fn - system file name + * @filelen - the file length the system file needs to be + * @multiple - the file length must be a multiple (versus the exact value) + * @pass - a metawalk function for checking the data blocks (if any) + * @builder - a rebuild function for the file + * + * Returns: 0 if all went well, else error. */ +static int check_pernode_for(int x, struct gfs2_inode *pernode, const char *fn, + unsigned long long filelen, int multiple, + struct metawalk_fxns *pass, + int builder(struct gfs2_inode *per_node, + unsigned int j)) +{ + struct gfs2_inode *ip; + int error, valid_size = 1; + + log_debug(_("Checking system file %s\n"), fn); + error = gfs2_lookupi(pernode, fn, strlen(fn), &ip); + if (error) { + log_err(_("System file %s is missing.\n"), fn); + if (!query( _("Rebuild the system file? (y/n) "))) + return 0; + goto build_it; + } + if (!ip->i_di.di_size) + valid_size = 0; + else if (!multiple && ip->i_di.di_size != filelen) + valid_size = 0; + else if (multiple && (ip->i_di.di_size % filelen)) + valid_size = 0; + if (!valid_size) { + log_err(_("System file %s has an invalid size. Is %llu, " + "should be %llu.\n"), fn, ip->i_di.di_size, filelen); + if (!query( _("Rebuild the system file? (y/n) "))) + goto out_good; + fsck_inode_put(&ip); + goto build_it; + } + if (pass) { + error = check_metatree(ip, pass); + if (!error) + goto out_good; + log_err(_("System file %s has bad contents.\n"), fn); + if (!query( _("Delete and rebuild the system file? (y/n) "))) + goto out_good; + check_metatree(ip, &pass2_fxns_delete); + fsck_inode_put(&ip); + gfs2_dirent_del(pernode, fn, strlen(fn)); + goto build_it; + } +out_good: + fsck_inode_put(&ip); + return 0; + +build_it: + if (builder(pernode, x)) { + log_err(_("Error building %s\n"), fn); + return -1; + } + error = gfs2_lookupi(pernode, fn, strlen(fn), &ip); + if (error) { + log_err(_("Error rebuilding %s.\n"), fn); + return -1; + } + fsck_blockmap_set(ip, ip->i_di.di_num.no_addr, fn, gfs2_inode_file); + reprocess_inode(ip, fn); + log_err(_("System file %s rebuilt.\n"), fn); + goto out_good; +} + /* Check system directory inode */ /* Should work for all system directories: root, master, jindex, per_node */ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname, @@ -1707,7 +1817,26 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname, sysinode->i_di.di_num.no_addr); } } - return 0; + error = 0; + if (sysinode == sysinode->i_sbd->md.pinode) { + int j; + char fn[64]; + + /* Make sure all the per_node files are there, and valid */ + for (j = 0; j < sysinode->i_sbd->md.journals; j++) { + sprintf(fn, "inum_range%d", j); + error += check_pernode_for(j, sysinode, fn, 16, 0, + NULL, build_inum_range); + sprintf(fn, "statfs_change%d", j); + error += check_pernode_for(j, sysinode, fn, 24, 0, + NULL, build_statfs_change); + sprintf(fn, "quota_change%d", j); + error += check_pernode_for(j, sysinode, fn, 1048576, 1, + "a_change_fxns, + build_quota_change); + } + } + return error; } /** diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h index 1548cf3..f864a08 100644 --- a/gfs2/libgfs2/libgfs2.h +++ b/gfs2/libgfs2/libgfs2.h @@ -770,6 +770,10 @@ extern int do_init_statfs(struct gfs2_sbd *sdp); extern int gfs2_check_meta(struct gfs2_buffer_head *bh, int type); extern unsigned lgfs2_bm_scan(struct rgrp_tree *rgd, unsigned idx, uint64_t *buf, uint8_t state); +extern int build_inum_range(struct gfs2_inode *per_node, unsigned int j); +extern int build_statfs_change(struct gfs2_inode *per_node, unsigned int j); +extern int build_quota_change(struct gfs2_inode *per_node, unsigned int j); + /* super.c */ extern int check_sb(struct gfs2_sb *sb); extern int read_sb(struct gfs2_sbd *sdp); diff --git a/gfs2/libgfs2/structures.c b/gfs2/libgfs2/structures.c index 2a8c6f7..e888f1e 100644 --- a/gfs2/libgfs2/structures.c +++ b/gfs2/libgfs2/structures.c @@ -180,7 +180,7 @@ int build_jindex(struct gfs2_sbd *sdp) return 0; } -static int build_inum_range(struct gfs2_inode *per_node, unsigned int j) +int build_inum_range(struct gfs2_inode *per_node, unsigned int j) { struct gfs2_sbd *sdp = per_node->i_sbd; char name[256]; @@ -204,7 +204,7 @@ static int build_inum_range(struct gfs2_inode *per_node, unsigned int j) return 0; } -static int build_statfs_change(struct gfs2_inode *per_node, unsigned int j) +int build_statfs_change(struct gfs2_inode *per_node, unsigned int j) { struct gfs2_sbd *sdp = per_node->i_sbd; char name[256]; @@ -228,7 +228,7 @@ static int build_statfs_change(struct gfs2_inode *per_node, unsigned int j) return 0; } -static int build_quota_change(struct gfs2_inode *per_node, unsigned int j) +int build_quota_change(struct gfs2_inode *per_node, unsigned int j) { struct gfs2_sbd *sdp = per_node->i_sbd; struct gfs2_meta_header mh; diff --git a/gfs2/libgfs2/super.c b/gfs2/libgfs2/super.c index eb97c40..f87734a 100644 --- a/gfs2/libgfs2/super.c +++ b/gfs2/libgfs2/super.c @@ -119,6 +119,7 @@ int read_sb(struct gfs2_sbd *sdp) sdp->sb_addr = GFS2_SB_ADDR * GFS2_BASIC_BLOCK / sdp->bsize; sdp->sd_blocks_per_bitmap = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header)) * GFS2_NBBY; + sdp->qcsize = GFS2_DEFAULT_QCSIZE; return 0; }