From: Edward Shishkin <edward.shishkin@gmail.com>
To: ReiserFS development mailing list <reiserfs-devel@vger.kernel.org>
Subject: [PATCH] reiser4: fix problem of non-deletable directories
Date: Fri, 26 Sep 2014 22:01:01 +0200 [thread overview]
Message-ID: <5425C5FD.6020907@gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 1 bytes --]
[-- Attachment #2: reiser4-fix-problem-non-deletable-dirs.patch --]
[-- Type: text/x-patch, Size: 6682 bytes --]
Problem:
parse_cut() calculates cut mode incorrectly when the range contains
objects with non-unique keys, e.g. directory items.
Scenario of corruption.
A node contains only one cde-item with 44 (#0-#43) units, and the units
#42,#43 have identical keys (because of hash collision). We shift units
#0-#42 to left. In this case parse_cut() jumps to the branch "removed
completely". As the result the whole item is removed, while only units
#0-#42 are copied to the left neighbor. unlink() can not find directory
entry which corresponds to unexpectedly killed unit #43. rmdir() doesn't
decrement size of the directory in the error path. As the result, the
directory becomes non-deletable.
Fixup:
For ranges with non-unique keys use a special version of parse_cut(),
which doesn't calculate cut mode by keys.
Signed-off-by: Edward Shishkin <edward.shishkin@gmail.com>
---
fs/reiser4/plugin/node/node40.c | 148 ++++++++++++++++++++++++++++++++--------
1 file changed, 122 insertions(+), 26 deletions(-)
--- a/fs/reiser4/plugin/node/node40.c
+++ b/fs/reiser4/plugin/node/node40.c
@@ -1017,36 +1017,32 @@ int shrink_item_node40(coord_t * coord,
return 0;
}
-/* this is used by cut_node40 and kill_node40. It analyses input parameters and calculates cut mode. There are 2 types
- of cut. First is when a unit is removed from the middle of an item. In this case this function returns 1. All the
- rest fits into second case: 0 or 1 of items getting tail cut, 0 or more items removed completely and 0 or 1 item
- getting head cut. Function returns 0 in this case */
-static int
-parse_cut(struct cut40_info *cinfo, const struct cut_kill_params *params)
+/*
+ * Evaluate cut mode, if key range has been specified.
+ *
+ * This is for the case when units are not minimal objects
+ * addressed by keys.
+ *
+ * This doesn't work when range contains objects with
+ * non-unique keys (e.g. directory items).
+ */
+static int parse_cut_by_key_range(struct cut40_info *cinfo,
+ const struct cut_kill_params *params)
{
- reiser4_key left_key, right_key;
reiser4_key min_from_key, max_to_key;
- const reiser4_key *from_key, *to_key;
-
- init_cinfo(cinfo);
-
- /* calculate minimal key stored in first item of items to be cut (params->from) */
+ const reiser4_key *from_key = params->from_key;
+ const reiser4_key *to_key = params->to_key;
+ /*
+ * calculate minimal key stored in first item
+ * of items to be cut (params->from)
+ */
item_key_by_coord(params->from, &min_from_key);
- /* and max key stored in last item of items to be cut (params->to) */
+ /*
+ * calculate maximal key stored in last item
+ * of items to be cut (params->to)
+ */
max_item_key_by_coord(params->to, &max_to_key);
- /* if cut key range is not defined in input parameters - define it using cut coord range */
- if (params->from_key == NULL) {
- assert("vs-1513", params->to_key == NULL);
- unit_key_by_coord(params->from, &left_key);
- from_key = &left_key;
- max_unit_key_by_coord(params->to, &right_key);
- to_key = &right_key;
- } else {
- from_key = params->from_key;
- to_key = params->to_key;
- }
-
if (params->from->item_pos == params->to->item_pos) {
if (keylt(&min_from_key, from_key)
&& keylt(to_key, &max_to_key))
@@ -1069,7 +1065,7 @@ parse_cut(struct cut40_info *cinfo, cons
} else {
cinfo->first_removed = params->from->item_pos + 1;
cinfo->removed_count =
- params->to->item_pos - params->from->item_pos - 1;
+ params->to->item_pos - params->from->item_pos - 1;
if (keygt(from_key, &min_from_key)) {
/* first item is not cut completely */
@@ -1089,10 +1085,110 @@ parse_cut(struct cut40_info *cinfo, cons
if (cinfo->removed_count)
cinfo->mode |= CMODE_WHOLE;
}
+ return 0;
+}
+
+/*
+ * Evaluate cut mode, if the key range hasn't been specified.
+ * In this case the range can include objects with non-unique
+ * keys (e.g. directory entries).
+ *
+ * This doesn't work when units are not the minimal objects
+ * addressed by keys (e.g. bytes in file's body stored in
+ * unformatted nodes).
+ */
+static int parse_cut_by_coord_range(struct cut40_info *cinfo,
+ const struct cut_kill_params *params)
+{
+ coord_t *from = params->from;
+ coord_t *to = params->to;
+
+ if (from->item_pos == to->item_pos) {
+ /*
+ * cut is performed on only one item
+ */
+ if (from->unit_pos > 0 &&
+ to->unit_pos < coord_last_unit_pos(to))
+ /*
+ * cut from the middle of item
+ */
+ return 1;
+ if (from->unit_pos > 0) {
+ /*
+ * tail of item is to be cut
+ */
+ cinfo->tail_removed = params->from->item_pos;
+ cinfo->mode |= CMODE_TAIL;
+ } else if (to->unit_pos < coord_last_unit_pos(to)) {
+ /*
+ * head of item is to be cut
+ */
+ cinfo->head_removed = params->from->item_pos;
+ cinfo->mode |= CMODE_HEAD;
+ } else {
+ /*
+ * item is removed completely
+ */
+ assert("edward-1631",
+ from->unit_pos == 0 &&
+ to->unit_pos == coord_last_unit_pos(to));
+
+ cinfo->first_removed = params->from->item_pos;
+ cinfo->removed_count = 1;
+ cinfo->mode |= CMODE_WHOLE;
+ }
+ } else {
+ cinfo->first_removed = from->item_pos + 1;
+ cinfo->removed_count =
+ to->item_pos - from->item_pos - 1;
+ if (from->unit_pos > 0) {
+ /*
+ * first item is not cut completely
+ */
+ cinfo->tail_removed = from->item_pos;
+ cinfo->mode |= CMODE_TAIL;
+ } else {
+ cinfo->first_removed--;
+ cinfo->removed_count++;
+ }
+ if (to->unit_pos < coord_last_unit_pos(to)) {
+ /*
+ * last item is not cut completely
+ */
+ cinfo->head_removed = to->item_pos;
+ cinfo->mode |= CMODE_HEAD;
+ } else {
+ cinfo->removed_count++;
+ }
+ if (cinfo->removed_count)
+ cinfo->mode |= CMODE_WHOLE;
+ }
return 0;
}
+/*
+ * this is used by cut_node40 and kill_node40. It analyses input parameters
+ * and calculates cut mode. There are 2 types of cut. First is when a unit is
+ * removed from the middle of an item. In this case this function returns 1.
+ * All the rest fits into second case: 0 or 1 of items getting tail cut, 0 or
+ * more items removed completely and 0 or 1 item getting head cut. Function
+ * returns 0 in this case
+ */
+static int parse_cut(struct cut40_info *cinfo,
+ const struct cut_kill_params *params)
+{
+ init_cinfo(cinfo);
+ if (params->from_key == NULL) {
+ /*
+ * cut key range is not defined in input parameters
+ */
+ assert("vs-1513", params->to_key == NULL);
+ return parse_cut_by_coord_range(cinfo, params);
+ } else
+ return parse_cut_by_key_range(cinfo, params);
+}
+
static void
call_kill_hooks(znode * node, pos_in_node_t from, pos_in_node_t count,
carry_kill_data * kdata)
next reply other threads:[~2014-09-26 20:01 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-09-26 20:01 Edward Shishkin [this message]
2014-09-27 2:22 ` [PATCH] reiser4: fix problem of non-deletable directories Evgeniy
2014-10-12 11:43 ` Edward Shishkin
2014-09-27 23:16 ` Ivan Shapovalov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5425C5FD.6020907@gmail.com \
--to=edward.shishkin@gmail.com \
--cc=reiserfs-devel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.