[Ocfs2-tools-devel] [PATCH] Compress dirs option in fsck
Joel Becker
Joel.Becker at oracle.com
Wed Aug 26 17:57:01 PDT 2009
On Wed, Aug 19, 2009 at 05:14:59PM -0500, Goldwyn Rodrigues wrote:
> This patch adds the option to compress directories (-D) in fsck.
> The option compresses the directory entries and consolidates a hole at
> the end of the directory block. This consolidated hole increases the
> chance of ocfs2_prepare_dir_for_insert (kmp) to find a hole using
> ocfs2_find_dir_space_* functions while inserting a new directory entry
> in the directory.
I like the idea. A couple of comments.
> diff --git a/fsck.ocfs2/pass2.c b/fsck.ocfs2/pass2.c
> index 810bf10..2d9d074 100644
> --- a/fsck.ocfs2/pass2.c
> +++ b/fsck.ocfs2/pass2.c
> @@ -668,6 +668,7 @@ static unsigned
> pass2_dir_block_iterate(o2fsck_dirblock_entry *dbe,
> struct dirblock_data *dd = priv_data;
> struct ocfs2_dir_entry *dirent, *prev = NULL;
> unsigned int offset = 0, ret_flags = 0, end = dd->fs->fs_blocksize;
> + unsigned int write_off, saved_reclen;
> struct ocfs2_dinode *di = (struct ocfs2_dinode *)dd->inoblock_buf;
> errcode_t ret = 0;
>
> @@ -723,6 +724,8 @@ static unsigned
> pass2_dir_block_iterate(o2fsck_dirblock_entry *dbe,
> end = ocfs2_dir_trailer_blk_off(dd->fs);
> }
>
> + write_off = offset;
> +
> while (offset < end) {
> dirent = (struct ocfs2_dir_entry *)(dd->dirblock_buf + offset);
>
> @@ -804,8 +807,31 @@ static unsigned
> pass2_dir_block_iterate(o2fsck_dirblock_entry *dbe,
> dirent->name, (uint64_t)dirent->inode);
> o2fsck_icount_delta(dd->ost->ost_icount_refs, dirent->inode, 1);
> next:
> - offset += dirent->rec_len;
> + saved_reclen=dirent->rec_len;
> + if ((dd->ost->ost_rehash_dirs) && dirent->inode) {
> + dirent->rec_len = OCFS2_DIR_REC_LEN(dirent->name_len);
> + if (write_off < offset) {
> + /* memcpy works good even though
> + it is the same buffer*/
You need to use memmove() here. Even if the memory work didn't
overlap (and it can), saving a cycle or two isn't going to matter when
our limiting factor is the dirblock I/O.
> + verbosef("ino: %llu woff: %u off: %u\n",
> + dirent->inode, write_off, offset);
> + memcpy(dd->dirblock_buf + write_off,
> + dd->dirblock_buf + offset,
> + dirent->rec_len);
> + dirent = dd->dirblock_buf + write_off;
This needs a cast as you assign it.
> + }
> + write_off += dirent->rec_len;
> + ret_flags |= OCFS2_DIRENT_CHANGED;
> + }
> prev = dirent;
> + offset += saved_reclen;
> + }
> +
> + /* Zero the rest of the block */
> + if (dd->ost->ost_rehash_dirs) {
> + memset(dd->dirblock_buf + write_off, '\0', end - write_off);
> + ret_flags |= OCFS2_DIRENT_CHANGED;
> + dirent->rec_len = dirent->rec_len + end - write_off;
> }
What happens if:
1) The first dirent is an empty one.
2) The second dirent has a problem that is fixed. DIRENT_CHANGED is set.
The second dirent is memmove()d to the front of the block, with
dirent->rec_len = REC_LEN(name_len).
3) The third dirent has a problem that cannot be fixed, and we jump to
out:
4) ocfs2_dir_block_iterate() writes the dirblock because of
DIRENT_CHANGED.
What you'll have is a new first dirent with a rec_len that
doesn't cover the space between it and the next dirent. The next fsck
will then be forced to wipe the entire dirblock.
Instead, when you shift a dirent, you need to set its rec_len to
cover the space between its new location and its old end. Something
like:
+ saved_reclen=dirent->rec_len;
+ if ((dd->ost->ost_rehash_dirs) && dirent->inode) {
+ if (write_off < offset) {
+ /* Bring prev->rec_len back to write_off */
+ if (prev)
+ prev->rec_len =
+ OCFS2_DIR_REC_LEN(prev->name_len);
+ verbosef("ino: %llu woff: %u off: %u\n",
+ dirent->inode, write_off, offset);
+ memmove(dd->dirblock_buf + write_off,
+ dd->dirblock_buf + offset,
+ OCFS2_DIR_REC_LEN(dirent->name_len);
+ dirent = dd->dirblock_buf + write_off;
+ /* Cover space from our new location to
+ * the next dirent */
+ dirent->rec_len = offset + saved_reclen
+ - write_off;
+ }
+ write_off += OCFS2_DIR_REC_LEN(dirent->name_len);
+ ret_flags |= OCFS2_DIRENT_CHANGED;
+ }
Joel
--
"I inject pure kryptonite into my brain.
It improves my kung fu, and it eases the pain."
Joel Becker
Principal Software Developer
Oracle
E-mail: joel.becker at oracle.com
Phone: (650) 506-8127
More information about the Ocfs2-tools-devel
mailing list