Esempio n. 1
0
static errcode_t create_orphan_file(ocfs2_filesys *fs, uint16_t slot)
{
	errcode_t ret;
	uint64_t dir, tmp_blkno;
	char name[OCFS2_MAX_FILENAME_LEN];
	int namelen;

	ret = ocfs2_lookup_system_inode(fs, ORPHAN_DIR_SYSTEM_INODE,
					slot, &dir);
	if (ret)
		return ret;

	namelen = sprintf(name, "test%ld", random());

	ret = ocfs2_lookup(fs, dir, name, namelen, NULL, &tmp_blkno);
	if (!ret)
		return 0;
	else if (ret != OCFS2_ET_FILE_NOT_FOUND)
		return ret;

	ret = ocfs2_new_inode(fs, &tmp_blkno, S_IFREG | 0755);
	if (ret)
		return ret;

	ret = ocfs2_link(fs, dir, name,
			 tmp_blkno, OCFS2_FT_REG_FILE);
	if (ret)
		return ret;

	return 0;
}
Esempio n. 2
0
static void create_named_directory(ocfs2_filesys *fs, char *dirname,
				   uint64_t *blkno)
{
	errcode_t ret;
	struct ocfs2_super_block *sb = OCFS2_RAW_SB(fs->fs_super);

	ret = ocfs2_lookup(fs, sb->s_root_blkno, dirname, strlen(dirname), NULL,
			   blkno);
	if (!ret)
		return;
	else if (ret != OCFS2_ET_FILE_NOT_FOUND)
		FSWRK_COM_FATAL(progname, ret);

	ret  = ocfs2_new_inode(fs, blkno, S_IFDIR | 0755);
	if (ret)
		FSWRK_COM_FATAL(progname, ret);

	ret = ocfs2_init_dir(fs, *blkno, fs->fs_root_blkno);
	if (ret)
		FSWRK_COM_FATAL(progname, ret);

	ret = ocfs2_link(fs, fs->fs_root_blkno, dirname, *blkno, OCFS2_FT_DIR);
	if (ret)
		FSWRK_COM_FATAL(progname, ret);

	return;
}
Esempio n. 3
0
static errcode_t create_system_file(ocfs2_filesys *fs, int type, int node)
{
	char fname[OCFS2_MAX_FILENAME_LEN];
	uint64_t blkno;
	errcode_t ret;

	ocfs2_sprintf_system_inode_name(fname, sizeof(fname),
		type, node);
	ret = ocfs2_lookup(fs, fs->fs_sysdir_blkno, fname, strlen(fname), NULL,
			   &blkno);
	if (!ret) {
		verbosef(VL_APP, "System file \"%s\" already exists!\n",
			 fname);
		return 0;
	}
	ret = ocfs2_new_system_inode(fs, &blkno,
				ocfs2_system_inodes[type].si_mode,
				ocfs2_system_inodes[type].si_iflags);
	if (ret) {
		tcom_err(ret, "while creating system file \"%s\"", fname);
		return ret;
	}

	ret = ocfs2_link(fs, fs->fs_sysdir_blkno, fname, blkno,
			 OCFS2_FT_REG_FILE);
	if (ret) {
		tcom_err(ret, "while linking file \"%s\" in the system "
			 "directory", fname);
		return ret;
	}
	return 0;
}
Esempio n. 4
0
static void fix_dot_dot(o2fsck_state *ost, o2fsck_dir_parent *dir)
{
	errcode_t ret;

	struct fix_dot_dot_args args = {
		.ost = ost,
		.parent = dir->dp_dirent,
		.fixed = 0,
	};

	ret = ocfs2_dir_iterate(ost->ost_fs, dir->dp_ino, 
				OCFS2_DIRENT_FLAG_INCLUDE_EMPTY, NULL,
				fix_dot_dot_dirent, &args);
	if (ret) {
		com_err("fix_dot_dot", ret, "while iterating through dir "
			"inode %"PRIu64"'s directory entries.", dir->dp_dirent);
		/* XXX mark fs invalid */
		return;
	}

	if (!args.fixed) {
		fprintf(stderr, "Didn't find a '..' entry to fix.\n");
		/* XXX mark fs invalid */
		return;
	}

	dir->dp_dot_dot = dir->dp_dirent;
}

