[Ocfs2-tools-devel] [PATCH 3/4] Ocfs2-tools: Fix bug for fswreck to handle corruption of inlined directory correctly.
Tristan Ye
tristan.ye at oracle.com
Wed Jun 24 03:44:14 PDT 2009
There is a known issue that inline-data didn't work correctly in fswreck's
directory codes somehow, where it tries to add dirents to dirblocks even for
inlined dirs. Therefore, corruptions using add_ent_to_dir() should really use
ocfs2_link() instead to cover the inlined dirs, as well, the corruptions which
directly modify dirents also have to consider inlined case(it should be doable
with ocfs2_dir_iterate()).
Signed-off-by: Tristan Ye <tristan.ye at oracle.com>
---
fswreck/dir.c | 315 +++++++++++++++++++++++++++++++++++----------------------
1 files changed, 195 insertions(+), 120 deletions(-)
diff --git a/fswreck/dir.c b/fswreck/dir.c
index 112f394..89e7e61 100644
--- a/fswreck/dir.c
+++ b/fswreck/dir.c
@@ -86,93 +86,170 @@ void create_directory(ocfs2_filesys *fs,
return;
}
-/* Add an entry in the directory.
- * Currently this is only a simple function, and we don't consider
- * the situation that this block is not enough for the entry.
- * The mechanism is copied from ocfs2 kernel code.
- */
-static void add_dir_ent(ocfs2_filesys *fs,
- struct ocfs2_dir_entry *de,
- uint64_t blkno, char *name, int namelen, umode_t mode,
- struct ocfs2_dir_entry **retent)
+struct dirent_corrupt_struct {
+
+ const char *oldname;
+ const char *name;
+ int namelen;
+ int done;
+ int reserved;
+};
+
+static int rename_dirent_proc(struct ocfs2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data)
{
- struct ocfs2_dir_entry *de1 = NULL;
- uint32_t offset = 0;
- uint16_t rec_len = OCFS2_DIR_REC_LEN(namelen);
-
- while (1) {
- if ((de->inode == 0 && de->rec_len >= rec_len) ||
- (de->rec_len >=
- (OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) {
- offset += de->rec_len;
- if (de->inode) {
- de1 = (struct ocfs2_dir_entry *)((char *) de +
- OCFS2_DIR_REC_LEN(de->name_len));
- de1->rec_len = de->rec_len -
- OCFS2_DIR_REC_LEN(de->name_len);
- de->rec_len = OCFS2_DIR_REC_LEN(de->name_len);
- de = de1;
- }
- de->file_type = OCFS2_FT_UNKNOWN;
- de->inode = blkno;
- ocfs2_set_de_type(de, mode);
- de->name_len = namelen;
- memcpy(de->name, name, namelen);
- break;
- }
- offset += de->rec_len;
- de = (struct ocfs2_dir_entry *) ((char *) de + de->rec_len);
- if (offset >= fs->fs_blocksize)
- FSWRK_FATAL("no space for the new dirent");
- }
+ struct dirent_corrupt_struct *dcs = (struct dirent_corrupt_struct *) priv_data;
- *retent = de;
- return;
+ if (dcs->oldname && ((dirent->name_len & 0xFF) != dcs->namelen))
+ return 0;
+ if (dcs->oldname && strncmp(dcs->oldname, dirent->name,
+ dirent->name_len & 0xFF))
+ return 0;
+
+ strcpy(dirent->name, dcs->name);
+
+ dcs->done++;
+
+ return OCFS2_DIRENT_ABORT|OCFS2_DIRENT_CHANGED;
}
-static void damage_dir_content(ocfs2_filesys *fs, uint64_t dir,
- enum fsck_type type)
+static int rename_dirent(ocfs2_filesys *fs, uint64_t dir,
+ const char *name, const char *oldname)
{
- errcode_t ret;
- char *buf = NULL;
- uint64_t blkno, tmp_blkno;
- uint64_t contig;
- ocfs2_cached_inode *cinode = NULL;
- struct ocfs2_dir_entry *de = NULL, *newent = NULL;
- char name[OCFS2_MAX_FILENAME_LEN];
- int namelen;
- mode_t mode;
+ errcode_t rc;
+ struct dirent_corrupt_struct dcs;
- ret = ocfs2_read_cached_inode(fs, dir, &cinode);
- if (ret)
- FSWRK_COM_FATAL(progname, ret);
+ if (!(fs->fs_flags & OCFS2_FLAG_RW))
+ return OCFS2_ET_RO_FILESYS;
- /* get first blockno */
- ret = ocfs2_extent_map_get_blocks(cinode, 0, 1, &blkno, &contig, NULL);
- if (ret)
- FSWRK_COM_FATAL(progname, ret);
+ dcs.name = name;
+ dcs.oldname = oldname;
+ dcs.namelen = oldname ? strlen(oldname) : 0;
+ dcs.done = 0;
- ret = ocfs2_malloc_block(fs->fs_io, &buf);
- if (ret)
- FSWRK_COM_FATAL(progname, ret);
+ rc = ocfs2_dir_iterate(fs, dir, 0, 0, rename_dirent_proc, &dcs);
+ if (rc)
+ return rc;
- ret = ocfs2_read_blocks(fs, blkno, 1, buf);
- if (ret)
- FSWRK_COM_FATAL(progname, ret);
+ return (dcs.done) ? 0 : OCFS2_ET_DIR_NO_SPACE;
+}
+
+static int corrupt_dirent_ino_proc(struct ocfs2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data)
+{
+ struct dirent_corrupt_struct *dcs = (struct dirent_corrupt_struct*) priv_data;
+
+ if (dcs->oldname && ((dirent->name_len & 0xFF) != dcs->namelen))
+ return 0;
+ if (dcs->oldname && strncmp(dcs->oldname, dirent->name,
+ dirent->name_len & 0xFF))
+ return 0;
+
+ dirent->inode += dcs->reserved;
+
+ dcs->reserved = dirent->inode;
+
+ dcs->done++;
+
+ return OCFS2_DIRENT_ABORT|OCFS2_DIRENT_CHANGED;
+}
+
+static int corrupt_dirent_ino(ocfs2_filesys *fs, uint64_t dir,
+ const char *name, uint64_t *new_ino, int inc)
+{
+ errcode_t rc;
+ struct dirent_corrupt_struct dcs;
+
+ if (!(fs->fs_flags & OCFS2_FLAG_RW))
+ return OCFS2_ET_RO_FILESYS;
+
+ dcs.oldname = name;
+ dcs.namelen = name ? strlen(name) : 0;
+ dcs.done = 0;
+ dcs.reserved = inc;
+
+ rc = ocfs2_dir_iterate(fs, dir, 0, 0, corrupt_dirent_ino_proc, &dcs);
+ if (rc)
+ return rc;
+
+ *new_ino = dcs.reserved;
+
+ return (dcs.done) ? 0 : OCFS2_ET_DIR_NO_SPACE;
+}
+
+static int corrupt_dirent_reclen_proc(struct ocfs2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data)
+{
+ struct dirent_corrupt_struct *dcs = (struct dirent_corrupt_struct*) priv_data;
+
+ if (dcs->oldname && ((dirent->name_len & 0xFF) != dcs->namelen))
+ return 0;
+ if (dcs->oldname && strncmp(dcs->oldname, dirent->name,
+ dirent->name_len & 0xFF))
+ return 0;
+
+ dirent->rec_len += dcs->reserved;
+
+ dcs->done++;
+
+ dcs->reserved = dirent->rec_len;
- de = (struct ocfs2_dir_entry *)buf;
+ return OCFS2_DIRENT_ABORT|OCFS2_DIRENT_CHANGED;
+}
+
+static int corrupt_dirent_reclen(ocfs2_filesys *fs, uint64_t dir,
+ const char *name, uint64_t *new_reclen,
+ int inc)
+{
+ errcode_t rc;
+ struct dirent_corrupt_struct dcs;
+
+ if (!(fs->fs_flags & OCFS2_FLAG_RW))
+ return OCFS2_ET_RO_FILESYS;
+
+ dcs.oldname = name;
+ dcs.namelen = name ? strlen(name) : 0;
+ dcs.done = 0;
+ dcs.reserved = inc;
+
+ rc = ocfs2_dir_iterate(fs, dir, 0, 0, corrupt_dirent_reclen_proc, &dcs);
+ if (rc)
+ return rc;
+
+ *new_reclen = dcs.reserved;
+
+ return (dcs.done) ? 0 : OCFS2_ET_DIR_NO_SPACE;
+}
+
+static void damage_dir_content(ocfs2_filesys *fs, uint64_t dir,
+ enum fsck_type type)
+{
+ errcode_t ret;
+ uint64_t tmp_blkno, tmp_no;
+ char name[OCFS2_MAX_FILENAME_LEN];
+ mode_t mode;
- sprintf(name, "test");
- namelen = strlen(name);
+ memset(name, 0, sizeof(name));
+ sprintf(name, "testXXXXXX");
+ if (!mktemp(name))
+ FSWRK_COM_FATAL(progname, errno);
switch (type) {
case DIRENT_DOTTY_DUP:
/* add another "." at the end of the directory */
sprintf(name, ".");
- namelen = strlen(name);
- add_dir_ent(fs, de,
- blkno, name, namelen, cinode->ci_inode->i_mode,
- &newent);
+ ret = ocfs2_link(fs, dir, name, dir, OCFS2_FT_DIR);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
fprintf(stdout, "DIRENT_DOTTY_DUP: "
"Corrupt directory#%"PRIu64
", add another '.' to it.\n", dir);
@@ -180,8 +257,7 @@ static void damage_dir_content(ocfs2_filesys *fs, uint64_t dir,
case DIRENT_NOT_DOTTY:
/* rename the first ent from "." to "a". */
sprintf(name, "a");
- namelen = strlen(name);
- memcpy(de->name, name, namelen);
+ rename_dirent(fs, dir, name, ".");
fprintf(stdout, "DIRENT_NOT_DOTTY: "
"Corrupt directory#%"PRIu64
", change '.' to %s.\n", dir, name);
@@ -190,21 +266,20 @@ static void damage_dir_content(ocfs2_filesys *fs, uint64_t dir,
fprintf(stdout, "DIRENT_DOT_INODE: "
"Corrupt directory#%"PRIu64
", change dot inode to #%"PRIu64".\n", dir, (dir+10));
- de->inode += 10;
+ corrupt_dirent_ino(fs, dir, ".", &tmp_no, 10);
break;
case DIRENT_DOT_EXCESS:
+ corrupt_dirent_reclen(fs, dir, ".", &tmp_no, OCFS2_DIR_PAD);
fprintf(stdout, "DIR_DOT_EXCESS: "
"Corrupt directory#%"PRIu64","
- "change dot's dirent length from %u to %u\n",
- dir, de->rec_len, (de->rec_len + OCFS2_DIR_PAD));
- de->rec_len += OCFS2_DIR_PAD;
+ "change dot's dirent length from %lu to %lu\n",
+ dir, tmp_no - OCFS2_DIR_PAD, tmp_no);
break;
case DIRENT_ZERO:
- name[0] = '\0';
- namelen = strlen(name);
- add_dir_ent(fs, de,
- dir + 100, name, namelen, S_IFREG | 0755,
- &newent);
+ memset(name, 0, 1);
+ ret = ocfs2_link(fs, dir, name, dir + 100, OCFS2_FT_DIR);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
fprintf(stdout, "DIRENT_ZERO: "
"Corrupt directory#%"PRIu64
", add an zero entry to it.\n", dir);
@@ -215,29 +290,29 @@ static void damage_dir_content(ocfs2_filesys *fs, uint64_t dir,
ret = ocfs2_new_inode(fs, &tmp_blkno, mode);
if (ret)
FSWRK_COM_FATAL(progname, ret);
- add_dir_ent(fs, de,
- tmp_blkno, name, namelen, mode,
- &newent);
+ ret = ocfs2_link(fs, dir, name, tmp_blkno, OCFS2_FT_REG_FILE);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
fprintf(stdout, "DIRENT_NAME_CHARS: "
"Corrupt directory#%"PRIu64
", add an invalid entry to it.\n", dir);
break;
case DIRENT_INODE_RANGE:
- tmp_blkno = fs->fs_blocks + 1;
- add_dir_ent(fs, de,
- tmp_blkno, name, namelen, S_IFREG | 0755,
- &newent);
+ tmp_blkno = fs->fs_blocks;
+ ret = ocfs2_link(fs, dir, name, tmp_blkno, OCFS2_FT_REG_FILE);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+ corrupt_dirent_ino(fs, dir, name, &tmp_no, 1);
fprintf(stdout, "DIRENT_INODE_RANGE: "
"Corrupt directory#%"PRIu64
", add an entry whose inode exceeds"
" the limits.\n", dir);
break;
case DIRENT_INODE_FREE:
- mode = S_IFREG | 0755;
tmp_blkno = dir + 1000;
- add_dir_ent(fs, de,
- tmp_blkno, name, namelen, mode,
- &newent);
+ ret = ocfs2_link(fs, dir, name, tmp_blkno, OCFS2_FT_REG_FILE);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
fprintf(stdout, "DIRENT_INODE_FREE: "
"Corrupt directory#%"PRIu64
", add an entry's inode#%"PRIu64
@@ -248,9 +323,9 @@ static void damage_dir_content(ocfs2_filesys *fs, uint64_t dir,
ret = ocfs2_new_inode(fs, &tmp_blkno, mode);
if (ret)
FSWRK_COM_FATAL(progname, ret);
- add_dir_ent(fs, de,
- tmp_blkno, name, namelen,S_IFLNK | 0755,
- &newent);
+ ret = ocfs2_link(fs, dir, name, tmp_blkno, OCFS2_FT_SYMLINK);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
fprintf(stdout, "DIRENT_TYPE: "
"Corrupt directory#%"PRIu64
", change an entry's mode from %u to %u.\n",
@@ -261,12 +336,12 @@ static void damage_dir_content(ocfs2_filesys *fs, uint64_t dir,
ret = ocfs2_new_inode(fs, &tmp_blkno, mode);
if (ret)
FSWRK_COM_FATAL(progname, ret);
- add_dir_ent(fs, de,
- tmp_blkno, name, namelen, mode,
- &newent);
- add_dir_ent(fs, de,
- tmp_blkno, name, namelen, mode,
- &newent);
+ ret = ocfs2_link(fs, dir, name, tmp_blkno, OCFS2_FT_REG_FILE);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+ ret = ocfs2_link(fs, dir, name, tmp_blkno, OCFS2_FT_REG_FILE);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
fprintf(stdout, "DIRENT_DUPLICATE: "
"Corrupt directory#%"PRIu64
", add two entries with the same name '%s'.\n",
@@ -277,27 +352,19 @@ static void damage_dir_content(ocfs2_filesys *fs, uint64_t dir,
ret = ocfs2_new_inode(fs, &tmp_blkno, mode);
if (ret)
FSWRK_COM_FATAL(progname, ret);
- add_dir_ent(fs, de,
- tmp_blkno, name, namelen, mode,
- &newent);
+ ret = ocfs2_link(fs, dir, name, tmp_blkno, OCFS2_FT_REG_FILE);
+ if (ret)
+ FSWRK_COM_FATAL(progname, ret);
+ corrupt_dirent_reclen(fs, dir, name, &tmp_no, 1);
fprintf(stdout, "DIRENT_LENGTH: "
"Corrupt directory#%"PRIu64
- ", modify entry#%"PRIu64" from %u to %u.\n",
- dir, tmp_blkno, newent->rec_len, (newent->rec_len+1));
- newent->rec_len += 1;
+ ", modify entry#%"PRIu64" from %lu to %lu.\n",
+ dir, tmp_blkno, tmp_no - 1, tmp_no);
break;
default:
FSWRK_FATAL("Invalid type = %d\n", type);
}
- ret = io_write_block(fs->fs_io, blkno, 1, buf);
- if (ret)
- FSWRK_COM_FATAL(progname, ret);
-
- if (buf)
- ocfs2_free(&buf);
- if (cinode)
- ocfs2_free_cached_inode(fs, cinode);
return;
}
@@ -382,11 +449,19 @@ void mess_up_dir_inode(ocfs2_filesys *fs, enum fsck_type type, uint64_t blkno)
if (!(di->i_flags & OCFS2_VALID_FL))
FSWRK_FATAL("not a valid file");
- el = &(di->id2.i_list);
- if (el->l_next_free_rec == 0)
- FSWRK_FATAL("directory empty");
+ if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) {
+
+ FSWRK_FATAL("Inlined directory");
+
+ } else {
+
+ el = &(di->id2.i_list);
+ if (el->l_next_free_rec == 0)
+ FSWRK_FATAL("directory empty");
+
+ el->l_next_free_rec = 0;
+ }
- el->l_next_free_rec = 0;
fprintf(stdout, "DIR_ZERO: "
"Corrupt directory#%"PRIu64", empty its content.\n",
tmp_blkno);
--
1.5.5
More information about the Ocfs2-tools-devel
mailing list