Ejemplo n.º 1
0
/* this could certainly be more clever to issue reads in groups */
static unsigned pass2_dir_block_iterate(o2fsck_dirblock_entry *dbe, 
					void *priv_data) 
{
	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;
	struct ocfs2_dinode *di = (struct ocfs2_dinode *)dd->inoblock_buf; 
	errcode_t ret = 0;

	if (!o2fsck_test_inode_allocated(dd->ost, dbe->e_ino)) {
		printf("Directory block %"PRIu64" belongs to directory inode "
		       "%"PRIu64" which isn't allocated.  Ignoring this "
		       "block.", dbe->e_blkno, dbe->e_ino);
		goto out;
	}

	if (dbe->e_ino != dd->last_ino) {
		o2fsck_strings_free(&dd->strings);
		dd->last_ino = dbe->e_ino;

		ret = ocfs2_read_inode(dd->ost->ost_fs, dbe->e_ino,
				       dd->inoblock_buf);
		if (ret) {
			com_err(whoami, ret, "while reading dir inode %"PRIu64,
				dbe->e_ino);
			ret_flags |= OCFS2_DIRENT_ABORT;
			goto out;
		}

		verbosef("dir inode %"PRIu64" i_size %"PRIu64"\n",
			 dbe->e_ino, (uint64_t)di->i_size);

	}

	verbosef("dir block %"PRIu64" block offs %"PRIu64" in ino\n",
		 dbe->e_blkno, dbe->e_blkcount);

	if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) {
		if (dbe->e_ino != dbe->e_blkno)
			goto out;

		memcpy(dd->dirblock_buf, dd->inoblock_buf,
		       dd->fs->fs_blocksize);
		offset = offsetof(struct ocfs2_dinode, id2.i_data.id_data);
	} else {
		if (dbe->e_blkcount >= ocfs2_blocks_in_bytes(dd->fs,
Ejemplo n.º 2
0
/* detecting dups is irritating because of the storage requirements of
 * detecting duplicates.  e2fsck avoids the storage burden for a regular fsck
 * pass by only detecting duplicate entries that occur in the same directory
 * block.  its repair pass then suffers under enormous directories because it
 * reads the whole thing into memory to detect duplicates.
 *
 * we'll take a compromise which expands the reach of a regular fsck pass by
 * using a slightly larger block size but which repairs in place rather than
 * reading the dir into memory.
 *
 * if we ever truly care to invest in duplicate detection and repair we could
 * either explicitly use some external sort and merge algo or perhaps just
 * combine mmap and some internal sort that has strong enough locality of
 * reference to work well with the vm.
 */
static errcode_t fix_dirent_dups(o2fsck_state *ost,
				 o2fsck_dirblock_entry *dbe,
				 struct ocfs2_dir_entry *dirent,
				 o2fsck_strings *strings,
				 unsigned int *flags)
{
	errcode_t ret = 0;
	char *new_name = NULL;
	int was_set, i;

	/* start over every N bytes of dirent */
	if (o2fsck_strings_bytes_allocated(strings) > (4 * 1024 * 1024))
		o2fsck_strings_free(strings);

	ret = o2fsck_strings_insert(strings, dirent->name, dirent->name_len, 
				    &was_set);
	if (ret) {
		com_err(whoami, ret, "while allocating space to find "
			"duplicate directory entries");
		goto out;
	}

	if (!was_set)
		goto out;

	new_name = calloc(1, dirent->rec_len + 1);
	if (new_name == NULL) {
		ret = OCFS2_ET_NO_MEMORY;
		com_err(whoami, ret, "while trying to generate a new name "
			"for duplicate file name '%.*s' in dir inode "
			"%"PRIu64, dirent->name_len, dirent->name,
			dbe->e_ino);
		goto out;
	}

	/* just simple mangling for now */ 
	memcpy(new_name, dirent->name, dirent->name_len);
	was_set = 1;
	/* append '_' to free space in the dirent until its unique */
	for (i = dirent->name_len ; was_set && i < dirent->rec_len; i++){
		new_name[i] = '_';
		if (!o2fsck_strings_exists(strings, new_name, strlen(new_name)))
			was_set = 0;
	}

	/* rename characters at the end to '_' until its unique */
	for (i = dirent->name_len - 1 ; was_set && i >= 0; i--) {
		new_name[i] = '_';
		if (!o2fsck_strings_exists(strings, new_name, strlen(new_name)))
			was_set = 0;
	}

	if (was_set) {
		printf("Directory inode %"PRIu64" contains a duplicate "
		       "occurance " "of the file name '%.*s' but fsck was "
		       "unable to come up with a unique name so this duplicate "
		       "name will not be dealt with.\n.",
			dbe->e_ino, dirent->name_len, dirent->name);
		goto out;
	}

	if (!prompt(ost, PY, PR_DIRENT_DUPLICATE,
		    "Directory inode %"PRIu64" contains a duplicate occurance "
		    "of the file name '%.*s'.  Replace this duplicate name "
		    "with '%s'?", dbe->e_ino, dirent->name_len, dirent->name,
		    new_name)) {
		/* we don't really care that we leak new_name's recording
		 * in strings, it'll be freed later */
		goto out;
	}

	ret = o2fsck_strings_insert(strings, new_name, strlen(new_name),
				    NULL);
	if (ret) {
		com_err(whoami, ret, "while allocating space to track "
			"duplicates of a newly renamed dirent");
		goto out;
	}

	dirent->name_len = strlen(new_name);
	memcpy(dirent->name, new_name, dirent->name_len);
	*flags |= OCFS2_DIRENT_CHANGED;

out:
	if (new_name != NULL)
		free(new_name);
	return ret;
}
Ejemplo n.º 3
0
/* this could certainly be more clever to issue reads in groups */
static unsigned pass2_dir_block_iterate(o2fsck_dirblock_entry *dbe, 
					void *priv_data) 
{
	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;

	if (!o2fsck_test_inode_allocated(dd->ost, dbe->e_ino)) {
		printf("Directory block %"PRIu64" belongs to directory inode "
		       "%"PRIu64" which isn't allocated.  Ignoring this "
		       "block.", dbe->e_blkno, dbe->e_ino);
		goto out;
	}

	if (dbe->e_ino != dd->last_ino) {
		o2fsck_strings_free(&dd->strings);
		dd->last_ino = dbe->e_ino;

		ret = ocfs2_read_inode(dd->ost->ost_fs, dbe->e_ino,
				       dd->inoblock_buf);
		if (ret == OCFS2_ET_BAD_CRC32) {
			if (prompt(dd->ost, PY, PR_BAD_CRC32, 
						"Directory inode %"PRIu64" "
						"has bad CRC32. Recalculate CRC32 "
						"and write inode block?", dbe->e_ino)) {
				ocfs2_write_inode(dd->ost->ost_fs, dbe->e_ino,
						dd->inoblock_buf);
			}
		} else if (ret) {
			com_err(whoami, ret, "while reading dir inode %"PRIu64,
				dbe->e_ino);
			ret_flags |= OCFS2_DIRENT_ABORT;
			goto out;
		}

		verbosef("dir inode %"PRIu64" i_size %"PRIu64"\n",
			 dbe->e_ino, (uint64_t)di->i_size);

		/* Set the flag for index rebuilding */
		if (ocfs2_supports_indexed_dirs(OCFS2_RAW_SB(dd->fs->fs_super))
			&& !(di->i_dyn_features & OCFS2_INLINE_DATA_FL)
			&& !(di->i_dyn_features & OCFS2_INDEXED_DIR_FL) 
			&& prompt(dd->ost, PY, PR_DX_TREE_MISSING, 
				  "Directory %"PRIu64" is missing index. "
				  "Rebuild?", dbe->e_ino))
				ret_flags |= OCFS2_DIRENT_CHANGED;

	}

	verbosef("dir block %"PRIu64" block offs %"PRIu64" in ino\n",
		 dbe->e_blkno, dbe->e_blkcount);

	if (di->i_dyn_features & OCFS2_INLINE_DATA_FL) {
		if (dbe->e_ino != dbe->e_blkno)
			goto out;

		memcpy(dd->dirblock_buf, dd->inoblock_buf,
		       dd->fs->fs_blocksize);
		offset = offsetof(struct ocfs2_dinode, id2.i_data.id_data);
	} else {
		if (dbe->e_blkcount >= ocfs2_blocks_in_bytes(dd->fs,