Merge remote-tracking branches 'regulator/topic/88pm800', 'regulator/topic/ab8500...
[firefly-linux-kernel-4.4.55.git] / fs / reiserfs / do_balan.c
index cffcb67a54366f2bd39f534ce72449cf19c07044..54fdf196bfb29c736c0ecf89490a1688a5edaafe 100644 (file)
@@ -72,21 +72,161 @@ inline void do_balance_mark_leaf_dirty(struct tree_balance *tb,
  *    if snum1 is larger than 0 we put items into the new node s1
  *    if snum2 is larger than 0 we put items into the new node s2
  * Note that all *num* count new items being created.
- *
- * It would be easier to read balance_leaf() if each of these summary
- * lines was a separate procedure rather than being inlined.  I think
- * that there are many passages here and in balance_leaf_when_delete() in
- * which two calls to one procedure can replace two passages, and it
- * might save cache space and improve software maintenance costs to do so.
- *
- * Vladimir made the perceptive comment that we should offload most of
- * the decision making in this function into fix_nodes/check_balance, and
- * then create some sort of structure in tb that says what actions should
- * be performed by do_balance.
- *
- * -Hans
  */
 
+static void balance_leaf_when_delete_del(struct tree_balance *tb)
+{
+       struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
+       int item_pos = PATH_LAST_POSITION(tb->tb_path);
+       struct buffer_info bi;
+#ifdef CONFIG_REISERFS_CHECK
+       struct item_head *ih = item_head(tbS0, item_pos);
+#endif
+
+       RFALSE(ih_item_len(ih) + IH_SIZE != -tb->insert_size[0],
+              "vs-12013: mode Delete, insert size %d, ih to be deleted %h",
+              -tb->insert_size[0], ih);
+
+       buffer_info_init_tbS0(tb, &bi);
+       leaf_delete_items(&bi, 0, item_pos, 1, -1);
+
+       if (!item_pos && tb->CFL[0]) {
+               if (B_NR_ITEMS(tbS0)) {
+                       replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0, 0);
+               } else {
+                       if (!PATH_H_POSITION(tb->tb_path, 1))
+                               replace_key(tb, tb->CFL[0], tb->lkey[0],
+                                           PATH_H_PPARENT(tb->tb_path, 0), 0);
+               }
+       }
+
+       RFALSE(!item_pos && !tb->CFL[0],
+              "PAP-12020: tb->CFL[0]==%p, tb->L[0]==%p", tb->CFL[0],
+              tb->L[0]);
+}
+
+/* cut item in S[0] */
+static void balance_leaf_when_delete_cut(struct tree_balance *tb)
+{
+       struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
+       int item_pos = PATH_LAST_POSITION(tb->tb_path);
+       struct item_head *ih = item_head(tbS0, item_pos);
+       int pos_in_item = tb->tb_path->pos_in_item;
+       struct buffer_info bi;
+       buffer_info_init_tbS0(tb, &bi);
+
+       if (is_direntry_le_ih(ih)) {
+               /*
+                * UFS unlink semantics are such that you can only
+                * delete one directory entry at a time.
+                *
+                * when we cut a directory tb->insert_size[0] means
+                * number of entries to be cut (always 1)
+                */
+               tb->insert_size[0] = -1;
+               leaf_cut_from_buffer(&bi, item_pos, pos_in_item,
+                                    -tb->insert_size[0]);
+
+               RFALSE(!item_pos && !pos_in_item && !tb->CFL[0],
+                      "PAP-12030: can not change delimiting key. CFL[0]=%p",
+                      tb->CFL[0]);
+
+               if (!item_pos && !pos_in_item && tb->CFL[0])
+                       replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0, 0);
+       } else {
+               leaf_cut_from_buffer(&bi, item_pos, pos_in_item,
+                                    -tb->insert_size[0]);
+
+               RFALSE(!ih_item_len(ih),
+                      "PAP-12035: cut must leave non-zero dynamic "
+                      "length of item");
+       }
+}
+
+static int balance_leaf_when_delete_left(struct tree_balance *tb)
+{
+       struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
+       int n = B_NR_ITEMS(tbS0);
+
+       /* L[0] must be joined with S[0] */
+       if (tb->lnum[0] == -1) {
+               /* R[0] must be also joined with S[0] */
+               if (tb->rnum[0] == -1) {
+                       if (tb->FR[0] == PATH_H_PPARENT(tb->tb_path, 0)) {
+                               /*
+                                * all contents of all the
+                                * 3 buffers will be in L[0]
+                                */
+                               if (PATH_H_POSITION(tb->tb_path, 1) == 0 &&
+                                   1 < B_NR_ITEMS(tb->FR[0]))
+                                       replace_key(tb, tb->CFL[0],
+                                                   tb->lkey[0], tb->FR[0], 1);
+
+                               leaf_move_items(LEAF_FROM_S_TO_L, tb, n, -1,
+                                               NULL);
+                               leaf_move_items(LEAF_FROM_R_TO_L, tb,
+                                               B_NR_ITEMS(tb->R[0]), -1,
+                                               NULL);
+
+                               reiserfs_invalidate_buffer(tb, tbS0);
+                               reiserfs_invalidate_buffer(tb, tb->R[0]);
+
+                               return 0;
+                       }
+
+                       /* all contents of all the 3 buffers will be in R[0] */
+                       leaf_move_items(LEAF_FROM_S_TO_R, tb, n, -1, NULL);
+                       leaf_move_items(LEAF_FROM_L_TO_R, tb,
+                                       B_NR_ITEMS(tb->L[0]), -1, NULL);
+
+                       /* right_delimiting_key is correct in R[0] */
+                       replace_key(tb, tb->CFR[0], tb->rkey[0], tb->R[0], 0);
+
+                       reiserfs_invalidate_buffer(tb, tbS0);
+                       reiserfs_invalidate_buffer(tb, tb->L[0]);
+
+                       return -1;
+               }
+
+               RFALSE(tb->rnum[0] != 0,
+                      "PAP-12045: rnum must be 0 (%d)", tb->rnum[0]);
+               /* all contents of L[0] and S[0] will be in L[0] */
+               leaf_shift_left(tb, n, -1);
+
+               reiserfs_invalidate_buffer(tb, tbS0);
+
+               return 0;
+       }
+
+       /*
+        * a part of contents of S[0] will be in L[0] and
+        * the rest part of S[0] will be in R[0]
+        */
+
+       RFALSE((tb->lnum[0] + tb->rnum[0] < n) ||
+              (tb->lnum[0] + tb->rnum[0] > n + 1),
+              "PAP-12050: rnum(%d) and lnum(%d) and item "
+              "number(%d) in S[0] are not consistent",
+              tb->rnum[0], tb->lnum[0], n);
+       RFALSE((tb->lnum[0] + tb->rnum[0] == n) &&
+              (tb->lbytes != -1 || tb->rbytes != -1),
+              "PAP-12055: bad rbytes (%d)/lbytes (%d) "
+              "parameters when items are not split",
+              tb->rbytes, tb->lbytes);
+       RFALSE((tb->lnum[0] + tb->rnum[0] == n + 1) &&
+              (tb->lbytes < 1 || tb->rbytes != -1),
+              "PAP-12060: bad rbytes (%d)/lbytes (%d) "
+              "parameters when items are split",
+              tb->rbytes, tb->lbytes);
+
+       leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
+       leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
+
+       reiserfs_invalidate_buffer(tb, tbS0);
+
+       return 0;
+}
+
 /*
  * Balance leaf node in case of delete or cut: insert_size[0] < 0
  *
@@ -100,7 +240,6 @@ static int balance_leaf_when_delete(struct tree_balance *tb, int flag)
 {
        struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
        int item_pos = PATH_LAST_POSITION(tb->tb_path);
-       int pos_in_item = tb->tb_path->pos_in_item;
        struct buffer_info bi;
        int n;
        struct item_head *ih;
@@ -117,166 +256,23 @@ static int balance_leaf_when_delete(struct tree_balance *tb, int flag)
 
        /* Delete or truncate the item */
 
