Whamcloud - gitweb
LU-1976 io: check index node before recycle empty leaf
authorFan Yong <yong.fan@whamcloud.com>
Thu, 20 Sep 2012 15:45:19 +0000 (23:45 +0800)
committerOleg Drokin <green@whamcloud.com>
Sat, 22 Sep 2012 04:23:57 +0000 (00:23 -0400)
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 <yong.fan@whamcloud.com>
Change-Id: I26063407f6c52f3e51ddb40e6c27aaa5cf63ec2b
Reviewed-on: http://review.whamcloud.com/4061
Tested-by: Hudson
Reviewed-by: wangdi <di.wang@whamcloud.com>
Reviewed-by: Alex Zhuravlev <bzzz@whamcloud.com>
Tested-by: Maloo <whamcloud.maloo@gmail.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/osd-ldiskfs/osd_iam.c
lustre/osd-ldiskfs/osd_iam_lfix.c

index e0217a1..6ede899 100644 (file)
@@ -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;
index 7858ef4..4f52757 100644 (file)
@@ -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) {
                 /*