This is the mail archive of the
cluster-cvs@sourceware.org
mailing list for the cluster.
cluster: RHEL5 - GFS2: gfs2_edit fixes for 5.4
- From: Bob Peterson <rpeterso at fedoraproject dot org>
- To: cluster-cvs-relay at redhat dot com
- Date: Tue, 17 Feb 2009 18:18:52 +0000 (UTC)
- Subject: cluster: RHEL5 - GFS2: gfs2_edit fixes for 5.4
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=ae88c56fccf59bf2e4fd7efc8505ffc552d534f7
Commit: ae88c56fccf59bf2e4fd7efc8505ffc552d534f7
Parent: 8722e7de933138606b4e65a325e4884e95ff5ae5
Author: Bob Peterson <rpeterso@redhat.com>
AuthorDate: Tue Feb 17 11:54:50 2009 -0600
Committer: Bob Peterson <rpeterso@redhat.com>
CommitterDate: Tue Feb 17 11:54:50 2009 -0600
GFS2: gfs2_edit fixes for 5.4
bz 483799
1. The ability for gfs2_edit to report on whether a given block is
free, allocated data, or allocated metadata or unlinked metadata.
This works on the interactive screen as well as -p blockalloc
Values printed are: 0 (free), 1 (data), 2 (unlinked), 3 (meta).
2. The ability for gfs2_edit to report on the metadata block type.
Use: -p <block> blocktype
Valid block types are: 0 (clump), 1 (superblock),
2 (Resource Group Header), 3 (Resource Group Bitmap),
4 (Dinode), 5 (Indirect Block), 6 (Directory Leaf),
7 (Journaled Data), 8 (Log Header), 9 (Log descriptor),
10 (Ext. attrib), 11 (Eattr Data), 12 (Log Buffer), 13 (invalid),
14 (Quota Change).
3. The ability for gfs2_edit to print out specific fields from
a structure, such as an inode or rg. -p <block> field <fieldname>
4. The ability for gfs2_edit to edit the file system through the
command line, like: -p <block> field <fieldname> <newval>
5. The ability to search for blocks of a given metadata type, which
is useful for digging through journals looking for evidence of
something that's gone wrong. In command-line mode, use:
-p <block> find <sb|rg|rb|di|in|lf|jd|lh|ld|ea|ed|lb|13|qc>
In interactive mode, change the block number to "/sb", "/rg", etc.
6. The ability to edit fields in structure mode. Right now, only
dinode and rg structures are editable. Others are ignored.
7. Fixed a bug whereby -p size went on to print other things.
8. The ability for gfs2_edit to print or change the metadata
block type through the cli. Use: -p <block> blocktype [newtype]
9. The ability for gfs2_edit to locate which RG or bitmap block
a certain block is associated with. (i.e. locate the RG that's
prior to the specified block). For RG use: -p <block> blockrg
For bitmaps use: -p <block> blockbits
---
gfs2/edit/gfs2hex.c | 75 ++--
gfs2/edit/hexedit.c | 1071 +++++++++++++++++++++++++++++++++++++++---------
gfs2/edit/hexedit.h | 12 +-
gfs2/fsck/fs_bits.h | 5 -
gfs2/libgfs2/fs_bits.c | 105 +-----
gfs2/man/gfs2_edit.8 | 120 +++++-
6 files changed, 1030 insertions(+), 358 deletions(-)
diff --git a/gfs2/edit/gfs2hex.c b/gfs2/edit/gfs2hex.c
index 8b18708..7538b81 100644
--- a/gfs2/edit/gfs2hex.c
+++ b/gfs2/edit/gfs2hex.c
@@ -41,12 +41,31 @@ extern struct gfs2_dinode di;
extern int line, termlines;
extern char edit_fmt[80];
extern char estring[1024];
+extern char efield[64];
extern int edit_mode INIT(0);
extern int edit_row[DMODES], edit_col[DMODES];
extern int edit_size[DMODES], last_entry_onscreen[DMODES];
extern char edit_fmt[80];
extern enum dsp_mode dmode INIT(HEX_MODE); /* display mode */
+const char *block_type_str[15] = {
+ "Clump",
+ "Superblock",
+ "Resource Group Header",
+ "Resource Group Bitmap",
+ "Dinode",
+ "Indirect Block",
+ "Leaf",
+ "Journaled Data",
+ "Log Header",
+ "Log descriptor",
+ "Ext. attrib",
+ "Eattr Data",
+ "Log Buffer",
+ "Metatype 13",
+ "Quota Change",
+};
+
void eol(int col) /* end of line */
{
if (termlines) {
@@ -166,6 +185,7 @@ void print_it(const char *label, const char *fmt, const char *fmt2, ...)
if (termlines) {
refresh();
if (line == (edit_row[dmode] * lines_per_row[dmode]) + 4) {
+ strcpy(efield, label + 2); /* it's indented */
strcpy(estring, tmp_string);
strcpy(edit_fmt, fmt);
edit_size[dmode] = strlen(estring);
@@ -487,57 +507,46 @@ int display_gfs2(void)
{
case GFS2_MAGIC:
gfs2_meta_header_in(&mh, buf);
+ if (mh.mh_type > GFS2_METATYPE_QC)
+ print_gfs2("Unknown metadata type");
+ else
+ print_gfs2("%s:", block_type_str[mh.mh_type]);
+ eol(0);
switch (mh.mh_type)
{
case GFS2_METATYPE_SB:
- print_gfs2("Superblock:");
- eol(0);
gfs2_sb_in(&sbd.sd_sb, buf);
gfs2_sb_print2(&sbd.sd_sb);
break;
-
+
case GFS2_METATYPE_RG:
- print_gfs2("Resource Group Header:");
- eol(0);
gfs2_rgrp_in(&rg, buf);
gfs2_rgrp_print(&rg);
break;
-
+
case GFS2_METATYPE_RB:
- print_gfs2("Resource Group Bitmap:");
- eol(0);
gfs2_meta_header_print(&mh);
break;
-
+
case GFS2_METATYPE_DI:
- print_gfs2("Dinode:");
- eol(0);
gfs2_dinode_print(&di);
break;
-
+
+ case GFS2_METATYPE_IN:
+ gfs2_meta_header_print(&mh);
+ break;
+
case GFS2_METATYPE_LF:
- print_gfs2("Leaf:");
- eol(0);
gfs2_leaf_in(&lf, buf);
gfs2_leaf_print(&lf);
break;
-
- case GFS2_METATYPE_IN:
- print_gfs2("Indirect Block:");
- eol(0);
- gfs2_meta_header_print(&mh);
- break;
-
+
case GFS2_METATYPE_JD:
- print_gfs2("Journaled File Block:");
- eol(0);
gfs2_meta_header_print(&mh);
break;
-
+
case GFS2_METATYPE_LH:
- print_gfs2("Log Header:");
- eol(0);
if (gfs1) {
gfs_log_header_in(&lh1, buf);
gfs_log_header_print(&lh1);
@@ -546,42 +555,30 @@ int display_gfs2(void)
gfs2_log_header_print(&lh);
}
break;
-
+
case GFS2_METATYPE_LD:
- print_gfs2("Log descriptor");
- eol(0);
gfs2_log_descriptor_in(&ld, buf);
gfs2_log_descriptor_print(&ld);
break;
case GFS2_METATYPE_EA:
- print_gfs2("Eattr Block:");
- eol(0);
do_eattr_extended(buf);
break;
case GFS2_METATYPE_ED:
- print_gfs2("Eattr Data Block:");
- eol(0);
gfs2_meta_header_print(&mh);
break;
case GFS2_METATYPE_LB:
- print_gfs2("Log Buffer");
- eol(0);
gfs2_meta_header_print(&mh);
break;
case GFS2_METATYPE_QC:
- print_gfs2("Quota Change");
- eol(0);
gfs2_quota_change_in(&qc, buf);
gfs2_quota_change_print(&qc);
break;
default:
- print_gfs2("Unknown metadata type");
- eol(0);
break;
}
break;
diff --git a/gfs2/edit/hexedit.c b/gfs2/edit/hexedit.c
index f62c705..2da61ce 100644
--- a/gfs2/edit/hexedit.c
+++ b/gfs2/edit/hexedit.c
@@ -44,6 +44,11 @@
#define RGLIST_DUMMY_BLOCK -2
+const char *mtypes[] = {"none", "sb", "rg", "rb", "di", "in", "lf", "jd",
+ "lh", "ld", "ea", "ed", "lb", "13", "qc"};
+const char *allocdesc[] = {"Free ", "Data ", "Unlnk",
+ "Meta ", "Resrv"};
+
int display(int identify_only);
extern void eol(int col);
extern void do_leaf_extended(char *buf, struct iinfo *indir);
@@ -52,6 +57,113 @@ extern void savemeta(const char *out_fn, int slow);
extern void restoremeta(const char *in_fn, const char *out_device,
int printblocksonly);
+/* for assigning numeric fields: */
+#define checkassign(strfield, struct, member, value) do { \
+ if (strcmp(#member, strfield) == 0) { \
+ struct->member = (typeof(struct->member)) value; \
+ return 0; \
+ } \
+ } while(0)
+
+/* for assigning string fields: */
+#define checkassigns(strfield, struct, member, val) do { \
+ if (strcmp(#member, strfield) == 0) { \
+ memcpy(struct->member, val, sizeof(struct->member)); \
+ return 0; \
+ } \
+ } while(0)
+
+/* for printing numeric fields: */
+#define checkprint(strfield, struct, member) do { \
+ if (strcmp(#member, strfield) == 0) { \
+ if (dmode == HEX_MODE) \
+ printf("0x%llx\n", \
+ (unsigned long long)struct->member); \
+ else \
+ printf("%llu\n", \
+ (unsigned long long)struct->member); \
+ return 0; \
+ } \
+ } while(0)
+
+/* for printing string fields: */
+#define checkprints(strfield, struct, member) do { \
+ if (strcmp(#member, strfield) == 0) { \
+ printf("%s\n", struct->member); \
+ return 0; \
+ } \
+ } while(0)
+
+int gfs2_dinode_printval(struct gfs2_dinode *di, const char *strfield)
+{
+ checkprint(strfield, di, di_mode);
+ checkprint(strfield, di, di_uid);
+ checkprint(strfield, di, di_gid);
+ checkprint(strfield, di, di_nlink);
+ checkprint(strfield, di, di_size);
+ checkprint(strfield, di, di_blocks);
+ checkprint(strfield, di, di_atime);
+ checkprint(strfield, di, di_mtime);
+ checkprint(strfield, di, di_ctime);
+ checkprint(strfield, di, di_major);
+ checkprint(strfield, di, di_minor);
+ checkprint(strfield, di, di_goal_meta);
+ checkprint(strfield, di, di_goal_data);
+ checkprint(strfield, di, di_flags);
+ checkprint(strfield, di, di_payload_format);
+ checkprint(strfield, di, di_height);
+ checkprint(strfield, di, di_depth);
+ checkprint(strfield, di, di_entries);
+ checkprint(strfield, di, di_eattr);
+
+ return -1;
+}
+
+int gfs2_dinode_assignval(struct gfs2_dinode *di, const char *strfield,
+ uint64_t value)
+{
+ checkassign(strfield, di, di_mode, value);
+ checkassign(strfield, di, di_uid, value);
+ checkassign(strfield, di, di_gid, value);
+ checkassign(strfield, di, di_nlink, value);
+ checkassign(strfield, di, di_size, value);
+ checkassign(strfield, di, di_blocks, value);
+ checkassign(strfield, di, di_atime, value);
+ checkassign(strfield, di, di_mtime, value);
+ checkassign(strfield, di, di_ctime, value);
+ checkassign(strfield, di, di_major, value);
+ checkassign(strfield, di, di_minor, value);
+ checkassign(strfield, di, di_goal_meta, value);
+ checkassign(strfield, di, di_goal_data, value);
+ checkassign(strfield, di, di_flags, value);
+ checkassign(strfield, di, di_payload_format, value);
+ checkassign(strfield, di, di_height, value);
+ checkassign(strfield, di, di_depth, value);
+ checkassign(strfield, di, di_entries, value);
+ checkassign(strfield, di, di_eattr, value);
+
+ return -1;
+}
+
+int gfs2_rgrp_printval(struct gfs2_rgrp *rg, const char *strfield)
+{
+ checkprint(strfield, rg, rg_flags);
+ checkprint(strfield, rg, rg_free);
+ checkprint(strfield, rg, rg_dinodes);
+
+ return -1;
+}
+
+int gfs2_rgrp_assignval(struct gfs2_rgrp *rg, const char *strfield,
+ uint64_t value)
+{
+ checkassign(strfield, rg, rg_flags, value);
+ checkassign(strfield, rg, rg_free, value);
+ checkassign(strfield, rg, rg_dinodes, value);
+
+ return -1;
+}
+
/* ------------------------------------------------------------------------ */
/* UpdateSize - screen size changed, so update it */
/* ------------------------------------------------------------------------ */
@@ -348,6 +460,67 @@ int get_block_type(const char *lpBuffer)
return ret_type;
}
+/*
+ * fs_get_bitmap - get value of FS bitmap
+ * @sdp: super block
+ * @blkno: block number relative to file system
+ *
+ * This function gets the value of a bit of the
+ * file system bitmap.
+ * Possible state values for a block in the bitmap are:
+ * GFS_BLKST_FREE (0)
+ * GFS_BLKST_USED (1)
+ * GFS_BLKST_INVALID (2)
+ * GFS_BLKST_DINODE (3)
+ *
+ * Returns: state on success, -1 on error
+ */
+int gfs2_get_bitmap(struct gfs2_sbd *sdp, uint64_t blkno,
+ struct rgrp_list *rgd)
+{
+ int buf, val;
+ uint32_t rgrp_block;
+ struct gfs2_bitmap *bits = NULL;
+ unsigned int bit;
+ unsigned char *byte;
+ int local_rgd = 0;
+
+ if(gfs2_check_range(sdp, blkno))
+ return -1;
+ if(rgd == NULL) {
+ local_rgd = 1;
+ rgd = gfs2_blk2rgrpd(sdp, blkno);
+ }
+ if(rgd == NULL)
+ return -1;
+ if(gfs2_rgrp_read(sdp, rgd))
+ return -1;
+
+ rgrp_block = (uint32_t)(blkno - rgd->ri.ri_data0);
+
+ for(buf= 0; buf < rgd->ri.ri_length; buf++){
+ bits = &(rgd->bits[buf]);
+ if(rgrp_block < ((bits->bi_start + bits->bi_len)*GFS2_NBBY)){
+ break;
+ }
+ }
+
+ if(buf >= rgd->ri.ri_length){
+ gfs2_rgrp_relse(rgd, not_updated);
+ return -1;
+ }
+
+ byte = (unsigned char *)(rgd->bh[buf]->b_data + bits->bi_offset) +
+ (rgrp_block/GFS2_NBBY - bits->bi_start);
+ bit = (rgrp_block % GFS2_NBBY) * GFS2_BIT_SIZE;
+
+ val = ((*byte >> bit) & GFS2_BIT_MASK);
+ if(local_rgd)
+ gfs2_rgrp_relse(rgd, not_updated);
+
+ return val;
+}
+
/* ------------------------------------------------------------------------ */
/* display_block_type */
/* returns: metatype if block is a GFS2 structure block type */
@@ -465,32 +638,41 @@ int display_block_type(const char *lpBuffer, int from_restore)
if (from_restore)
return ret_type;
if (termlines && dmode == HEX_MODE) {
- /* calculate how much of the buffer we can fit on screen */
+ int type;
+ struct rgrp_list *rgd;
+
+ rgd = gfs2_blk2rgrpd(&sbd, block);
+ if (rgd) {
+ type = gfs2_get_bitmap(&sbd, block, rgd);
+ gfs2_rgrp_relse(rgd, not_updated);
+ } else
+ type = 4;
screen_chunk_size = ((termlines - 4) * 16) >> 8 << 8;
if (!screen_chunk_size)
screen_chunk_size = 256;
- print_gfs2("(p.%d of %d)", (offset / screen_chunk_size) + 1,
- (sbd.bsize % screen_chunk_size) > 0 ?
- sbd.bsize / screen_chunk_size + 1 : sbd.bsize /
- screen_chunk_size);
+ print_gfs2("(p.%d of %d--%s)",
+ (offset / screen_chunk_size) + 1,
+ (sbd.bsize % screen_chunk_size) > 0 ?
+ sbd.bsize / screen_chunk_size + 1 : sbd.bsize /
+ screen_chunk_size, allocdesc[type]);
/*eol(9);*/
}
if (block == sbd.sd_sb.sb_root_dir.no_addr)
- print_gfs2("-------------------- Root directory ------------------");
+ print_gfs2("--------------- Root directory ------------------");
else if (!gfs1 && block == sbd.sd_sb.sb_master_dir.no_addr)
- print_gfs2("------------------- Master directory -----------------");
+ print_gfs2("-------------- Master directory -----------------");
else if (!gfs1 && block == RGLIST_DUMMY_BLOCK)
- print_gfs2("----------------------- RG List ----------------------");
+ print_gfs2("------------------ RG List ----------------------");
else {
if (gfs1) {
if (block == sbd1->sb_rindex_di.no_addr)
- print_gfs2("--------------------- rindex file -------------------");
+ print_gfs2("---------------- rindex file -------------------");
else if (block == gfs1_quota_di.no_addr)
- print_gfs2("--------------------- Quota file --------------------");
+ print_gfs2("---------------- Quota file --------------------");
else if (block == sbd1->sb_jindex_di.no_addr)
- print_gfs2("-------------------- Journal Index ------------------");
+ print_gfs2("--------------- Journal Index ------------------");
else if (block == gfs1_license_di.no_addr)
- print_gfs2("-------------------- License file -------------------");
+ print_gfs2("--------------- License file -------------------");
}
else {
int d;
@@ -498,17 +680,17 @@ int display_block_type(const char *lpBuffer, int from_restore)
for (d = 2; d < 8; d++) {
if (block == masterdir.dirent[d].block) {
if (!strncmp(masterdir.dirent[d].filename, "jindex", 6))
- print_gfs2("-------------------- Journal Index ------------------");
+ print_gfs2("--------------- Journal Index ------------------");
else if (!strncmp(masterdir.dirent[d].filename, "per_node", 8))
- print_gfs2("-------------------- Per-node Dir -------------------");
+ print_gfs2("--------------- Per-node Dir -------------------");
else if (!strncmp(masterdir.dirent[d].filename, "inum", 4))
- print_gfs2("--------------------- Inum file ---------------------");
+ print_gfs2("---------------- Inum file ---------------------");
else if (!strncmp(masterdir.dirent[d].filename, "statfs", 6))
- print_gfs2("--------------------- statfs file -------------------");
+ print_gfs2("---------------- statfs file -------------------");
else if (!strncmp(masterdir.dirent[d].filename, "rindex", 6))
- print_gfs2("--------------------- rindex file -------------------");
+ print_gfs2("---------------- rindex file -------------------");
else if (!strncmp(masterdir.dirent[d].filename, "quota", 5))
- print_gfs2("--------------------- Quota file --------------------");
+ print_gfs2("---------------- Quota file --------------------");
}
}
}
@@ -634,19 +816,10 @@ static int risize(void)
/* ------------------------------------------------------------------------ */
void rgcount(void)
{
- uint64_t block;
- struct gfs2_buffer_head *ribh;
- struct gfs2_inode *riinode;
-
- if (gfs1)
- block = sbd1->sb_rindex_di.no_addr;
- else
- block = masterblock("rindex");
- ribh = bread(&sbd.buf_list, block);
- riinode = inode_get(&sbd, ribh);
printf("%lld RGs in this file system.\n",
- (unsigned long long)riinode->i_di.di_size / risize());
- inode_put(riinode, not_updated);
+ (unsigned long long)sbd.md.riinode->i_di.di_size / risize());
+ inode_put(sbd.md.riinode, not_updated);
+ gfs2_rgrp_free(&sbd.rglist, not_updated);
exit(EXIT_SUCCESS);
}
@@ -899,7 +1072,7 @@ void gfs_jindex_in(struct gfs_jindex *jindex, char *buf)
/* ------------------------------------------------------------------------ */
void gfs_jindex_print(struct gfs_jindex *ji)
{
- pv(ji, ji_addr, "%llu", "0x%llx");
+ pv((unsigned long long)ji, ji_addr, "%llu", "0x%llx");
pv(ji, ji_nsegment, "%u", "0x%x");
pv(ji, ji_pad, "%u", "0x%x");
}
@@ -932,6 +1105,7 @@ int print_jindex(struct gfs2_inode *di)
lines_per_row[dmode] <= termlines - start_line - 2)) {
if (edit_row[dmode] == print_entry_ndx) {
COLORS_HIGHLIGHT;
+ strcpy(efield, "ji_addr");
sprintf(estring, "%" PRIx64, ji.ji_addr);
}
print_gfs2("Journal #%d", print_entry_ndx);
@@ -952,8 +1126,15 @@ int print_jindex(struct gfs2_inode *di)
int print_inum(struct gfs2_inode *di)
{
uint64_t buf, inodenum;
+ int rc;
- if (gfs2_readi(di, (void *)&buf, 0, sizeof(buf)) != sizeof(buf)) {
+ rc = gfs2_readi(di, (void *)&buf, 0, sizeof(buf));
+ if (!rc) {
+ print_gfs2("The inum file is empty.");
+ eol(0);
+ return 0;
+ }
+ if (rc != sizeof(buf)) {
print_gfs2("Error reading inum file.");
eol(0);
return -1;
@@ -970,8 +1151,15 @@ int print_inum(struct gfs2_inode *di)
int print_statfs(struct gfs2_inode *di)
{
struct gfs2_statfs_change buf, sfc;
+ int rc;
- if (gfs2_readi(di, (void *)&buf, 0, sizeof(buf)) != sizeof(buf)) {
+ rc = gfs2_readi(di, (void *)&buf, 0, sizeof(buf));
+ if (!rc) {
+ print_gfs2("The statfs file is empty.");
+ eol(0);
+ return 0;
+ }
+ if (rc != sizeof(buf)) {
print_gfs2("Error reading statfs file.");
eol(0);
return -1;
@@ -1086,9 +1274,8 @@ int display_leaf(struct iinfo *ind)
eol(5);
if (termlines) {
if (edit_row[dmode] >=0 &&
- line - start_line - 1 ==
- edit_row[dmode] -
- start_row[dmode]) {
+ line - start_line - 1 ==
+ edit_row[dmode] - start_row[dmode]) {
COLORS_HIGHLIGHT;
sprintf(estring, "%"PRIx64,
ind->ii[0].dirent[d].block);
@@ -1262,10 +1449,20 @@ int display_indirect(struct iinfo *ind, int indblocks, int level, uint64_t start
more_indir = malloc(sizeof(struct iinfo));
tmpbuf = malloc(sbd.bsize);
if (tmpbuf) {
- do_lseek(sbd.device_fd,
- ind->ii[pndx].block * sbd.bsize);
- do_read(sbd.device_fd, tmpbuf,
- sbd.bsize); /* read in the desired block */
+ lseek(sbd.device_fd,
+ ind->ii[pndx].block * sbd.bsize,
+ SEEK_SET);
+ /* read in the desired block */
+ if (read(sbd.device_fd, tmpbuf, sbd.bsize) !=
+ sbd.bsize) {
+ fprintf(stderr, "bad read: %s from %s:"
+ "%d: block %lld (0x%llx)\n",
+ strerror(errno),
+ __FUNCTION__, __LINE__,
+ (unsigned long long)ind->ii[pndx].block,
+ (unsigned long long)ind->ii[pndx].block);
+ exit(-1);
+ }
memset(more_indir, 0, sizeof(struct iinfo));
if (S_ISDIR(di.di_mode)) {
do_leaf_extended(tmpbuf, more_indir);
@@ -1342,6 +1539,8 @@ int block_is_inum_file(void)
/* ------------------------------------------------------------------------ */
int block_is_statfs_file(void)
{
+ if (gfs1 && block == gfs1_license_di.no_addr)
+ return TRUE;
if (!gfs1 && block == masterblock("statfs"))
return TRUE;
return FALSE;
@@ -1352,8 +1551,9 @@ int block_is_statfs_file(void)
/* ------------------------------------------------------------------------ */
int block_is_quota_file(void)
{
- if ((gfs1 && block == gfs1_quota_di.no_addr) ||
- (block == masterblock("quota")))
+ if (gfs1 && block == gfs1_quota_di.no_addr)
+ return TRUE;
+ if (!gfs1 && block == masterblock("quota"))
return TRUE;
return FALSE;
}
@@ -1436,10 +1636,16 @@ int display_extended(void)
/* ------------------------------------------------------------------------ */
void read_superblock(int fd)
{
+ int count;
+
sbd1 = (struct gfs_sb *)&sbd.sd_sb;
ioctl(fd, BLKFLSBUF, 0);
- do_lseek(fd, 0x10 * 4096);
- do_read(fd, buf, sbd.bsize); /* read in the desired block */
+ lseek(fd, 0x10 * 4096, SEEK_SET);
+ if (read(fd, buf, sbd.bsize) != sbd.bsize) {
+ fprintf(stderr, "bad read: %s from %s:%d: superblock\n",
+ strerror(errno), __FUNCTION__, __LINE__);
+ exit(-1);
+ }
memset(&sbd, 0, sizeof(struct gfs2_sbd));
sbd.device_fd = fd;
sbd.bsize = GFS2_DEFAULT_BSIZE;
@@ -1472,6 +1678,27 @@ void read_superblock(int fd)
sbd.bsize = GFS2_DEFAULT_BSIZE;
compute_constants(&sbd);
block = 0x10 * (GFS2_DEFAULT_BSIZE / sbd.bsize);
+ device_geometry(&sbd);
+ fix_device_geometry(&sbd);
+ if(gfs1) {
+ sbd.sd_inptrs = (sbd.bsize - sizeof(struct gfs_indirect)) /
+ sizeof(uint64_t);
+ sbd.sd_diptrs = (sbd.bsize - sizeof(struct gfs_dinode)) /
+ sizeof(uint64_t);
+ sbd.md.riinode = gfs2_load_inode(&sbd,
+ sbd1->sb_rindex_di.no_addr);
+ } else {
+ sbd.sd_inptrs = (sbd.bsize - sizeof(struct gfs2_meta_header)) /
+ sizeof(uint64_t);
+ sbd.sd_diptrs = (sbd.bsize - sizeof(struct gfs2_dinode)) /
+ sizeof(uint64_t);
+ sbd.master_dir = gfs2_load_inode(&sbd,
+ sbd.sd_sb.sb_master_dir.no_addr);
+ gfs2_lookupi(sbd.master_dir, "rindex", 6, &sbd.md.riinode);
+ }
+
+ sbd.fssize = sbd.device.length;
+ ri_update(&sbd, 0, &count);
}
/* ------------------------------------------------------------------------ */
@@ -1480,8 +1707,17 @@ void read_superblock(int fd)
void read_master_dir(void)
{
ioctl(sbd.device_fd, BLKFLSBUF, 0);
- do_lseek(sbd.device_fd, sbd.sd_sb.sb_master_dir.no_addr * sbd.bsize);
- do_read(sbd.device_fd, buf, sbd.bsize); /* read in the desired block */
+ lseek(sbd.device_fd, sbd.sd_sb.sb_master_dir.no_addr * sbd.bsize,
+ SEEK_SET);
+ if (read(sbd.device_fd, buf, sbd.bsize) != sbd.bsize) {
+ fprintf(stderr, "read error: %s from %s:%d: "
+ "master dir block %lld (0x%llx)\n",
+ strerror(errno), __FUNCTION__,
+ __LINE__,
+ (unsigned long long)sbd.sd_sb.sb_master_dir.no_addr,
+ (unsigned long long)sbd.sd_sb.sb_master_dir.no_addr);
+ exit(-1);
+ }
gfs2_dinode_in(&di, buf); /* parse disk inode into structure */
do_dinode_extended(&di, buf); /* get extended data, if any */
memcpy(&masterdir, &indirect[0], sizeof(struct indirect_info));
@@ -1508,8 +1744,16 @@ int display(int identify_only)
if (block_in_mem != blk) { /* If we changed blocks from the last read */
dev_offset = blk * sbd.bsize;
ioctl(sbd.device_fd, BLKFLSBUF, 0);
- do_lseek(sbd.device_fd, dev_offset);
- do_read(sbd.device_fd, buf, sbd.bsize); /* read desired block */
+ lseek(sbd.device_fd, dev_offset, SEEK_SET);
+ if (read(sbd.device_fd, buf, sbd.bsize) != sbd.bsize) {
+ fprintf(stderr, "read error: %s from %s:%d: "
+ "offset %lld (0x%llx)\n",
+ strerror(errno), __FUNCTION__,
+ __LINE__,
+ (unsigned long long)dev_offset,
+ (unsigned long long)dev_offset);
+ exit(-1);
+ }
block_in_mem = blk; /* remember which block is in memory */
}
line = 1;
@@ -1679,6 +1923,145 @@ uint64_t find_journal_block(const char *journal, uint64_t *j_size)
}
/* ------------------------------------------------------------------------ */
+/* Find next metadata block of a given type AFTER a given point in the fs */
+/* */
+/* This is used to find blocks that aren't represented in the bitmaps, such */
+/* as the RGs and bitmaps or the superblock. */
+/* ------------------------------------------------------------------------ */
+uint64_t find_metablockoftype_slow(uint64_t startblk, int metatype, int print)
+{
+ uint64_t blk, last_fs_block;
+ int found = 0;
+ struct gfs2_buffer_head *bh;
+
+ last_fs_block = lseek(sbd.device_fd, 0, SEEK_END) / sbd.bsize;
+ for (blk = startblk + 1; blk < last_fs_block; blk++) {
+ bh = bread(&sbd.buf_list, blk);
+ /* Can't use get_block_type here (returns false "none") */
+ if (bh->b_data[0] == 0x01 && bh->b_data[1] == 0x16 &&
+ bh->b_data[2] == 0x19 && bh->b_data[3] == 0x70 &&
+ bh->b_data[4] == 0x00 && bh->b_data[5] == 0x00 &&
+ bh->b_data[6] == 0x00 && bh->b_data[7] == metatype) {
+ found = 1;
+ brelse(bh, not_updated);
+ break;
+ }
+ brelse(bh, not_updated);
+ }
+ if (!found)
+ blk = 0;
+ if (print) {
+ if (dmode == HEX_MODE)
+ printf("0x%llx\n", (unsigned long long)blk);
+ else
+ printf("%llu\n", (unsigned long long)blk);
+ }
+ gfs2_rgrp_free(&sbd.rglist, not_updated);
+ if (print)
+ exit(0);
+ return blk;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Find next "metadata in use" block AFTER a given point in the fs */
+/* */
+/* This version does its magic by searching the bitmaps of the RG. After */
+/* all, if we're searching for a dinode, we want a real allocated inode, */
+/* not just some block that used to be an inode in a previous incarnation. */
+/* ------------------------------------------------------------------------ */
+uint64_t find_metablockoftype_rg(uint64_t startblk, int metatype, int print)
+{
+ uint64_t blk;
+ int first = 1, found = 0;
+ struct rgrp_list *rgd;
+ struct gfs2_rindex *ri;
+ osi_list_t *tmp;
+
+ blk = 0;
+ /* Skip the rgs prior to the block we've been given */
+ for(tmp = sbd.rglist.next; tmp != &sbd.rglist; tmp = tmp->next){
+ rgd = osi_list_entry(tmp, struct rgrp_list, list);
+ ri = &rgd->ri;
+ if (first && startblk <= ri->ri_data0) {
+ startblk = ri->ri_data0;
+ break;
+ } else if (ri->ri_addr <= startblk &&
+ startblk < ri->ri_data0 + ri->ri_data)
+ break;
+ else
+ rgd = NULL;
+ first = 0;
+ }
+ if (!rgd) {
+ if (print)
+ printf("0\n");
+ gfs2_rgrp_free(&sbd.rglist, not_updated);
+ if (print)
+ exit(-1);
+ }
+ for(; !found && tmp != &sbd.rglist; tmp = tmp->next){
+ rgd = osi_list_entry(tmp, struct rgrp_list, list);
+ first = 1;
+ do {
+ if (gfs2_next_rg_metatype(&sbd, rgd, &blk, metatype,
+ first))
+ break;
+ if (blk > startblk) {
+ found = 1;
+ break;
+ }
+ first = 0;
+ } while (blk <= startblk);
+ }
+ if (!found)
+ blk = 0;
+ if (print) {
+ if (dmode == HEX_MODE)
+ printf("0x%llx\n", (unsigned long long)blk);
+ else
+ printf("%llu\n", (unsigned long long)blk);
+ }
+ gfs2_rgrp_free(&sbd.rglist, not_updated);
+ if (print)
+ exit(0);
+ return blk;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Find next metadata block AFTER a given point in the fs */
+/* ------------------------------------------------------------------------ */
+uint64_t find_metablockoftype(const char *strtype, int print)
+{
+ int mtype = 0;
+ uint64_t startblk, blk = 0;
+
+ if (print)
+ startblk = blockstack[blockhist % BLOCK_STACK_SIZE].block;
+ else
+ startblk = block;
+
+ for (mtype = GFS2_METATYPE_NONE;
+ mtype <= GFS2_METATYPE_QC; mtype++)
+ if (!strcasecmp(strtype, mtypes[mtype]))
+ break;
+ if (!strcmp(strtype, "dinode"))
+ mtype = GFS2_METATYPE_DI;
+ if (mtype >= GFS2_METATYPE_NONE && mtype <= GFS2_METATYPE_RB)
+ blk = find_metablockoftype_slow(startblk, mtype, print);
+ else if (mtype >= GFS2_METATYPE_DI && mtype <= GFS2_METATYPE_QC)
+ blk = find_metablockoftype_rg(startblk, mtype, print);
+ else if (print) {
+ fprintf(stderr, "Error: metadata type not "
+ "specified: must be one of:\n");
+ fprintf(stderr, "sb rg rb di in lf jd lh ld"
+ " ea ed lb 13 qc\n");
+ gfs2_rgrp_free(&sbd.rglist, not_updated);
+ exit(-1);
+ }
+ return blk;
+}
+
+/* ------------------------------------------------------------------------ */
/* Check if the word is a keyword such as "sb" or "rindex" */
/* Returns: block number if it is, else 0 */
/* ------------------------------------------------------------------------ */
@@ -1733,7 +2116,9 @@ uint64_t check_keywords(const char *kword)
uint64_t j_size;
blk = find_journal_block(kword, &j_size);
- } else if (kword[0]=='0' && kword[1]=='x') /* hex addr */
+ } else if (kword[0]=='/') /* search */
+ blk = find_metablockoftype(&kword[1], 0);
+ else if (kword[0]=='0' && kword[1]=='x') /* hex addr */
sscanf(kword, "%"SCNx64, &blk);/* retrieve in hex */
else
sscanf(kword, "%" PRIu64, &blk); /* retrieve decimal */
@@ -1752,7 +2137,7 @@ uint64_t goto_block(void)
memset(string, 0, sizeof(string));
sprintf(string,"%"PRId64, block);
if (bobgets(string, 1, 7, 16, &ch)) {
- if (isalnum(string[0]))
+ if (isalnum(string[0]) || string[0] == '/')
temp_blk = check_keywords(string);
else if (string[0] == '+') {
if (string[1] == '0' && string[2] == 'x')
@@ -1844,8 +2229,17 @@ void hex_edit(int *exitch)
ch += (estring[i+1] - 'A' + 0x0a);
buf[offset + hexoffset] = ch;
}
- do_lseek(sbd.device_fd, dev_offset);
- do_write(sbd.device_fd, buf, sbd.bsize);
+ lseek(sbd.device_fd, dev_offset, SEEK_SET);
+ if (write(sbd.device_fd, buf, sbd.bsize) !=
+ sbd.bsize) {
+ fprintf(stderr, "write error: %s from %s:%d: "
+ "offset %lld (0x%llx)\n",
+ strerror(errno),
+ __FUNCTION__, __LINE__,
+ (unsigned long long)dev_offset,
+ (unsigned long long)dev_offset);
+ exit(-1);
+ }
fsync(sbd.device_fd);
}
}
@@ -1944,6 +2338,196 @@ void jump(void)
}
/* ------------------------------------------------------------------------ */
+/* print block type */
+/* ------------------------------------------------------------------------ */
+void print_block_type(uint64_t block, int type, const char *additional)
+{
+ if (type <= GFS2_METATYPE_QC)
+ printf("%d (Block %lld is type %d: %s%s)\n", type,
+ (unsigned long long)block, type, block_type_str[type],
+ additional);
+ else
+ printf("%d (Block %lld is type %d: unknown%s)\n", type,
+ (unsigned long long)block, type, additional);
+}
+
+/* ------------------------------------------------------------------------ */
+/* find_print block type */
+/* ------------------------------------------------------------------------ */
+void find_print_block_type(void)
+{
+ uint64_t block;
+ struct gfs2_buffer_head *bh;
+ int type;
+
+ block = blockstack[blockhist % BLOCK_STACK_SIZE].block;
+ bh = bread(&sbd.buf_list, block);
+ type = get_block_type(bh->b_data);
+ print_block_type(block, type, "");
+ brelse(bh, NOT_UPDATED);
+ gfs2_rgrp_free(&sbd.rglist, not_updated);
+ exit(0);
+}
+
+/* ------------------------------------------------------------------------ */
+/* Find and print the resource group associated with a given block */
+/* ------------------------------------------------------------------------ */
+void find_print_block_rg(int bitmap)
+{
+ uint64_t block, rgblock;
+ int i;
+ struct rgrp_list *rgd;
+
+ block = blockstack[blockhist % BLOCK_STACK_SIZE].block;
+ if (block == sbd.sb_addr)
+ printf("0 (the superblock is not in the bitmap)\n");
+ else {
+ rgd = gfs2_blk2rgrpd(&sbd, block);
+ if (rgd) {
+ rgblock = rgd->ri.ri_addr;
+ if (bitmap) {
+ struct gfs2_bitmap *bits = NULL;
+
+ for (i = 0; i < rgd->ri.ri_length; i++) {
+ bits = &(rgd->bits[i]);
+ if (block - rgd->ri.ri_data0 <
+ ((bits->bi_start + bits->bi_len) *
+ GFS2_NBBY)) {
+ break;
+ }
+ }
+ if (i < rgd->ri.ri_length)
+ rgblock += i;
+
+ }
+ if (dmode == HEX_MODE)
+ printf("0x%llx\n",(unsigned long long)rgblock);
+ else
+ printf("%llu\n", (unsigned long long)rgblock);
+ } else {
+ printf("-1 (block invalid or part of an rgrp).\n");
+ }
+ }
+ gfs2_rgrp_free(&sbd.rglist, not_updated);
+ exit(0);
+}
+
+/* ------------------------------------------------------------------------ */
+/* find/change/print block allocation (what the bitmap says about block) */
+/* ------------------------------------------------------------------------ */
+void find_change_block_alloc(int *newval)
+{
+ uint64_t block;
+ int type;
+ struct rgrp_list *rgd;
+
+ if (newval &&
+ (*newval < GFS2_BLKST_FREE || *newval > GFS2_BLKST_DINODE)) {
+ int i;
+
+ printf("Error: value %d is not valid.\nValid values are:\n",
+ *newval);
+ for (i = GFS2_BLKST_FREE; i <= GFS2_BLKST_DINODE; i++)
+ printf("%d - %s\n", i, allocdesc[i]);
+ gfs2_rgrp_free(&sbd.rglist, not_updated);
+ exit(-1);
+ }
+ block = blockstack[blockhist % BLOCK_STACK_SIZE].block;
+ if (block == sbd.sb_addr)
+ printf("3 (the superblock is not in the bitmap)\n");
+ else {
+ if (newval) {
+ if (gfs2_set_bitmap(&sbd, block, *newval))
+ printf("-1 (block invalid or part of an rgrp).\n");
+ else
+ printf("%d\n", *newval);
+ } else {
+ rgd = gfs2_blk2rgrpd(&sbd, block);
+ if (rgd) {
+ type = gfs2_get_bitmap(&sbd, block, rgd);
+ printf("%d (%s)\n", type, allocdesc[type]);
+ gfs2_rgrp_relse(rgd, not_updated);
+ } else {
+ gfs2_rgrp_free(&sbd.rglist, not_updated);
+ printf("-1 (block invalid or part of an rgrp).\n");
+ exit(-1);
+ }
+ }
+ }
+ gfs2_rgrp_free(&sbd.rglist, (newval) ? updated : not_updated);
+ if (newval)
+ bcommit(&sbd.nvbuf_list);
+ exit(0);
+}
+
+/* ------------------------------------------------------------------------ */
+/* process request to print a certain field from a previously pushed block */
+/* ------------------------------------------------------------------------ */
+void process_field(const char *field, uint64_t *newval, int print_field)
+{
+ uint64_t block;
+ struct gfs2_buffer_head *bh;
+ int type;
+ struct gfs2_rgrp rg;
+
+ block = blockstack[blockhist % BLOCK_STACK_SIZE].block;
+ bh = bread(&sbd.buf_list, block);
+ type = get_block_type(bh->b_data);
+ switch (type) {
+ case GFS2_METATYPE_SB:
+ if (print_field)
+ print_block_type(block, type,
+ " which is not implemented");
+ break;
+ case GFS2_METATYPE_RG:
+ gfs2_rgrp_in(&rg, bh->b_data);
+ if (newval) {
+ gfs2_rgrp_assignval(&rg, field, *newval);
+ gfs2_rgrp_out(&rg, bh->b_data);
+ if (print_field)
+ gfs2_rgrp_printval(&rg, field);
+ } else {
+ if (print_field && gfs2_rgrp_printval(&rg, field))
+ printf("Field '%s' not found.\n", field);
+ }
+ break;
+ case GFS2_METATYPE_RB:
+ if (print_field)
+ print_block_type(block, type,
+ " which is not implemented");
+ break;
+ case GFS2_METATYPE_DI:
+ gfs2_dinode_in(&di, bh->b_data);
+ if (newval) {
+ gfs2_dinode_assignval(&di, field, *newval);
+ gfs2_dinode_out(&di, bh->b_data);
+ if (print_field)
+ gfs2_dinode_printval(&di, field);
+ } else {
+ if (print_field && gfs2_dinode_printval(&di, field))
+ printf("Field '%s' not found.\n", field);
+ }
+ break;
+ case GFS2_METATYPE_IN:
+ case GFS2_METATYPE_LF:
+ case GFS2_METATYPE_JD:
+ case GFS2_METATYPE_LH:
+ case GFS2_METATYPE_LD:
+ case GFS2_METATYPE_EA:
+ case GFS2_METATYPE_ED:
+ case GFS2_METATYPE_LB:
+ case GFS2_METATYPE_QC:
+ default:
+ if (print_field)
+ print_block_type(block, type,
+ " which is not implemented");
+ break;
+ }
+ brelse(bh, newval ? UPDATED : NOT_UPDATED);
+ bcommit(&sbd.buf_list);
+}
+
+/* ------------------------------------------------------------------------ */
/* interactive_mode - accept keystrokes from user and display structures */
/* ------------------------------------------------------------------------ */
void interactive_mode(void)
@@ -1977,10 +2561,20 @@ void interactive_mode(void)
else {
if (dmode == HEX_MODE)
hex_edit(&ch);
- else if (dmode == GFS2_MODE)
+ else if (dmode == GFS2_MODE) {
+ uint64_t val;
+
bobgets(estring, edit_row[dmode]+4, 24,
- edit_size[dmode], &ch);
- else
+ 10, &ch);
+ if (estring[0] == '0' &&
+ estring[1] == 'x')
+ sscanf(estring, "%"SCNx64,
+ &val);
+ else
+ val = (uint64_t)atoll(estring);
+ process_field(efield, &val, 0);
+ block_in_mem = -1;
+ } else
bobgets(estring, edit_row[dmode]+6, 14,
edit_size[dmode], &ch);
}
@@ -2226,10 +2820,10 @@ void gfs_log_header_print(struct gfs_log_header *lh)
gfs2_meta_header_print(&lh->lh_header);
pv(lh, lh_flags, "%u", "0x%.8X");
pv(lh, lh_pad, "%u", "%x");
- pv(lh, lh_first, "%llu", "%llx");
- pv(lh, lh_sequence, "%llu", "%llx");
- pv(lh, lh_tail, "%llu", "%llx");
- pv(lh, lh_last_dump, "%llu", "%llx");
+ pv((unsigned long long)lh, lh_first, "%llu", "%llx");
+ pv((unsigned long long)lh, lh_sequence, "%llu", "%llx");
+ pv((unsigned long long)lh, lh_tail, "%llu", "%llx");
+ pv((unsigned long long)lh, lh_last_dump, "%llu", "%llx");
}
/* ------------------------------------------------------------------------ */
@@ -2289,8 +2883,8 @@ int fsck_readi(struct gfs2_inode *ip, void *buf, uint64_t offset,
if (!size)
return 0;
if (isdir) {
- lblock = offset;
- o = do_div(lblock, sdp->sd_jbsize);
+ o = offset % sdp->sd_jbsize;
+ lblock = offset / sdp->sd_jbsize;
} else {
lblock = offset >> sdp->sd_sb.sb_bsize_shift;
o = offset & (sdp->bsize - 1);
@@ -2474,7 +3068,7 @@ void dump_journal(const char *journal)
/* ------------------------------------------------------------------------ */
void usage(void)
{
- fprintf(stderr,"\nFormat is: gfs2_edit [-c 1] [-V] [-x] [-h] [identify] [-p structures|blocks] /dev/device\n\n");
+ fprintf(stderr,"\nFormat is: gfs2_edit [-c 1] [-V] [-x] [-h] [identify] [-p structures|blocks][blocktype][blockalloc [val]][blockbits][blockrg][find sb|rg|rb|di|in|lf|jd|lh|ld|ea|ed|lb|13|qc][field <f>[val]] /dev/device\n\n");
fprintf(stderr,"If only the device is specified, it enters into hexedit mode.\n");
fprintf(stderr,"identify - prints out only the block type, not the details.\n");
fprintf(stderr,"printsavedmeta - prints out the saved metadata blocks from a savemeta file.\n");
@@ -2500,6 +3094,20 @@ void usage(void)
fprintf(stderr," rg X - print resource group X.\n");
fprintf(stderr," rgs - prints all the resource groups (rgs).\n");
fprintf(stderr," quota - prints the quota file.\n");
+ fprintf(stderr," 0x1234 - prints the specified block\n");
+ fprintf(stderr,"-p <block> blocktype - prints the type "
+ "of the specified block\n");
+ fprintf(stderr,"-p <block> blockrg - prints the resource group "
+ "block corresponding to the specified block\n");
+ fprintf(stderr,"-p <block> blockbits - prints the block with "
+ "the bitmap corresponding to the specified block\n");
+ fprintf(stderr,"-p <block> blockalloc [0|1|2|3] - print or change "
+ "the allocation type of the specified block\n");
+ fprintf(stderr,"-p <block> field [new_value] - prints or change the "
+ "structure field\n");
+ fprintf(stderr,"-p <b> find sb|rg|rb|di|in|lf|jd|lh|ld|ea|ed|lb|"
+ "13|qc - find block of given type after block <b>\n");
+ fprintf(stderr," <b> specifies the starting block for search\n");
fprintf(stderr,"-s specifies a starting block such as root, rindex, quota, inum.\n");
fprintf(stderr,"-x print in hexmode.\n");
fprintf(stderr,"-h prints this help.\n\n");
@@ -2514,6 +3122,16 @@ void usage(void)
fprintf(stderr," gfs2_edit identify -p 0x27381 /dev/bobs_vg/lvol0\n");
fprintf(stderr," To print out the fourth Resource Group. (the first R is #0)\n");
fprintf(stderr," gfs2_edit -p rg 3 /dev/sdb1\n");
+ fprintf(stderr," To print out the metadata type of block 1234\n");
+ fprintf(stderr," gfs2_edit -p 1234 blocktype /dev/roth_vg/roth_lb\n");
+ fprintf(stderr," To print out the allocation type of block 2345\n");
+ fprintf(stderr," gfs2_edit -p 2345 blockalloc /dev/vg/lv\n");
+ fprintf(stderr," To change the allocation type of block 2345 to a 'free block'\n");
+ fprintf(stderr," gfs2_edit -p 2345 blockalloc 0 /dev/vg/lv\n");
+ fprintf(stderr," To print out the file size of the dinode at block 0x118\n");
+ fprintf(stderr," gfs2_edit -p 0x118 field di_size /dev/roth_vg/roth_lb\n");
+ fprintf(stderr," To find any dinode higher than the quota file dinode:\n");
+ fprintf(stderr," gfs2_edit -p quota find di /dev/x/y\n");
fprintf(stderr," To set the Resource Group flags for rg #7 to 3.\n");
fprintf(stderr," gfs2_edit rgflags 7 3 /dev/sdc2\n");
fprintf(stderr," To save off all metadata for /dev/vg/lv:\n");
@@ -2521,6 +3139,55 @@ void usage(void)
}/* usage */
/* ------------------------------------------------------------------------ */
+/* parameterpass1 - pre-processing for command-line parameters */
+/* ------------------------------------------------------------------------ */
+void parameterpass1(int argc, char *argv[], int i)
+{
+ if (!strcasecmp(argv[i], "-V")) {
+ printf("%s version %s (built %s %s)\n",
+ prog_name, GFS2_RELEASE_NAME,
+ __DATE__, __TIME__);
+ printf("%s\n", REDHAT_COPYRIGHT);
+ exit(0);
+ }
+ else if (!strcasecmp(argv[i], "-h") ||
+ !strcasecmp(argv[i], "-help") ||
+ !strcasecmp(argv[i], "-usage")) {
+ usage();
+ exit(0);
+ }
+ else if (!strcasecmp(argv[i], "-c")) {
+ i++;
+ color_scheme = atoi(argv[i]);
+ }
+ else if (!strcasecmp(argv[i], "-p") ||
+ !strcasecmp(argv[i], "-print")) {
+ termlines = 0; /* initial value--we'll figure
+ it out later */
+ dmode = GFS2_MODE;
+ }
+ else if (!strcasecmp(argv[i], "savemeta"))
+ termlines = 0;
+ else if (!strcasecmp(argv[i], "savemetaslow"))
+ termlines = 0;
+ else if (!strcasecmp(argv[i], "savergs"))
+ termlines = 0;
+ else if (!strcasecmp(argv[i], "printsavedmeta"))
+ restoremeta(argv[i+1], argv[i+2],
+ TRUE);
+ else if (!strcasecmp(argv[i], "restoremeta"))
+ restoremeta(argv[i+1], argv[i+2], FALSE);
+ else if (!strcmp(argv[i], "rgcount"))
+ termlines = 0;
+ else if (!strcmp(argv[i], "rgflags"))
+ termlines = 0;
+ else if (!strcmp(argv[i], "rg"))
+ termlines = 0;
+ else if (!device[0] && strchr(argv[i],'/'))
+ strcpy(device, argv[i]);
+}
+
+/* ------------------------------------------------------------------------ */
/* process_parameters - process commandline parameters */
/* pass - we make two passes through the parameters; the first pass gathers */
/* normals parameters, device name, etc. The second pass is for */
@@ -2529,156 +3196,163 @@ void usage(void)
void process_parameters(int argc, char *argv[], int pass)
{
int i;
+ uint64_t keyword_blk;
if (argc < 2) {
usage();
die("no device specified\n");
}
for (i = 1; i < argc; i++) {
- if (!pass) {
- if (!strcasecmp(argv[i], "-V")) {
- printf("%s version %s (built %s %s)\n", prog_name,
- GFS2_RELEASE_NAME, __DATE__, __TIME__);
- printf("%s\n", REDHAT_COPYRIGHT);
- exit(0);
+ if (!pass) { /* first pass */
+ parameterpass1(argc, argv, i);
+ continue;
+ }
+ /* second pass */
+ if (!strcasecmp(argv[i], "-s")) {
+ i++;
+ if (i >= argc - 1) {
+ printf("Error: starting block not specified "
+ "with -s.\n");
+ printf("%s -s [starting block | keyword] "
+ "<device>\n", argv[0]);
+ printf("For example: %s -s \"rg 3\" "
+ "/dev/exxon_vg/exxon_lv\n", argv[0]);
+ exit(EXIT_FAILURE);
}
- else if (!strcasecmp(argv[i], "-h") ||
- !strcasecmp(argv[i], "-help") ||
- !strcasecmp(argv[i], "-usage")) {
- usage();
+ starting_blk = check_keywords(argv[i]);
+ continue;
+ }
+ if (termlines || strchr(argv[i],'/')) /* if print or slash */
+ continue;
+
+ if (!strncmp(argv[i], "journal", 7) &&
+ isdigit(argv[i][7])) {
+ dump_journal(argv[i]);
+ continue;
+ }
+ keyword_blk = check_keywords(argv[i]);
+ if (keyword_blk)
+ push_block(keyword_blk);
+ else if (!strcasecmp(argv[i], "-x"))
+ dmode = HEX_MODE;
+ else if (argv[i][0] == '-') /* if it starts with a dash */
+ ; /* ignore it--meant for pass == 0 */
+ else if (!strcmp(argv[i], "identify"))
+ identify = TRUE;
+ else if (!strcmp(argv[i], "size")) {
+ printf("Device size: %" PRIu64 " (0x%" PRIx64 ")\n",
+ max_block, max_block);
+ exit(EXIT_SUCCESS);
+ } else if (!strcmp(argv[i], "rgcount"))
+ rgcount();
+ else if (!strcmp(argv[i], "field")) {
+ uint64_t newval;
+
+ i++;
+ if (i >= argc - 1) {
+ printf("Error: field not specified.\n");
+ printf("Format is: %s -p <block> field "
+ "<field> [newvalue]\n", argv[0]);
+ gfs2_rgrp_free(&sbd.rglist, not_updated);
+ exit(EXIT_FAILURE);
+ }
+ if (isdigit(argv[i + 1][0])) {
+ if (argv[i + 1][0]=='0' && argv[i + 1][1]=='x')
+ sscanf(argv[i + 1], "%"SCNx64,
+ &newval);
+ else
+ newval = (uint64_t)atoll(argv[i + 1]);
+ process_field(argv[i], &newval, 1);
+ gfs2_rgrp_free(&sbd.rglist, not_updated);
+ exit(0);
+ } else {
+ process_field(argv[i], NULL, 1);
+ gfs2_rgrp_free(&sbd.rglist, not_updated);
exit(0);
}
- else if (!strcasecmp(argv[i], "-c")) {
- i++;
- color_scheme = atoi(argv[i]);
+ } else if (!strcmp(argv[i], "blocktype")) {
+ find_print_block_type();
+ } else if (!strcmp(argv[i], "blockrg")) {
+ find_print_block_rg(0);
+ } else if (!strcmp(argv[i], "blockbits")) {
+ find_print_block_rg(1);
+ } else if (!strcmp(argv[i], "blockalloc")) {
+ if (isdigit(argv[i + 1][0])) {
+ int newval;
+
+ if (argv[i + 1][0]=='0' && argv[i + 1][1]=='x')
+ sscanf(argv[i + 1], "%x", &newval);
+ else
+ newval = (uint64_t)atoi(argv[i + 1]);
+ find_change_block_alloc(&newval);
+ } else {
+ find_change_block_alloc(NULL);
}
- else if (!strcasecmp(argv[i], "-p") ||
- !strcasecmp(argv[i], "-print")) {
- termlines = 0; /* initial value--we'll figure it out later */
- dmode = GFS2_MODE;
+ } else if (!strcmp(argv[i], "find")) {
+ find_metablockoftype(argv[i + 1], 1);
+ } else if (!strcmp(argv[i], "rgflags")) {
+ int rg, set = FALSE;
+ uint32_t new_flags = 0;
+
+ i++;
+ if (i >= argc - 1) {
+ printf("Error: rg # not specified.\n");
+ printf("Format is: %s rgflags rgnum"
+ "[newvalue]\n", argv[0]);
+ gfs2_rgrp_free(&sbd.rglist, not_updated);
+ exit(EXIT_FAILURE);
}
- else if (!strcasecmp(argv[i], "savemeta"))
- termlines = 0;
- else if (!strcasecmp(argv[i], "savemetaslow"))
- termlines = 0;
- else if (!strcasecmp(argv[i], "savergs"))
- termlines = 0;
- else if (!strcasecmp(argv[i], "printsavedmeta"))
- restoremeta(argv[i+1], argv[i+2],
- TRUE);
- else if (!strcasecmp(argv[i], "restoremeta"))
- restoremeta(argv[i+1], argv[i+2], FALSE);
- else if (!strcmp(argv[i], "rgcount"))
- termlines = 0;
- else if (!strcmp(argv[i], "rgflags"))
- termlines = 0;
- else if (!strcmp(argv[i], "rg"))
- termlines = 0;
- else if (!device[0] && strchr(argv[i],'/'))
- strcpy(device, argv[i]);
- }
- else { /* second pass */
- if (!strcasecmp(argv[i], "-s")) {
- i++;
- if (i >= argc - 1) {
- printf("Error: starting block not specified with -s.\n");
- printf("%s -s [starting block | keyword] <device>\n",
- argv[0]);
- printf("For example: %s -s \"rg 3\" /dev/exxon_vg/exxon_lv\n",
- argv[0]);
- exit(EXIT_FAILURE);
- }
- starting_blk = check_keywords(argv[i]);
+ if (argv[i][0]=='0' && argv[i][1]=='x')
+ sscanf(argv[i], "%"SCNx32, &rg);
+ else
+ rg = atoi(argv[i]);
+ i++;
+ if (i < argc - 1 &&
+ isdigit(argv[i][0])) {
+ set = TRUE;
+ if (argv[i][0]=='0' && argv[i][1]=='x')
+ sscanf(argv[i], "%"SCNx32, &new_flags);
+ else
+ new_flags = atoi(argv[i]);
}
- else if (!termlines && !strchr(argv[i],'/')) { /* if print, no slash */
- uint64_t keyword_blk;
-
- if (!strncmp(argv[i], "journal", 7) &&
- isdigit(argv[i][7])) {
- dump_journal(argv[i]);
- continue;
- }
- keyword_blk = check_keywords(argv[i]);
- if (keyword_blk) {
- push_block(keyword_blk);
- }
- else if (!strcasecmp(argv[i], "-x"))
- dmode = HEX_MODE;
- else if (argv[i][0] == '-') /* if it starts with a dash */
- ; /* ignore it--meant for pass == 0 */
- else if (!strcmp(argv[i], "identify"))
- identify = TRUE;
- else if (!strcmp(argv[i], "size"))
- printf("Device size: %" PRIu64 " (0x%" PRIx64 ")\n",
- max_block, max_block);
- else if (!strcmp(argv[i], "rgcount"))
- rgcount();
- else if (!strcmp(argv[i], "rgflags")) {
- int rg, set = FALSE;
- uint32_t new_flags = 0;
-
- i++;
- if (i >= argc - 1) {
- printf("Error: rg # not specified.\n");
- printf("Format is: %s rgflags rgnum"
- "[newvalue]\n",
- argv[0]);
- exit(EXIT_FAILURE);
- }
- if (argv[i][0]=='0' && argv[i][1]=='x')
- sscanf(argv[i], "%"SCNx32,
- &rg);
- else
- rg = atoi(argv[i]);
- i++;
- if (i < argc - 1 &&
- isdigit(argv[i][0])) {
- set = TRUE;
- if (argv[i][0]=='0' &&
- argv[i][1]=='x')
- sscanf(argv[i],
- "%"SCNx32,
- &new_flags);
- else
- new_flags =
- atoi(argv[i]);
- }
- set_rgrp_flags(rg, new_flags, set,
- FALSE);
- exit(EXIT_SUCCESS);
- }
- else if (!strcmp(argv[i], "rg")) {
- int rg;
-
- i++;
- if (i >= argc - 1) {
- printf("Error: rg # not specified.\n");
- printf("Format is: %s rg rgnum"
- "\n", argv[0]);
- exit(EXIT_FAILURE);
- }
- rg = atoi(argv[i]);
- i++;
- set_rgrp_flags(rg, 0, FALSE, TRUE);
- exit(EXIT_SUCCESS);
- }
- else if (!strcasecmp(argv[i], "savemeta"))
- savemeta(argv[i+2], 0);
- else if (!strcasecmp(argv[i], "savemetaslow"))
- savemeta(argv[i+2], 1);
- else if (!strcasecmp(argv[i], "savergs"))
- savemeta(argv[i+2], 2);
- else if (isdigit(argv[i][0])) { /* decimal addr */
- sscanf(argv[i], "%"SCNd64, &temp_blk);
- push_block(temp_blk);
- }
- else {
- fprintf(stderr,"I don't know what '%s' means.\n", argv[i]);
- usage();
- exit(0);
- }
+ set_rgrp_flags(rg, new_flags, set, FALSE);
+ gfs2_rgrp_free(&sbd.rglist, not_updated);
+ exit(EXIT_SUCCESS);
+ } else if (!strcmp(argv[i], "rg")) {
+ int rg;
+
+ i++;
+ if (i >= argc - 1) {
+ printf("Error: rg # not specified.\n");
+ printf("Format is: %s rg rgnum\n", argv[0]);
+ gfs2_rgrp_free(&sbd.rglist, not_updated);
+ exit(EXIT_FAILURE);
+ }
+ rg = atoi(argv[i]);
+ if (!strcasecmp(argv[i + 1], "find")) {
+ temp_blk = get_rg_addr(rg);
+ push_block(temp_blk);
+ } else {
+ set_rgrp_flags(rg, 0, FALSE, TRUE);
+ gfs2_rgrp_free(&sbd.rglist, not_updated);
+ exit(EXIT_SUCCESS);
}
}
+ else if (!strcasecmp(argv[i], "savemeta"))
+ savemeta(argv[i+2], 0);
+ else if (!strcasecmp(argv[i], "savemetaslow"))
+ savemeta(argv[i+2], 1);
+ else if (!strcasecmp(argv[i], "savergs"))
+ savemeta(argv[i+2], 2);
+ else if (isdigit(argv[i][0])) { /* decimal addr */
+ sscanf(argv[i], "%"SCNd64, &temp_blk);
+ push_block(temp_blk);
+ } else {
+ fprintf(stderr,"I don't know what '%s' means.\n",
+ argv[i]);
+ usage();
+ exit(EXIT_FAILURE);
+ }
} /* for */
}/* process_parameters */
@@ -2768,5 +3442,6 @@ int main(int argc, char *argv[])
free(buf);
if (indirect)
free(indirect);
+ gfs2_rgrp_free(&sbd.rglist, not_updated);
exit(EXIT_SUCCESS);
}
diff --git a/gfs2/edit/hexedit.h b/gfs2/edit/hexedit.h
index d3a3a9f..a3f2b5d 100644
--- a/gfs2/edit/hexedit.h
+++ b/gfs2/edit/hexedit.h
@@ -73,6 +73,7 @@ EXTERN int edit_mode INIT(0);
EXTERN int line;
EXTERN char edit_fmt[80];
EXTERN char estring[1024]; /* edit string */
+EXTERN char efield[64];
EXTERN uint64_t dev_offset INIT(0);
EXTERN uint64_t max_block INIT(0);
EXTERN char *buf INIT(NULL);
@@ -103,6 +104,7 @@ EXTERN int gfs1 INIT(0);
EXTERN int editing INIT(0);
EXTERN uint64_t temp_blk;
EXTERN uint64_t starting_blk;
+EXTERN const char *block_type_str[15];
struct gfs_jindex {
uint64_t ji_addr; /* starting block of the journal */
@@ -249,16 +251,6 @@ EXTERN enum dsp_mode dmode INIT(HEX_MODE);
/* Memory macros */
-#define type_zalloc(ptr, type, count) \
-{ \
- (ptr) = (type *)malloc(sizeof(type) * (count)); \
- if ((ptr)) \
- memset((char *)(ptr), 0, sizeof(type) * (count)); \
- else \
- die("unable to allocate memory on line %d of file %s\n", \
- __LINE__, __FILE__); \
-}
-
#define type_alloc(ptr, type, count) \
{ \
(ptr) = (type *)malloc(sizeof(type) * (count)); \
diff --git a/gfs2/fsck/fs_bits.h b/gfs2/fsck/fs_bits.h
index 10addf6..15d6679 100644
--- a/gfs2/fsck/fs_bits.h
+++ b/gfs2/fsck/fs_bits.h
@@ -39,9 +39,4 @@ uint32_t gfs2_blkalloc_internal(struct rgrp_list *rgd, uint32_t goal,
unsigned char old_state,
unsigned char new_state, int do_it);
-/* functions with blk #'s that are file system relative */
-int gfs2_get_bitmap(struct gfs2_sbd *sdp, uint64_t blkno,
- struct rgrp_list *rgd);
-int gfs2_set_bitmap(struct gfs2_sbd *sdp, uint64_t blkno, int state);
-
#endif /* __FS_BITS_H__ */
diff --git a/gfs2/libgfs2/fs_bits.c b/gfs2/libgfs2/fs_bits.c
index 024426f..4cd41b4 100644
--- a/gfs2/libgfs2/fs_bits.c
+++ b/gfs2/libgfs2/fs_bits.c
@@ -17,32 +17,6 @@
#include "libgfs2.h"
-/**
- * fs_setbit - Set a bit in the bitmaps
- * @buffer: the buffer that holds the bitmaps
- * @buflen: the length (in bytes) of the buffer
- * @block: the block to set
- * @new_state: the new state of the block
- *
- */
-static void gfs2_setbit(unsigned char *buffer, unsigned int buflen,
- uint32_t block, unsigned char new_state)
-{
- unsigned char *byte, *end, cur_state;
- unsigned int bit;
-
- byte = buffer + (block / GFS2_NBBY);
- bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE;
- end = buffer + buflen;
-
- if(byte < end) {
- cur_state = (*byte >> bit) & GFS2_BIT_MASK;
-
- *byte ^= cur_state << bit;
- *byte |= new_state << bit;
- }
-}
-
uint32_t gfs2_bitfit_core(struct gfs2_sbd *sbp, uint64_t goal, uint64_t start,
uint64_t len, unsigned char old_state,
struct gfs2_block_list *bl)
@@ -179,68 +153,6 @@ int gfs2_check_range(struct gfs2_sbd *sdp, uint64_t blkno)
}
/*
- * fs_get_bitmap - get value of FS bitmap
- * @sdp: super block
- * @blkno: block number relative to file system
- *
- * This function gets the value of a bit of the
- * file system bitmap.
- * Possible state values for a block in the bitmap are:
- * GFS_BLKST_FREE (0)
- * GFS_BLKST_USED (1)
- * GFS_BLKST_INVALID (2)
- * GFS_BLKST_DINODE (3)
- *
- * Returns: state on success, -1 on error
- */
-int gfs2_get_bitmap(struct gfs2_sbd *sdp, uint64_t blkno,
- struct rgrp_list *rgd)
-{
- int buf, val;
- uint32_t rgrp_block;
- struct gfs2_bitmap *bits = NULL;
- unsigned int bit;
- unsigned char *byte;
- int local_rgd = 0;
-
- if(gfs2_check_range(sdp, blkno))
- return -1;
- if(rgd == NULL) {
- local_rgd = 1;
- rgd = gfs2_blk2rgrpd(sdp, blkno);
- }
- if(rgd == NULL)
- return -1;
- if(gfs2_rgrp_read(sdp, rgd))
- return -1;
-
- rgrp_block = (uint32_t)(blkno - rgd->ri.ri_data0);
-
- for(buf= 0; buf < rgd->ri.ri_length; buf++){
- bits = &(rgd->bits[buf]);
- if(rgrp_block < ((bits->bi_start + bits->bi_len)*GFS2_NBBY)){
- break;
- }
- }
-
- if(buf >= rgd->ri.ri_length){
- gfs2_rgrp_relse(rgd, not_updated);
- return -1;
- }
-
- byte = (unsigned char *)(rgd->bh[buf]->b_data + bits->bi_offset) +
- (rgrp_block/GFS2_NBBY - bits->bi_start);
- bit = (rgrp_block % GFS2_NBBY) * GFS2_BIT_SIZE;
-
- val = ((*byte >> bit) & GFS2_BIT_MASK);
- if(local_rgd)
- gfs2_rgrp_relse(rgd, not_updated);
-
- return val;
-}
-
-
-/*
* fs_set_bitmap
* @sdp: super block
* @blkno: block number relative to file system
@@ -257,12 +169,12 @@ int gfs2_set_bitmap(struct gfs2_sbd *sdp, uint64_t blkno, int state)
uint32_t rgrp_block;
struct gfs2_bitmap *bits = NULL;
struct rgrp_list *rgd;
+ unsigned char *byte, cur_state;
+ unsigned int bit;
/* FIXME: should GFS2_BLKST_INVALID be allowed */
- if((state != GFS2_BLKST_FREE) && (state != GFS2_BLKST_USED) &&
- (state != GFS2_BLKST_DINODE)){
+ if ((state < GFS2_BLKST_FREE) || (state > GFS2_BLKST_DINODE))
return -1;
- }
rgd = gfs2_blk2rgrpd(sdp, blkno);
@@ -278,9 +190,14 @@ int gfs2_set_bitmap(struct gfs2_sbd *sdp, uint64_t blkno, int state)
break;
}
- gfs2_setbit((unsigned char *)rgd->bh[buf]->b_data + bits->bi_offset,
- bits->bi_len, (rgrp_block - (bits->bi_start * GFS2_NBBY)),
- state);
+ byte = (unsigned char *)(rgd->bh[buf]->b_data + bits->bi_offset) +
+ (rgrp_block/GFS2_NBBY - bits->bi_start);
+ bit = (rgrp_block % GFS2_NBBY) * GFS2_BIT_SIZE;
+
+ cur_state = (*byte >> bit) & GFS2_BIT_MASK;
+ *byte ^= cur_state << bit;
+ *byte |= state << bit;
+
gfs2_rgrp_relse(rgd, updated);
return 0;
}
diff --git a/gfs2/man/gfs2_edit.8 b/gfs2/man/gfs2_edit.8
index 36a6018..a14f2b4 100644
--- a/gfs2/man/gfs2_edit.8
+++ b/gfs2/man/gfs2_edit.8
@@ -3,7 +3,7 @@
.TH gfs2_edit 8
.SH NAME
-gfs2_edit - Display, print or edit GFS2 internal structures.
+gfs2_edit - Display, print or edit GFS2 or GFS internal structures.
.SH SYNOPSIS
.B gfs2_edit
@@ -21,12 +21,12 @@ These options should be used with great care.
.SH OPTIONS
.TP
-\fB-p\fP [\fIstructure\fR | \fIblock\fR]
+\fB-p\fP [\fIstruct\fR | \fIblock\fR] [\fIblocktype\fR] [\fIblockalloc [val]\fR] [\fIblockbits\fR] [\fIblockrg\fR] [\fIfind sb|rg|rb|di|in|lf|jd|lh|ld|ea|ed|lb|13|qc\fR] [\fIfield <field> [val]\fR]
Print a gfs2 data structure in human-readable format to stdout.
You can enter either a block number or a data structure name. Block numbers
may be specified in hex (e.g., 0x10) or decimal (e.g., 16).
-You can specify the following data structure names with the -p option.
+You can specify the following well-known locations with the -p option.
\fIsb\fR, \fIsuperblock\fR - Print the superblock.
@@ -69,14 +69,64 @@ If you specify -p without a block or structure name, gfs2_edit prints the
superblock.
You can specify more than one data structure with a single -p option.
-For example, "gfs2_edit -p inum statfs /dev/sda1" prints the system inum
+For example, \fBgfs2_edit -p inum statfs /dev/sda1\fP prints the system inum
file and the system statfs file on /dev/sda1.
-.TP
-\fB-p\fs [\fIstructure\fR | \fIblock\fR]
-Specify a starting block for interactive mode. Any of the keywords found
-in the -p option may be specified. If you want to start on a particular
-resource group, specify it in quotes, e.g. -p "rg 3"
+Optionally, you may specify the keyword \fIblocktype\fR to print out the
+gfs2 block type for the specified block. Valid gfs2 block types are:
+0 (Clump), 1 (Superblock), 2 (Resource Group Header), 3 (Resource Group
+Bitmap), 4 (Dinode), 5 (Indirect Block), 6 (Leaf), 7 (Journaled data),
+8 (Log Header), 9 (Log descriptor), 10 (Extended attribute),
+11 (Eattr Data), 12 (Log Buffer), 13 (Invalid), and 14 (Quota Change).
+
+Optionally, you may specify the keyword \fIblockalloc\fR with an
+optional value to assign. If no value is specified, the blockalloc
+keyword will print the block allocation type for the specified block.
+Valid block allocation types are: 0 (Free block), 1 (Data block),
+2 (Unlinked block), and 3 (Metadata block). If a value from 0 to 3 is
+specified, the resource group bitmap will be changed to the new value.
+This may be used, for example, to artificially free or allocate a block
+in order to test gfs2_fsck's ability to detect and fix the problem.
+
+Optionally, you may specify the keyword \fIblockbits\fR. This option
+will locate and print the block containing the bitmap corresponding to
+the specified block.
+
+Optionally, you may specify the keyword \fIblockrg\fR. This option
+will locate and print the block number of the resource group that holds
+information about the specified block.
+
+You may also use gfs2_edit to find the next occurrence of a metadata
+block of a certain type. Valid metadata types are: \fInone\fR (unused
+metadata clump block), \fIsb\fR (superblock), \fIrg\fR (resource group),
+\fIrb\fR (rg bitmap), \fIdi\fR (disk inode aka dinode), \fIin\fR (indirect
+block list), \fIlf\fR (directory leaf), \fIjd\fR (journaled data),
+\fIlh\fR (journal log header), \fIld\fR (journal log descriptor),
+\fIea\fR (extended attribute), \fIed\fR (ea data block), \fIlb\fR (log buffer),
+\fI13\fR (unused block type 13), \fIqc\fR (quota change).
+The block AFTER the one specified with -p is the starting point for
+the search. For example, if you specify \fBgfs2_edit -p rg 12 find rg
+/dev/your/device\fP, it will find the rg that follows rg 12 (normally,
+this would be rg 13). Note, however, that since metadata often appears
+in the journals, it could be a copy of a different RG, inside a journal.
+Also note that gfs2_edit will only find \fBallocated\fR metadata blocks
+unless the type specified is none, sb, rg or rb. In other words, if you
+try to find a disk inode, it will only find an allocated dinode, not a
+deallocated one.
+
+Optionally, you may specify the keyword \fIfield\fR followed by a
+valid metadata field name. Right now, only the fields in disk inodes
+and resource groups are allowed. If no value is specified after the
+field, the value of the field will be printed to stdout. If a value
+is specified, the field's value will be changed. This may be used,
+for example, to artificially change the di_size field for an inode
+in order to test gfs2_fsck's ability to detect and fix the problem.
+
+.TP
+\fB-s\fs [\fIstructure\fR | \fIblock\fR]
+Specify a starting block for interactive mode. Any of the well-known
+locations found in the -p option may be specified. If you want to start
+on a particular resource group, specify it in quotes, e.g. -s "rg 3"
.TP
\fB-h, -help, -usage\fP
Print help information.
@@ -245,9 +295,20 @@ not roll you back up.
\fB<enter>\fP - Edit value
The \fB<enter>\fP key causes you to go from display mode to edit mode.
If you are in hex mode and you hit enter, you can type new hex values
-at the cursor's current location. Note: Currently hitting \fB<enter>\fP
-in structure mode allows you to enter a new value, but it will not actually
-change the value on disk. That is a future feature.
+at the cursor's current location. Note: pressing \fB<enter>\fP
+in structure mode allows you to enter a new value, with the following
+restrictions: For gfs2 disk inodes and resource groups, it will
+actually change the value on disk. However, inode numbers may not be
+changed. For all other structures, the values entered are ignored.
+
+If you use the up arrow key to highlight the block number, then press
+\fB<enter>\fP, you may then enter a new block number, or any of the
+well-known block locations listed above (e.g. sb, rindex, inum, rg 17,
+etc.) and gfs2_edit will jump to the block specified. If you specify
+a slash character followed by a metadata type, gfs2_edit will search for
+the next occurrence of that metadata block type, and jump there. It
+will take you to block 0 if it does not find any more blocks of the
+specified metadata type.
.TP
\fB<home>\fP
@@ -315,6 +376,41 @@ Print the rg_flags value for the fourth Resource Group on /dev/sdb1.
gfs2_edit rgflags 3 8 /dev/sdb1
Set the GFS2_RGF_NOALLOC flag on for the fourth Resource Group on /dev/sdb1.
+.TP
+gfs2_edit -p 25 blockalloc /dev/roth_vg/roth_lv
+Print the block allocation type of block 25.
+May produce this output:
+3 (Metadata)
+
+.TP
+gfs2_edit -p 25 blockalloc 1 /dev/roth_vg/roth_lv
+Change the block allocation type of block 25 to data.
+May produce this output:
+1
+
+.TP
+gfs2_edit -p 25 blocktype /dev/roth_vg/roth_lv
+Print the metadata block type of block 25.
+May produce this output:
+4 (Block 25 is type 4: Dinode)
+
+.TP
+gfs2_edit -p 25 field di_size /dev/roth_vg/roth_lv
+Print the di_size field of block 25.
+May produce this output:
+134217728
+
+.TP
+gfs2_edit -x -p 25 field di_size /dev/roth_vg/roth_lv
+Print the di_size field of block 25, in hexidecimal.
+May produce this output:
+0x8000000
+
+.TP
+gfs2_edit -p 25 field di_size 0x4000 /dev/roth_vg/roth_lv
+Change the di_size field of block 25 to the hexidecimal value 0x4000.
+May produce this output:
+16384
.SH KNOWN BUGS
.TP
The directory code does not work well. It might be confused