-       switch (flag) {
-       case M_DELETE:          /* delete item in S[0] */
-
-               RFALSE(ih_item_len(ih) + IH_SIZE != -tb->insert_size[0],
-                      "vs-12013: mode Delete, insert size %d, ih to be deleted %h",
-                      -tb->insert_size[0], ih);
-
-               leaf_delete_items(&bi, 0, item_pos, 1, -1);
-
-               if (!item_pos && tb->CFL[0]) {
-                       if (B_NR_ITEMS(tbS0)) {
-                               replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0,
-                                           0);
-                       } else {
-                               if (!PATH_H_POSITION(tb->tb_path, 1))
-                                       replace_key(tb, tb->CFL[0], tb->lkey[0],
-                                                   PATH_H_PPARENT(tb->tb_path,
-                                                                  0), 0);
-                       }
-               }
-
-               RFALSE(!item_pos && !tb->CFL[0],
-                      "PAP-12020: tb->CFL[0]==%p, tb->L[0]==%p", tb->CFL[0],
-                      tb->L[0]);
+       BUG_ON(flag != M_DELETE && flag != M_CUT);
+       if (flag == M_DELETE)
+               balance_leaf_when_delete_del(tb);
+       else /* M_CUT */
+               balance_leaf_when_delete_cut(tb);
 
