ref: d50817eb368e41137c872ddc02b3653c3209f8d9
parent: 7e64817a1cf30c6ce31a9a23ab3301dc5fa3056b
author: ngkaho1234 <ngkaho1234@gmail.com>
date: Fri Jan 1 22:36:09 EST 2016
ext4: rework ext4_dir_rm to split it into many small transactions.
--- a/lwext4/ext4.c
+++ b/lwext4/ext4.c
@@ -2430,7 +2430,6 @@
return ENOENT;
EXT4_MP_LOCK(mp);
- ext4_trans_start(mp);
struct ext4_fs *const fs = &mp->fs;
@@ -2446,31 +2445,37 @@
len = ext4_path_check(path, &is_goal);
inode_current = f.inode;
- dir_end = false;
ext4_block_cache_write_back(mp->fs.bdev, 1);
do {
- /*Load directory node.*/
- r = ext4_fs_get_inode_ref(fs, inode_current, &act);
- if (r != EOK) {
- break;
- }
- /*Initialize iterator.*/
- r = ext4_dir_iterator_init(&it, &act, 0);
- if (r != EOK) {
- ext4_fs_put_inode_ref(&act);
- break;
- }
+ uint64_t act_curr_pos = 0;
+ has_children = false;
+ dir_end = false;
- while (r == EOK) {
+ while (r == EOK && !has_children && !dir_end) {
+ /*Load directory node.*/
+ r = ext4_fs_get_inode_ref(fs, inode_current, &act);
+ if (r != EOK) {
+ break;
+ }
+
+ /*Initialize iterator.*/
+ r = ext4_dir_iterator_init(&it, &act, act_curr_pos);
+ if (r != EOK) {
+ ext4_fs_put_inode_ref(&act);
+ break;
+ }
+
if (!it.curr) {
dir_end = true;
- break;
+ goto End;
}
+ ext4_trans_start(mp);
+
/*Get up directory inode when ".." entry*/
if ((it.curr->name_len == 2) &&
ext4_is_dots(it.curr->name, it.curr->name_len)) {
@@ -2486,13 +2491,13 @@
cinode = ext4_dir_en_get_inode(it.curr);
r = ext4_fs_get_inode_ref(fs, cinode, &child);
if (r != EOK)
- break;
+ goto End;
/*If directory with no leaf children*/
r = ext4_has_children(&has_children, &child);
if (r != EOK) {
ext4_fs_put_inode_ref(&child);
- break;
+ goto End;
}
if (has_children) {
@@ -2502,9 +2507,16 @@
inode_current = cinode;
depth++;
ext4_fs_put_inode_ref(&child);
- break;
+ goto End;
}
+ /* Truncate */
+ r = ext4_fs_truncate_inode(&child, 0);
+ if (r != EOK) {
+ ext4_fs_put_inode_ref(&child);
+ goto End;
+ }
+
/*No children in child directory or file. Just
* unlink.*/
r = ext4_unlink(f.mp, &act, &child,
@@ -2512,102 +2524,115 @@
it.curr->name_len);
if (r != EOK) {
ext4_fs_put_inode_ref(&child);
- break;
+ goto End;
}
ext4_inode_set_del_time(child.inode, -1L);
ext4_inode_set_links_cnt(child.inode, 0);
child.dirty = true;
- /*Turncate*/
- r = ext4_fs_truncate_inode(&child, 0);
- if (r != EOK) {
- ext4_fs_put_inode_ref(&child);
- break;
- }
r = ext4_fs_free_inode(&child);
if (r != EOK) {
ext4_fs_put_inode_ref(&child);
- break;
+ goto End;
}
r = ext4_fs_put_inode_ref(&child);
if (r != EOK)
- break;
+ goto End;
+
}
r = ext4_dir_iterator_next(&it);
+ if (r != EOK)
+ goto End;
+
+ act_curr_pos = it.curr_off;
+End:
+ ext4_dir_iterator_fini(&it);
+ if (r == EOK)
+ r = ext4_fs_put_inode_ref(&act);
+ else
+ ext4_fs_put_inode_ref(&act);
+
+ if (r != EOK)
+ ext4_trans_abort(mp);
+ else
+ ext4_trans_stop(mp);
}
if (dir_end) {
/*Directory iterator reached last entry*/
- ext4_has_children(&has_children, &act);
- if (!has_children) {
+ depth--;
+ if (depth)
inode_current = inode_up;
- if (depth)
- depth--;
- }
- /*Last unlink*/
- if (!depth) {
- /*Load parent.*/
- struct ext4_inode_ref parent;
- r = ext4_fs_get_inode_ref(&f.mp->fs, inode_up,
- &parent);
- if (r != EOK)
- goto End;
- /* In this place all directories should be
- * unlinked.
- * Last unlink from root of current directory*/
- r = ext4_unlink(f.mp, &parent, &act,
- (char *)path, len);
- if (r != EOK) {
- ext4_fs_put_inode_ref(&parent);
- goto End;
- }
+ }
- if (ext4_inode_get_links_cnt(act.inode) == 2) {
- ext4_inode_set_del_time(act.inode, -1L);
- ext4_inode_set_links_cnt(act.inode, 0);
- act.dirty = true;
- /*Turncate*/
- r = ext4_fs_truncate_inode(&act, 0);
- if (r != EOK) {
- ext4_fs_put_inode_ref(&parent);
- goto End;
- }
+ } while (depth);
- r = ext4_fs_free_inode(&act);
- if (r != EOK) {
- ext4_fs_put_inode_ref(&parent);
- goto End;
- }
- }
+ /*Last unlink*/
+ if (r == EOK && !depth) {
+ /*Load parent.*/
+ struct ext4_inode_ref parent;
+ r = ext4_fs_get_inode_ref(&f.mp->fs, inode_up,
+ &parent);
+ if (r != EOK)
+ goto Finish;
+ r = ext4_fs_get_inode_ref(&f.mp->fs, inode_current,
+ &act);
+ if (r != EOK) {
+ ext4_fs_put_inode_ref(&act);
+ goto Finish;
+ }
- r = ext4_fs_put_inode_ref(&parent);
- if (r != EOK)
- goto End;
+ ext4_trans_start(mp);
+
+ /* In this place all directories should be
+ * unlinked.
+ * Last unlink from root of current directory*/
+ r = ext4_unlink(f.mp, &parent, &act,
+ (char *)path, len);
+ if (r != EOK) {
+ ext4_fs_put_inode_ref(&parent);
+ ext4_fs_put_inode_ref(&act);
+ goto Finish;
+ }
+
+ if (ext4_inode_get_links_cnt(act.inode) == 2) {
+ ext4_inode_set_del_time(act.inode, -1L);
+ ext4_inode_set_links_cnt(act.inode, 0);
+ act.dirty = true;
+ /*Turncate*/
+ r = ext4_fs_truncate_inode(&act, 0);
+ if (r != EOK) {
+ ext4_fs_put_inode_ref(&parent);
+ ext4_fs_put_inode_ref(&act);
+ goto Finish;
}
+
+ r = ext4_fs_free_inode(&act);
+ if (r != EOK) {
+ ext4_fs_put_inode_ref(&parent);
+ ext4_fs_put_inode_ref(&act);
+ goto Finish;
+ }
}
- End:
- ext4_dir_iterator_fini(&it);
- ext4_fs_put_inode_ref(&act);
- dir_end = false;
+ r = ext4_fs_put_inode_ref(&parent);
+ if (r != EOK)
+ goto Finish;
- /*When something goes wrong. End loop.*/
+ r = ext4_fs_put_inode_ref(&act);
+ Finish:
if (r != EOK)
- break;
+ ext4_trans_abort(mp);
+ else
+ ext4_trans_stop(mp);
+ }
- } while (depth);
-
ext4_block_cache_write_back(mp->fs.bdev, 0);
EXT4_MP_UNLOCK(mp);
-
- if (r != EOK)
- ext4_trans_abort(mp);
- else
- ext4_trans_stop(mp);
return r;
}