/* add a directory entry that points to a given inode in lost+found. */
void o2fsck_reconnect_file(o2fsck_state *ost, uint64_t inode)
{
	static char iname[NAME_MAX + 1];
	char name[] = "lost+found";
	int namelen = sizeof(name) - 1;
	o2fsck_dir_parent *dp;
	errcode_t ret;
	uint8_t type;
	int len;

	if (ost->ost_lostfound_ino == 0) {
		ret = ocfs2_lookup(ost->ost_fs, ost->ost_fs->fs_root_blkno,
				   name, namelen, NULL,
				   &ost->ost_lostfound_ino);
		if (ret) {
			com_err(whoami, ret, "while trying to find the "
				"/lost+found directory so that inode "
				"%"PRIu64" could be moved there.", inode);
			goto out;
		}
	}

	len = snprintf(iname, sizeof(iname), "#%"PRIu64, inode);
	if (len <= 0) {
		ret = OCFS2_ET_NO_MEMORY;
		com_err(whoami, ret, "while trying to build a new file name "
			"for inode %"PRIu64" to use in /lost+found", inode);
		goto out;
	}

	ret = o2fsck_type_from_dinode(ost, inode, &type);
	if (ret)
		goto out;

	ret = ocfs2_link(ost->ost_fs, ost->ost_lostfound_ino, iname, inode,
			 type);
	if (ret) {
		com_err(whoami, ret, "while trying to link inode %"PRIu64" "
			"into /lost+found", inode);
		goto out;
	}

	/* add another ref to account for this new dirent */
	o2fsck_icount_delta(ost->ost_icount_refs, inode, 1);

	/* if we just added a directory to l+f we need to track that 
	 * the new dirent points to the dir.  we leave the dot_dot tracking
	 * intact because we didn't change that in the dirblock.. */
	if (type == OCFS2_FT_DIR) {
		dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents, inode);
		if (dp == NULL) {
			ret = OCFS2_ET_INTERNAL_FAILURE;
			com_err(whoami, ret, "while looking up the directory "
				"parent structure for inode %"PRIu64, inode);
			goto out;
		}
		dp->dp_dirent = ost->ost_lostfound_ino;
	}

out:
	return;
}

static uint64_t loop_no = 0;