-               break;
-
-       case M_CUT:{            /* cut item in S[0] */
-                       if (is_direntry_le_ih(ih)) {
-
-                               /*
-                                * UFS unlink semantics are such that you
-                                * can only delete one directory entry at
-                                * a time.
-                                */
-
-                               /*
-                                * when we cut a directory tb->insert_size[0]
-                                * means number of entries to be cut (always 1)
-                                */
-                               tb->insert_size[0] = -1;
-                               leaf_cut_from_buffer(&bi, item_pos, pos_in_item,
-                                                    -tb->insert_size[0]);
-
-                               RFALSE(!item_pos && !pos_in_item && !tb->CFL[0],
-                                      "PAP-12030: can not change delimiting key. CFL[0]=%p",
-                                      tb->CFL[0]);
-
-                               if (!item_pos && !pos_in_item && tb->CFL[0]) {
-                                       replace_key(tb, tb->CFL[0], tb->lkey[0],
-                                                   tbS0, 0);
-                               }
-                       } else {
-                               leaf_cut_from_buffer(&bi, item_pos, pos_in_item,
-                                                    -tb->insert_size[0]);
-
-                               RFALSE(!ih_item_len(ih),
-                                      "PAP-12035: cut must leave non-zero dynamic length of item");
-                       }
-                       break;
-               }
-
-       default:
-               print_cur_tb("12040");
-               reiserfs_panic(tb->tb_sb, "PAP-12040",
-                              "unexpected mode: %s(%d)",
-                              (flag ==
-                               M_PASTE) ? "PASTE" : ((flag ==
-                                                      M_INSERT) ? "INSERT" :
-                                                     "UNKNOWN"), flag);
-       }
 
        /*
         * the rule is that no shifting occurs unless by shifting
         * a node can be freed
         */
        n = B_NR_ITEMS(tbS0);
-       /* L[0] takes part in balancing */
-       if (tb->lnum[0]) {
-               /* L[0] must be joined with S[0] */
-               if (tb->lnum[0] == -1) {
-                       /* R[0] must be also joined with S[0] */
-                       if (tb->rnum[0] == -1) {
-                               if (tb->FR[0] == PATH_H_PPARENT(tb->tb_path, 0)) {
-                                       /*
-                                        * all contents of all the 3 buffers
-                                        * will be in L[0]
-                                        */
-                                       if (PATH_H_POSITION(tb->tb_path, 1) == 0
-                                           && 1 < B_NR_ITEMS(tb->FR[0]))
-                                               replace_key(tb, tb->CFL[0],
-                                                           tb->lkey[0],
-                                                           tb->FR[0], 1);
-
-                                       leaf_move_items(LEAF_FROM_S_TO_L, tb, n,
-                                                       -1, NULL);
-                                       leaf_move_items(LEAF_FROM_R_TO_L, tb,
-                                                       B_NR_ITEMS(tb->R[0]),
-                                                       -1, NULL);
-
-                                       reiserfs_invalidate_buffer(tb, tbS0);
-                                       reiserfs_invalidate_buffer(tb,
-                                                                  tb->R[0]);
-
-                                       return 0;
-                               }
-                               /*
-                                * all contents of all the 3 buffers will
-                                * be in R[0]
-                                */
-                               leaf_move_items(LEAF_FROM_S_TO_R, tb, n, -1,
-                                               NULL);
-                               leaf_move_items(LEAF_FROM_L_TO_R, tb,
-                                               B_NR_ITEMS(tb->L[0]), -1, NULL);
 
-                               /* right_delimiting_key is correct in R[0] */
-                               replace_key(tb, tb->CFR[0], tb->rkey[0],
-                                           tb->R[0], 0);
 
-                               reiserfs_invalidate_buffer(tb, tbS0);
-                               reiserfs_invalidate_buffer(tb, tb->L[0]);
-
-                               return -1;
-                       }
-
-                       RFALSE(tb->rnum[0] != 0,
-                              "PAP-12045: rnum must be 0 (%d)", tb->rnum[0]);
-                       /* all contents of L[0] and S[0] will be in L[0] */
-                       leaf_shift_left(tb, n, -1);
-
-                       reiserfs_invalidate_buffer(tb, tbS0);
-
-                       return 0;
-               }
-
-               /*
-                * a part of contents of S[0] will be in L[0] and the
-                * rest part of S[0] will be in R[0]
-                */
-
-               RFALSE((tb->lnum[0] + tb->rnum[0] < n) ||
-                      (tb->lnum[0] + tb->rnum[0] > n + 1),
-                      "PAP-12050: rnum(%d) and lnum(%d) and item number(%d) in S[0] are not consistent",
-                      tb->rnum[0], tb->lnum[0], n);
-               RFALSE((tb->lnum[0] + tb->rnum[0] == n) &&
-                      (tb->lbytes != -1 || tb->rbytes != -1),
-                      "PAP-12055: bad rbytes (%d)/lbytes (%d) parameters when items are not split",
-                      tb->rbytes, tb->lbytes);
-               RFALSE((tb->lnum[0] + tb->rnum[0] == n + 1) &&
-                      (tb->lbytes < 1 || tb->rbytes != -1),
-                      "PAP-12060: bad rbytes (%d)/lbytes (%d) parameters when items are split",
-                      tb->rbytes, tb->lbytes);
-
-               leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
-               leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
-
-               reiserfs_invalidate_buffer(tb, tbS0);
-
-               return 0;
-       }
+       /* L[0] takes part in balancing */
+       if (tb->lnum[0])
+               return balance_leaf_when_delete_left(tb);
 
        if (tb->rnum[0] == -1) {
                /* all contents of R[0] and S[0] will be in R[0] */
@@ -1253,7 +1249,7 @@ static void balance_leaf_new_nodes(struct tree_balance *tb,
                       || buffer_journal_dirty(tb->S_new[i])
                       || buffer_dirty(tb->S_new[i]),
                       "PAP-12247: S_new[%d] : (%b)",
-                      i, format_bh(tb->S_new[i]));
+                      i, tb->S_new[i]);
        }
 }
 
