Пример #1
0
Файл: block.c Проект: ejrh/ejrh
static BLOCK *find_free_slot(FS *fs)
{
    int attempts = 0, max = 3;
    
    while (attempts < max)
    {
        BLOCK *ptr = fs->cache_tail;
        attempts++;
    
        while (ptr != NULL)
        {
            if (!(ptr->flags & F_CACHED)
                    || (!(ptr->flags & F_DIRTY) && ptr->pins == 0))
            {
                flush_block(fs, ptr);
                remove_block_from_hash(fs, ptr);
                ptr->flags = 0;
                set_flag(ptr,  F_CACHED);
                ptr->pins = 0;
                return ptr;
            }
            
            ptr = ptr->prev;
        }
        
        flush_fs(fs);
    }
    
    error("No more free slots in cache -- increase size or find bug");
    return NULL;
}
Пример #2
0
caddr_t
setup(caddr_t dev)
{
	int corefs;
	static char devstr[MAXPATHLEN + 1];

	havesb = 0;
	devname = devstr;

	derive_devstr(dev, devstr, sizeof (devstr));
	errorlocked = is_errorlocked(devstr);
	corefs = check_mount_state(devstr, sizeof (devstr));

	sblock_init();

	if (open_and_intro(devstr, corefs) == -1)
		goto cleanup;

	/*
	 * Check log state
	 */
	if (!logsetup(devstr))
		goto cleanup;

	/*
	 * Flush fs if we're going to do anything other than a sanity check.
	 * Note, if logging then the fs was already flushed in logsetup().
	 */
	if (!islog && !mflag)
		flush_fs();

	if (find_superblock(devstr) == -1)
		goto cleanup;

	fixup_superblock();

	if (errorlocked &&
	    (initial_error_state_adjust() == -1))
		goto cleanup;

	/*
	 * asblk could be dirty because we found a mismatch between
	 * the primary superblock and one of its backups in checksb().
	 */
	if (asblk.b_dirty && !bflag) {
		(void) memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize);
		flush(fswritefd, &asblk);
	}

	getsummaryinfo();

	/*
	 * if not error-locked, using the standard superblock,
	 *   not bad log, not forced, preening, and is clean;
	 *   stop checking
	 */
	if (!errorlocked && (bflag == 0) &&
	    ((!islog || islogok) &&
	    (fflag == 0) && preen &&
	    (FSOKAY == (sblock.fs_state + sblock.fs_time)) &&
	    ((sblock.fs_clean == FSLOG && islog) ||
	    ((sblock.fs_clean == FSCLEAN) || (sblock.fs_clean == FSSTABLE))))) {
		iscorrupt = 0;
		printclean();
		goto cleanup;
	}

	if (create_and_init_maps() == -1)
		goto nomaps;

	bufinit();
	return (devstr);

nomaps:
	ckfini();
	exitstat = EXERRFATAL;
	/* FALLTHROUGH */

cleanup:
	unbufinit();
	uncreate_maps();
	ungetsummaryinfo();

	/*
	 * Can't get rid of the superblock buffer, because our
	 * caller references it to generate the summary statistics.
	 */

	return (NULL);
}
Пример #3
0
/*
 * Roll the embedded log, if any, and set up the global variables
 * islog and islogok.
 */
