cluster: RHEL56 - fsck.gfs2 deletes directories if they get too big
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 52b6962e42c46f4344bd94dbd7911a73e6005246
Parent: e8cc459b6ac847c1dd92a17ce833b74e46228ab0
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Aug 17 13:55:49 2010 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Wed Aug 18 09:20:08 2010 -0500
fsck.gfs2 deletes directories if they get too big
This patch fixes a problem whereby too many levels of
indirection caused fsck.gfs2 to get confused and delete
directories. The problem was that gfs2.fsck only understood
three levels of data for directories: (1) dinode, (2) block
pointers to leaf blocks, (3) leaf blocks. If a directory
gets sufficiently big, it goes into four or more levels of
indirection, with level 2 (and possibly more) being indirect
blocks leading to the leaf blocks.
rhbz#624689
---
gfs2/fsck/metawalk.c | 45 ++++++++++++++++++++++-----------------------
gfs2/fsck/metawalk.h | 5 +++--
gfs2/fsck/pass1.c | 40 +++++++++++++++++++++++-----------------
gfs2/fsck/pass1b.c | 15 ++++++++-------
4 files changed, 56 insertions(+), 49 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 09305da..330dace 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1138,7 +1138,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
uint32_t height = ip->i_di.di_height;
struct gfs2_buffer_head *bh, *nbh, *metabh = ip->i_bh;
osi_list_t *prev_list, *cur_list, *tmp;
- int i, head_size, iblk_type;
+ int h, head_size, iblk_type;
uint64_t *ptr, block;
int error = 0, err;
@@ -1149,35 +1149,34 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
because it checks everything through the hash table using
"depth" field calculations. However, we still have to check the
indirect blocks, even if the height == 1. */
- if (S_ISDIR(ip->i_di.di_mode)) {
+ if (S_ISDIR(ip->i_di.di_mode))
height++;
- iblk_type = GFS2_METATYPE_JD;
- } else {
- iblk_type = GFS2_METATYPE_IN;
- }
/* if(<there are no indirect blocks to check>) */
if (height < 2)
return 0;
- for (i = 1; i < height; i++) {
- prev_list = &mlp[i - 1];
- cur_list = &mlp[i];
+ for (h = 1; h < height; h++) {
+ if (h > 1) {
+ if (S_ISDIR(ip->i_di.di_mode) &&
+ h == ip->i_di.di_height + 1)
+ iblk_type = GFS2_METATYPE_JD;
+ else
+ iblk_type = GFS2_METATYPE_IN;
+ head_size = sizeof(struct gfs2_meta_header);
+ } else {
+ iblk_type = GFS2_METATYPE_DI;
+ head_size = sizeof(struct gfs2_dinode);
+ }
+ prev_list = &mlp[h - 1];
+ cur_list = &mlp[h];
for (tmp = prev_list->next; tmp != prev_list; tmp = tmp->next){
bh = osi_list_entry(tmp, struct gfs2_buffer_head,
b_altlist);
- if (i > 1) {
- /* if this isn't really a block list skip it */
- if (gfs2_check_meta(bh, iblk_type))
- continue;
- head_size = sizeof(struct gfs2_meta_header);
- } else {
- /* if this isn't really a dinode, skip it */
- if (gfs2_check_meta(bh, GFS2_METATYPE_DI))
- continue;
- head_size = sizeof(struct gfs2_dinode);
- }
+ if (gfs2_check_meta(bh, iblk_type))
+ continue;
+
/* Now check the metadata itself */
for (ptr = (uint64_t *)(bh->b_data + head_size);
(char *)ptr < (bh->b_data + ip->i_sbd->bsize);
@@ -1190,7 +1189,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
continue;
block = be64_to_cpu(*ptr);
- err = pass->check_metalist(ip, block, &nbh,
+ err = pass->check_metalist(ip, block, &nbh, h,
pass->private);
/* check_metalist should hold any buffers
it gets with "bread". */
@@ -1472,7 +1471,7 @@ int remove_dentry_from_dir(struct gfs2_sbd *sbp, uint64_t dir,
}
int delete_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
return delete_block_if_notdup(ip, block, bh, _("metadata"), private);
}
@@ -1504,7 +1503,7 @@ int delete_eattr_leaf(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
}
static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
uint8_t q;
const char *desc = (const char *)private;
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index 3ea2991..4489c60 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -31,7 +31,7 @@ extern int delete_block(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, const char *btype,
void *private);
extern int delete_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h, void *private);
extern int delete_leaf(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
extern int delete_data(struct gfs2_inode *ip, uint64_t block, void *private);
@@ -74,7 +74,8 @@ struct metawalk_fxns {
int (*check_leaf) (struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
int (*check_metalist) (struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h,
+ void *private);
int (*check_data) (struct gfs2_inode *ip, uint64_t block,
void *private);
int (*check_eattr_indir) (struct gfs2_inode *ip, uint64_t block,
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index bea0ef5..5f18818 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -50,9 +50,10 @@ struct block_count {
static int leaf(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h, void *private);
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h,
+ void *private);
static int check_data(struct gfs2_inode *ip, uint64_t block, void *private);
static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
void *private);
@@ -75,7 +76,8 @@ static int check_extended_leaf_eattr(struct gfs2_inode *ip, uint64_t *data_ptr,
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,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h,
+ void *private);
static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
static int invalidate_data(struct gfs2_inode *ip, uint64_t block,
@@ -126,7 +128,8 @@ struct metawalk_fxns invalidate_fxns = {
* deleted, do you? Or worse, reused for lost+found.
*/
static int resuscitate_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
struct block_count *bc = (struct block_count *)private;
@@ -220,7 +223,7 @@ static int leaf(struct gfs2_inode *ip, uint64_t block,
}
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
uint8_t q;
int found_dup = 0, iblk_type;
@@ -240,7 +243,7 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
return 1;
}
- if (S_ISDIR(ip->i_di.di_mode)) {
+ if (S_ISDIR(ip->i_di.di_mode) && h == ip->i_di.di_height) {
iblk_type = GFS2_METATYPE_JD;
blktypedesc = _("a directory hash table block");
} else {
@@ -263,13 +266,13 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
nbh = bread(ip->i_sbd, block);
if (gfs2_check_meta(nbh, iblk_type)){
- log_debug( _("Inode %lld (0x%llx) has a bad indirect block "
- "pointer %lld (0x%llx) (points to something "
- "that is not %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)block,
- (unsigned long long)block, blktypedesc);
+ log_err( _("Inode %lld (0x%llx) has a bad indirect block "
+ "pointer %lld (0x%llx) (points to something "
+ "that is not %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)block,
+ (unsigned long long)block, blktypedesc);
if(!found_dup) {
fsck_blockmap_set(ip, block, _("bad indirect"),
gfs2_meta_inval);
@@ -291,7 +294,8 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
}
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
struct duptree *d;
int found_dup = 0, iblk_type;
@@ -305,7 +309,7 @@ static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
_("itself"), gfs2_block_free);
return 1;
}
- if (S_ISDIR(ip->i_di.di_mode))
+ if (S_ISDIR(ip->i_di.di_mode) && h == ip->i_di.di_height)
iblk_type = GFS2_METATYPE_JD;
else
iblk_type = GFS2_METATYPE_IN;
@@ -849,7 +853,8 @@ static int mark_block_invalid(struct gfs2_inode *ip, uint64_t block,
}
static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
return mark_block_invalid(ip, block, ref_as_meta, _("metadata"));
}
@@ -930,7 +935,8 @@ static int rangecheck_block(struct gfs2_inode *ip, uint64_t block,
}
static int rangecheck_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
return rangecheck_block(ip, block, bh, _("metadata"), private);
}
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 8b67573..a0c5c88 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -42,7 +42,7 @@ struct dup_handler {
};
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h, void *private);
static int check_data(struct gfs2_inode *ip, uint64_t block, void *private);
static int check_eattr_indir(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct gfs2_buffer_head **bh,
@@ -89,7 +89,7 @@ struct metawalk_fxns find_dirents = {
};
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
return add_duplicate_ref(ip, block, ref_as_meta, 1, INODE_VALID);
}
@@ -213,7 +213,8 @@ static int find_dentry(struct gfs2_inode *ip, struct gfs2_dirent *de,
}
static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
struct dup_handler *dh = (struct dup_handler *) private;
struct duptree *d;
@@ -262,21 +263,21 @@ static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
static int clear_dup_data(struct gfs2_inode *ip, uint64_t block, void *private)
{
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
static int clear_dup_eattr_indir(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct gfs2_buffer_head **bh,
void *private)
{
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
static int clear_dup_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct gfs2_buffer_head **bh,
void *private)
{
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
static int clear_eattr_entry (struct gfs2_inode *ip,
@@ -329,7 +330,7 @@ static int clear_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
{
uint64_t block = be64_to_cpu(*ea_data_ptr);
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
/* Finds all references to duplicate blocks in the metadata */
13 years, 8 months
cluster: RHEL6 - fenced: use post_join_delay after cluster join
by David Teigland
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: d8a76837ecd24a5f7ab9a2ebf72745e6c6752c0b
Parent: 6bcd9db82232332f40667a6dd409829f7c15a1a0
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Aug 17 16:42:30 2010 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Aug 17 16:42:30 2010 -0500
fenced: use post_join_delay after cluster join
When the cluster has lost quorum due to a node failure,
the next event is generally a cluster node join which
gives the cluster quorum again. With quorum, fenced
begins fencing any failed nodes, applying post_fail_delay
since the last cpg event was a node failure. In this
case, however, post_join_delay is more appropriate since
the chances are good that nodes being fenced will be joining.
Detect this case where a node joins the cluster giving it
quorum, and use post_join_delay.
bz 624844
Signed-off-by: David Teigland <teigland(a)redhat.com>
---
fence/fenced/fd.h | 1 +
fence/fenced/main.c | 1 +
fence/fenced/member_cman.c | 12 ++++++++++++
fence/fenced/recover.c | 5 ++++-
4 files changed, 18 insertions(+), 1 deletions(-)
diff --git a/fence/fenced/fd.h b/fence/fenced/fd.h
index 39a34ad..a5a78bf 100644
--- a/fence/fenced/fd.h
+++ b/fence/fenced/fd.h
@@ -64,6 +64,7 @@ extern int daemon_quit;
extern int cluster_down;
extern struct list_head domains;
extern int cluster_quorate;
+extern int cluster_quorate_from_last_update;
extern uint32_t cluster_ringid_seq;
extern uint64_t quorate_time;
extern int our_nodeid;
diff --git a/fence/fenced/main.c b/fence/fenced/main.c
index a371dc8..e5ab568 100644
--- a/fence/fenced/main.c
+++ b/fence/fenced/main.c
@@ -1069,6 +1069,7 @@ int daemon_quit;
int cluster_down;
struct list_head domains;
int cluster_quorate;
+int cluster_quorate_from_last_update;
uint32_t cluster_ringid_seq;
uint64_t quorate_time;
int our_nodeid;
diff --git a/fence/fenced/member_cman.c b/fence/fenced/member_cman.c
index b9d8341..0919b8e 100644
--- a/fence/fenced/member_cman.c
+++ b/fence/fenced/member_cman.c
@@ -150,6 +150,7 @@ static void update_cluster(void)
{
cman_cluster_t info;
int quorate = cluster_quorate;
+ int removed = 0, added = 0;
int i, rv;
rv = cman_get_cluster(ch, &info);
@@ -183,6 +184,7 @@ static void update_cluster(void)
old_nodes[i].cn_nodeid, cluster_ringid_seq);
node_history_cluster_remove(old_nodes[i].cn_nodeid);
+ removed++;
}
}
@@ -194,8 +196,18 @@ static void update_cluster(void)
cman_nodes[i].cn_nodeid, cluster_ringid_seq);
node_history_cluster_add(cman_nodes[i].cn_nodeid);
+ added++;
}
}
+
+ if (removed) {
+ cluster_quorate_from_last_update = 0;
+ } else if (added) {
+ if (!quorate && cluster_quorate)
+ cluster_quorate_from_last_update = 1;
+ else
+ cluster_quorate_from_last_update = 0;
+ }
}
/* Note: in fence delay loop we aren't processing callbacks so won't
diff --git a/fence/fenced/recover.c b/fence/fenced/recover.c
index d3bf35f..a7ca047 100644
--- a/fence/fenced/recover.c
+++ b/fence/fenced/recover.c
@@ -181,7 +181,7 @@ void delay_fencing(struct fd *fd, int node_join)
if (list_empty(&fd->victims))
return;
- if (node_join) {
+ if (node_join || cluster_quorate_from_last_update) {
delay = cfgd_post_join_delay;
delay_type = "post_join_delay";
} else {
@@ -189,6 +189,9 @@ void delay_fencing(struct fd *fd, int node_join)
delay_type = "post_fail_delay";
}
+ log_debug("delay %s %d quorate_from_last_update %d",
+ delay_type, delay, cluster_quorate_from_last_update);
+
if (delay == 0)
goto out;
13 years, 8 months
cluster: RHEL56 - gfs_controld: fix plock owner in unmount
by David Teigland
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: e8cc459b6ac847c1dd92a17ce833b74e46228ab0
Parent: 4010dd2e3ffaa95630b74a889737aa6eef37d50e
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Aug 16 16:20:10 2010 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Aug 17 14:52:39 2010 -0500
gfs_controld: fix plock owner in unmount
When a node owns any plock resources on a file system and that
fs is unmounted, the remaining nodes do nothing to change the
owner value on those resources. Any process that attempts to
access those plock resources will become stuck and require a
reboot. The fix is to change the owner to 0 (unowned) on any
resources owned by a node that unmounts.
bz 624554
Signed-off-by: David Teigland <teigland(a)redhat.com>
---
group/gfs_controld/lock_dlm.h | 1 +
group/gfs_controld/plock.c | 31 +++++++++++++++++++++++++++++++
group/gfs_controld/recover.c | 9 +++++++++
3 files changed, 41 insertions(+), 0 deletions(-)
diff --git a/group/gfs_controld/lock_dlm.h b/group/gfs_controld/lock_dlm.h
index cc12e1c..0a15fe1 100644
--- a/group/gfs_controld/lock_dlm.h
+++ b/group/gfs_controld/lock_dlm.h
@@ -314,6 +314,7 @@ void retrieve_plocks(struct mountgroup *mg);
int dump_plocks(char *name, int fd);
void process_saved_plocks(struct mountgroup *mg);
void purge_plocks(struct mountgroup *mg, int nodeid, int unmount);
+void remove_resource_owner(struct mountgroup *mg, int nodeid);
int unlink_checkpoint(struct mountgroup *mg);
void update_dmsetup_wait(void);
diff --git a/group/gfs_controld/plock.c b/group/gfs_controld/plock.c
index 0d8c82d..4330a2c 100644
--- a/group/gfs_controld/plock.c
+++ b/group/gfs_controld/plock.c
@@ -2365,6 +2365,37 @@ void purge_plocks(struct mountgroup *mg, int nodeid, int unmount)
unlink_checkpoint(mg);
}
+/* when a node unmounts we need to remove it as the owner of any resources */
+
+void remove_resource_owner(struct mountgroup *mg, int nodeid)
+{
+ struct resource *r, *r2;
+ int rem = 0;
+
+ if (!config_plock_ownership)
+ return;
+
+ list_for_each_entry_safe(r, r2, &mg->resources, list) {
+ if (r->owner == nodeid) {
+ log_plock(mg, "rem owner %d from %llu",
+ nodeid, (unsigned long long)r->number);
+ r->owner = 0;
+ r->flags |= R_GOT_UNOWN;
+ rem++;
+
+ /* should probably wait to do this until after
+ the finish barrier when we know everyone has
+ changed owner to 0 */
+ send_pending_plocks(mg, r);
+ }
+ }
+
+ if (rem)
+ mg->last_plock_time = time(NULL);
+
+ log_group(mg, "removed owner %d from %d resources", nodeid, rem);
+}
+
int dump_plocks(char *name, int fd)
{
struct mountgroup *mg;
diff --git a/group/gfs_controld/recover.c b/group/gfs_controld/recover.c
index 931b357..597516c 100644
--- a/group/gfs_controld/recover.c
+++ b/group/gfs_controld/recover.c
@@ -2576,6 +2576,14 @@ void reset_unfinished_recoveries(struct mountgroup *mg)
}
}
+void reset_plock_resources(struct mountgroup *mg)
+{
+ struct mg_member *memb;
+
+ list_for_each_entry(memb, &mg->members_gone, list)
+ remove_resource_owner(mg, memb->nodeid);
+}
+
/*
old method:
A is rw mount, B mounts rw
@@ -2623,6 +2631,7 @@ void do_start(struct mountgroup *mg, int type, int member_count, int *nodeids)
recover_members(mg, member_count, nodeids, &pos, &neg);
reset_unfinished_recoveries(mg);
+ reset_plock_resources(mg);
if (mg->init) {
if (member_count == 1)
13 years, 8 months
cluster: RHEL56 - gfs_controld: fix plock owner syncing
by David Teigland
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 4010dd2e3ffaa95630b74a889737aa6eef37d50e
Parent: 0fc5da5fdc190ed50e94640136fea177a900ea57
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Aug 13 15:59:59 2010 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Aug 17 14:52:39 2010 -0500
gfs_controld: fix plock owner syncing
- The R_GOT_UNOWN flag was not always being set on resources when
the owner was set to 0. This would cause subsequent syncing of
plock state to write the incorrect owner into the checkpoint.
bz 624156
Signed-off-by: David Teigland <teigland(a)redhat.com>
---
group/gfs_controld/plock.c | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/group/gfs_controld/plock.c b/group/gfs_controld/plock.c
index 1b9120d..0d8c82d 100644
--- a/group/gfs_controld/plock.c
+++ b/group/gfs_controld/plock.c
@@ -1857,10 +1857,13 @@ static int unpack_section_buf(struct mountgroup *mg, char *numbuf, int buflen)
INIT_LIST_HEAD(&r->waiters);
INIT_LIST_HEAD(&r->pending);
- if (config_plock_ownership)
+ if (config_plock_ownership) {
sscanf(numbuf, "r%llu.%d", &num, &owner);
- else
+ if (!owner)
+ r->flags |= R_GOT_UNOWN;
+ } else {
sscanf(numbuf, "r%llu", &num);
+ }
r->number = num;
r->owner = owner;
@@ -2335,6 +2338,7 @@ void purge_plocks(struct mountgroup *mg, int nodeid, int unmount)
if (r->owner == nodeid) {
r->owner = 0;
+ r->flags |= R_GOT_UNOWN;
send_pending_plocks(mg, r);
}
13 years, 8 months
cluster: RHEL56 - fenced: use post_join_delay after cluster join
by David Teigland
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 0fc5da5fdc190ed50e94640136fea177a900ea57
Parent: c5311da33ef0b2558f3a75d1a9ab763e8ac8d365
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu Aug 5 17:05:26 2010 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Aug 17 14:51:40 2010 -0500
fenced: use post_join_delay after cluster join
When the cluster has lost quorum due to a node failure,
the next event is generally a cluster node join which
gives the cluster quorum again. With quorum, fenced
begins fencing any failed nodes, applying post_fail_delay
since the last cpg event was a node failure. In this
case, however, post_join_delay is more appropriate since
the chances are good that nodes being fenced will be joining.
Detect this case where a node joins the cluster giving it
quorum, and use post_join_delay.
bz 575952
Signed-off-by: David Teigland <teigland(a)redhat.com>
---
fence/fenced/member_cman.c | 70 ++++++++++++++++++++++++++++++++++++++++++--
fence/fenced/recover.c | 6 +++-
2 files changed, 72 insertions(+), 4 deletions(-)
diff --git a/fence/fenced/member_cman.c b/fence/fenced/member_cman.c
index 9e22ece..6ef74c3 100644
--- a/fence/fenced/member_cman.c
+++ b/fence/fenced/member_cman.c
@@ -17,9 +17,14 @@
#define BUFLEN 128
static cman_handle_t ch;
-static int cman_quorate;
+static cman_node_t old_nodes[MAX_NODES];
+static int old_node_count;
+static int old_quorate;
static cman_node_t cman_nodes[MAX_NODES];
static int cman_node_count;
+static int cman_quorate;
+int cman_quorate_from_last_change;
+
static char name_buf[CMAN_MAX_NODENAME_LEN+1];
extern struct list_head domains;
@@ -27,6 +32,26 @@ extern struct list_head domains;
char *our_name;
int our_nodeid;
+static int _is_member(cman_node_t *node_list, int count, int nodeid)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (node_list[i].cn_nodeid == nodeid)
+ return node_list[i].cn_member;
+ }
+ return 0;
+}
+
+static int is_old_member(int nodeid)
+{
+ return _is_member(old_nodes, old_node_count, nodeid);
+}
+
+static int is_cman_member(int nodeid)
+{
+ return _is_member(cman_nodes, cman_node_count, nodeid);
+}
static int name_equal(char *name1, char *name2)
{
@@ -89,15 +114,54 @@ static cman_node_t *find_cluster_node_name(char *name)
static void statechange(void)
{
- int rv;
+ int i, rv;
+ int removed = 0, added = 0;
+
+ old_quorate = cman_quorate;
+ old_node_count = cman_node_count;
+ memcpy(&old_nodes, &cman_nodes, sizeof(old_nodes));
cman_quorate = cman_is_quorate(ch);
cman_node_count = 0;
memset(&cman_nodes, 0, sizeof(cman_nodes));
-
rv = cman_get_nodes(ch, MAX_NODES, &cman_node_count, cman_nodes);
if (rv < 0)
log_error("cman_get_nodes error %d %d", rv, errno);
+
+ /* Never allow node ID 0 to be considered a member #315711 */
+ for (i = 0; i < cman_node_count; i++) {
+ if (cman_nodes[i].cn_nodeid == 0) {
+ cman_nodes[i].cn_member = 0;
+ break;
+ }
+ }
+
+ for (i = 0; i < old_node_count; i++) {
+ if (old_nodes[i].cn_member &&
+ !is_cman_member(old_nodes[i].cn_nodeid)) {
+ removed++;
+ log_debug("cman: node %d removed",
+ old_nodes[i].cn_nodeid);
+ }
+ }
+
+ for (i = 0; i < cman_node_count; i++) {
+ if (cman_nodes[i].cn_member &&
+ !is_old_member(cman_nodes[i].cn_nodeid)) {
+ added++;
+ log_debug("cman: node %d added",
+ cman_nodes[i].cn_nodeid);
+ }
+ }
+
+ if (removed) {
+ cman_quorate_from_last_change = 0;
+ } else if (added) {
+ if (!old_quorate && cman_quorate)
+ cman_quorate_from_last_change = 1;
+ else
+ cman_quorate_from_last_change = 0;
+ }
}
static void cman_callback(cman_handle_t h, void *private, int reason, int arg)
diff --git a/fence/fenced/recover.c b/fence/fenced/recover.c
index 7f8aace..732ec81 100644
--- a/fence/fenced/recover.c
+++ b/fence/fenced/recover.c
@@ -18,6 +18,7 @@
extern int our_nodeid;
extern commandline_t comline;
+extern int cman_quorate_from_last_change;
/* Fencing recovery algorithm
@@ -302,7 +303,7 @@ static void delay_fencing(fd_t *fd, int start_type)
fd_node_t *node;
char *delay_type;
- if (start_type == GROUP_NODE_JOIN) {
+ if ((start_type == GROUP_NODE_JOIN) || cman_quorate_from_last_change) {
delay = comline.post_join_delay;
delay_type = "post_join_delay";
} else {
@@ -310,6 +311,9 @@ static void delay_fencing(fd_t *fd, int start_type)
delay_type = "post_fail_delay";
}
+ log_debug("delay_fencing %s %d quorate_from_last_change %d",
+ delay_type, delay, cman_quorate_from_last_change);
+
if (delay == 0)
goto out;
13 years, 8 months
cluster: RHEL60 - fsck.gfs2 deletes directories if they get too big
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 6a73e92beebf62fe1a1da1284dcd56a028e4662f
Parent: ba3ddbcd0a1123350774e75ac1845c4fae61f697
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Aug 17 12:26:47 2010 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Aug 17 12:40:38 2010 -0500
fsck.gfs2 deletes directories if they get too big
This patch fixes a problem whereby too many levels of
indirection caused fsck.gfs2 to get confused and delete
directories. The problem was that gfs2.fsck only understood
three levels of data for directories: (1) dinode, (2) block
pointers to leaf blocks, (3) leaf blocks. If a directory
gets sufficiently big, it goes into four or more levels of
indirection, with level 2 (and possibly more) being indirect
blocks leading to the leaf blocks.
rhbz#624691
---
gfs2/fsck/metawalk.c | 45 ++++++++++++++++++++++-----------------------
gfs2/fsck/metawalk.h | 5 +++--
gfs2/fsck/pass1.c | 40 +++++++++++++++++++++++-----------------
gfs2/fsck/pass1b.c | 15 ++++++++-------
4 files changed, 56 insertions(+), 49 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 0ab8d7e..ef1b6b5 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1125,7 +1125,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
uint32_t height = ip->i_di.di_height;
struct gfs2_buffer_head *bh, *nbh, *metabh = ip->i_bh;
osi_list_t *prev_list, *cur_list, *tmp;
- int i, head_size, iblk_type;
+ int h, head_size, iblk_type;
uint64_t *ptr, block;
int error = 0, err;
@@ -1136,35 +1136,34 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
because it checks everything through the hash table using
"depth" field calculations. However, we still have to check the
indirect blocks, even if the height == 1. */
- if (S_ISDIR(ip->i_di.di_mode)) {
+ if (S_ISDIR(ip->i_di.di_mode))
height++;
- iblk_type = GFS2_METATYPE_JD;
- } else {
- iblk_type = GFS2_METATYPE_IN;
- }
/* if(<there are no indirect blocks to check>) */
if (height < 2)
return 0;
- for (i = 1; i < height; i++) {
- prev_list = &mlp[i - 1];
- cur_list = &mlp[i];
+ for (h = 1; h < height; h++) {
+ if (h > 1) {
+ if (S_ISDIR(ip->i_di.di_mode) &&
+ h == ip->i_di.di_height + 1)
+ iblk_type = GFS2_METATYPE_JD;
+ else
+ iblk_type = GFS2_METATYPE_IN;
+ head_size = sizeof(struct gfs2_meta_header);
+ } else {
+ iblk_type = GFS2_METATYPE_DI;
+ head_size = sizeof(struct gfs2_dinode);
+ }
+ prev_list = &mlp[h - 1];
+ cur_list = &mlp[h];
for (tmp = prev_list->next; tmp != prev_list; tmp = tmp->next){
bh = osi_list_entry(tmp, struct gfs2_buffer_head,
b_altlist);
- if (i > 1) {
- /* if this isn't really a block list skip it */
- if (gfs2_check_meta(bh, iblk_type))
- continue;
- head_size = sizeof(struct gfs2_meta_header);
- } else {
- /* if this isn't really a dinode, skip it */
- if (gfs2_check_meta(bh, GFS2_METATYPE_DI))
- continue;
- head_size = sizeof(struct gfs2_dinode);
- }
+ if (gfs2_check_meta(bh, iblk_type))
+ continue;
+
/* Now check the metadata itself */
for (ptr = (uint64_t *)(bh->b_data + head_size);
(char *)ptr < (bh->b_data + ip->i_sbd->bsize);
@@ -1177,7 +1176,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
continue;
block = be64_to_cpu(*ptr);
- err = pass->check_metalist(ip, block, &nbh,
+ err = pass->check_metalist(ip, block, &nbh, h,
pass->private);
/* check_metalist should hold any buffers
it gets with "bread". */
@@ -1459,7 +1458,7 @@ int remove_dentry_from_dir(struct gfs2_sbd *sbp, uint64_t dir,
}
int delete_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
return delete_block_if_notdup(ip, block, bh, _("metadata"), private);
}
@@ -1491,7 +1490,7 @@ int delete_eattr_leaf(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
}
static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
uint8_t q;
const char *desc = (const char *)private;
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index c602492..7aae9f2 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -19,7 +19,7 @@ extern int delete_block(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, const char *btype,
void *private);
extern int delete_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h, void *private);
extern int delete_leaf(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
extern int delete_data(struct gfs2_inode *ip, uint64_t block, void *private);
@@ -62,7 +62,8 @@ struct metawalk_fxns {
int (*check_leaf) (struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
int (*check_metalist) (struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h,
+ void *private);
int (*check_data) (struct gfs2_inode *ip, uint64_t block,
void *private);
int (*check_eattr_indir) (struct gfs2_inode *ip, uint64_t block,
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 6c4762d..4fb7abf 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -35,9 +35,10 @@ struct block_count {
static int leaf(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h, void *private);
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h,
+ void *private);
static int check_data(struct gfs2_inode *ip, uint64_t block, void *private);
static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
void *private);
@@ -60,7 +61,8 @@ static int check_extended_leaf_eattr(struct gfs2_inode *ip, uint64_t *data_ptr,
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,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h,
+ void *private);
static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
static int invalidate_data(struct gfs2_inode *ip, uint64_t block,
@@ -111,7 +113,8 @@ struct metawalk_fxns invalidate_fxns = {
* deleted, do you? Or worse, reused for lost+found.
*/
static int resuscitate_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
struct block_count *bc = (struct block_count *)private;
@@ -205,7 +208,7 @@ static int leaf(struct gfs2_inode *ip, uint64_t block,
}
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
uint8_t q;
int found_dup = 0, iblk_type;
@@ -225,7 +228,7 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
return 1;
}
- if (S_ISDIR(ip->i_di.di_mode)) {
+ if (S_ISDIR(ip->i_di.di_mode) && h == ip->i_di.di_height) {
iblk_type = GFS2_METATYPE_JD;
blktypedesc = _("a directory hash table block");
} else {
@@ -248,13 +251,13 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
nbh = bread(ip->i_sbd, block);
if (gfs2_check_meta(nbh, iblk_type)){
- log_debug( _("Inode %lld (0x%llx) has a bad indirect block "
- "pointer %lld (0x%llx) (points to something "
- "that is not %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)block,
- (unsigned long long)block, blktypedesc);
+ log_err( _("Inode %lld (0x%llx) has a bad indirect block "
+ "pointer %lld (0x%llx) (points to something "
+ "that is not %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)block,
+ (unsigned long long)block, blktypedesc);
if(!found_dup) {
fsck_blockmap_set(ip, block, _("bad indirect"),
gfs2_meta_inval);
@@ -276,7 +279,8 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
}
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
struct duptree *d;
int found_dup = 0, iblk_type;
@@ -290,7 +294,7 @@ static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
_("itself"), gfs2_block_free);
return 1;
}
- if (S_ISDIR(ip->i_di.di_mode))
+ if (S_ISDIR(ip->i_di.di_mode) && h == ip->i_di.di_height)
iblk_type = GFS2_METATYPE_JD;
else
iblk_type = GFS2_METATYPE_IN;
@@ -834,7 +838,8 @@ static int mark_block_invalid(struct gfs2_inode *ip, uint64_t block,
}
static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
return mark_block_invalid(ip, block, ref_as_meta, _("metadata"));
}
@@ -915,7 +920,8 @@ static int rangecheck_block(struct gfs2_inode *ip, uint64_t block,
}
static int rangecheck_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
return rangecheck_block(ip, block, bh, _("metadata"), private);
}
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 680eb38..4d97879 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -27,7 +27,7 @@ struct dup_handler {
};
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h, void *private);
static int check_data(struct gfs2_inode *ip, uint64_t block, void *private);
static int check_eattr_indir(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct gfs2_buffer_head **bh,
@@ -74,7 +74,7 @@ struct metawalk_fxns find_dirents = {
};
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
return add_duplicate_ref(ip, block, ref_as_meta, 1, INODE_VALID);
}
@@ -197,7 +197,8 @@ static int find_dentry(struct gfs2_inode *ip, struct gfs2_dirent *de,
}
static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
struct dup_handler *dh = (struct dup_handler *) private;
struct duptree *d;
@@ -246,21 +247,21 @@ static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
static int clear_dup_data(struct gfs2_inode *ip, uint64_t block, void *private)
{
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
static int clear_dup_eattr_indir(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct gfs2_buffer_head **bh,
void *private)
{
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
static int clear_dup_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct gfs2_buffer_head **bh,
void *private)
{
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
static int clear_eattr_entry (struct gfs2_inode *ip,
@@ -313,7 +314,7 @@ static int clear_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
{
uint64_t block = be64_to_cpu(*ea_data_ptr);
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
/* Finds all references to duplicate blocks in the metadata */
13 years, 8 months
cluster: RHEL6 - fsck.gfs2 deletes directories if they get too big
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: 6bcd9db82232332f40667a6dd409829f7c15a1a0
Parent: aa4bde63a2307636f5f64c03082aab80eb6dd27e
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Aug 17 12:26:47 2010 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Aug 17 12:36:23 2010 -0500
fsck.gfs2 deletes directories if they get too big
This patch fixes a problem whereby too many levels of
indirection caused fsck.gfs2 to get confused and delete
directories. The problem was that gfs2.fsck only understood
three levels of data for directories: (1) dinode, (2) block
pointers to leaf blocks, (3) leaf blocks. If a directory
gets sufficiently big, it goes into four or more levels of
indirection, with level 2 (and possibly more) being indirect
blocks leading to the leaf blocks.
rhbz#624691
---
gfs2/fsck/metawalk.c | 45 ++++++++++++++++++++++-----------------------
gfs2/fsck/metawalk.h | 5 +++--
gfs2/fsck/pass1.c | 40 +++++++++++++++++++++++-----------------
gfs2/fsck/pass1b.c | 15 ++++++++-------
4 files changed, 56 insertions(+), 49 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 0ab8d7e..ef1b6b5 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1125,7 +1125,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
uint32_t height = ip->i_di.di_height;
struct gfs2_buffer_head *bh, *nbh, *metabh = ip->i_bh;
osi_list_t *prev_list, *cur_list, *tmp;
- int i, head_size, iblk_type;
+ int h, head_size, iblk_type;
uint64_t *ptr, block;
int error = 0, err;
@@ -1136,35 +1136,34 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
because it checks everything through the hash table using
"depth" field calculations. However, we still have to check the
indirect blocks, even if the height == 1. */
- if (S_ISDIR(ip->i_di.di_mode)) {
+ if (S_ISDIR(ip->i_di.di_mode))
height++;
- iblk_type = GFS2_METATYPE_JD;
- } else {
- iblk_type = GFS2_METATYPE_IN;
- }
/* if(<there are no indirect blocks to check>) */
if (height < 2)
return 0;
- for (i = 1; i < height; i++) {
- prev_list = &mlp[i - 1];
- cur_list = &mlp[i];
+ for (h = 1; h < height; h++) {
+ if (h > 1) {
+ if (S_ISDIR(ip->i_di.di_mode) &&
+ h == ip->i_di.di_height + 1)
+ iblk_type = GFS2_METATYPE_JD;
+ else
+ iblk_type = GFS2_METATYPE_IN;
+ head_size = sizeof(struct gfs2_meta_header);
+ } else {
+ iblk_type = GFS2_METATYPE_DI;
+ head_size = sizeof(struct gfs2_dinode);
+ }
+ prev_list = &mlp[h - 1];
+ cur_list = &mlp[h];
for (tmp = prev_list->next; tmp != prev_list; tmp = tmp->next){
bh = osi_list_entry(tmp, struct gfs2_buffer_head,
b_altlist);
- if (i > 1) {
- /* if this isn't really a block list skip it */
- if (gfs2_check_meta(bh, iblk_type))
- continue;
- head_size = sizeof(struct gfs2_meta_header);
- } else {
- /* if this isn't really a dinode, skip it */
- if (gfs2_check_meta(bh, GFS2_METATYPE_DI))
- continue;
- head_size = sizeof(struct gfs2_dinode);
- }
+ if (gfs2_check_meta(bh, iblk_type))
+ continue;
+
/* Now check the metadata itself */
for (ptr = (uint64_t *)(bh->b_data + head_size);
(char *)ptr < (bh->b_data + ip->i_sbd->bsize);
@@ -1177,7 +1176,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
continue;
block = be64_to_cpu(*ptr);
- err = pass->check_metalist(ip, block, &nbh,
+ err = pass->check_metalist(ip, block, &nbh, h,
pass->private);
/* check_metalist should hold any buffers
it gets with "bread". */
@@ -1459,7 +1458,7 @@ int remove_dentry_from_dir(struct gfs2_sbd *sbp, uint64_t dir,
}
int delete_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
return delete_block_if_notdup(ip, block, bh, _("metadata"), private);
}
@@ -1491,7 +1490,7 @@ int delete_eattr_leaf(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
}
static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
uint8_t q;
const char *desc = (const char *)private;
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index c602492..7aae9f2 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -19,7 +19,7 @@ extern int delete_block(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, const char *btype,
void *private);
extern int delete_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h, void *private);
extern int delete_leaf(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
extern int delete_data(struct gfs2_inode *ip, uint64_t block, void *private);
@@ -62,7 +62,8 @@ struct metawalk_fxns {
int (*check_leaf) (struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
int (*check_metalist) (struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h,
+ void *private);
int (*check_data) (struct gfs2_inode *ip, uint64_t block,
void *private);
int (*check_eattr_indir) (struct gfs2_inode *ip, uint64_t block,
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 6c4762d..4fb7abf 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -35,9 +35,10 @@ struct block_count {
static int leaf(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h, void *private);
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h,
+ void *private);
static int check_data(struct gfs2_inode *ip, uint64_t block, void *private);
static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
void *private);
@@ -60,7 +61,8 @@ static int check_extended_leaf_eattr(struct gfs2_inode *ip, uint64_t *data_ptr,
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,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h,
+ void *private);
static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
static int invalidate_data(struct gfs2_inode *ip, uint64_t block,
@@ -111,7 +113,8 @@ struct metawalk_fxns invalidate_fxns = {
* deleted, do you? Or worse, reused for lost+found.
*/
static int resuscitate_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
struct block_count *bc = (struct block_count *)private;
@@ -205,7 +208,7 @@ static int leaf(struct gfs2_inode *ip, uint64_t block,
}
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
uint8_t q;
int found_dup = 0, iblk_type;
@@ -225,7 +228,7 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
return 1;
}
- if (S_ISDIR(ip->i_di.di_mode)) {
+ if (S_ISDIR(ip->i_di.di_mode) && h == ip->i_di.di_height) {
iblk_type = GFS2_METATYPE_JD;
blktypedesc = _("a directory hash table block");
} else {
@@ -248,13 +251,13 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
nbh = bread(ip->i_sbd, block);
if (gfs2_check_meta(nbh, iblk_type)){
- log_debug( _("Inode %lld (0x%llx) has a bad indirect block "
- "pointer %lld (0x%llx) (points to something "
- "that is not %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)block,
- (unsigned long long)block, blktypedesc);
+ log_err( _("Inode %lld (0x%llx) has a bad indirect block "
+ "pointer %lld (0x%llx) (points to something "
+ "that is not %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)block,
+ (unsigned long long)block, blktypedesc);
if(!found_dup) {
fsck_blockmap_set(ip, block, _("bad indirect"),
gfs2_meta_inval);
@@ -276,7 +279,8 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
}
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
struct duptree *d;
int found_dup = 0, iblk_type;
@@ -290,7 +294,7 @@ static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
_("itself"), gfs2_block_free);
return 1;
}
- if (S_ISDIR(ip->i_di.di_mode))
+ if (S_ISDIR(ip->i_di.di_mode) && h == ip->i_di.di_height)
iblk_type = GFS2_METATYPE_JD;
else
iblk_type = GFS2_METATYPE_IN;
@@ -834,7 +838,8 @@ static int mark_block_invalid(struct gfs2_inode *ip, uint64_t block,
}
static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
return mark_block_invalid(ip, block, ref_as_meta, _("metadata"));
}
@@ -915,7 +920,8 @@ static int rangecheck_block(struct gfs2_inode *ip, uint64_t block,
}
static int rangecheck_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
return rangecheck_block(ip, block, bh, _("metadata"), private);
}
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 680eb38..4d97879 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -27,7 +27,7 @@ struct dup_handler {
};
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h, void *private);
static int check_data(struct gfs2_inode *ip, uint64_t block, void *private);
static int check_eattr_indir(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct gfs2_buffer_head **bh,
@@ -74,7 +74,7 @@ struct metawalk_fxns find_dirents = {
};
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
return add_duplicate_ref(ip, block, ref_as_meta, 1, INODE_VALID);
}
@@ -197,7 +197,8 @@ static int find_dentry(struct gfs2_inode *ip, struct gfs2_dirent *de,
}
static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
struct dup_handler *dh = (struct dup_handler *) private;
struct duptree *d;
@@ -246,21 +247,21 @@ static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
static int clear_dup_data(struct gfs2_inode *ip, uint64_t block, void *private)
{
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
static int clear_dup_eattr_indir(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct gfs2_buffer_head **bh,
void *private)
{
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
static int clear_dup_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct gfs2_buffer_head **bh,
void *private)
{
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
static int clear_eattr_entry (struct gfs2_inode *ip,
@@ -313,7 +314,7 @@ static int clear_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
{
uint64_t block = be64_to_cpu(*ea_data_ptr);
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
/* Finds all references to duplicate blocks in the metadata */
13 years, 8 months
cluster: STABLE3 - fsck.gfs2 deletes directories if they get too big
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: d22e78f8fc996480d873585ad2939be826343b05
Parent: 53bd302eba05edd46de41b158fae8860137f453b
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Aug 17 12:26:47 2010 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Aug 17 12:26:47 2010 -0500
fsck.gfs2 deletes directories if they get too big
This patch fixes a problem whereby too many levels of
indirection caused fsck.gfs2 to get confused and delete
directories. The problem was that gfs2.fsck only understood
three levels of data for directories: (1) dinode, (2) block
pointers to leaf blocks, (3) leaf blocks. If a directory
gets sufficiently big, it goes into four or more levels of
indirection, with level 2 (and possibly more) being indirect
blocks leading to the leaf blocks.
rhbz#624691
---
gfs2/fsck/metawalk.c | 45 ++++++++++++++++++++++-----------------------
gfs2/fsck/metawalk.h | 5 +++--
gfs2/fsck/pass1.c | 40 +++++++++++++++++++++++-----------------
gfs2/fsck/pass1b.c | 15 ++++++++-------
4 files changed, 56 insertions(+), 49 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 0ab8d7e..ef1b6b5 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1125,7 +1125,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
uint32_t height = ip->i_di.di_height;
struct gfs2_buffer_head *bh, *nbh, *metabh = ip->i_bh;
osi_list_t *prev_list, *cur_list, *tmp;
- int i, head_size, iblk_type;
+ int h, head_size, iblk_type;
uint64_t *ptr, block;
int error = 0, err;
@@ -1136,35 +1136,34 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
because it checks everything through the hash table using
"depth" field calculations. However, we still have to check the
indirect blocks, even if the height == 1. */
- if (S_ISDIR(ip->i_di.di_mode)) {
+ if (S_ISDIR(ip->i_di.di_mode))
height++;
- iblk_type = GFS2_METATYPE_JD;
- } else {
- iblk_type = GFS2_METATYPE_IN;
- }
/* if(<there are no indirect blocks to check>) */
if (height < 2)
return 0;
- for (i = 1; i < height; i++) {
- prev_list = &mlp[i - 1];
- cur_list = &mlp[i];
+ for (h = 1; h < height; h++) {
+ if (h > 1) {
+ if (S_ISDIR(ip->i_di.di_mode) &&
+ h == ip->i_di.di_height + 1)
+ iblk_type = GFS2_METATYPE_JD;
+ else
+ iblk_type = GFS2_METATYPE_IN;
+ head_size = sizeof(struct gfs2_meta_header);
+ } else {
+ iblk_type = GFS2_METATYPE_DI;
+ head_size = sizeof(struct gfs2_dinode);
+ }
+ prev_list = &mlp[h - 1];
+ cur_list = &mlp[h];
for (tmp = prev_list->next; tmp != prev_list; tmp = tmp->next){
bh = osi_list_entry(tmp, struct gfs2_buffer_head,
b_altlist);
- if (i > 1) {
- /* if this isn't really a block list skip it */
- if (gfs2_check_meta(bh, iblk_type))
- continue;
- head_size = sizeof(struct gfs2_meta_header);
- } else {
- /* if this isn't really a dinode, skip it */
- if (gfs2_check_meta(bh, GFS2_METATYPE_DI))
- continue;
- head_size = sizeof(struct gfs2_dinode);
- }
+ if (gfs2_check_meta(bh, iblk_type))
+ continue;
+
/* Now check the metadata itself */
for (ptr = (uint64_t *)(bh->b_data + head_size);
(char *)ptr < (bh->b_data + ip->i_sbd->bsize);
@@ -1177,7 +1176,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
continue;
block = be64_to_cpu(*ptr);
- err = pass->check_metalist(ip, block, &nbh,
+ err = pass->check_metalist(ip, block, &nbh, h,
pass->private);
/* check_metalist should hold any buffers
it gets with "bread". */
@@ -1459,7 +1458,7 @@ int remove_dentry_from_dir(struct gfs2_sbd *sbp, uint64_t dir,
}
int delete_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
return delete_block_if_notdup(ip, block, bh, _("metadata"), private);
}
@@ -1491,7 +1490,7 @@ int delete_eattr_leaf(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
}
static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
uint8_t q;
const char *desc = (const char *)private;
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index c602492..7aae9f2 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -19,7 +19,7 @@ extern int delete_block(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, const char *btype,
void *private);
extern int delete_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h, void *private);
extern int delete_leaf(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
extern int delete_data(struct gfs2_inode *ip, uint64_t block, void *private);
@@ -62,7 +62,8 @@ struct metawalk_fxns {
int (*check_leaf) (struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
int (*check_metalist) (struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h,
+ void *private);
int (*check_data) (struct gfs2_inode *ip, uint64_t block,
void *private);
int (*check_eattr_indir) (struct gfs2_inode *ip, uint64_t block,
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 6c4762d..4fb7abf 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -35,9 +35,10 @@ struct block_count {
static int leaf(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h, void *private);
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h,
+ void *private);
static int check_data(struct gfs2_inode *ip, uint64_t block, void *private);
static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
void *private);
@@ -60,7 +61,8 @@ static int check_extended_leaf_eattr(struct gfs2_inode *ip, uint64_t *data_ptr,
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,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h,
+ void *private);
static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
static int invalidate_data(struct gfs2_inode *ip, uint64_t block,
@@ -111,7 +113,8 @@ struct metawalk_fxns invalidate_fxns = {
* deleted, do you? Or worse, reused for lost+found.
*/
static int resuscitate_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
struct block_count *bc = (struct block_count *)private;
@@ -205,7 +208,7 @@ static int leaf(struct gfs2_inode *ip, uint64_t block,
}
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
uint8_t q;
int found_dup = 0, iblk_type;
@@ -225,7 +228,7 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
return 1;
}
- if (S_ISDIR(ip->i_di.di_mode)) {
+ if (S_ISDIR(ip->i_di.di_mode) && h == ip->i_di.di_height) {
iblk_type = GFS2_METATYPE_JD;
blktypedesc = _("a directory hash table block");
} else {
@@ -248,13 +251,13 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
nbh = bread(ip->i_sbd, block);
if (gfs2_check_meta(nbh, iblk_type)){
- log_debug( _("Inode %lld (0x%llx) has a bad indirect block "
- "pointer %lld (0x%llx) (points to something "
- "that is not %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)block,
- (unsigned long long)block, blktypedesc);
+ log_err( _("Inode %lld (0x%llx) has a bad indirect block "
+ "pointer %lld (0x%llx) (points to something "
+ "that is not %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)block,
+ (unsigned long long)block, blktypedesc);
if(!found_dup) {
fsck_blockmap_set(ip, block, _("bad indirect"),
gfs2_meta_inval);
@@ -276,7 +279,8 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
}
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
struct duptree *d;
int found_dup = 0, iblk_type;
@@ -290,7 +294,7 @@ static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
_("itself"), gfs2_block_free);
return 1;
}
- if (S_ISDIR(ip->i_di.di_mode))
+ if (S_ISDIR(ip->i_di.di_mode) && h == ip->i_di.di_height)
iblk_type = GFS2_METATYPE_JD;
else
iblk_type = GFS2_METATYPE_IN;
@@ -834,7 +838,8 @@ static int mark_block_invalid(struct gfs2_inode *ip, uint64_t block,
}
static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
return mark_block_invalid(ip, block, ref_as_meta, _("metadata"));
}
@@ -915,7 +920,8 @@ static int rangecheck_block(struct gfs2_inode *ip, uint64_t block,
}
static int rangecheck_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
return rangecheck_block(ip, block, bh, _("metadata"), private);
}
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 680eb38..4d97879 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -27,7 +27,7 @@ struct dup_handler {
};
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h, void *private);
static int check_data(struct gfs2_inode *ip, uint64_t block, void *private);
static int check_eattr_indir(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct gfs2_buffer_head **bh,
@@ -74,7 +74,7 @@ struct metawalk_fxns find_dirents = {
};
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
return add_duplicate_ref(ip, block, ref_as_meta, 1, INODE_VALID);
}
@@ -197,7 +197,8 @@ static int find_dentry(struct gfs2_inode *ip, struct gfs2_dirent *de,
}
static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
struct dup_handler *dh = (struct dup_handler *) private;
struct duptree *d;
@@ -246,21 +247,21 @@ static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
static int clear_dup_data(struct gfs2_inode *ip, uint64_t block, void *private)
{
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
static int clear_dup_eattr_indir(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct gfs2_buffer_head **bh,
void *private)
{
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
static int clear_dup_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct gfs2_buffer_head **bh,
void *private)
{
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
static int clear_eattr_entry (struct gfs2_inode *ip,
@@ -313,7 +314,7 @@ static int clear_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
{
uint64_t block = be64_to_cpu(*ea_data_ptr);
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
/* Finds all references to duplicate blocks in the metadata */
13 years, 8 months
gfs2-utils: master - fsck.gfs2 deletes directories if they get too big
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: fb5bd562b6768e9110357434f3441e006a795d96
Parent: d3d8ba6be4786077cb5a9fea13e035a51ef92022
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Aug 17 12:26:47 2010 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Aug 17 12:32:05 2010 -0500
fsck.gfs2 deletes directories if they get too big
This patch fixes a problem whereby too many levels of
indirection caused fsck.gfs2 to get confused and delete
directories. The problem was that gfs2.fsck only understood
three levels of data for directories: (1) dinode, (2) block
pointers to leaf blocks, (3) leaf blocks. If a directory
gets sufficiently big, it goes into four or more levels of
indirection, with level 2 (and possibly more) being indirect
blocks leading to the leaf blocks.
rhbz#624691
---
gfs2/fsck/metawalk.c | 45 ++++++++++++++++++++++-----------------------
gfs2/fsck/metawalk.h | 5 +++--
gfs2/fsck/pass1.c | 40 +++++++++++++++++++++++-----------------
gfs2/fsck/pass1b.c | 15 ++++++++-------
4 files changed, 56 insertions(+), 49 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 7ea4b59..5cb531d 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1127,7 +1127,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
uint32_t height = ip->i_di.di_height;
struct gfs2_buffer_head *bh, *nbh, *metabh = ip->i_bh;
osi_list_t *prev_list, *cur_list, *tmp;
- int i, head_size, iblk_type;
+ int h, head_size, iblk_type;
uint64_t *ptr, block;
int error = 0, err;
@@ -1138,35 +1138,34 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
because it checks everything through the hash table using
"depth" field calculations. However, we still have to check the
indirect blocks, even if the height == 1. */
- if (S_ISDIR(ip->i_di.di_mode)) {
+ if (S_ISDIR(ip->i_di.di_mode))
height++;
- iblk_type = GFS2_METATYPE_JD;
- } else {
- iblk_type = GFS2_METATYPE_IN;
- }
/* if(<there are no indirect blocks to check>) */
if (height < 2)
return 0;
- for (i = 1; i < height; i++) {
- prev_list = &mlp[i - 1];
- cur_list = &mlp[i];
+ for (h = 1; h < height; h++) {
+ if (h > 1) {
+ if (S_ISDIR(ip->i_di.di_mode) &&
+ h == ip->i_di.di_height + 1)
+ iblk_type = GFS2_METATYPE_JD;
+ else
+ iblk_type = GFS2_METATYPE_IN;
+ head_size = sizeof(struct gfs2_meta_header);
+ } else {
+ iblk_type = GFS2_METATYPE_DI;
+ head_size = sizeof(struct gfs2_dinode);
+ }
+ prev_list = &mlp[h - 1];
+ cur_list = &mlp[h];
for (tmp = prev_list->next; tmp != prev_list; tmp = tmp->next){
bh = osi_list_entry(tmp, struct gfs2_buffer_head,
b_altlist);
- if (i > 1) {
- /* if this isn't really a block list skip it */
- if (gfs2_check_meta(bh, iblk_type))
- continue;
- head_size = sizeof(struct gfs2_meta_header);
- } else {
- /* if this isn't really a dinode, skip it */
- if (gfs2_check_meta(bh, GFS2_METATYPE_DI))
- continue;
- head_size = sizeof(struct gfs2_dinode);
- }
+ if (gfs2_check_meta(bh, iblk_type))
+ continue;
+
/* Now check the metadata itself */
for (ptr = (uint64_t *)(bh->b_data + head_size);
(char *)ptr < (bh->b_data + ip->i_sbd->bsize);
@@ -1179,7 +1178,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
continue;
block = be64_to_cpu(*ptr);
- err = pass->check_metalist(ip, block, &nbh,
+ err = pass->check_metalist(ip, block, &nbh, h,
pass->private);
/* check_metalist should hold any buffers
it gets with "bread". */
@@ -1461,7 +1460,7 @@ int remove_dentry_from_dir(struct gfs2_sbd *sbp, uint64_t dir,
}
int delete_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
return delete_block_if_notdup(ip, block, bh, _("metadata"), private);
}
@@ -1493,7 +1492,7 @@ int delete_eattr_leaf(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
}
static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
uint8_t q;
const char *desc = (const char *)private;
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index c602492..7aae9f2 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -19,7 +19,7 @@ extern int delete_block(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, const char *btype,
void *private);
extern int delete_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h, void *private);
extern int delete_leaf(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
extern int delete_data(struct gfs2_inode *ip, uint64_t block, void *private);
@@ -62,7 +62,8 @@ struct metawalk_fxns {
int (*check_leaf) (struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
int (*check_metalist) (struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h,
+ void *private);
int (*check_data) (struct gfs2_inode *ip, uint64_t block,
void *private);
int (*check_eattr_indir) (struct gfs2_inode *ip, uint64_t block,
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index a335d28..72d35ad 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -37,9 +37,10 @@ struct block_count {
static int leaf(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h, void *private);
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h,
+ void *private);
static int check_data(struct gfs2_inode *ip, uint64_t block, void *private);
static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
void *private);
@@ -62,7 +63,8 @@ static int check_extended_leaf_eattr(struct gfs2_inode *ip, uint64_t *data_ptr,
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,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h,
+ void *private);
static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private);
static int invalidate_data(struct gfs2_inode *ip, uint64_t block,
@@ -113,7 +115,8 @@ struct metawalk_fxns invalidate_fxns = {
* deleted, do you? Or worse, reused for lost+found.
*/
static int resuscitate_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
struct block_count *bc = (struct block_count *)private;
@@ -207,7 +210,7 @@ static int leaf(struct gfs2_inode *ip, uint64_t block,
}
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
uint8_t q;
int found_dup = 0, iblk_type;
@@ -227,7 +230,7 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
return 1;
}
- if (S_ISDIR(ip->i_di.di_mode)) {
+ if (S_ISDIR(ip->i_di.di_mode) && h == ip->i_di.di_height) {
iblk_type = GFS2_METATYPE_JD;
blktypedesc = _("a directory hash table block");
} else {
@@ -250,13 +253,13 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
nbh = bread(ip->i_sbd, block);
if (gfs2_check_meta(nbh, iblk_type)){
- log_debug( _("Inode %lld (0x%llx) has a bad indirect block "
- "pointer %lld (0x%llx) (points to something "
- "that is not %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)block,
- (unsigned long long)block, blktypedesc);
+ log_err( _("Inode %lld (0x%llx) has a bad indirect block "
+ "pointer %lld (0x%llx) (points to something "
+ "that is not %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)block,
+ (unsigned long long)block, blktypedesc);
if(!found_dup) {
fsck_blockmap_set(ip, block, _("bad indirect"),
gfs2_meta_inval);
@@ -278,7 +281,8 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
}
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
struct duptree *d;
int found_dup = 0, iblk_type;
@@ -292,7 +296,7 @@ static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
_("itself"), gfs2_block_free);
return 1;
}
- if (S_ISDIR(ip->i_di.di_mode))
+ if (S_ISDIR(ip->i_di.di_mode) && h == ip->i_di.di_height)
iblk_type = GFS2_METATYPE_JD;
else
iblk_type = GFS2_METATYPE_IN;
@@ -836,7 +840,8 @@ static int mark_block_invalid(struct gfs2_inode *ip, uint64_t block,
}
static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
return mark_block_invalid(ip, block, ref_as_meta, _("metadata"));
}
@@ -917,7 +922,8 @@ static int rangecheck_block(struct gfs2_inode *ip, uint64_t block,
}
static int rangecheck_metadata(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
return rangecheck_block(ip, block, bh, _("metadata"), private);
}
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index c3290c2..12b6a3b 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -29,7 +29,7 @@ struct dup_handler {
};
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private);
+ struct gfs2_buffer_head **bh, int h, void *private);
static int check_data(struct gfs2_inode *ip, uint64_t block, void *private);
static int check_eattr_indir(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct gfs2_buffer_head **bh,
@@ -76,7 +76,7 @@ struct metawalk_fxns find_dirents = {
};
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h, void *private)
{
return add_duplicate_ref(ip, block, ref_as_meta, 1, INODE_VALID);
}
@@ -199,7 +199,8 @@ static int find_dentry(struct gfs2_inode *ip, struct gfs2_dirent *de,
}
static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, void *private)
+ struct gfs2_buffer_head **bh, int h,
+ void *private)
{
struct dup_handler *dh = (struct dup_handler *) private;
struct duptree *d;
@@ -248,21 +249,21 @@ static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
static int clear_dup_data(struct gfs2_inode *ip, uint64_t block, void *private)
{
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
static int clear_dup_eattr_indir(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct gfs2_buffer_head **bh,
void *private)
{
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
static int clear_dup_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct gfs2_buffer_head **bh,
void *private)
{
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
static int clear_eattr_entry (struct gfs2_inode *ip,
@@ -315,7 +316,7 @@ static int clear_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
{
uint64_t block = be64_to_cpu(*ea_data_ptr);
- return clear_dup_metalist(ip, block, NULL, private);
+ return clear_dup_metalist(ip, block, NULL, 0, private);
}
/* Finds all references to duplicate blocks in the metadata */
13 years, 8 months
cluster: RHEL48 - fence_scsi: replace open3 calls with qx commands
by Chris Feist
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=...
Commit: bc85a6cb6f9359dd6ff4d04c8030c8b8c89be22f
Parent: eeb82f2666b3fff9669a6956d4e0e27d40b1d47c
Author: Ryan O'Hara <rohara(a)redhat.com>
AuthorDate: Wed Apr 7 11:26:43 2010 -0500
Committer: Chris Feist <cfeist(a)redhat.com>
CommitterDate: Mon Aug 16 16:17:17 2010 -0500
fence_scsi: replace open3 calls with qx commands
The open3 calls will block when the buffer becomes full, which causes
fence_scsi to block. This can occur if fence_scsi needs to process
several devices. All open3 calls should be replaced with qx commands,
which does not suffer from this problem. (BZ 545193)
Signed-off-by: Ryan O'Hara <rohara(a)redhat.com>
---
fence/agents/scsi/fence_scsi.pl | 134 ++++++++++-----------------------------
1 files changed, 33 insertions(+), 101 deletions(-)
diff --git a/fence/agents/scsi/fence_scsi.pl b/fence/agents/scsi/fence_scsi.pl
index 9c0a5c3..7ab621e 100755
--- a/fence/agents/scsi/fence_scsi.pl
+++ b/fence/agents/scsi/fence_scsi.pl
@@ -2,9 +2,17 @@
use Getopt::Std;
use XML::LibXML;
-use IPC::Open3;
use POSIX;
+my $ME = $0;
+
+END {
+ defined fileno STDOUT or return;
+ close STDOUT and return;
+ warn "$ME: failed to close standard output: $!\n";
+ $? ||= 1;
+}
+
my @device_list;
$_ = $0;
@@ -63,32 +71,23 @@ sub get_cluster_id
{
my $cluster_id;
- my ($in, $out, $err);
my $cmd = "cman_tool status";
-
- my $pid = open3($in, $out, $err, $cmd) or die "$!\n";
-
- waitpid($pid, 0);
+ my @out = qx { $cmd };
die "Unable to execute cman_tool.\n" if ($?>>8);
- while (<$out>)
+ foreach (@out)
{
chomp;
- my ($name, $value) = split(/\s*:\s*/, $_);
+ my ($param, $value) = split(/\s*:\s*/, $_);
- if ($name eq "Cluster ID")
- {
+ if ($param =~ /^cluster\s+id/i) {
$cluster_id = $value;
last;
}
}
- close($in);
- close($out);
- close($err);
-
print "[$pname]: get_cluster_id: cluster_id=$cluster_id\n" if $opt_v;
return $cluster_id;
@@ -121,32 +120,23 @@ sub get_host_id
{
my $host_id;
- my ($in, $out, $err);
my $cmd = "cman_tool status";
-
- my $pid = open3($in, $out, $err, $cmd) or die "$!\n";
-
- waitpid($pid, 0);
+ my @out = qx { $cmd };
die "Unable to execute cman_tool.\n" if ($?>>8);
- while (<$out>)
+ foreach (@out)
{
chomp;
- my ($name, $value) = split(/\s*:\s*/, $_);
+ my ($param, $value) = split(/\s*:\s*/, $_);
- if ($name eq "Node ID")
- {
+ if ($param =~ /^node\s+id/i) {
$host_id = $value;
last;
}
}
- close($in);
- close($out);
- close($err);
-
print "[$pname]: get_host_id: host_id=$host_id\n" if $opt_v;
return $host_id;
@@ -156,32 +146,23 @@ sub get_host_name
{
my $host_name;
- my ($in, $out, $err);
my $cmd = "cman_tool status";
-
- my $pid = open3($in, $out, $err, $cmd) or die "$!\n";
-
- waitpid($pid, 0);
+ my @out = qx { $cmd };
die "Unable to execute cman_tool.\n" if ($?>>8);
- while (<$out>)
+ foreach (@out)
{
chomp;
- my ($name, $value) = split(/\s*:\s*/, $_);
+ my ($param, $value) = split(/\s*:\s*/, $_);
- if ($name eq "Node name")
- {
+ if ($param =~ /^node\s+name/i) {
$host_name = $value;
last;
}
}
- close($in);
- close($out);
- close($err);
-
print "[$pname]: get_host_name: host_name=$host_name\n" if $opt_v;
return $host_name;
@@ -260,26 +241,23 @@ sub get_key_list
{
($dev) = @_;
- my ($in, $out, $err);
-
my $cmd = "sg_persist -d $dev -i -k";
- my $pid = open3($in, $out, $err, $cmd) or die "$!\n";
-
- waitpid($pid, 0);
+ my @out = qx { $cmd };
die "Unable to execute sg_persist.\n" if ($?>>8);
my %key_list;
- while (<$out>)
+ foreach (@out)
{
chomp;
+
if ($_ =~ /^\s*0x/)
{
s/^\s+0x//;
s/\s+$//;
- $key_list{$_} = 1;
+ $key_list{$_} = undef;
}
}
@@ -299,27 +277,19 @@ sub get_key_list
}
}
- close($in);
- close($out);
- close($err);
-
return %key_list;
}
sub get_scsi_devices
{
- my ($in, $out, $err);
-
my $cmd = "vgs --config 'global { locking_type = 0 }'" .
- " --noheadings --separator : -o vg_attr,pv_name 2> /dev/null";
+ " --noheadings --separator : -o vg_attr,pv_name";
- my $pid = open3($in, $out, $err, $cmd) or die "$!\n";
-
- waitpid($pid, 0);
+ my @out = qx { $cmd 2> /dev/null};
die "Unable to execute vgs.\n" if ($?>>8);
- while (<$out>)
+ foreach (@out)
{
chomp;
@@ -347,42 +317,14 @@ sub get_scsi_devices
$index++;
}
}
-
- close($in);
- close($out);
- close($err);
}
sub check_sg_persist
{
- my ($in, $out, $err);
my $cmd = "sg_persist -V";
- my $pid = open3($in, $out, $err, $cmd) or die "$!\n";
-
- waitpid($pid, 0);
+ my $out = qx { $cmd };
die "Unable to execute sg_persist.\n" if ($?>>8);
-
- close($in);
- close($out);
- close($err);
-}
-
-sub do_register
-{
- ($dev, $key) = @_;
-
- my ($in, $out, $err);
- my $cmd = "sg_persist -n -d $dev -o -G -S $key";
- my $pid = open3($in, $out, $err, $cmd) or die "$!\n";
-
- waitpid($pid, 0);
-
- die "Unable to execute sg_persist ($dev).\n" if ($?>>8);
-
- close($in);
- close($out);
- close($err);
}
sub fence_node
@@ -406,17 +348,13 @@ sub fence_node
print "[$pname]: unregister key 0x$node_key from device $dev\n";
}
- if (!$key_list{$host_key})
+ if (! exists $key_list{$host_key})
{
- do_register($dev, $host_key);
+ fail "Unable to perform fence operation.";
}
- if (!$key_list{$node_key})
+ if (! exists $key_list{$node_key})
{
- if ($opt_v)
- {
- print "[$pname]: key 0x$node_key is not registered with device $dev\n";
- }
next;
}
@@ -429,15 +367,9 @@ sub fence_node
$cmd = "sg_persist -n -d $dev -o -A -K $host_key -S $node_key -T 5";
}
- my $pid = open3($in, $out, $err, $cmd) or die "$!\n";
-
- waitpid($pid, 0);
+ my $out = qx { $cmd };
die "Unable to execute sg_persist ($dev).\n" if ($?>>8);
-
- close($in);
- close($out);
- close($err);
}
}
13 years, 8 months