@@ -1263,18 +1259,49 @@ static void balance_leaf_finish_node_insert(struct tree_balance *tb,
 {
        struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
        struct buffer_info bi;
-                       buffer_info_init_tbS0(tb, &bi);
-                       leaf_insert_into_buf(&bi, tb->item_pos, ih,
-                                            body, tb->zeroes_num);
-
-                       /*
-                        * If we insert the first key
-                        * change the delimiting key
-                        */
-                       if (tb->item_pos == 0) {
-                               if (tb->CFL[0]) /* can be 0 in reiserfsck */
-                                       replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0, 0);
-                       }
+       buffer_info_init_tbS0(tb, &bi);
+       leaf_insert_into_buf(&bi, tb->item_pos, ih, body, tb->zeroes_num);
+
+       /* If we insert the first key change the delimiting key */
+       if (tb->item_pos == 0) {
+               if (tb->CFL[0]) /* can be 0 in reiserfsck */
+                       replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0, 0);
+
+       }
+}
+
+static void balance_leaf_finish_node_paste_dirent(struct tree_balance *tb,
+                                                 struct item_head *ih,
+                                                 const char *body)
+{
+       struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
+       struct item_head *pasted = item_head(tbS0, tb->item_pos);
+       struct buffer_info bi;
+
+       if (tb->pos_in_item >= 0 && tb->pos_in_item <= ih_entry_count(pasted)) {
+               RFALSE(!tb->insert_size[0],
+                      "PAP-12260: insert_size is 0 already");
+
+               /* prepare space */
+               buffer_info_init_tbS0(tb, &bi);
+               leaf_paste_in_buffer(&bi, tb->item_pos, tb->pos_in_item,
+                                    tb->insert_size[0], body, tb->zeroes_num);
+
+               /* paste entry */
+               leaf_paste_entries(&bi, tb->item_pos, tb->pos_in_item, 1,
+                                  (struct reiserfs_de_head *)body,
+                                  body + DEH_SIZE, tb->insert_size[0]);
+
+               if (!tb->item_pos && !tb->pos_in_item) {
+                       RFALSE(!tb->CFL[0] || !tb->L[0],
+                              "PAP-12270: CFL[0]/L[0] must  be specified");
+                       if (tb->CFL[0])
+                               replace_key(tb, tb->CFL[0], tb->lkey[0],
+                                           tbS0, 0);
+               }
+
+               tb->insert_size[0] = 0;
+       }
 }
 
 static void balance_leaf_finish_node_paste(struct tree_balance *tb,
@@ -1283,74 +1310,37 @@ static void balance_leaf_finish_node_paste(struct tree_balance *tb,
 {
        struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
        struct buffer_info bi;
-                               struct item_head *pasted;
-
-                               pasted = item_head(tbS0, tb->item_pos);
-                               /* when directory, may be new entry already pasted */
-                               if (is_direntry_le_ih(pasted)) {
-                                       if (tb->pos_in_item >= 0 && tb->pos_in_item <= ih_entry_count(pasted)) {
-
-                                               RFALSE(!tb->insert_size[0],
-                                                      "PAP-12260: insert_size is 0 already");
-
-                                               /* prepare space */
-                                               buffer_info_init_tbS0(tb, &bi);
-                                               leaf_paste_in_buffer(&bi, tb->item_pos, tb->pos_in_item,
-                                                                    tb->insert_size[0], body,
-                                                                    tb->zeroes_num);
-
-                                               /* paste entry */
-                                               leaf_paste_entries(&bi, tb->item_pos, tb->pos_in_item, 1,
-                                                                  (struct reiserfs_de_head *)body,
-                                                                  body + DEH_SIZE,
-                                                                  tb->insert_size[0]);
-                                               if (!tb->item_pos && !tb->pos_in_item) {
-                                                       RFALSE(!tb->CFL[0] || !tb->L[0],
-                                                              "PAP-12270: CFL[0]/L[0] must be specified");
-                                                       if (tb->CFL[0])
-                                                               replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0, 0);
-                                               }
-                                               tb->insert_size[0] = 0;
-                                       }
-                               } else {        /* regular object */
-                                       if (tb->pos_in_item == ih_item_len(pasted)) {
-
-                                               RFALSE(tb->insert_size[0] <= 0,
-                                                      "PAP-12275: insert size must not be %d",
-                                                      tb->insert_size[0]);
-                                               buffer_info_init_tbS0(tb, &bi);
-                                               leaf_paste_in_buffer(&bi, tb->item_pos, tb->pos_in_item,
-                                                                    tb->insert_size[0], body, tb->zeroes_num);
-
-                                               if (is_indirect_le_ih(pasted)) {
-#if 0
-                                                       RFALSE(tb->
-                                                              insert_size[0] !=
-                                                              UNFM_P_SIZE,
-                                                              "PAP-12280: insert_size for indirect item must be %d, not %d",
-                                                              UNFM_P_SIZE,
-                                                              tb->
-                                                              insert_size[0]);
-#endif
-                                                       set_ih_free_space(pasted, 0);
-                                               }
-                                               tb->insert_size[0] = 0;
-                                       }
+       struct item_head *pasted = item_head(tbS0, tb->item_pos);
+
+       /* when directory, may be new entry already pasted */
+       if (is_direntry_le_ih(pasted)) {
+               balance_leaf_finish_node_paste_dirent(tb, ih, body);
+               return;
+       }
+
+       /* regular object */
+
+       if (tb->pos_in_item == ih_item_len(pasted)) {
+               RFALSE(tb->insert_size[0] <= 0,
+                      "PAP-12275: insert size must not be %d",
+                      tb->insert_size[0]);
+               buffer_info_init_tbS0(tb, &bi);
+               leaf_paste_in_buffer(&bi, tb->item_pos,
+                                    tb->pos_in_item, tb->insert_size[0], body,
+                                    tb->zeroes_num);
+
+               if (is_indirect_le_ih(pasted))
+                       set_ih_free_space(pasted, 0);
+
+               tb->insert_size[0] = 0;
+       }
 #ifdef CONFIG_REISERFS_CHECK
-                                       else {
-                                               if (tb->insert_size[0]) {
-                                                       print_cur_tb("12285");
-                                                       reiserfs_panic(tb->tb_sb,
-                                                           "PAP-12285",
-                                                           "insert_size "
-                                                           "must be 0 "
-                                                           "(%d)",
-                                                           tb->insert_size[0]);
-                                               }
-                                       }
-#endif                         /* CONFIG_REISERFS_CHECK */
-
-                               }
+       else if (tb->insert_size[0]) {
+               print_cur_tb("12285");
+               reiserfs_panic(tb->tb_sb, "PAP-12285",
+                   "insert_size must be 0 (%d)", tb->insert_size[0]);
+       }
+#endif
 }
 
 /*
@@ -1899,9 +1889,8 @@ void do_balance(struct tree_balance *tb, struct item_head *ih,
 
        /* Balance internal level of the tree. */
        for (h = 1; h < MAX_HEIGHT && tb->insert_size[h]; h++)
-               child_pos =
-                   balance_internal(tb, h, child_pos, insert_key, insert_ptr);
+               child_pos = balance_internal(tb, h, child_pos, insert_key,
+                                            insert_ptr);
 
        do_balance_completed(tb);
-
 }