Whamcloud - gitweb
LU-1976 io: check index node before recycle empty leaf
[fs/lustre-release.git] / lustre / osd-ldiskfs / osd_iam.c
index 16f6089..d29a564 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;