static int
logsetup(caddr_t devstr)
{
	void		*buf;
	extent_block_t	*ebp;
	ml_unit_t	*ul;
	ml_odunit_t	*ud;
	void		*ud_buf;
	int		badlog;

	islog = islogok = 0;
	if (bflag != 0)
		return (1); /* can't roll log while alternate sb specified */

	/*
	 * Roll the log, if any.  A bad sb implies we'll be using
	 * an alternate sb as far as logging goes, so just fail back
	 * to the caller if we can't read the default sb.  Suppress
	 * complaints, because the caller will be reading the same
	 * superblock again and running full verification on it, so
	 * whatever is bad will be reported then.
	 */
	sblock.fs_logbno = 0;
	badlog = 0;
	if (!read_super_block(0))
		return (1);

	/*
	 * Roll the log in 3 cases:
	 * 1. If it's unmounted (mount_point == NULL) and it's not marked
	 *    as fully rolled (sblock.fs_rolled != FS_ALL_ROLLED)
	 * 2. If it's mounted and anything other than a sanity
	 *    check fsck (mflag) is being done, as we have the current
	 *    super block. Note, only a sanity check is done for
	 *    root/usr at boot. If a roll were done then the expensive
	 *    ufs_flush() gets called, leading to a slower boot.
	 * 3. If anything other then a sanity check (mflag) is being done
	 *    to a mounted filesystem while it is in read-only state
	 *    (e.g. root during early boot stages) we have to detect this
	 *    and have to roll the log as well. NB. the read-only mount
	 *    will flip fs_clean from FSLOG to FSSTABLE and marks the
	 *    log as FS_NEED_ROLL.
	 */
	if (sblock.fs_logbno &&
	    (((mount_point == NULL) && (sblock.fs_rolled != FS_ALL_ROLLED)) ||
	    ((mount_point != NULL) && !mflag))) {
		int roll_log_err = 0;

		if (sblock.fs_ronly && (sblock.fs_clean == FSSTABLE) &&
			(sblock.fs_state + sblock.fs_time == FSOKAY)) {
			/*
			 * roll the log without a mount
			 */
			flush_fs();
		}
		if (sblock.fs_clean == FSLOG &&
			(sblock.fs_state + sblock.fs_time == FSOKAY)) {
			if (rl_roll_log(devstr) != RL_SUCCESS)
				roll_log_err = 1;
		}
		if (roll_log_err) {
			(void) printf("Can't roll the log for %s.\n", devstr);
			/*
			 * There are two cases where we want to set
			 * an error code and return:
			 *  - We're preening
			 *  - We're not on a live root and the user
			 *    chose *not* to ignore the log
			 * Otherwise, we want to mark the log as bad
			 * and continue to check the filesystem.  This
			 * has the side effect of destroying the log.
			 */
			if (preen || (!hotroot &&
			    reply(
			"DISCARDING THE LOG MAY DISCARD PENDING TRANSACTIONS.\n"
					"DISCARD THE LOG AND CONTINUE") == 0)) {
				exitstat = EXERRFATAL;
				return (0);
			}
			++badlog;
		}
	}

	/* Logging UFS may be enabled */
	if (sblock.fs_logbno) {
		++islog;

		/* log is not okay; check the fs */
		if (FSOKAY != (sblock.fs_state + sblock.fs_time))
			return (1);

		/*
		 * If logging or (stable and mounted) then continue
		 */
		if (!((sblock.fs_clean == FSLOG) ||
		    (sblock.fs_clean == FSSTABLE) && (mount_point != NULL)))
			return (1);

		/* get the log allocation block */
		buf = malloc(dev_bsize);
		if (buf == NULL) {
			return (1);
		}
		ud_buf = malloc(dev_bsize);
		if (ud_buf == NULL) {
			free(buf);
			return (1);
		}
		(void) fsck_bread(fsreadfd, buf,
		    logbtodb(&sblock, sblock.fs_logbno),
		    dev_bsize);
		ebp = (extent_block_t *)buf;

		/* log allocation block is not okay; check the fs */
		if (ebp->type != LUFS_EXTENTS) {
			free(buf);
			free(ud_buf);
			return (1);
		}

		/* get the log state block(s) */
		if (fsck_bread(fsreadfd, ud_buf,
		    (logbtodb(&sblock, ebp->extents[0].pbno)),
		    dev_bsize)) {
			(void) fsck_bread(fsreadfd, ud_buf,
			    (logbtodb(&sblock, ebp->extents[0].pbno)) + 1,
			    dev_bsize);
		}
		ud = (ml_odunit_t *)ud_buf;
		ul = (ml_unit_t *)malloc(sizeof (*ul));
		if (ul == NULL) {
			free(buf);
			free(ud_buf);
			return (1);
		}
		ul->un_ondisk = *ud;

		/* log state is okay; don't need to check the fs */
		if ((ul->un_chksum == ul->un_head_ident + ul->un_tail_ident) &&
		    (ul->un_version == LUFS_VERSION_LATEST) &&
		    (ul->un_badlog == 0) && (!badlog)) {
			++islogok;
		}
		free(ud_buf);
		free(buf);
		free(ul);
	}

	return (1);
}