Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=3d2064e22d…
Commit: 3d2064e22dbc3e884c7c4e37ed5edc372494656c
Parent: fbe26dc0d7dc0d2b369cffc20e3f306c44b1a2cc
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Mon Jan 28 09:11:17 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon May 20 11:12:45 2013 -0500
fsck.gfs2: Special case '..' when processing bad formal inode number
In a recent patch to fsck.gfs2, we added the ability to make sure the
formal inode number in each directory entry matches the formal inode
number in the dinode. If it doesn't match, fsck tries to fix it up.
We can't do much for regular files, but we can fix up directories.
If the directory linkage is intact, it just fixes the formal inode number.
But to check if the directory linkage is intact, we were checking to make
sure the child directory points to the parent with its "..". For example,
suppose we have gfs2 mounted as /mnt/gfs2, and at the root, we have
directory "a", and within "a" we have a subdirectory "b". In other words:
/mnt/gfs2/a/b/...
Now suppose fsck.gfs2 finds a formal inode number mismatch between the
dirent inside "a" which points to "b" and the inode "b" itself. Since
both "a" and "b" are directories, it tries to determine if the directory
linkage is intact by testing whether b's ".." dirent actually points
back to "a". And if it's good, we can just fix the formal inode number
so that they match.
That's all well and good, and works for the most part. However, if
the dirent found to be wrong isn't "b" but ".." we've got a problem.
Today's algorithm would look up the ".." of ".." which won't be
pointingi back to what we want.
For this patch, I'm special-casing ".." and making it just delete the
correct directory entry. However, we have to do it in such a way that
it doesn't decrement di_entries, since the entry is invalid.
---
gfs2/fsck/pass2.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 01c78f3..00e226c 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -260,7 +260,7 @@ static int bad_formal_ino(struct gfs2_inode *ip, struct gfs2_dirent *dent,
(unsigned long long)entry.no_formal_ino,
(unsigned long long)ii->di_num.no_formal_ino,
(unsigned long long)ii->di_num.no_formal_ino);
- if (q != gfs2_inode_dir) {
+ if (q != gfs2_inode_dir || !strcmp("..", tmp_name)) {
if (query( _("Remove the corrupt directory entry? (y/n) ")))
return 1;
log_err( _("Corrupt directory entry not removed.\n"));
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=fbe26dc0d7…
Commit: fbe26dc0d7dc0d2b369cffc20e3f306c44b1a2cc
Parent: 8c92d6111f9388ec48af7bd297cfd8fe87352499
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Mar 6 12:27:40 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon May 20 11:12:45 2013 -0500
fsck.gfs2: Add new function to check dir hash tables
It's very important that fsck.gfs2 checks for a valid directory hash
table before operating further on the directory. Before this patch,
we were doing some incomplete testing, after we had already operated
on the directory, with function check_num_ptrs. This patch replaces
that scheme with a new one that preemptively checks the hash table
with a new function called check_hash_tbl.
We've got to make sure the hash table is sane. Each leaf needs to
be counted a proper power of 2. We can't just have 3 pointers to a leaf.
The number of pointers must correspond to the proper leaf depth, and they
must all fall on power-of-two boundaries. For example, suppose we have
directory that's had one of its middle leaf blocks split several times.
The split history might look something like this:
leaf
split lindex length depth pointers leaf split
----- ------ ------ ----- -------- -------------
0: 0x00 0x100 0 00 - ff <--split to 1:
1: 0x00 0x80 1 00 - 7f <--split to 2:
0x80 0x80 1 80 - ff
2: 0x00 0x40 2 00 - 3f <--split to 3:
0x40 0x40 2 40 - 7f
0x80 0x80 1 80 - ff
3: 0x00 0x20 3 00 - 1f
0x20 0x20 3 20 - 3f <--split to 4
0x40 0x40 2 40 - 7f
0x80 0x80 1 80 - ff
4: 0x00 0x20 3 00 - 1f
0x20 0x10 4 20 - 2f
0x30 0x10 4 30 - 3f <--split to 5
0x40 0x40 2 40 - 7f
0x80 0x80 1 80 - ff
5: 0x00 0x20 3 00 - 1f
0x20 0x10 4 20 - 2f
0x30 0x8 5 30 - 37 <--split to 6
0x38 0x8 5 38 - 3f
0x40 0x40 2 40 - 7f
0x80 0x80 1 80 - ff
6: 0x00 0x20 3 00 - 1f
0x20 0x10 4 20 - 2f
0x30 0x4 6 30 - 33
0x34 0x4 6 34 - 37
0x38 0x8 5 38 - 3f
0x40 0x40 2 40 - 7f
0x80 0x80 1 80 - ff
You can see from this example that it's impossible for a leaf block to have
a lf_depth of 5 and lindex 0x34. As shown in "5:" above, a leaf depth of 5
can only fall at offset 0x30 or 0x38. If it somehow falls elsewhere, say
0x34, the proper depth should be 6, and there should only be 4 pointers,
as per split "6:" above. The leaf block pointers all need to fall properly
on these boundaries, otherwise the kernel code's calculations will land it
on the wrong leaf block while it's searching, and the result will be files
you can see with ls, but can't open, delete or use them.
---
gfs2/fsck/metawalk.c | 174 +++++++++++++++--
gfs2/fsck/metawalk.h | 12 +-
gfs2/fsck/pass1.c | 142 --------------
gfs2/fsck/pass2.c | 532 ++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 700 insertions(+), 160 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index a40a6af..02408e0 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -714,6 +714,24 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
/* Readahead */
dir_leaf_reada(ip, tbl, hsize);
+ if (pass->check_hash_tbl) {
+ error = pass->check_hash_tbl(ip, tbl, hsize, pass->private);
+ if (error < 0) {
+ free(tbl);
+ posix_fadvise(sdp->device_fd, 0, 0, POSIX_FADV_NORMAL);
+ return error;
+ }
+ /* If hash table changes were made, read it in again. */
+ if (error) {
+ free(tbl);
+ tbl = get_dir_hash(ip);
+ if (tbl == NULL) {
+ perror("get_dir_hash");
+ return -1;
+ }
+ }
+ }
+
/* Find the first valid leaf pointer in range and use it as our "old"
leaf. That way, bad blocks at the beginning will be overwritten
with the first valid leaf. */
@@ -766,21 +784,6 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
posix_fadvise(sdp->device_fd, 0, 0, POSIX_FADV_NORMAL);
return 0;
}
- /* If the old leaf was a duplicate referenced by a
- previous dinode, we can't check the number of
- pointers because the number of pointers may be for
- that other dinode's reference, not this one. */
- if (pass->check_num_ptrs && !old_was_dup &&
- valid_block(ip->i_sbd, old_leaf)) {
- error = pass->check_num_ptrs(ip, old_leaf,
- &ref_count,
- &lindex,
- &oldleaf);
- if (error) {
- free(tbl);
- return error;
- }
- }
error = check_leaf(ip, lindex, pass, &ref_count,
&leaf_no, old_leaf, &bad_leaf,
first_ok_leaf, &leaf, &oldleaf);
@@ -1687,3 +1690,144 @@ void reprocess_inode(struct gfs2_inode *ip, const char *desc)
log_err( _("Error %d reprocessing the %s metadata tree.\n"),
error, desc);
}
+
+/*
+ * write_new_leaf - allocate and write a new leaf to cover a gap in hash table
+ * @dip: the directory inode
+ * @start_lindex: where in the hash table to start writing
+ * @num_copies: number of copies of the pointer to write into hash table
+ * @before_or_after: desc. of whether this is being added before/after/etc.
+ * @bn: pointer to return the newly allocated leaf's block number
+ */
+int write_new_leaf(struct gfs2_inode *dip, int start_lindex, int num_copies,
+ const char *before_or_after, uint64_t *bn)
+{
+ struct gfs2_buffer_head *nbh;
+ struct gfs2_leaf *leaf;
+ struct gfs2_dirent *dent;
+ int count, i;
+ int factor = 0, pad_size;
+ uint64_t *cpyptr;
+ char *padbuf;
+ int divisor = num_copies;
+ int end_lindex = start_lindex + num_copies;
+
+ padbuf = malloc(num_copies * sizeof(uint64_t));
+ /* calculate the depth needed for the new leaf */
+ while (divisor > 1) {
+ factor++;
+ divisor /= 2;
+ }
+ /* Make sure the number of copies is properly a factor of 2 */
+ if ((1 << factor) != num_copies) {
+ log_err(_("Program error: num_copies not a factor of 2.\n"));
+ log_err(_("num_copies=%d, dinode = %lld (0x%llx)\n"),
+ num_copies,
+ (unsigned long long)dip->i_di.di_num.no_addr,
+ (unsigned long long)dip->i_di.di_num.no_addr);
+ log_err(_("lindex = %d (0x%x)\n"), start_lindex, start_lindex);
+ stack;
+ free(padbuf);
+ return -1;
+ }
+
+ /* allocate and write out a new leaf block */
+ *bn = meta_alloc(dip);
+ fsck_blockmap_set(dip, *bn, _("directory leaf"), gfs2_leaf_blk);
+ log_err(_("A new directory leaf was allocated at block %lld "
+ "(0x%llx) to fill the %d (0x%x) pointer gap %s the existing "
+ "pointer at index %d (0x%x).\n"), (unsigned long long)*bn,
+ (unsigned long long)*bn, num_copies, num_copies,
+ before_or_after, start_lindex, start_lindex);
+ dip->i_di.di_blocks++;
+ bmodified(dip->i_bh);
+ nbh = bget(dip->i_sbd, *bn);
+ memset(nbh->b_data, 0, dip->i_sbd->bsize);
+ leaf = (struct gfs2_leaf *)nbh->b_data;
+ leaf->lf_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
+ leaf->lf_header.mh_type = cpu_to_be32(GFS2_METATYPE_LF);
+ leaf->lf_header.mh_format = cpu_to_be32(GFS2_FORMAT_LF);
+ leaf->lf_depth = cpu_to_be16(dip->i_di.di_depth - factor);
+
+ /* initialize the first dirent on the new leaf block */
+ dent = (struct gfs2_dirent *)(nbh->b_data + sizeof(struct gfs2_leaf));
+ dent->de_rec_len = cpu_to_be16(dip->i_sbd->bsize -
+ sizeof(struct gfs2_leaf));
+ bmodified(nbh);
+ brelse(nbh);
+
+ /* pad the hash table with the new leaf block */
+ cpyptr = (uint64_t *)padbuf;
+ for (i = start_lindex; i < end_lindex; i++) {
+ *cpyptr = cpu_to_be64(*bn);
+ cpyptr++;
+ }
+ pad_size = num_copies * sizeof(uint64_t);
+ log_err(_("Writing to the hash table of directory %lld "
+ "(0x%llx) at index: 0x%x for 0x%lx pointers.\n"),
+ (unsigned long long)dip->i_di.di_num.no_addr,
+ (unsigned long long)dip->i_di.di_num.no_addr,
+ start_lindex, pad_size / sizeof(uint64_t));
+ if (dip->i_sbd->gfs1)
+ count = gfs1_writei(dip, padbuf, start_lindex *
+ sizeof(uint64_t), pad_size);
+ else
+ count = gfs2_writei(dip, padbuf, start_lindex *
+ sizeof(uint64_t), pad_size);
+ free(padbuf);
+ if (count != pad_size) {
+ log_err( _("Error: bad write while fixing directory leaf "
+ "pointers.\n"));
+ return -1;
+ }
+ return 0;
+}
+
+/* repair_leaf - Warn the user of an error and ask permission to fix it
+ * Process a bad leaf pointer and ask to repair the first time.
+ * The repair process involves extending the previous leaf's entries
+ * so that they replace the bad ones. We have to hack up the old
+ * leaf a bit, but it's better than deleting the whole directory,
+ * which is what used to happen before. */
+int repair_leaf(struct gfs2_inode *ip, uint64_t *leaf_no, int lindex,
+ int ref_count, const char *msg)
+{
+ int new_leaf_blks = 0, error, refs;
+ uint64_t bn = 0;
+
+ log_err( _("Directory Inode %llu (0x%llx) points to leaf %llu"
+ " (0x%llx) %s.\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)*leaf_no,
+ (unsigned long long)*leaf_no, msg);
+ if (!query( _("Attempt to patch around it? (y/n) "))) {
+ log_err( _("Bad leaf left in place.\n"));
+ goto out;
+ }
+ /* We can only write leafs in quantities that are factors of
+ two, since leaves are doubled, not added sequentially.
+ So if we have a hole that's not a factor of 2, we have to
+ break it down into separate leaf blocks that are. */
+ while (ref_count) {
+ refs = 1;
+ while (refs <= ref_count) {
+ if (refs * 2 > ref_count)
+ break;
+ refs *= 2;
+ }
+ error = write_new_leaf(ip, lindex, refs, _("replacing"), &bn);
+ if (error)
+ return error;
+
+ new_leaf_blks++;
+ lindex += refs;
+ ref_count -= refs;
+ }
+ log_err( _("Directory Inode %llu (0x%llx) repaired.\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr);
+out:
+ *leaf_no = bn;
+ return new_leaf_blks;
+}
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index e114427..c43baf0 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -39,6 +39,11 @@ extern struct gfs2_inode *fsck_system_inode(struct gfs2_sbd *sdp,
uint64_t block);
extern int find_remove_dup(struct gfs2_inode *ip, uint64_t block,
const char *btype);
+extern int write_new_leaf(struct gfs2_inode *dip, int start_lindex,
+ int num_copies, const char *before_or_after,
+ uint64_t *bn);
+extern int repair_leaf(struct gfs2_inode *ip, uint64_t *leaf_no, int lindex,
+ int ref_count, const char *msg);
extern int free_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
const char *btype);
@@ -95,9 +100,10 @@ struct metawalk_fxns {
int (*finish_eattr_indir) (struct gfs2_inode *ip, int leaf_pointers,
int leaf_pointer_errors, void *private);
void (*big_file_msg) (struct gfs2_inode *ip, uint64_t blks_checked);
- int (*check_num_ptrs) (struct gfs2_inode *ip, uint64_t leafno,
- int *ref_count, int *lindex,
- struct gfs2_leaf *leaf);
+ int (*check_hash_tbl) (struct gfs2_inode *ip, uint64_t *tbl,
+ unsigned hsize, void *private);
+ int (*repair_leaf) (struct gfs2_inode *ip, uint64_t *leaf_no,
+ int lindex, int ref_count, const char *msg);
};
#endif /* _METAWALK_H */
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 9a34e97..cc69e84 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -60,8 +60,6 @@ static int check_extended_leaf_eattr(struct gfs2_inode *ip, uint64_t *data_ptr,
struct gfs2_ea_header *ea_hdr,
struct gfs2_ea_header *ea_hdr_prev,
void *private);
-static int check_num_ptrs(struct gfs2_inode *ip, uint64_t leafno,
- int *ref_count, int *lindex, struct gfs2_leaf *leaf);
static int finish_eattr_indir(struct gfs2_inode *ip, int leaf_pointers,
int leaf_pointer_errors, void *private);
static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
@@ -92,7 +90,6 @@ struct metawalk_fxns pass1_fxns = {
.check_eattr_extentry = check_extended_leaf_eattr,
.finish_eattr_indir = finish_eattr_indir,
.big_file_msg = big_file_comfort,
- .check_num_ptrs = check_num_ptrs,
};
struct metawalk_fxns undo_fxns = {
@@ -204,145 +201,6 @@ struct metawalk_fxns sysdir_fxns = {
.check_dentry = resuscitate_dentry,
};
-/*
- * fix_leaf_pointers - fix a directory dinode that has a number of pointers
- * that is not a multiple of 2.
- * dip - the directory inode having the problem
- * lindex - the index of the leaf right after the problem (need to back up)
- * cur_numleafs - current (incorrect) number of instances of the leaf block
- * correct_numleafs - the correct number instances of the leaf block
- */
-static int fix_leaf_pointers(struct gfs2_inode *dip, int *lindex,
- int cur_numleafs, int correct_numleafs)
-{
- int count;
- char *ptrbuf;
- int start_lindex = *lindex - cur_numleafs; /* start of bad ptrs */
- int tot_num_ptrs = (1 << dip->i_di.di_depth) - start_lindex;
- int bufsize = tot_num_ptrs * sizeof(uint64_t);
- int off_by = cur_numleafs - correct_numleafs;
-
- ptrbuf = malloc(bufsize);
- if (!ptrbuf) {
- log_err( _("Error: Cannot allocate memory to fix the leaf "
- "pointers.\n"));
- return -1;
- }
- /* Read all the pointers, starting with the first bad one */
- count = gfs2_readi(dip, ptrbuf, start_lindex * sizeof(uint64_t),
- bufsize);
- if (count != bufsize) {
- log_err( _("Error: bad read while fixing leaf pointers.\n"));
- free(ptrbuf);
- return -1;
- }
-
- bufsize -= off_by * sizeof(uint64_t); /* We need to write fewer */
- /* Write the same pointers, but offset them so they fit within the
- smaller factor of 2. So if we have 12 pointers, write out only
- the last 8 of them. If we have 7, write the last 4, etc.
- We need to write these starting at the current lindex and adjust
- lindex accordingly. */
- if (dip->i_sbd->gfs1)
- count = gfs1_writei(dip, ptrbuf + (off_by * sizeof(uint64_t)),
- start_lindex * sizeof(uint64_t), bufsize);
- else
- count = gfs2_writei(dip, ptrbuf + (off_by * sizeof(uint64_t)),
- start_lindex * sizeof(uint64_t), bufsize);
- if (count != bufsize) {
- log_err( _("Error: bad read while fixing leaf pointers.\n"));
- free(ptrbuf);
- return -1;
- }
- /* Now zero out the hole left at the end */
- memset(ptrbuf, 0, off_by * sizeof(uint64_t));
- if (dip->i_sbd->gfs1)
- gfs1_writei(dip, ptrbuf, (start_lindex * sizeof(uint64_t)) +
- bufsize, off_by * sizeof(uint64_t));
- else
- gfs2_writei(dip, ptrbuf, (start_lindex * sizeof(uint64_t)) +
- bufsize, off_by * sizeof(uint64_t));
- free(ptrbuf);
- *lindex -= off_by; /* adjust leaf index to account for the change */
- return 0;
-}
-
-/**
- * check_num_ptrs - check a previously processed leaf's pointer count in the
- * hash table.
- *
- * The number of pointers in a directory hash table that point to any given
- * leaf block should always be a factor of two. The difference between the
- * leaf block's depth and the dinode's di_depth gives us the factor.
- * This function makes sure the leaf follows the rules properly.
- *
- * ip - pointer to the in-core inode structure
- * leafno - the leaf number we're operating on
- * ref_count - the number of pointers to this leaf we actually counted.
- * exp_count - the number of pointers to this leaf we expect based on
- * ip depth minus leaf depth.
- * lindex - leaf index number
- * leaf - the leaf structure for the leaf block to check
- */
-static int check_num_ptrs(struct gfs2_inode *ip, uint64_t leafno,
- int *ref_count, int *lindex, struct gfs2_leaf *leaf)
-{
- int factor = 0, divisor = *ref_count, multiple = 1, error = 0;
- struct gfs2_buffer_head *lbh;
- int exp_count;
-
- /* Check to see if the number of pointers we found is a power of 2.
- It needs to be and if it's not we need to fix it.*/
- while (divisor > 1) {
- factor++;
- divisor /= 2;
- multiple = multiple << 1;
- }
- if (*ref_count != multiple) {
- log_err( _("Directory #%llu (0x%llx) has an invalid number of "
- "pointers to leaf #%llu (0x%llx)\n\tFound: %u, "
- "which is not a factor of 2.\n"),
- (unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)leafno,
- (unsigned long long)leafno, *ref_count);
- if (!query( _("Attempt to fix it? (y/n) "))) {
- log_err( _("Directory inode was not fixed.\n"));
- return 1;
- }
- error = fix_leaf_pointers(ip, lindex, *ref_count, multiple);
- if (error)
- return error;
- *ref_count = multiple;
- log_err( _("Directory inode was fixed.\n"));
- }
- /* Check to see if the counted number of leaf pointers is what we
- expect based on the leaf depth. */
- exp_count = (1 << (ip->i_di.di_depth - leaf->lf_depth));
- if (*ref_count != exp_count) {
- log_err( _("Directory #%llu (0x%llx) has an incorrect number "
- "of pointers to leaf #%llu (0x%llx)\n\tFound: "
- "%u, Expected: %u\n"),
- (unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)leafno,
- (unsigned long long)leafno, *ref_count, exp_count);
- if (!query( _("Attempt to fix it? (y/n) "))) {
- log_err( _("Directory leaf was not fixed.\n"));
- return 1;
- }
- lbh = bread(ip->i_sbd, leafno);
- gfs2_leaf_in(leaf, lbh);
- log_err( _("Leaf depth was %d, changed to %d\n"),
- leaf->lf_depth, ip->i_di.di_depth - factor);
- leaf->lf_depth = ip->i_di.di_depth - factor;
- gfs2_leaf_out(leaf, lbh);
- brelse(lbh);
- log_err( _("Directory leaf was fixed.\n"));
- }
- return 0;
-}
-
static int check_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
{
struct block_count *bc = (struct block_count *) private;
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 7c0c104..01c78f3 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -15,6 +15,7 @@
#include "eattr.h"
#include "metawalk.h"
#include "link.h"
+#include "lost_n_found.h"
#include "inode_hash.h"
#define MAX_FILENAME 256
@@ -295,6 +296,11 @@ static int bad_formal_ino(struct gfs2_inode *ip, struct gfs2_dirent *dent,
return 0;
}
+static int hash_table_index(uint32_t hash, struct gfs2_inode *ip)
+{
+ return hash >> (32 - ip->i_di.di_depth);
+}
+
/* basic_dentry_checks - fundamental checks for directory entries
*
* @ip: pointer to the incode inode structure
@@ -715,6 +721,530 @@ nuke_dentry:
return 1;
}
+/* pad_with_leafblks - pad a hash table with pointers to new leaf blocks
+ *
+ * @ip: pointer to the dinode structure
+ * @tbl: pointer to the hash table in memory
+ * @lindex: index location within the hash table to pad
+ * @len: number of pointers to be padded
+ */
+static void pad_with_leafblks(struct gfs2_inode *ip, uint64_t *tbl,
+ int lindex, int len)
+{
+ int new_len, i;
+ uint32_t proper_start = lindex;
+ uint64_t new_leaf_blk;
+
+ log_err(_("Padding inode %llu (0x%llx) hash table at offset %d (0x%x) "
+ "for %d pointers.\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr, lindex, lindex,
+ len);
+ while (len) {
+ new_len = 1;
+ /* Determine the next factor of 2 down from extras. We can't
+ just write out a leaf block on a power-of-two boundary.
+ We also need to make sure it has a length that will
+ ensure a "proper start" block as well. */
+ while ((new_len << 1) <= len) {
+ /* Translation: If doubling the size of the new leaf
+ will make its start boundary wrong, we have to
+ settle for a smaller length (and iterate more). */
+ proper_start = (lindex & ~((new_len << 1) - 1));
+ if (lindex != proper_start)
+ break;
+ new_len <<= 1;
+ }
+ write_new_leaf(ip, lindex, new_len, "after", &new_leaf_blk);
+ log_err(_("New leaf block was allocated at %llu (0x%llx) for "
+ "index %d (0x%x), length %d\n"),
+ (unsigned long long)new_leaf_blk,
+ (unsigned long long)new_leaf_blk,
+ lindex, lindex, new_len);
+ fsck_blockmap_set(ip, new_leaf_blk, _("pad leaf"),
+ gfs2_leaf_blk);
+ /* Fix the hash table in memory to have the new leaf */
+ for (i = 0; i < new_len; i++)
+ tbl[lindex + i] = cpu_to_be64(new_leaf_blk);
+ len -= new_len;
+ lindex += new_len;
+ }
+}
+
+/* lost_leaf - repair a leaf block that's on the wrong directory inode
+ *
+ * If the correct index is less than the starting index, we have a problem.
+ * Since we process the index sequentially, the previous index has already
+ * been processed, fixed, and is now correct. But this leaf wants to overwrite
+ * a previously written good leaf. The only thing we can do is move all the
+ * directory entries to lost+found so we don't overwrite the good leaf. Then
+ * we need to pad the gap we leave.
+ */
+static int lost_leaf(struct gfs2_inode *ip, uint64_t *tbl, uint64_t leafno,
+ int ref_count, int lindex, struct gfs2_buffer_head *bh)
+{
+ char *filename;
+ char *bh_end = bh->b_data + ip->i_sbd->bsize;
+ struct gfs2_dirent de, *dent;
+ int error;
+
+ log_err(_("Leaf block %llu (0x%llx) seems to be out of place and its "
+ "contents need to be moved to lost+found.\n"),
+ (unsigned long long)leafno, (unsigned long long)leafno);
+ if (!query( _("Attempt to fix it? (y/n) "))) {
+ log_err( _("Directory leaf was not fixed.\n"));
+ return 0;
+ }
+ make_sure_lf_exists(ip);
+
+ dent = (struct gfs2_dirent *)(bh->b_data + sizeof(struct gfs2_leaf));
+ while (1) {
+ char tmp_name[PATH_MAX];
+
+ memset(&de, 0, sizeof(struct gfs2_dirent));
+ gfs2_dirent_in(&de, (char *)dent);
+ filename = (char *)dent + sizeof(struct gfs2_dirent);
+ memset(tmp_name, 0, sizeof(tmp_name));
+ if (de.de_name_len > sizeof(filename)) {
+ log_debug(_("Encountered bad filename length; "
+ "stopped processing.\n"));
+ break;
+ }
+ memcpy(tmp_name, filename, de.de_name_len);
+ if ((de.de_name_len == 1 && filename[0] == '.')) {
+ log_debug(_("Skipping entry '.'\n"));
+ } else if (de.de_name_len == 2 && filename[0] == '.' &&
+ filename[1] == '.') {
+ log_debug(_("Skipping entry '..'\n"));
+ } else if (!de.de_inum.no_formal_ino) { /* sentinel */
+ log_debug(_("Skipping sentinel '%s'\n"), tmp_name);
+ } else {
+ uint32_t count;
+ struct dir_status ds = {0};
+ uint8_t q = 0;
+
+ error = basic_dentry_checks(ip, dent, &de.de_inum,
+ tmp_name, &count, &de,
+ &ds, &q, bh);
+ if (error) {
+ log_err(_("Not relocating corrupt entry "
+ "\"%s\".\n"), tmp_name);
+ } else {
+ error = dir_add(lf_dip, filename,
+ de.de_name_len, &de.de_inum,
+ de.de_type);
+ if (error && error != -EEXIST) {
+ log_err(_("Error %d encountered while "
+ "trying to relocate \"%s\" "
+ "to lost+found.\n"), error,
+ tmp_name);
+ return error;
+ }
+ /* This inode is linked from lost+found */
+ incr_link_count(de.de_inum, lf_dip,
+ _("from lost+found"));
+ /* If it's a directory, lost+found is
+ back-linked to it via .. */
+ if (q == gfs2_inode_dir)
+ incr_link_count(lf_dip->i_di.di_num,
+ NULL,
+ _("to lost+found"));
+ log_err(_("Relocated \"%s\", block %llu "
+ "(0x%llx) to lost+found.\n"),
+ tmp_name,
+ (unsigned long long)de.de_inum.no_addr,
+ (unsigned long long)de.de_inum.no_addr);
+ }
+ }
+ if ((char *)dent + de.de_rec_len >= bh_end)
+ break;
+ dent = (struct gfs2_dirent *)((char *)dent + de.de_rec_len);
+ }
+ log_err(_("Directory entries from misplaced leaf block were relocated "
+ "to lost+found.\n"));
+ /* Free the lost leaf. */
+ fsck_blockmap_set(ip, leafno, _("lost leaf"), gfs2_block_free);
+ ip->i_di.di_blocks--;
+ bmodified(ip->i_bh);
+ /* Now we have to deal with the bad hash table entries pointing to the
+ misplaced leaf block. But we can't just fill the gap with a single
+ leaf. We have to write on nice power-of-two boundaries, and we have
+ to pad out any extra pointers. */
+ pad_with_leafblks(ip, tbl, lindex, ref_count);
+ return 1;
+}
+
+/* fix_hashtable - fix a corrupt hash table
+ *
+ * The main intent of this function is to sort out hash table problems.
+ * That is, it needs to determine if leaf blocks are in the wrong place,
+ * if the count of pointers is wrong, and if there are extra pointers.
+ * Everything should be placed on correct power-of-two boundaries appropriate
+ * to their leaf depth, and extra pointers should be correctly padded with new
+ * leaf blocks.
+ *
+ * @ip: the directory dinode structure pointer
+ * @tbl: hash table that's already read into memory
+ * @hsize: hash table size, as dictated by the dinode's di_depth
+ * @leafblk: the leaf block number that appears at this lindex in the tbl
+ * @lindex: leaf index that has a problem
+ * @proper_start: where this leaf's pointers should start, as far as the
+ * hash table is concerned (sight unseen; trusting the leaf
+ * really belongs here).
+ * @len: count of pointers in the hash table to this leafblk
+ * @proper_len: pointer to return the proper number of pointers, as the kernel
+ * calculates it, based on the leaf depth.
+ * @factor: the proper depth, given this number of pointers (rounded down).
+ *
+ * Returns: 0 - no changes made, or X if changes were made
+ */
+static int fix_hashtable(struct gfs2_inode *ip, uint64_t *tbl, unsigned hsize,
+ uint64_t leafblk, int lindex, uint32_t proper_start,
+ int len, int *proper_len, int factor)
+{
+ struct gfs2_buffer_head *lbh;
+ struct gfs2_leaf *leaf;
+ struct gfs2_dirent dentry, *de;
+ int changes = 0, error, i, extras, hash_index;
+ uint64_t new_leaf_blk;
+ uint32_t leaf_proper_start;
+
+ *proper_len = len;
+ log_err(_("Dinode %llu (0x%llx) has a hash table error at index "
+ "0x%x, length 0x%x: leaf block %llu (0x%llx)\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr, lindex, len,
+ (unsigned long long)leafblk, (unsigned long long)leafblk);
+ if (!query( _("Fix the hash table? (y/n) "))) {
+ log_err(_("Hash table not fixed.\n"));
+ return 0;
+ }
+
+ lbh = bread(ip->i_sbd, leafblk);
+ leaf = (struct gfs2_leaf *)lbh->b_data;
+ /* If the leaf's depth is out of range for this dinode, it's obviously
+ attached to the wrong dinode. Move the dirents to lost+found. */
+ if (be16_to_cpu(leaf->lf_depth) > ip->i_di.di_depth) {
+ log_err(_("This leaf block's depth (%d) is too big for this "
+ "dinode's depth (%d)\n"),
+ be16_to_cpu(leaf->lf_depth), ip->i_di.di_depth);
+ error = lost_leaf(ip, tbl, leafblk, len, lindex, lbh);
+ brelse(lbh);
+ return error;
+ }
+
+ memset(&dentry, 0, sizeof(struct gfs2_dirent));
+ de = (struct gfs2_dirent *)(lbh->b_data + sizeof(struct gfs2_leaf));
+ gfs2_dirent_in(&dentry, (char *)de);
+
+ /* If this is an empty leaf, we can just delete it and pad. */
+ if ((dentry.de_rec_len == cpu_to_be16(ip->i_sbd->bsize -
+ sizeof(struct gfs2_leaf))) &&
+ (dentry.de_inum.no_formal_ino == 0)) {
+ brelse(lbh);
+ gfs2_free_block(ip->i_sbd, leafblk);
+ log_err(_("Out of place leaf block %llu (0x%llx) had no "
+ "entries, so it was deleted.\n"),
+ (unsigned long long)leafblk,
+ (unsigned long long)leafblk);
+ pad_with_leafblks(ip, tbl, lindex, len);
+ log_err(_("Reprocessing index 0x%x (case 1).\n"), lindex);
+ return 1;
+ }
+
+ /* Calculate the proper number of pointers based on the leaf depth. */
+ *proper_len = 1 << (ip->i_di.di_depth - be16_to_cpu(leaf->lf_depth));
+
+ /* Look at the first dirent and check its hash value to see if it's
+ at the proper starting offset. */
+ hash_index = hash_table_index(dentry.de_hash, ip);
+ if (hash_index < lindex || hash_index > lindex + len) {
+ log_err(_("This leaf block has hash index %d, which is out of "
+ "bounds for where it appears in the hash table "
+ "(%d - %d)\n"),
+ hash_index, lindex, lindex + len);
+ error = lost_leaf(ip, tbl, leafblk, len, lindex, lbh);
+ brelse(lbh);
+ return error;
+ }
+
+ /* Now figure out where this leaf should start, and pad any pointers
+ up to that point with new leaf blocks. */
+ leaf_proper_start = (hash_index & ~(*proper_len - 1));
+ if (lindex < leaf_proper_start) {
+ log_err(_("Leaf pointers start at %d (0x%x), should be %d "
+ "(%x).\n"), lindex, lindex,
+ leaf_proper_start, leaf_proper_start);
+ pad_with_leafblks(ip, tbl, lindex, leaf_proper_start - lindex);
+ brelse(lbh);
+ return 1; /* reprocess the starting lindex */
+ }
+ /* If the proper start according to the leaf's hash index is later
+ than the proper start according to the hash table, it's once
+ again lost and we have to relocate it. The same applies if the
+ leaf's hash index is prior to the proper state, but the leaf is
+ already at its maximum depth. */
+ if ((leaf_proper_start < proper_start) ||
+ ((*proper_len > len || lindex > leaf_proper_start) &&
+ be16_to_cpu(leaf->lf_depth) == ip->i_di.di_depth)) {
+ log_err(_("Leaf block should start at 0x%x, but it appears at "
+ "0x%x in the hash table.\n"), leaf_proper_start,
+ proper_start);
+ error = lost_leaf(ip, tbl, leafblk, len, lindex, lbh);
+ brelse(lbh);
+ return error;
+ }
+
+ /* If we SHOULD have more pointers than we do, we can solve the
+ problem by splitting the block to a lower depth. Then we may have
+ the right number of pointers. If the leaf block pointers start
+ later than they should, we can split the leaf to give it a smaller
+ footprint in the hash table. */
+ if ((*proper_len > len || lindex > leaf_proper_start) &&
+ ip->i_di.di_depth > be16_to_cpu(leaf->lf_depth)) {
+ log_err(_("For depth %d, length %d, the proper start is: "
+ "0x%x.\n"), factor, len, proper_start);
+ changes++;
+ new_leaf_blk = find_free_blk(ip->i_sbd);
+ dir_split_leaf(ip, lindex, leafblk, lbh);
+ /* re-read the leaf to pick up dir_split_leaf's changes */
+ gfs2_leaf_in(leaf, lbh);
+ *proper_len = 1 << (ip->i_di.di_depth -
+ be16_to_cpu(leaf->lf_depth));
+ log_err(_("Leaf block %llu (0x%llx) was split from length "
+ "%d to %d\n"), (unsigned long long)leafblk,
+ (unsigned long long)leafblk, len, *proper_len);
+ if (*proper_len < 0) {
+ log_err(_("Programming error: proper_len=%d, "
+ "di_depth = %d, lf_depth = %d.\n"),
+ *proper_len, ip->i_di.di_depth,
+ be16_to_cpu(leaf->lf_depth));
+ exit(FSCK_ERROR);
+ }
+ log_err(_("New split-off leaf block was allocated at %lld "
+ "(0x%llx) for index %d (0x%x)\n"),
+ (unsigned long long)new_leaf_blk,
+ (unsigned long long)new_leaf_blk, lindex, lindex);
+ fsck_blockmap_set(ip, new_leaf_blk, _("split leaf"),
+ gfs2_leaf_blk);
+ log_err(_("Hash table repaired.\n"));
+ /* Fix up the hash table in memory to include the new leaf */
+ for (i = 0; i < *proper_len; i++)
+ tbl[lindex + i] = cpu_to_be64(new_leaf_blk);
+ if (*proper_len < (len >> 1)) {
+ log_err(_("One leaf split is not enough. The hash "
+ "table will need to be reprocessed.\n"));
+ brelse(lbh);
+ return changes;
+ }
+ lindex += (*proper_len); /* skip the new leaf from the split */
+ len -= (*proper_len);
+ }
+ if (*proper_len < len) {
+ log_err(_("There are %d pointers, but leaf 0x%llx's "
+ "depth, %d, only allows %d\n"),
+ len, (unsigned long long)leafblk,
+ be16_to_cpu(leaf->lf_depth), *proper_len);
+ }
+ brelse(lbh);
+ /* At this point, lindex should be at the proper end of the pointers.
+ Now we need to replace any extra duplicate pointers to the old
+ (original) leafblk (that ran off the end) with new leaf blocks. */
+ lindex += (*proper_len); /* Skip past the normal good pointers */
+ len -= (*proper_len);
+ extras = 0;
+ for (i = 0; i < len; i++) {
+ if (be64_to_cpu(tbl[lindex + i]) == leafblk)
+ extras++;
+ else
+ break;
+ }
+ if (extras) {
+ log_err(_("Found %d extra pointers to leaf %llu (0x%llx)\n"),
+ extras, (unsigned long long)leafblk,
+ (unsigned long long)leafblk);
+ pad_with_leafblks(ip, tbl, lindex, extras);
+ log_err(_("Reprocessing index 0x%x (case 2).\n"), lindex);
+ return 1;
+ }
+ return changes;
+}
+
+/* check_hash_tbl - check that the hash table is sane
+ *
+ * We've got to make sure the hash table is sane. Each leaf needs to
+ * be counted a proper power of 2. We can't just have 3 pointers to a leaf.
+ * The number of pointers must correspond to the proper leaf depth, and they
+ * must all fall on power-of-two boundaries. The leaf block pointers all need
+ * to fall properly on these boundaries, otherwise the kernel code's
+ * calculations will land it on the wrong leaf block while it's searching,
+ * and the result will be files you can see with ls, but can't open, delete
+ * or use them.
+ *
+ * The goal of this function is to check the hash table to make sure the
+ * boundaries and lengths all line up properly, and if not, to fix it.
+ *
+ * Note: There's a delicate balance here, because this function gets called
+ * BEFORE leaf blocks are checked by function check_leaf from function
+ * check_leaf_blks: the hash table has to be sane before we can start
+ * checking all the leaf blocks. And yet if there's hash table corruption
+ * we may need to reference leaf blocks to fix it, which means we need
+ * to check and/or fix a leaf block along the way.
+ */
+static int check_hash_tbl(struct gfs2_inode *ip, uint64_t *tbl,
+ unsigned hsize, void *private)
+{
+ int error = 0;
+ int lindex, len, proper_len, i, changes = 0;
+ uint64_t leafblk;
+ struct gfs2_leaf leaf;
+ struct gfs2_buffer_head *lbh;
+ int factor;
+ uint32_t proper_start;
+
+ lindex = 0;
+ while (lindex < hsize) {
+ if (fsck_abort)
+ return changes;
+ len = 1;
+ factor = 0;
+ leafblk = be64_to_cpu(tbl[lindex]);
+ while (lindex + (len << 1) - 1 < hsize) {
+ if (be64_to_cpu(tbl[lindex + (len << 1) - 1]) !=
+ leafblk)
+ break;
+ len <<= 1;
+ factor++;
+ }
+
+ /* Check for leftover pointers after the factor of two: */
+ proper_len = len; /* A factor of 2 that fits nicely */
+ while (lindex + len < hsize &&
+ be64_to_cpu(tbl[lindex + len]) == leafblk)
+ len++;
+
+ /* See if that leaf block is valid. If not, write a new one
+ that falls on a proper boundary. If it doesn't naturally,
+ we may need more. */
+ if (!valid_block(ip->i_sbd, leafblk)) {
+ uint64_t new_leafblk;
+
+ log_err(_("Dinode %llu (0x%llx) has bad leaf pointers "
+ "at offset %d for %d\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ lindex, len);
+ if (!query( _("Fix the hash table? (y/n) "))) {
+ log_err(_("Hash table not fixed.\n"));
+ lindex += len;
+ continue;
+ }
+ error = write_new_leaf(ip, lindex, proper_len,
+ _("replacing"), &new_leafblk);
+ if (error)
+ return error;
+
+ for (i = lindex; i < lindex + proper_len; i++)
+ tbl[i] = cpu_to_be64(new_leafblk);
+ lindex += proper_len;
+ continue;
+ }
+ /* Make sure they call on proper leaf-split boundaries. This
+ is the calculation used by the kernel, and dir_split_leaf */
+ proper_start = (lindex & ~(proper_len - 1));
+ if (lindex != proper_start) {
+ log_debug(_("lindex 0x%llx is not a proper starting "
+ "point for this leaf: 0x%llx\n"),
+ (unsigned long long)lindex,
+ (unsigned long long)proper_start);
+ changes = fix_hashtable(ip, tbl, hsize, leafblk,
+ lindex, proper_start, len,
+ &proper_len, factor);
+ /* Check if we need to split more leaf blocks */
+ if (changes) {
+ if (proper_len < (len >> 1))
+ log_err(_("More leaf splits are "
+ "needed; "));
+ log_err(_("Reprocessing index 0x%x (case 3).\n"),
+ lindex);
+ continue; /* Make it reprocess the lindex */
+ }
+ }
+ /* Check for extra pointers to this leaf. At this point, len
+ is the number of pointers we have. proper_len is the proper
+ number of pointers if the hash table is assumed correct.
+ Function fix_hashtable will read in the leaf block and
+ determine the "actual" proper length based on the leaf
+ depth, and adjust the hash table accordingly. */
+ if (len != proper_len) {
+ log_err(_("Length %d (0x%x) is not a proper length "
+ "for this leaf. Valid boundary assumed to "
+ "be %d (0x%x).\n"),
+ len, len, proper_len, proper_len);
+ lbh = bread(ip->i_sbd, leafblk);
+ gfs2_leaf_in(&leaf, lbh);
+ if (gfs2_check_meta(lbh, GFS2_METATYPE_LF) ||
+ leaf.lf_depth > ip->i_di.di_depth)
+ leaf.lf_depth = factor;
+ brelse(lbh);
+ changes = fix_hashtable(ip, tbl, hsize, leafblk,
+ lindex, lindex, len,
+ &proper_len, leaf.lf_depth);
+ /* If fixing the hash table made changes, we can no
+ longer count on the leaf block pointers all pointing
+ to the same leaf (which is checked below). To avoid
+ flagging another error, reprocess the offset. */
+ if (changes) {
+ log_err(_("Reprocessing index 0x%x (case 4).\n"),
+ lindex);
+ continue; /* Make it reprocess the lindex */
+ }
+ }
+
+ /* Now make sure they're all the same pointer */
+ for (i = lindex; i < lindex + proper_len; i++) {
+ if (fsck_abort)
+ return changes;
+
+ if (be64_to_cpu(tbl[i]) == leafblk) /* No problem */
+ continue;
+
+ log_err(_("Dinode %llu (0x%llx) has a hash table "
+ "inconsistency at index %d (0x%d) for %d\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ i, i, len);
+ if (!query( _("Fix the hash table? (y/n) "))) {
+ log_err(_("Hash table not fixed.\n"));
+ continue;
+ }
+ changes++;
+ /* Now we have to determine if the hash table is
+ corrupt, or if the leaf has the wrong depth. */
+ lbh = bread(ip->i_sbd, leafblk);
+ gfs2_leaf_in(&leaf, lbh);
+ brelse(lbh);
+ /* Calculate the expected pointer count based on the
+ leaf depth. */
+ proper_len = 1 << (ip->i_di.di_depth - leaf.lf_depth);
+ if (proper_len != len) {
+ log_debug(_("Length 0x%x is not proper for "
+ "this leaf: 0x%x"),
+ len, proper_len);
+ changes = fix_hashtable(ip, tbl, hsize,
+ leafblk, lindex,
+ lindex, len,
+ &proper_len,
+ leaf.lf_depth);
+ break;
+ }
+ }
+ lindex += proper_len;
+ }
+ if (!error && changes)
+ error = 1;
+ return error;
+}
struct metawalk_fxns pass2_fxns = {
.private = NULL,
@@ -725,6 +1255,8 @@ struct metawalk_fxns pass2_fxns = {
.check_eattr_leaf = check_eattr_leaf,
.check_dentry = check_dentry,
.check_eattr_entry = NULL,
+ .check_hash_tbl = check_hash_tbl,
+ .repair_leaf = repair_leaf,
};
/* Check system directory inode */
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=8c92d6111f…
Commit: 8c92d6111f9388ec48af7bd297cfd8fe87352499
Parent: afed5d57db947587e26fb9f8d3d08eccb1e01556
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Mar 6 12:15:33 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon May 20 11:12:45 2013 -0500
fsck.gfs2: Add formal inode check to basic dirent checks
This patch adds a check to the basic directory entry checks which
compares the formal inode number of the directory entry to the
formal inode number in the inode tree that was set up by pass1.
If the numbers don't match, this directory entry is corrupt.
---
gfs2/fsck/pass2.c | 20 ++++++++++++++++++++
1 files changed, 20 insertions(+), 0 deletions(-)
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 8d66ff4..7c0c104 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -315,6 +315,7 @@ static int basic_dentry_checks(struct gfs2_inode *ip, struct gfs2_dirent *dent,
uint32_t calculated_hash;
struct gfs2_inode *entry_ip = NULL;
int error;
+ struct inode_info *ii;
if (!valid_block(ip->i_sbd, entry->no_addr)) {
log_err( _("Block # referenced by directory entry %s in inode "
@@ -490,6 +491,25 @@ static int basic_dentry_checks(struct gfs2_inode *ip, struct gfs2_dirent *dent,
fsck_inode_put(&entry_ip);
return 1;
}
+ /* We need to verify the formal inode number matches. If it doesn't,
+ it needs to be deleted. */
+ ii = inodetree_find(entry->no_addr);
+ if (ii && ii->di_num.no_formal_ino != entry->no_formal_ino) {
+ log_err( _("Directory entry '%s' pointing to block %llu "
+ "(0x%llx) in directory %llu (0x%llx) has the "
+ "wrong 'formal' inode number.\n"), tmp_name,
+ (unsigned long long)entry->no_addr,
+ (unsigned long long)entry->no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr);
+ log_err( _("The directory entry has %llu (0x%llx) but the "
+ "inode has %llu (0x%llx)\n"),
+ (unsigned long long)entry->no_formal_ino,
+ (unsigned long long)entry->no_formal_ino,
+ (unsigned long long)ii->di_num.no_formal_ino,
+ (unsigned long long)ii->di_num.no_formal_ino);
+ return 1;
+ }
return 0;
}
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=824fe89669…
Commit: 824fe89669e6854b9c3d8ad94975f0801c118044
Parent: 26255a8ce1999ede7d06663e482fe974b6faaa7d
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Mar 6 10:29:38 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon May 20 11:12:45 2013 -0500
fsck.gfs2: shorten some debug messages in lost+found
This patch changes the debug output of lost+found such that it
only prints the block number in hexadecimal. This shortens the output
and makes debug output easier to read.
---
gfs2/fsck/lost_n_found.c | 12 ++++--------
1 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c
index 3d9acb5..3226ac9 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -34,11 +34,9 @@ static void add_dotdot(struct gfs2_inode *ip)
if (di && valid_block(sdp, di->dotdot_parent.no_addr)) {
struct gfs2_inode *dip;
- log_debug(_("Directory %lld (0x%llx) already had a "
- "\"..\" link to %lld (0x%llx).\n"),
+ log_debug(_("Directory (0x%llx) already had a "
+ "\"..\" link to (0x%llx).\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)di->dotdot_parent.no_addr,
(unsigned long long)di->dotdot_parent.no_addr);
dip = fsck_load_inode(sdp, di->dotdot_parent.no_addr);
if (dip->i_di.di_num.no_formal_ino ==
@@ -76,15 +74,13 @@ static void add_dotdot(struct gfs2_inode *ip)
} else {
if (di)
log_debug(_("Couldn't find a valid \"..\" entry "
- "for orphan directory %lld (0x%llx): "
+ "for orphan directory (0x%llx): "
"'..' = 0x%llx\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)di->dotdot_parent.no_addr);
else
- log_debug(_("Couldn't find directory %lld (0x%llx) "
+ log_debug(_("Couldn't find directory (0x%llx) "
"in directory tree.\n"),
- (unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
}
if (gfs2_dirent_del(ip, "..", 2))
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=b5eb47795a…
Commit: b5eb47795a7cec433ba89c0717459eb7dd39a780
Parent: 286f616cdc0c68cd30bc8a5c42a4cc8ed4a7fa28
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Mon Feb 25 10:18:55 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon May 20 11:12:45 2013 -0500
fsck.gfs2: Split out function to make sure lost+found exists
This patch extracts a section of code from the lost+found functions
and makes a new make_sure_lf_exists function that can be called
from more places.
---
gfs2/fsck/lost_n_found.c | 130 +++++++++++++++++++++++-----------------------
gfs2/fsck/lost_n_found.h | 1 +
2 files changed, 66 insertions(+), 65 deletions(-)
diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c
index 1fb5076..f379646 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -88,6 +88,70 @@ static void add_dotdot(struct gfs2_inode *ip)
}
}
+void make_sure_lf_exists(struct gfs2_inode *ip)
+{
+ uint8_t q;
+ struct dir_info *di;
+ struct gfs2_sbd *sdp = ip->i_sbd;
+ uint32_t mode;
+
+ if (lf_dip)
+ return;
+
+ log_info( _("Locating/Creating lost+found directory\n"));
+
+ /* if this is gfs1, we have to trick createi into using
+ no_formal_ino = no_addr, so we set next_inum to the
+ free block we're about to allocate. */
+ if (sdp->gfs1)
+ sdp->md.next_inum = find_free_blk(sdp);
+ mode = (sdp->gfs1 ? DT2IF(GFS_FILE_DIR) : S_IFDIR) | 0700;
+ if (sdp->gfs1)
+ lf_dip = gfs_createi(sdp->md.rooti, "lost+found", mode, 0);
+ else
+ lf_dip = createi(sdp->md.rooti, "lost+found",
+ S_IFDIR | 0700, 0);
+ if (lf_dip == NULL) {
+ log_crit(_("Error creating lost+found: %s\n"),
+ strerror(errno));
+ exit(FSCK_ERROR);
+ }
+
+ /* createi will have incremented the di_nlink link count for the root
+ directory. We must set the nlink value in the hash table to keep
+ them in sync so that pass4 can detect and fix any descrepancies. */
+ set_di_nlink(sdp->md.rooti);
+
+ q = block_type(lf_dip->i_di.di_num.no_addr);
+ if (q != gfs2_inode_dir) {
+ /* This is a new lost+found directory, so set its block type
+ and increment link counts for the directories */
+ /* FIXME: i'd feel better about this if fs_mkdir returned
+ whether it created a new directory or just found an old one,
+ and we used that instead of the block_type to run this */
+ fsck_blockmap_set(ip, lf_dip->i_di.di_num.no_addr,
+ _("lost+found dinode"), gfs2_inode_dir);
+ dirtree_insert(lf_dip->i_di.di_num);
+ /* root inode links to lost+found */
+ incr_link_count(sdp->md.rooti->i_di.di_num, lf_dip, _("root"));
+ /* lost+found link for '.' from itself */
+ incr_link_count(lf_dip->i_di.di_num, lf_dip, "\".\"");
+ /* lost+found link for '..' back to root */
+ incr_link_count(lf_dip->i_di.di_num, sdp->md.rooti, "\"..\"");
+ if (sdp->gfs1)
+ lf_dip->i_di.__pad1 = GFS_FILE_DIR;
+ }
+ log_info( _("lost+found directory is dinode %lld (0x%llx)\n"),
+ (unsigned long long)lf_dip->i_di.di_num.no_addr,
+ (unsigned long long)lf_dip->i_di.di_num.no_addr);
+ di = dirtree_find(lf_dip->i_di.di_num.no_addr);
+ if (di) {
+ log_info( _("Marking lost+found inode connected\n"));
+ di->checked = 1;
+ di = NULL;
+ }
+}
+
/* add_inode_to_lf - Add dir entry to lost+found for the inode
* @ip: inode to add to lost + found
*
@@ -102,74 +166,10 @@ int add_inode_to_lf(struct gfs2_inode *ip){
__be32 inode_type;
uint64_t lf_blocks;
struct gfs2_sbd *sdp = ip->i_sbd;
- struct dir_info *di;
int err = 0;
uint32_t mode;
- if (!lf_dip) {
- uint8_t q;
-
- log_info( _("Locating/Creating lost+found directory\n"));
-
- /* if this is gfs1, we have to trick createi into using
- no_formal_ino = no_addr, so we set next_inum to the
- free block we're about to allocate. */
- if (sdp->gfs1)
- sdp->md.next_inum = find_free_blk(sdp);
- mode = (sdp->gfs1 ? DT2IF(GFS_FILE_DIR) : S_IFDIR) | 0700;
- if (sdp->gfs1)
- lf_dip = gfs_createi(sdp->md.rooti, "lost+found",
- mode, 0);
- else
- lf_dip = createi(sdp->md.rooti, "lost+found",
- S_IFDIR | 0700, 0);
- if (lf_dip == NULL) {
- log_crit(_("Error creating lost+found: %s\n"),
- strerror(errno));
- exit(FSCK_ERROR);
- }
-
- /* createi will have incremented the di_nlink link count for
- the root directory. We must set the nlink value
- in the hash table to keep them in sync so that pass4 can
- detect and fix any descrepancies. */
- set_di_nlink(sdp->md.rooti);
-
- q = block_type(lf_dip->i_di.di_num.no_addr);
- if (q != gfs2_inode_dir) {
- /* This is a new lost+found directory, so set its
- * block type and increment link counts for
- * the directories */
- /* FIXME: i'd feel better about this if
- * fs_mkdir returned whether it created a new
- * directory or just found an old one, and we
- * used that instead of the block_type to run
- * this */
- fsck_blockmap_set(ip, lf_dip->i_di.di_num.no_addr,
- _("lost+found dinode"),
- gfs2_inode_dir);
- /* root inode links to lost+found */
- incr_link_count(sdp->md.rooti->i_di.di_num,
- lf_dip, _("root"));
- /* lost+found link for '.' from itself */
- incr_link_count(lf_dip->i_di.di_num,
- lf_dip, "\".\"");
- /* lost+found link for '..' back to root */
- incr_link_count(lf_dip->i_di.di_num, sdp->md.rooti,
- "\"..\"");
- if (sdp->gfs1)
- lf_dip->i_di.__pad1 = GFS_FILE_DIR;
- }
- log_info( _("lost+found directory is dinode %lld (0x%llx)\n"),
- (unsigned long long)lf_dip->i_di.di_num.no_addr,
- (unsigned long long)lf_dip->i_di.di_num.no_addr);
- di = dirtree_find(lf_dip->i_di.di_num.no_addr);
- if (di) {
- log_info( _("Marking lost+found inode connected\n"));
- di->checked = 1;
- di = NULL;
- }
- }
+ make_sure_lf_exists(ip);
if (ip->i_di.di_num.no_addr == lf_dip->i_di.di_num.no_addr) {
log_err( _("Trying to add lost+found to itself...skipping"));
return 0;
diff --git a/gfs2/fsck/lost_n_found.h b/gfs2/fsck/lost_n_found.h
index f28a1d9..2b76cc2 100644
--- a/gfs2/fsck/lost_n_found.h
+++ b/gfs2/fsck/lost_n_found.h
@@ -4,5 +4,6 @@
#include "libgfs2.h"
int add_inode_to_lf(struct gfs2_inode *ip);
+void make_sure_lf_exists(struct gfs2_inode *ip);
#endif /* __LOST_N_FOUND_H__ */
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=1478c07d64…
Commit: 1478c07d6490490ddb10be606760208243cb0bbd
Parent: b6fa8428884dcdc33a84bb880ee7dad85a42040c
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Sat May 18 22:36:10 2013 +0100
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Sat May 18 22:36:10 2013 +0100
gfs2l: Read from stdin by default
Instead of requiring -f - in order to read from stdin, do that by
default.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/libgfs2/gfs2l.c | 7 +++----
1 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/gfs2/libgfs2/gfs2l.c b/gfs2/libgfs2/gfs2l.c
index 9fc647a..e58c827 100644
--- a/gfs2/libgfs2/gfs2l.c
+++ b/gfs2/libgfs2/gfs2l.c
@@ -9,7 +9,7 @@ static void usage(const char *cmd)
printf("Usage: %s [options] <fs_path>\n", cmd);
printf("Available options:\n");
printf(" -h Print this help message and exit\n");
- printf(" -f <script_path> Path to script file or '-' for stdin\n");
+ printf(" -f <script_path> Path to script file or '-' for stdin (the default)\n");
printf(" -T Print a list of gfs2 structure types and exit\n");
printf(" -F <type> Print a list of fields belonging to a type and exit\n");
}
@@ -55,12 +55,11 @@ static void print_fields(const char *name)
static int getopts(int argc, char *argv[], struct cmdopts *opts)
{
int opt;
+ opts->src = stdin;
while ((opt = getopt(argc, argv, "F:f:hT")) != -1) {
switch (opt) {
case 'f':
- if (!strcmp("-", optarg)) {
- opts->src = stdin;
- } else {
+ if (strcmp("-", optarg)) {
opts->src = fopen(optarg, "r");
if (opts->src == NULL) {
perror("Failed to open source file");
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=b6fa842888…
Commit: b6fa8428884dcdc33a84bb880ee7dad85a42040c
Parent: 6e455ab187d62be0faf7f714a340fe9121f1ef28
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Sat May 18 01:28:58 2013 +0100
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Sat May 18 01:28:58 2013 +0100
gfs2l: Add options to print block types and fields
This adds a -T option which prints out the list of possible meta header
types to be used in gfs2l scripts. It also adds -F <type> which prints
a list of fields in a block type given by <type>. The fields are
prefixed by their offset in the structure.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/libgfs2/gfs2l.c | 42 +++++++++++++++++++++++++++++++++++++++++-
1 files changed, 41 insertions(+), 1 deletions(-)
diff --git a/gfs2/libgfs2/gfs2l.c b/gfs2/libgfs2/gfs2l.c
index 50ddb82..9fc647a 100644
--- a/gfs2/libgfs2/gfs2l.c
+++ b/gfs2/libgfs2/gfs2l.c
@@ -10,6 +10,8 @@ static void usage(const char *cmd)
printf("Available options:\n");
printf(" -h Print this help message and exit\n");
printf(" -f <script_path> Path to script file or '-' for stdin\n");
+ printf(" -T Print a list of gfs2 structure types and exit\n");
+ printf(" -F <type> Print a list of fields belonging to a type and exit\n");
}
struct cmdopts {
@@ -18,10 +20,42 @@ struct cmdopts {
unsigned help:1;
};
+static int metastrcmp(const void *a, const void *b)
+{
+ const struct lgfs2_metadata *m1 = *(struct lgfs2_metadata **)a;
+ const struct lgfs2_metadata *m2 = *(struct lgfs2_metadata **)b;
+ return strcmp(m1->name, m2->name);
+}
+
+static void print_structs(void)
+{
+ const struct lgfs2_metadata *mlist[lgfs2_metadata_size];
+ int i;
+ for (i = 0; i < lgfs2_metadata_size; i++)
+ mlist[i] = &lgfs2_metadata[i];
+
+ qsort(mlist, lgfs2_metadata_size, sizeof(struct lgfs2_metadata *), metastrcmp);
+ for (i = 0; i < lgfs2_metadata_size; i++)
+ if (mlist[i]->mh_type != GFS2_METATYPE_NONE)
+ printf("%s\n", mlist[i]->name);
+}
+
+static void print_fields(const char *name)
+{
+ const struct lgfs2_metadata *m = lgfs2_find_mtype_name(name, LGFS2_MD_GFS1|LGFS2_MD_GFS2);
+ if (m != NULL) {
+ const struct lgfs2_metafield *fields = m->fields;
+ const unsigned nfields = m->nfields;
+ int i;
+ for (i = 0; i < nfields; i++)
+ printf("0x%.4x %s\n", fields[i].offset, fields[i].name);
+ }
+}
+
static int getopts(int argc, char *argv[], struct cmdopts *opts)
{
int opt;
- while ((opt = getopt(argc, argv, "f:h")) != -1) {
+ while ((opt = getopt(argc, argv, "F:f:hT")) != -1) {
switch (opt) {
case 'f':
if (!strcmp("-", optarg)) {
@@ -34,6 +68,12 @@ static int getopts(int argc, char *argv[], struct cmdopts *opts)
}
}
break;
+ case 'T':
+ print_structs();
+ exit(0);
+ case 'F':
+ print_fields(optarg);
+ exit(0);
case 'h':
opts->help = 1;
return 0;
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=6e455ab187…
Commit: 6e455ab187d62be0faf7f714a340fe9121f1ef28
Parent: 6ee32886070b682b8ccb02ddeeba86b28e6b83be
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Sat May 18 00:22:06 2013 +0100
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Sat May 18 00:22:06 2013 +0100
gfs2l: Add hash comments
gfs2l now recognises # as a line comment. This was added in order to
enable writing executable scripts with "#!gfs2l -f" at the top of the
file.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
gfs2/libgfs2/lexer.l | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/gfs2/libgfs2/lexer.l b/gfs2/libgfs2/lexer.l
index 36e1c2d..7fe1aba 100644
--- a/gfs2/libgfs2/lexer.l
+++ b/gfs2/libgfs2/lexer.l
@@ -32,7 +32,9 @@ number ({decnumber}|{hexnumber})
offset \+{number}
id {letter}({letter}|{decdigit}|\.)*
string \'([^\']|\\\')*\'
-comment \/\/.*\n
+ccomment \/\/.*\n
+shcomment \#.*\n
+comment ({ccomment}|{shcomment})
whitespace [ \t\r]+
%%
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=65ddd7e852…
Commit: 65ddd7e85220b9c3a295c45cb1bb3dc175f45d3c
Parent: 0492586f1f6e0198e9cc99eb846cc14d48e4c197
Author: Andrew Price <anprice(a)redhat.com>
AuthorDate: Fri May 3 22:51:23 2013 +0100
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Fri May 17 21:56:20 2013 +0100
gfs2-utils build: Fix reporting lack of check
Make configure.ac test the correct variable to conditionally warn of the
absence of 'check'.
Signed-off-by: Andrew Price <anprice(a)redhat.com>
---
configure.ac | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/configure.ac b/configure.ac
index 6940d79..c8e52a3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -278,4 +278,4 @@ AC_CONFIG_FILES([Makefile
AC_OUTPUT
-test x"$BUILD_TESTS" = x && AC_MSG_NOTICE([package 'check' not found; unit tests will not be built])
+test x"$have_check" = "xyes" || AC_MSG_NOTICE([package 'check' not found; unit tests will not be built])
Gitweb: http://git.fedorahosted.org/git/?p=dlm.git;a=commitdiff;h=41f4121768ab49488…
Commit: 41f4121768ab4948898945007f49168acfac6c9f
Parent: 2b697668c41a12e816a153dde96dea43bb0094d9
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri May 17 11:06:12 2013 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri May 17 11:06:12 2013 -0500
man: fix dlm.conf man page
Signed-off-by: David Teigland <teigland(a)redhat.com>
---
dlm_controld/dlm.conf.5 | 10 +++++-----
1 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/dlm_controld/dlm.conf.5 b/dlm_controld/dlm.conf.5
index 95f74b9..793435a 100644
--- a/dlm_controld/dlm.conf.5
+++ b/dlm_controld/dlm.conf.5
@@ -349,15 +349,15 @@ Example of nodeid 1 as master of all resources:
lockspace foo nodir=1
.br
-master node=1
+master foo node=1
Example of nodeid's 1 and 2 as masters of all resources:
lockspace foo nodir=1
.br
-master node=1
+master foo node=1
.br
-master node=2
+master foo node=2
Lock management will be partitioned among the available masters. There
can be any number of masters defined. The designated master nodes will
@@ -376,9 +376,9 @@ can also be assigned to master nodes, e.g.
lockspace foo nodir=1
.br
-master node=1 weight=2
+master foo node=1 weight=2
.br
-master node=2 weight=1
+master foo node=2 weight=1
In which case node 1 will master 2/3 of the total resources and node 2
will master the other 1/3.
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=0492586f1f…
Commit: 0492586f1f6e0198e9cc99eb846cc14d48e4c197
Parent: dfa6d76b29dcc48c20ebada3ad9f57598b72f490
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue May 14 13:50:38 2013 -0400
Committer: Andrew Price <anprice(a)redhat.com>
CommitterDate: Wed May 15 10:45:24 2013 +0100
gfs2: add native setup to man page
List the simplest sequence of steps to manually
set up and run gfs2/dlm.
Signed-off-by: David Teigland <teigland(a)redhat.com>
---
gfs2/man/gfs2.5 | 187 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 187 insertions(+), 0 deletions(-)
diff --git a/gfs2/man/gfs2.5 b/gfs2/man/gfs2.5
index 25effdd..0517944 100644
--- a/gfs2/man/gfs2.5
+++ b/gfs2/man/gfs2.5
@@ -196,3 +196,190 @@ The GFS2 documentation has been split into a number of sections:
\fBgfs2_tool\fP(8) Tool to manipulate a GFS2 file system (obsolete)
\fBtunegfs2\fP(8) Tool to manipulate GFS2 superblocks
+.SH SETUP
+
+GFS2 clustering is driven by the dlm, which depends on dlm_controld to
+provide clustering from userspace. dlm_controld clustering is built on
+corosync cluster/group membership and messaging.
+
+Follow these steps to manually configure and run gfs2/dlm/corosync.
+
+.B 1. create /etc/corosync/corosync.conf and copy to all nodes
+
+In this sample, replace cluster_name and IP addresses, and add nodes as
+needed. If using only two nodes, uncomment the two_node line.
+See corosync.conf(5) for more information.
+
+.nf
+totem {
+ version: 2
+ secauth: off
+ cluster_name: abc
+}
+
+nodelist {
+ node {
+ ring0_addr: 10.10.10.1
+ nodeid: 1
+ }
+ node {
+ ring0_addr: 10.10.10.2
+ nodeid: 2
+ }
+ node {
+ ring0_addr: 10.10.10.3
+ nodeid: 3
+ }
+}
+
+quorum {
+ provider: corosync_votequorum
+# two_node: 1
+}
+
+logging {
+ to_syslog: yes
+}
+.fi
+
+.PP
+
+.B 2. start corosync on all nodes
+
+.nf
+systemctl start corosync
+.fi
+
+Run corosync-quorumtool to verify that all nodes are listed.
+
+.PP
+
+.B 3. create /etc/dlm/dlm.conf and copy to all nodes
+
+.B *
+To use no fencing, use this line:
+
+.nf
+enable_fencing=0
+.fi
+
+.B *
+To use no fencing, but exercise fencing functions, use this line:
+
+.nf
+fence_all /bin/true
+.fi
+
+The "true" binary will be executed for all nodes and will succeed (exit 0)
+immediately.
+
+.B *
+To use manual fencing, use this line:
+
+.nf
+fence_all /bin/false
+.fi
+
+The "false" binary will be executed for all nodes and will fail (exit 1)
+immediately.
+
+When a node fails, manually run: dlm_tool fence_ack <nodeid>
+
+.B *
+To use stonith/pacemaker for fencing, use this line:
+
+.nf
+fence_all /usr/sbin/dlm_stonith
+.fi
+
+The "dlm_stonith" binary will be executed for all nodes. If
+stonith/pacemaker systems are not available, dlm_stonith will fail and
+this config becomes the equivalent of the previous /bin/false config.
+
+.B *
+To use an APC power switch, use these lines:
+
+.nf
+device apc /usr/sbin/fence_apc ipaddr=1.1.1.1 login=admin password=pw
+connect apc node=1 port=1
+connect apc node=2 port=2
+connect apc node=3 port=3
+.fi
+
+Other network switch based agents are configured similarly.
+
+.B *
+To use sanlock/watchdog fencing, use these lines:
+
+.nf
+device wd /usr/sbin/fence_sanlock path=/dev/fence/leases
+connect wd node=1 host_id=1
+connect wd node=2 host_id=2
+unfence wd
+.fi
+
+See fence_sanlock(8) for more information.
+
+.B *
+For other fencing configurations see dlm.conf(5) man page.
+
+.PP
+
+.B 4. start dlm_controld on all nodes
+
+.nf
+systemctl start dlm
+.fi
+
+Run "dlm_tool status" to verify that all nodes are listed.
+
+.PP
+
+.B 5. if using clvm, start clvmd on all nodes
+
+systemctl clvmd start
+
+.PP
+
+.B 6. make new gfs2 file systems
+
+mkfs.gfs2 -p lock_dlm -t cluster_name:fs_name -j num /path/to/storage
+
+The cluster_name must match the name used in step 1 above.
+The fs_name must be a unique name in the cluster.
+The -j option is the number of journals to create, there must
+be one for each node that will mount the fs.
+
+.PP
+
+.B 7. mount gfs2 file systems
+
+mount /path/to/storage /mountpoint
+
+Run "dlm_tool ls" to verify the nodes that have each fs mounted.
+
+.PP
+
+.B 8. shut down
+
+.nf
+umount -a -t gfs2
+systemctl clvmd stop
+systemctl dlm stop
+systemctl corosync stop
+.fi
+
+.PP
+
+.B More setup information:
+.br
+.BR dlm_controld (8),
+.br
+.BR dlm_tool (8),
+.br
+.BR dlm.conf (5),
+.br
+.BR corosync (8),
+.br
+.BR corosync.conf (5)
+.br