static errcode_t connect_directory(o2fsck_state *ost,
				   o2fsck_dir_parent *dir)
{
	o2fsck_dir_parent *dp = dir, *par;
	errcode_t ret = 0;
	int fix;

	verbosef("checking dir inode %"PRIu64" parent %"PRIu64" dot_dot "
		"%"PRIu64"\n", dir->dp_ino, dp->dp_dirent, dp->dp_dot_dot);

	loop_no++;

	while(!dp->dp_connected) {

		/* we either will ascend to a parent that is connected or
		 * we'll graft the subtree with this directory on to lost
		 * and found. */ 
		dp->dp_connected = 1;

		/* move on to the parent dir only if it exists and we haven't
		 * already traversed it in this instance of parent walking */
		if (dp->dp_dirent) {
			par = o2fsck_dir_parent_lookup(&ost->ost_dir_parents, 
							dp->dp_dirent);
			if (par == NULL) {
				ret = OCFS2_ET_INTERNAL_FAILURE;
				com_err(whoami, ret, "no dir info for parent "
					"%"PRIu64, dp->dp_dirent);
				goto out;
			}
			if (par->dp_loop_no != loop_no) {
				par->dp_loop_no = loop_no;
				dp = par;
				continue;
			}
		}

		/* ok, we hit an orphan subtree with no parent or are at 
		 * the dir in a subtree that is the first to try to reference
		 * a dir in its children */
		fix = prompt(ost, PY, PR_DIR_NOT_CONNECTED,
			     "Directory inode %"PRIu64" isn't "
			     "connected to the filesystem.  Move it to "
			     "lost+found?", dp->dp_ino);
		if (fix)
			o2fsck_reconnect_file(ost, dp->dp_ino);

		break;
	}

	/* 
	 * orphan dirs are a magically awesome special case.  they have
	 * their i_link_count increased when subdirs are added but
	 * the subdirs '..' entry isn't updated to point to the orphan
	 * dir.  we alter our book-keeping to it look like the '..'
	 * was reasonable on disk.
	 */
	if (dir->dp_in_orphan_dir) {
		/* previous '..' entry is garbage */
		if (dir->dp_dot_dot)
			o2fsck_icount_delta(ost->ost_icount_refs,
					    dir->dp_dot_dot, -1);
		/* pretend '..' pointed to the orphan dir */
		dir->dp_dot_dot = dir->dp_dirent;
		o2fsck_icount_delta(ost->ost_icount_refs, dir->dp_dot_dot, 1);
	}
	if (dir->dp_dirent != dir->dp_dot_dot) {
		fix = prompt(ost, PY, PR_DIR_DOTDOT,
			     "Directory inode %"PRIu64" is "
			     "referenced by a dirent in directory %"PRIu64" "
			     "but its '..' entry points to inode %"PRIu64". "
			     "Fix the '..' entry to reference %"PRIu64"?", 
			     dir->dp_ino, dir->dp_dirent, dir->dp_dot_dot, 
			     dir->dp_dirent);
		if (fix)
			fix_dot_dot(ost, dir);
	}
out:
	return ret;
}
Esempio n. 5
0
static void check_lostfound(o2fsck_state *ost)
{
	char name[] = "lost+found";
	int namelen = sizeof(name) - 1;
	uint64_t blkno;
	errcode_t ret;

	ret = ocfs2_lookup(ost->ost_fs, ost->ost_fs->fs_root_blkno, name,
			   namelen, NULL, &ost->ost_lostfound_ino);
	if (ret == 0)
		return;

	if (!prompt(ost, PY, PR_LOSTFOUND_MISSING,
		    "/lost+found does not exist.  Create it so "
		    "that we can possibly fill it with orphaned inodes?"))
		return;

	ret = ocfs2_new_inode(ost->ost_fs, &blkno, 0755 | S_IFDIR);
	if (ret) {
		com_err(whoami, ret, "while trying to allocate a new inode "
			"for /lost+found");
		return;
	}

	ret = ocfs2_init_dir(ost->ost_fs, blkno, ost->ost_fs->fs_root_blkno);
	if (ret) {
		com_err(whoami, ret, "while trying to expand a new "
			"/lost+found directory");
		goto out;
	}

	ret = ocfs2_link(ost->ost_fs, ost->ost_fs->fs_root_blkno, name, blkno,
			 OCFS2_FT_DIR);
	if (ret) {
		com_err(whoami, ret, "while linking inode %"PRIu64" as "
			"/lost+found", blkno);
		goto out;
	}

	/* XXX maybe this should be a helper to clean up the dir tracking
	 * for any new dir.  "2" for both the l+f dirent pointing to the
	 * inode and the "." dirent in its dirblock */
	o2fsck_icount_set(ost->ost_icount_in_inodes, blkno, 2);
	o2fsck_icount_set(ost->ost_icount_refs, blkno, 2);
	ret = o2fsck_add_dir_parent(&ost->ost_dir_parents, blkno, 
				    ost->ost_fs->fs_root_blkno,
				    ost->ost_fs->fs_root_blkno, 0);
	if (ret) {
		com_err(whoami, ret, "while recording a new /lost+found "
			"directory");
		goto out;
	}

	/* we've already iterated through the dirblocks in pass2 so there
	 * is no need to register l+f's new dir block */

	ost->ost_lostfound_ino = blkno;
	blkno = 0;
out:
	if (blkno) {
		ret = ocfs2_delete_inode(ost->ost_fs, blkno);
		if (ret) {
			com_err(whoami, ret, "while trying to clean up an "
			        "an allocated inode after linking /lost+found "
				"failed");
		}
	}
}
static errcode_t add_slots(ocfs2_filesys *fs, int num_slots)
{
	errcode_t ret;
	uint16_t old_num = OCFS2_RAW_SB(fs->fs_super)->s_max_slots;
	char fname[OCFS2_MAX_FILENAME_LEN];
	uint64_t blkno;
	int i, j, max_slots;
	int ftype;
	struct tools_progress *prog = NULL;

	if (ocfs2_uses_extended_slot_map(OCFS2_RAW_SB(fs->fs_super))) {
		ret = TUNEFS_ET_TOO_MANY_SLOTS_EXTENDED;
		max_slots = INT16_MAX;
	} else {
		ret = TUNEFS_ET_TOO_MANY_SLOTS_OLD;
		max_slots = OCFS2_MAX_SLOTS;
	}
	if (num_slots > max_slots)
		goto bail;

	prog = tools_progress_start("Adding slots", "addslots",
				    (NUM_SYSTEM_INODES -
				     OCFS2_LAST_GLOBAL_SYSTEM_INODE - 1) *
				    (num_slots - old_num));
	if (!prog) {
		ret = TUNEFS_ET_NO_MEMORY;
		goto bail;
	}

	ret = 0;
	for (i = OCFS2_LAST_GLOBAL_SYSTEM_INODE + 1; i < NUM_SYSTEM_INODES; ++i) {
		for (j = old_num; j < num_slots; ++j) {
			ocfs2_sprintf_system_inode_name(fname,
							OCFS2_MAX_FILENAME_LEN,
							i, j);
			verbosef(VL_APP, "Creating system file \"%s\"\n",
				 fname);

			/* Goto next if file already exists */
			ret = ocfs2_lookup(fs, fs->fs_sysdir_blkno, fname,
					   strlen(fname), NULL, &blkno);
			if (!ret) {
				verbosef(VL_APP,
					 "System file \"%s\" already exists\n",
					 fname);
				tools_progress_step(prog, 1);
				continue;
			}

			/* create inode for system file */
			ret = ocfs2_new_system_inode(fs, &blkno,
						     ocfs2_system_inodes[i].si_mode,
						     ocfs2_system_inodes[i].si_iflags);
			if (ret) {
				verbosef(VL_APP,
					 "%s while creating inode for "
					 "system file \"%s\"\n",
					 error_message(ret), fname);
				goto bail;
			}

			ftype = (S_ISDIR(ocfs2_system_inodes[i].si_mode) ?
				 OCFS2_FT_DIR : OCFS2_FT_REG_FILE);

			/* if dir, alloc space to it */
			if (ftype == OCFS2_FT_DIR) {
				ret = ocfs2_init_dir(fs, blkno,
						     fs->fs_sysdir_blkno);
				if (ret) {
					verbosef(VL_APP,
						 "%s while initializing "
						 "directory \"%s\"\n",
						 error_message(ret),
						 fname);
					goto bail;
				}
			}

			/* Add the inode to the system dir */
			ret = ocfs2_link(fs, fs->fs_sysdir_blkno, fname,
					 blkno, ftype);
			if (ret) {
				verbosef(VL_APP,
					"%s while linking inode %"PRIu64" "
					"as \"%s\" in the system "
					"directory\n",
					error_message(ret), blkno, fname);
				goto bail;
			}
			verbosef(VL_APP, "System file \"%s\" created\n",
				 fname);
			tools_progress_step(prog, 1);
		}
	}

bail:
	if (prog)
		tools_progress_stop(prog);

	return ret;
}