From b1dbf5b1ad3a1fbc6bbcf4981230f04d16ecab16 Mon Sep 17 00:00:00 2001 From: Fan Yong Date: Thu, 20 Sep 2012 23:45:19 +0800 Subject: [PATCH] LU-1976 io: check index node before recycle empty leaf There may be multiple threads trying to shrink the same OI index node to recycle different empty OI leaf nodes concurrently, and someone may enlarged or split the index node before the threads shrinking the index node to recycle the empty OI leaf nodes. These concurrent OI index node modifications will change leaf node position in the index node. So before shrinking the index node, we need to check and adjust related frame pointer to avoid to shrink the index node improperly as to crash the memory. Signed-off-by: Fan Yong Change-Id: I26063407f6c52f3e51ddb40e6c27aaa5cf63ec2b Reviewed-on: http://review.whamcloud.com/4061 Tested-by: Hudson Reviewed-by: wangdi Reviewed-by: Alex Zhuravlev Tested-by: Maloo Reviewed-by: Oleg Drokin --- lustre/osd-ldiskfs/osd_iam.c | 32 ++++++++++++++++++++++++-------- lustre/osd-ldiskfs/osd_iam_lfix.c | 2 +- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/lustre/osd-ldiskfs/osd_iam.c b/lustre/osd-ldiskfs/osd_iam.c index e0217a1..6ede899 100644 --- a/lustre/osd-ldiskfs/osd_iam.c +++ b/lustre/osd-ldiskfs/osd_iam.c @@ -1738,6 +1738,10 @@ got: brelse(bh); bh = NULL; ldiskfs_std_error(inode->i_sb, *e); + } else { + /* Clear the reused node as new node does. */ + memset(bh->b_data, 0, inode->i_sb->s_blocksize); + set_buffer_uptodate(bh); } return bh; @@ -2069,7 +2073,7 @@ int split_index_node(handle_t *handle, struct iam_path *path, ++ frame; assert_inv(dx_node_check(path, frame)); bh_new[0] = NULL; /* buffer head is "consumed" */ - err = ldiskfs_journal_get_write_access(handle, bh2); + err = ldiskfs_journal_dirty_metadata(handle, bh2); if (err) goto journal_error; do_corr(schedule()); @@ -2261,6 +2265,7 @@ static iam_ptr_t iam_index_shrink(handle_t *h, struct iam_path *p, struct inode *inode = c->ic_object; struct iam_frame *frame = p->ip_frame; struct iam_entry *entries; + struct iam_entry *pos; struct dynlock_handle *lh; int count; int rc; @@ -2281,22 +2286,36 @@ static iam_ptr_t iam_index_shrink(handle_t *h, struct iam_path *p, return 0; } + rc = iam_txn_add(h, p, frame->bh); + if (rc != 0) { + iam_unlock_htree(c, lh); + return 0; + } + + iam_lock_bh(frame->bh); entries = frame->entries; count = dx_get_count(entries); /* NOT shrink the last entry in the index node, which can be reused * directly by next new node. */ if (count == 2) { + iam_unlock_bh(frame->bh); iam_unlock_htree(c, lh); return 0; } - rc = iam_txn_add(h, p, frame->bh); - if (rc != 0) { + pos = iam_find_position(p, frame); + /* There may be some new leaf nodes have been added or empty leaf nodes + * have been shrinked during my delete operation. + * + * If the empty leaf is not under current index node because the index + * node has been split, then just skip the empty leaf, which is rare. */ + if (unlikely(frame->leaf != dx_get_block(p, pos))) { + iam_unlock_bh(frame->bh); iam_unlock_htree(c, lh); return 0; } - iam_lock_bh(frame->bh); + frame->at = pos; if (frame->at < iam_entry_shift(p, entries, count - 1)) { struct iam_entry *n = iam_entry_shift(p, frame->at, 1); @@ -2325,14 +2344,11 @@ iam_install_idle_blocks(handle_t *h, struct iam_path *p, struct buffer_head *bh, struct iam_idle_head *head; int rc; - rc = iam_txn_add(h, p, bh); - if (rc != 0) - return rc; - head = (struct iam_idle_head *)(bh->b_data); head->iih_magic = cpu_to_le16(IAM_IDLE_HEADER_MAGIC); head->iih_count = 0; head->iih_next = *idle_blocks; + /* The bh already get_write_accessed. */ rc = iam_txn_dirty(h, p, bh); if (rc != 0) return rc; diff --git a/lustre/osd-ldiskfs/osd_iam_lfix.c b/lustre/osd-ldiskfs/osd_iam_lfix.c index 7858ef4..4f52757 100644 --- a/lustre/osd-ldiskfs/osd_iam_lfix.c +++ b/lustre/osd-ldiskfs/osd_iam_lfix.c @@ -484,7 +484,7 @@ static void iam_lfix_split(struct iam_leaf *l, struct buffer_head **bh, pivot = (const struct iam_ikey *)iam_leaf_key_at(start); memmove(iam_entries(new_leaf), start, finis - start); - hdr->ill_count = count - split; + hdr->ill_count = cpu_to_le16(count - split); lentry_count_set(l, split); if ((void *)l->il_at >= start) { /* -- 1.8.3.1