fsflush.c revision ad23a2db4cfc94c0ed1d58554479ce8d2e7e5768
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/tuneable.h>
#include <vm/seg_kmem.h>
/*
* To improve boot performance, don't run the inode flushing loop until
* the specified number of seconds after boot. To revert to the old
* behavior, set fsflush_iflush_delay to 0. We have not created any new
* filesystem danger that did not exist previously, since there is always a
* window in between when fsflush does the inode flush loop during which the
* system could crash, fail to sync the filesystem, and fsck will be needed
* to recover. We have, however, widened this window. Finally,
* we never delay inode flushing if we're booting into single user mode,
* where the administrator may be modifying files or using fsck. This
* modification avoids inode flushes during boot whose only purpose is to
* update atimes on files which have been accessed during boot.
*/
int fsflush_iflush_delay = 60;
/*
* some statistics for fsflush_do_pages
*/
typedef struct {
/* be less than fsf_scan due to large pages */
} fsf_stat_t;
/*
* data used to determine when we can coalese consecutive free pages
* into larger pages.
*/
#define MAX_PAGESIZES 32
/*
* Scan page_t's and issue I/O's for modified pages.
*
* Also coalesces consecutive small sized free pages into the next larger
* pagesize. This costs a tiny bit of time in fsflush, but will reduce time
* spent scanning on later passes and for anybody allocating large pages.
*/
static void
{
int mod;
static pgcnt_t last_total_pages = 0;
/*
* Check to see if total_pages has changed.
*/
if (total_pages != last_total_pages) {
}
/*
* On first time through initialize the cookie used for page_t scans
*/
pcount = 0;
/*
* move to the next page, skipping over large pages
* and issuing prefetches.
*/
prefetch_page_r((void *)pp);
/*
* Do a bunch of dirty tests (ie. no locking) to determine
* if we can quickly skip this page. These tests are repeated
* after acquiring the page lock.
*/
++nexamined;
continue;
}
/*
* skip free pages too, but try coalescing them into larger
* pagesizes
*/
/*
* skip pages with a file system identity or that
* are already maximum size
*/
continue;
}
/*
* If not in a coalescing candidate page or the size
* codes are different, start a new candidate.
*/
/*
* page must be properly aligned
*/
continue;
}
coal_cnt = 1;
continue;
}
/*
* acceptable to add this to existing candidate page
*/
++coal_cnt;
continue;
/*
* We've got enough pages to coalesce, so do it.
* After promoting, we clear coal_page, so it will
* take another pass to promote this to an even
* larger page.
*/
++ncoalesce;
continue;
} else {
}
PAGE_LOCKED(pp) ||
continue;
/*
* Reject pages that can't be "exclusively" locked.
*/
continue;
++nlocked;
/*
* After locking the page, redo the above checks.
* Since we locked the page, leave out the PAGE_LOCKED() test.
*/
continue;
}
/*
* Check the modified bit. Leaving the bit alone in hardware.
* It will be cleared if we do the putpage.
*/
if (IS_VMODSORT(vp))
else
if (mod) {
++nmodified;
/*
* Hold the vnode before releasing the page lock
* to prevent it from being freed and re-used by
* some other thread.
*/
kcred);
} else {
/*
* Catch any pages which should be on the cache list,
* but aren't yet.
*/
if (hat_page_is_mapped(pp) == 0) {
++releases;
} else {
}
}
}
/*
* maintain statistics
* reset every million wakeups, just to avoid overflow
*/
if (++fsf_cycles == 1000000) {
fsf_cycles = 0;
fsf_total.fsf_examined = 0;
fsf_total.fsf_locked = 0;
fsf_total.fsf_modified = 0;
fsf_total.fsf_coalesce = 0;
fsf_total.fsf_releases = 0;
} else {
}
}
/*
* As part of file system hardening, this daemon is awakened
* every second to flush cached data which includes the
* buffer cache, the inode cache and mapped pages.
*/
void
fsflush()
{
int autoup;
proc_fsflush->p_cstime = 0;
proc_fsflush->p_stime = 0;
proc_fsflush->p_cutime = 0;
proc_fsflush->p_utime = 0;
/*
* Setup page coalescing.
*/
}
loop:
/*
* Write back all old B_DELWRI buffers on the freelist.
*/
bcount = 0;
continue;
}
/*
* Go down only on the delayed write lists.
*/
} else {
bp);
}
} else {
}
}
}
/*
*
* There is no need to wakeup any thread waiting on bio_mem_cv
* since brelse will wake them up as soon as IO is complete.
*/
if (dopageflush)
if (!doiflush)
goto loop;
/*
* If the system was not booted to single user mode, skip the
* inode flushing until after fsflush_iflush_delay secs have elapsed.
*/
goto loop;
/*
* Flush cached attribute information (e.g. inodes).
*/
count = 0;
/*
* Sync back cached data.
*/
RLOCK_VFSSW();
RLOCK_VFSSW();
}
}
}
goto loop;
}