Browse Source

Numorous changes. See below:

- ext4: ext4_trunc_inode now requires inode index instead of an
          existing inode_ref.
  - ext4: the support of removing directory recursively is temporarily
          dropped.
  - ext4: ext4_dir_rm temporarily relies on ext4_fs_truncate instead of
          ext4_trunc_inode to ensure directory inode not having 0
          length in case of power failure.

  - ext4_journal: connect transactions having reference to the same blocks
                  together.
pull/11/head
ngkaho1234 9 years ago
parent
commit
b05eaa268d
  1. 348
      lwext4/ext4.c
  2. 165
      lwext4/ext4_journal.c
  3. 3
      lwext4/ext4_types.h

348
lwext4/ext4.c

@ -705,52 +705,73 @@ static bool ext4_parse_flags(const char *flags, uint32_t *file_flags)
} }
static int ext4_trunc_inode(struct ext4_mountpoint *mp, static int ext4_trunc_inode(struct ext4_mountpoint *mp,
struct ext4_inode_ref *inode_ref, uint64_t new_size) uint32_t index, uint64_t new_size)
{ {
int r = EOK; int r = EOK;
struct ext4_fs *const fs = &mp->fs; struct ext4_fs *const fs = &mp->fs;
uint64_t inode_size = ext4_inode_get_size(&fs->sb, inode_ref->inode); struct ext4_inode_ref inode_ref;
uint32_t index = inode_ref->index; uint64_t inode_size;
bool has_trans = mp->fs.jbd_journal && mp->fs.curr_trans;
r = ext4_fs_get_inode_ref(fs, index, &inode_ref);
if (r != EOK)
return r;
inode_size = ext4_inode_get_size(&fs->sb, inode_ref.inode);
ext4_fs_put_inode_ref(&inode_ref);
if (has_trans)
ext4_trans_stop(mp);
while (inode_size > new_size + CONFIG_MAX_TRUNCATE_SIZE) { while (inode_size > new_size + CONFIG_MAX_TRUNCATE_SIZE) {
inode_size -= CONFIG_MAX_TRUNCATE_SIZE; inode_size -= CONFIG_MAX_TRUNCATE_SIZE;
ext4_trans_start(mp); ext4_trans_start(mp);
r = ext4_fs_truncate_inode(inode_ref, inode_size); r = ext4_fs_get_inode_ref(fs, index, &inode_ref);
if (r != EOK) {
ext4_trans_abort(mp);
break;
}
r = ext4_fs_truncate_inode(&inode_ref, inode_size);
if (r != EOK) if (r != EOK)
return r; ext4_fs_put_inode_ref(&inode_ref);
else
r = ext4_fs_put_inode_ref(&inode_ref);
r = ext4_fs_put_inode_ref(inode_ref); if (r != EOK) {
if (r != EOK)
ext4_trans_abort(mp); ext4_trans_abort(mp);
else goto Finish;
} else
ext4_trans_stop(mp); ext4_trans_stop(mp);
r = ext4_fs_get_inode_ref(fs, index, inode_ref);
if (r != EOK)
return r;
} }
if (inode_size > new_size) { if (inode_size > new_size) {
inode_size = new_size; inode_size = new_size;
ext4_trans_start(mp); ext4_trans_start(mp);
r = ext4_fs_truncate_inode(inode_ref, inode_size); r = ext4_fs_get_inode_ref(fs, index, &inode_ref);
if (r != EOK) {
ext4_trans_abort(mp);
goto Finish;
}
r = ext4_fs_truncate_inode(&inode_ref, inode_size);
if (r != EOK) if (r != EOK)
return r; ext4_fs_put_inode_ref(&inode_ref);
else
r = ext4_fs_put_inode_ref(&inode_ref);
r = ext4_fs_put_inode_ref(inode_ref);
if (r != EOK) if (r != EOK)
ext4_trans_abort(mp); ext4_trans_abort(mp);
else else
ext4_trans_stop(mp); ext4_trans_stop(mp);
r = ext4_fs_get_inode_ref(fs, index, inode_ref);
if (r != EOK)
return r;
} }
Finish:
if (has_trans)
ext4_trans_start(mp);
return r; return r;
} }
@ -796,6 +817,9 @@ static int ext4_generic_open2(ext4_file *f, const char *path, int flags,
if (parent_inode) if (parent_inode)
*parent_inode = ref.index; *parent_inode = ref.index;
if (flags & O_CREAT)
ext4_trans_start(mp);
len = ext4_path_check(path, &is_goal); len = ext4_path_check(path, &is_goal);
while (1) { while (1) {
@ -905,7 +929,7 @@ static int ext4_generic_open2(ext4_file *f, const char *path, int flags,
if (is_goal) { if (is_goal) {
if ((f->flags & O_TRUNC) && (imode == EXT4_INODE_MODE_FILE)) { if ((f->flags & O_TRUNC) && (imode == EXT4_INODE_MODE_FILE)) {
r = ext4_trunc_inode(mp, &ref, 0); r = ext4_trunc_inode(mp, ref.index, 0);
if (r != EOK) { if (r != EOK) {
ext4_fs_put_inode_ref(&ref); ext4_fs_put_inode_ref(&ref);
return r; return r;
@ -923,6 +947,14 @@ static int ext4_generic_open2(ext4_file *f, const char *path, int flags,
} }
r = ext4_fs_put_inode_ref(&ref); r = ext4_fs_put_inode_ref(&ref);
if (flags & O_CREAT) {
if (r == EOK)
ext4_trans_stop(mp);
else
ext4_trans_abort(mp);
}
return r; return r;
} }
@ -1270,6 +1302,29 @@ int ext4_fremove(const char *path)
EXT4_MP_UNLOCK(mp); EXT4_MP_UNLOCK(mp);
return r; return r;
} }
/* We do not allow opening files here. */
if (ext4_inode_type(&mp->fs.sb, child.inode) ==
EXT4_INODE_MODE_DIRECTORY) {
ext4_fs_put_inode_ref(&parent);
ext4_fs_put_inode_ref(&child);
ext4_trans_abort(mp);
EXT4_MP_UNLOCK(mp);
return r;
}
/*Link count will be zero, the inode should be freed. */
if (ext4_inode_get_links_cnt(child.inode) == 1) {
ext4_block_cache_write_back(mp->fs.bdev, 1);
r = ext4_trunc_inode(mp, child.index, 0);
if (r != EOK) {
ext4_fs_put_inode_ref(&parent);
ext4_fs_put_inode_ref(&child);
ext4_trans_abort(mp);
EXT4_MP_UNLOCK(mp);
return r;
}
ext4_block_cache_write_back(mp->fs.bdev, 0);
}
/*Set path*/ /*Set path*/
path += name_off; path += name_off;
@ -1284,14 +1339,6 @@ int ext4_fremove(const char *path)
/*Link count is zero, the inode should be freed. */ /*Link count is zero, the inode should be freed. */
if (!ext4_inode_get_links_cnt(child.inode)) { if (!ext4_inode_get_links_cnt(child.inode)) {
ext4_inode_set_del_time(child.inode, -1L); ext4_inode_set_del_time(child.inode, -1L);
/*Turncate*/
ext4_block_cache_write_back(mp->fs.bdev, 1);
/*Truncate may be IO heavy. Do it writeback cache mode.*/
r = ext4_trunc_inode(mp, &child, 0);
ext4_block_cache_write_back(mp->fs.bdev, 0);
if (r != EOK)
goto Finish;
r = ext4_fs_free_inode(&child); r = ext4_fs_free_inode(&child);
if (r != EOK) if (r != EOK)
@ -1360,17 +1407,11 @@ int ext4_fopen(ext4_file *f, const char *path, const char *flags)
return ENOENT; return ENOENT;
EXT4_MP_LOCK(mp); EXT4_MP_LOCK(mp);
ext4_trans_start(mp);
ext4_block_cache_write_back(mp->fs.bdev, 1); ext4_block_cache_write_back(mp->fs.bdev, 1);
r = ext4_generic_open(f, path, flags, true, 0, 0); r = ext4_generic_open(f, path, flags, true, 0, 0);
ext4_block_cache_write_back(mp->fs.bdev, 0); ext4_block_cache_write_back(mp->fs.bdev, 0);
if (r != EOK)
ext4_trans_abort(mp);
else
ext4_trans_stop(mp);
EXT4_MP_UNLOCK(mp); EXT4_MP_UNLOCK(mp);
return r; return r;
} }
@ -1387,17 +1428,11 @@ int ext4_fopen2(ext4_file *f, const char *path, int flags)
filetype = EXT4_DE_REG_FILE; filetype = EXT4_DE_REG_FILE;
EXT4_MP_LOCK(mp); EXT4_MP_LOCK(mp);
ext4_trans_start(mp);
ext4_block_cache_write_back(mp->fs.bdev, 1); ext4_block_cache_write_back(mp->fs.bdev, 1);
r = ext4_generic_open2(f, path, flags, filetype, NULL, NULL); r = ext4_generic_open2(f, path, flags, filetype, NULL, NULL);
ext4_block_cache_write_back(mp->fs.bdev, 0); ext4_block_cache_write_back(mp->fs.bdev, 0);
if (r != EOK)
ext4_trans_abort(mp);
else
ext4_trans_stop(mp);
EXT4_MP_UNLOCK(mp); EXT4_MP_UNLOCK(mp);
return r; return r;
} }
@ -1438,7 +1473,7 @@ static int ext4_ftruncate_no_lock(ext4_file *f, uint64_t size)
if (r != EOK) if (r != EOK)
goto Finish; goto Finish;
r = ext4_trunc_inode(f->mp, &ref, size); r = ext4_trunc_inode(f->mp, ref.index, size);
if (r != EOK) if (r != EOK)
goto Finish; goto Finish;
@ -2463,26 +2498,19 @@ int ext4_dir_rm(const char *path)
ext4_file f; ext4_file f;
struct ext4_mountpoint *mp = ext4_get_mount(path); struct ext4_mountpoint *mp = ext4_get_mount(path);
struct ext4_inode_ref act; struct ext4_inode_ref act, parent;
struct ext4_inode_ref child;
struct ext4_dir_iter it;
uint32_t name_off; uint32_t name_off;
uint32_t inode_up; uint32_t inode_up, inode_current;
uint32_t inode_current;
uint32_t depth = 1;
bool has_children; bool has_children = false;
bool is_goal; bool is_goal;
bool dir_end;
if (!mp) if (!mp)
return ENOENT; return ENOENT;
EXT4_MP_LOCK(mp); EXT4_MP_LOCK(mp);
struct ext4_fs *const fs = &mp->fs;
/*Check if exist.*/ /*Check if exist.*/
r = ext4_generic_open(&f, path, "r", false, &inode_up, &name_off); r = ext4_generic_open(&f, path, "r", false, &inode_up, &name_off);
if (r != EOK) { if (r != EOK) {
@ -2498,188 +2526,74 @@ int ext4_dir_rm(const char *path)
ext4_block_cache_write_back(mp->fs.bdev, 1); ext4_block_cache_write_back(mp->fs.bdev, 1);
do { /*Load parent.*/
r = ext4_fs_get_inode_ref(&f.mp->fs, inode_up,
uint64_t act_curr_pos = 0; &parent);
has_children = false; if (r != EOK)
dir_end = false; goto Finish;
r = ext4_fs_get_inode_ref(&f.mp->fs, inode_current,
while (r == EOK && !has_children && !dir_end) { &act);
if (r != EOK) {
/*Load directory node.*/ ext4_fs_put_inode_ref(&parent);
r = ext4_fs_get_inode_ref(fs, inode_current, &act); goto Finish;
if (r != EOK) { }
break; r = ext4_has_children(&has_children, &act);
} if (r != EOK) {
ext4_fs_put_inode_ref(&parent);
/*Initialize iterator.*/ ext4_fs_put_inode_ref(&act);
r = ext4_dir_iterator_init(&it, &act, act_curr_pos); goto Finish;
if (r != EOK) { }
ext4_fs_put_inode_ref(&act); if (has_children) {
break; r = ENOTEMPTY;
} ext4_fs_put_inode_ref(&parent);
ext4_fs_put_inode_ref(&act);
if (!it.curr) { goto Finish;
dir_end = true; }
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)) {
inode_up = ext4_dir_en_get_inode(it.curr);
}
/*If directory or file entry, but not "." ".." entry*/
if (!ext4_is_dots(it.curr->name, it.curr->name_len)) {
/*Get child inode reference do unlink
* directory/file.*/
uint32_t cinode;
cinode = ext4_dir_en_get_inode(it.curr);
r = ext4_fs_get_inode_ref(fs, cinode, &child);
if (r != EOK)
goto End;
/*If directory with no leaf children*/
r = ext4_has_children(&has_children, &child);
if (r != EOK) {
ext4_fs_put_inode_ref(&child);
goto End;
}
if (has_children) {
/*Has directory children. Go into this
* directory.*/
inode_up = inode_current;
inode_current = cinode;
depth++;
ext4_fs_put_inode_ref(&child);
goto End;
}
/* Truncate */
r = ext4_trunc_inode(mp, &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,
(char *)it.curr->name,
it.curr->name_len);
if (r != EOK) {
ext4_fs_put_inode_ref(&child);
goto End;
}
ext4_inode_set_del_time(child.inode, -1L);
ext4_inode_set_links_cnt(child.inode, 0);
child.dirty = true;
r = ext4_fs_free_inode(&child);
if (r != EOK) {
ext4_fs_put_inode_ref(&child);
goto End;
}
r = ext4_fs_put_inode_ref(&child);
if (r != EOK)
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*/
depth--;
if (depth)
inode_current = inode_up;
}
} while (depth); ext4_trans_start(mp);
/*Last unlink*/ if (ext4_inode_get_links_cnt(act.inode) == 2) {
if (r == EOK && !depth) { /*Truncate*/
/*Load parent.*/ r = ext4_fs_truncate_inode(&act, 0);
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) { if (r != EOK) {
ext4_fs_put_inode_ref(&parent);
ext4_fs_put_inode_ref(&act); ext4_fs_put_inode_ref(&act);
goto Finish; goto Finish;
} }
}
ext4_trans_start(mp); /* 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;
/* In this place all directories should be r = ext4_fs_free_inode(&act);
* unlinked.
* Last unlink from root of current directory*/
r = ext4_unlink(f.mp, &parent, &act,
(char *)path, len);
if (r != EOK) { if (r != EOK) {
ext4_fs_put_inode_ref(&parent); ext4_fs_put_inode_ref(&parent);
ext4_fs_put_inode_ref(&act); ext4_fs_put_inode_ref(&act);
goto Finish; goto Finish;
} }
}
if (ext4_inode_get_links_cnt(act.inode) == 2) { r = ext4_fs_put_inode_ref(&parent);
ext4_inode_set_del_time(act.inode, -1L); if (r != EOK)
ext4_inode_set_links_cnt(act.inode, 0); goto Finish;
act.dirty = true;
/*Turncate*/
r = ext4_trunc_inode(mp, &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;
}
}
r = ext4_fs_put_inode_ref(&parent);
if (r != EOK)
goto Finish;
r = ext4_fs_put_inode_ref(&act); r = ext4_fs_put_inode_ref(&act);
Finish: Finish:
if (r != EOK) if (r != EOK)
ext4_trans_abort(mp); ext4_trans_abort(mp);
else else
ext4_trans_stop(mp); ext4_trans_stop(mp);
}
ext4_block_cache_write_back(mp->fs.bdev, 0); ext4_block_cache_write_back(mp->fs.bdev, 0);
EXT4_MP_UNLOCK(mp); EXT4_MP_UNLOCK(mp);

165
lwext4/ext4_journal.c

@ -1273,8 +1273,9 @@ static void jbd_journal_flush_trans(struct jbd_trans *trans)
struct ext4_fs *fs = journal->jbd_fs->inode_ref.fs; struct ext4_fs *fs = journal->jbd_fs->inode_ref.fs;
TAILQ_FOREACH_SAFE(jbd_buf, &trans->buf_queue, buf_node, TAILQ_FOREACH_SAFE(jbd_buf, &trans->buf_queue, buf_node,
tmp) { tmp) {
struct ext4_block block = jbd_buf->block; struct ext4_buf *buf = jbd_buf->block_rec->buf;
ext4_block_flush_buf(fs->bdev, block.buf); if (buf)
ext4_block_flush_buf(fs->bdev, buf);
} }
} }
@ -1458,6 +1459,18 @@ jbd_trans_block_rec_lookup(struct jbd_journal *journal,
&tmp); &tmp);
} }
static void
jbd_trans_change_ownership(struct jbd_block_rec *block_rec,
struct jbd_trans *new_trans,
struct ext4_buf *new_buf)
{
LIST_REMOVE(block_rec, tbrec_node);
/* Now this block record belongs to this transaction. */
LIST_INSERT_HEAD(&new_trans->tbrec_list, block_rec, tbrec_node);
block_rec->trans = new_trans;
block_rec->buf = new_buf;
}
static inline struct jbd_block_rec * static inline struct jbd_block_rec *
jbd_trans_insert_block_rec(struct jbd_trans *trans, jbd_trans_insert_block_rec(struct jbd_trans *trans,
ext4_fsblk_t lba, ext4_fsblk_t lba,
@ -1466,12 +1479,7 @@ jbd_trans_insert_block_rec(struct jbd_trans *trans,
struct jbd_block_rec *block_rec; struct jbd_block_rec *block_rec;
block_rec = jbd_trans_block_rec_lookup(trans->journal, lba); block_rec = jbd_trans_block_rec_lookup(trans->journal, lba);
if (block_rec) { if (block_rec) {
LIST_REMOVE(block_rec, tbrec_node); jbd_trans_change_ownership(block_rec, trans, buf);
/* Data should be flushed to disk already. */
ext4_assert(!block_rec->buf);
/* Now this block record belongs to this transaction. */
LIST_INSERT_HEAD(&trans->tbrec_list, block_rec, tbrec_node);
block_rec->trans = trans;
return block_rec; return block_rec;
} }
block_rec = calloc(1, sizeof(struct jbd_block_rec)); block_rec = calloc(1, sizeof(struct jbd_block_rec));
@ -1481,11 +1489,68 @@ jbd_trans_insert_block_rec(struct jbd_trans *trans,
block_rec->lba = lba; block_rec->lba = lba;
block_rec->buf = buf; block_rec->buf = buf;
block_rec->trans = trans; block_rec->trans = trans;
TAILQ_INIT(&block_rec->dirty_buf_queue);
LIST_INSERT_HEAD(&trans->tbrec_list, block_rec, tbrec_node); LIST_INSERT_HEAD(&trans->tbrec_list, block_rec, tbrec_node);
RB_INSERT(jbd_block, &trans->journal->block_rec_root, block_rec); RB_INSERT(jbd_block, &trans->journal->block_rec_root, block_rec);
return block_rec; return block_rec;
} }
static void
jbd_trans_finish_callback(struct jbd_journal *journal,
const struct jbd_trans *trans,
struct jbd_block_rec *block_rec,
bool abort)
{
struct ext4_fs *fs = journal->jbd_fs->inode_ref.fs;
if (block_rec->trans != trans)
return;
if (!abort) {
struct jbd_buf *jbd_buf, *tmp;
TAILQ_FOREACH_SAFE(jbd_buf,
&block_rec->dirty_buf_queue,
dirty_buf_node,
tmp) {
/* All we need is a fake ext4_buf. */
struct ext4_buf buf;
jbd_trans_end_write(fs->bdev->bc,
&buf,
EOK,
jbd_buf);
}
} else {
struct jbd_buf *jbd_buf;
struct ext4_block jbd_block = EXT4_BLOCK_ZERO(),
block = EXT4_BLOCK_ZERO();
jbd_buf = TAILQ_LAST(&block_rec->dirty_buf_queue,
jbd_buf_dirty);
if (jbd_buf) {
ext4_assert(ext4_block_get(fs->bdev,
&jbd_block,
jbd_buf->jbd_lba) == EOK);
ext4_assert(ext4_block_get_noread(fs->bdev,
&block,
block_rec->lba) == EOK);
memcpy(block.data, jbd_block.data,
journal->block_size);
jbd_trans_change_ownership(block_rec,
jbd_buf->trans, block.buf);
block.buf->end_write = jbd_trans_end_write;
block.buf->end_write_arg = jbd_buf;
ext4_bcache_set_flag(jbd_block.buf, BC_TMP);
ext4_bcache_set_dirty(block.buf);
ext4_block_set(fs->bdev, &jbd_block);
ext4_block_set(fs->bdev, &block);
return;
}
}
}
static inline void static inline void
jbd_trans_remove_block_rec(struct jbd_journal *journal, jbd_trans_remove_block_rec(struct jbd_journal *journal,
struct jbd_block_rec *block_rec, struct jbd_block_rec *block_rec,
@ -1511,35 +1576,41 @@ int jbd_trans_set_block_dirty(struct jbd_trans *trans,
{ {
struct jbd_buf *buf; struct jbd_buf *buf;
if (!ext4_bcache_test_flag(block->buf, BC_DIRTY) && struct jbd_block_rec *block_rec;
block->buf->end_write != jbd_trans_end_write) { if (block->buf->end_write == jbd_trans_end_write) {
struct jbd_block_rec *block_rec; buf = block->buf->end_write_arg;
buf = calloc(1, sizeof(struct jbd_buf)); if (buf && buf->trans == trans)
if (!buf) return EOK;
return ENOMEM; }
buf = calloc(1, sizeof(struct jbd_buf));
if (!buf)
return ENOMEM;
if ((block_rec = jbd_trans_insert_block_rec(trans, if ((block_rec = jbd_trans_insert_block_rec(trans,
block->lb_id, block->lb_id,
block->buf)) == NULL) { block->buf)) == NULL) {
free(buf); free(buf);
return ENOMEM; return ENOMEM;
} }
buf->block_rec = block_rec; TAILQ_INSERT_TAIL(&block_rec->dirty_buf_queue,
buf->trans = trans; buf,
buf->block = *block; dirty_buf_node);
ext4_bcache_inc_ref(block->buf);
/* If the content reach the disk, notify us buf->block_rec = block_rec;
* so that we may do a checkpoint. */ buf->trans = trans;
block->buf->end_write = jbd_trans_end_write; buf->block = *block;
block->buf->end_write_arg = buf; ext4_bcache_inc_ref(block->buf);
trans->data_cnt++; /* If the content reach the disk, notify us
TAILQ_INSERT_HEAD(&trans->buf_queue, buf, buf_node); * so that we may do a checkpoint. */
block->buf->end_write = jbd_trans_end_write;
block->buf->end_write_arg = buf;
ext4_bcache_set_dirty(block->buf); trans->data_cnt++;
} TAILQ_INSERT_HEAD(&trans->buf_queue, buf, buf_node);
ext4_bcache_set_dirty(block->buf);
return EOK; return EOK;
} }
@ -1606,6 +1677,7 @@ void jbd_journal_free_trans(struct jbd_journal *journal,
struct ext4_fs *fs = journal->jbd_fs->inode_ref.fs; struct ext4_fs *fs = journal->jbd_fs->inode_ref.fs;
TAILQ_FOREACH_SAFE(jbd_buf, &trans->buf_queue, buf_node, TAILQ_FOREACH_SAFE(jbd_buf, &trans->buf_queue, buf_node,
tmp) { tmp) {
block_rec = jbd_buf->block_rec;
if (abort) { if (abort) {
jbd_buf->block.buf->end_write = NULL; jbd_buf->block.buf->end_write = NULL;
jbd_buf->block.buf->end_write_arg = NULL; jbd_buf->block.buf->end_write_arg = NULL;
@ -1613,6 +1685,13 @@ void jbd_journal_free_trans(struct jbd_journal *journal,
ext4_block_set(fs->bdev, &jbd_buf->block); ext4_block_set(fs->bdev, &jbd_buf->block);
} }
TAILQ_REMOVE(&jbd_buf->block_rec->dirty_buf_queue,
jbd_buf,
dirty_buf_node);
jbd_trans_finish_callback(journal,
trans,
block_rec,
abort);
TAILQ_REMOVE(&trans->buf_queue, jbd_buf, buf_node); TAILQ_REMOVE(&trans->buf_queue, jbd_buf, buf_node);
free(jbd_buf); free(jbd_buf);
} }
@ -1691,6 +1770,15 @@ static int jbd_journal_prepare(struct jbd_journal *journal,
if (ext4_bcache_test_flag(jbd_buf->block.buf, if (ext4_bcache_test_flag(jbd_buf->block.buf,
BC_DIRTY)) BC_DIRTY))
break; break;
TAILQ_REMOVE(&jbd_buf->block_rec->dirty_buf_queue,
jbd_buf,
dirty_buf_node);
jbd_trans_finish_callback(journal,
trans,
jbd_buf->block_rec,
false);
/* The buffer has not been modified, just release /* The buffer has not been modified, just release
* that jbd_buf. */ * that jbd_buf. */
@ -1710,6 +1798,15 @@ static int jbd_journal_prepare(struct jbd_journal *journal,
bool uuid_exist = false; bool uuid_exist = false;
if (!ext4_bcache_test_flag(jbd_buf->block.buf, if (!ext4_bcache_test_flag(jbd_buf->block.buf,
BC_DIRTY)) { BC_DIRTY)) {
TAILQ_REMOVE(&jbd_buf->block_rec->dirty_buf_queue,
jbd_buf,
dirty_buf_node);
jbd_trans_finish_callback(journal,
trans,
jbd_buf->block_rec,
false);
/* The buffer has not been modified, just release /* The buffer has not been modified, just release
* that jbd_buf. */ * that jbd_buf. */
jbd_trans_remove_block_rec(journal, jbd_trans_remove_block_rec(journal,
@ -1791,6 +1888,7 @@ again:
memcpy(data_block.data, jbd_buf->block.data, memcpy(data_block.data, jbd_buf->block.data,
journal->block_size); journal->block_size);
jbd_buf->jbd_lba = data_block.lb_id;
rc = jbd_block_set(journal->jbd_fs, &data_block); rc = jbd_block_set(journal->jbd_fs, &data_block);
if (rc != EOK) if (rc != EOK)
@ -1943,6 +2041,13 @@ static void jbd_trans_end_write(struct ext4_bcache *bc __unused,
trans->error = res; trans->error = res;
TAILQ_REMOVE(&trans->buf_queue, jbd_buf, buf_node); TAILQ_REMOVE(&trans->buf_queue, jbd_buf, buf_node);
TAILQ_REMOVE(&jbd_buf->block_rec->dirty_buf_queue,
jbd_buf,
dirty_buf_node);
jbd_trans_finish_callback(journal,
trans,
jbd_buf->block_rec,
false);
jbd_buf->block_rec->buf = NULL; jbd_buf->block_rec->buf = NULL;
free(jbd_buf); free(jbd_buf);

3
lwext4/ext4_types.h

@ -1098,10 +1098,12 @@ struct jbd_fs {
}; };
struct jbd_buf { struct jbd_buf {
uint64_t jbd_lba;
struct ext4_block block; struct ext4_block block;
struct jbd_trans *trans; struct jbd_trans *trans;
struct jbd_block_rec *block_rec; struct jbd_block_rec *block_rec;
TAILQ_ENTRY(jbd_buf) buf_node; TAILQ_ENTRY(jbd_buf) buf_node;
TAILQ_ENTRY(jbd_buf) dirty_buf_node;
}; };
struct jbd_revoke_rec { struct jbd_revoke_rec {
@ -1115,6 +1117,7 @@ struct jbd_block_rec {
struct jbd_trans *trans; struct jbd_trans *trans;
RB_ENTRY(jbd_block_rec) block_rec_node; RB_ENTRY(jbd_block_rec) block_rec_node;
LIST_ENTRY(jbd_block_rec) tbrec_node; LIST_ENTRY(jbd_block_rec) tbrec_node;
TAILQ_HEAD(jbd_buf_dirty, jbd_buf) dirty_buf_queue;
}; };
struct jbd_trans { struct jbd_trans {

Loading…
Cancel
Save