17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
580d34432Sfrankho * Common Development and Distribution License (the "License").
680d34432Sfrankho * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22*d3d50737SRafael Vanoni * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
277c478bd9Sstevel@tonic-gate /* All Rights Reserved */
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988
317c478bd9Sstevel@tonic-gate * The Regents of the University of California
327c478bd9Sstevel@tonic-gate * All Rights Reserved
337c478bd9Sstevel@tonic-gate *
347c478bd9Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from
357c478bd9Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its
367c478bd9Sstevel@tonic-gate * contributors.
377c478bd9Sstevel@tonic-gate */
387c478bd9Sstevel@tonic-gate
397c478bd9Sstevel@tonic-gate #include <sys/types.h>
407c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
417c478bd9Sstevel@tonic-gate #include <sys/param.h>
427c478bd9Sstevel@tonic-gate #include <sys/time.h>
437c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
447c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate #ifdef _KERNEL
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate #include <sys/systm.h>
497c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
507c478bd9Sstevel@tonic-gate #include <sys/buf.h>
517c478bd9Sstevel@tonic-gate #include <sys/conf.h>
527c478bd9Sstevel@tonic-gate #include <sys/user.h>
537c478bd9Sstevel@tonic-gate #include <sys/var.h>
547c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
557c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
567c478bd9Sstevel@tonic-gate #include <sys/proc.h>
577c478bd9Sstevel@tonic-gate #include <sys/debug.h>
587c478bd9Sstevel@tonic-gate #include <sys/fssnap_if.h>
597c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
607c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_trans.h>
617c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_panic.h>
627c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_bio.h>
637c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_log.h>
647c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
657c478bd9Sstevel@tonic-gate #include <sys/policy.h>
667c478bd9Sstevel@tonic-gate #include <vm/hat.h>
677c478bd9Sstevel@tonic-gate #include <vm/as.h>
687c478bd9Sstevel@tonic-gate #include <vm/seg.h>
697c478bd9Sstevel@tonic-gate #include <vm/pvn.h>
707c478bd9Sstevel@tonic-gate #include <vm/seg_map.h>
717c478bd9Sstevel@tonic-gate #include <sys/swap.h>
727c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h>
737c478bd9Sstevel@tonic-gate
747c478bd9Sstevel@tonic-gate #else /* _KERNEL */
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate #define ASSERT(x) /* don't use asserts for fsck et al */
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
797c478bd9Sstevel@tonic-gate
807c478bd9Sstevel@tonic-gate #ifdef _KERNEL
817c478bd9Sstevel@tonic-gate
827c478bd9Sstevel@tonic-gate /*
837c478bd9Sstevel@tonic-gate * Used to verify that a given entry on the ufs_instances list (see below)
847c478bd9Sstevel@tonic-gate * still refers to a mounted file system.
857c478bd9Sstevel@tonic-gate *
867c478bd9Sstevel@tonic-gate * XXX: This is a crock that substitutes for proper locking to coordinate
877c478bd9Sstevel@tonic-gate * updates to and uses of the entries in ufs_instances.
887c478bd9Sstevel@tonic-gate */
897c478bd9Sstevel@tonic-gate struct check_node {
907c478bd9Sstevel@tonic-gate struct vfs *vfsp;
917c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfs;
927c478bd9Sstevel@tonic-gate dev_t vfs_dev;
937c478bd9Sstevel@tonic-gate };
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate static vfs_t *still_mounted(struct check_node *);
967c478bd9Sstevel@tonic-gate
977c478bd9Sstevel@tonic-gate /*
987c478bd9Sstevel@tonic-gate * All ufs file system instances are linked together into a list starting at
997c478bd9Sstevel@tonic-gate * ufs_instances. The list is updated as part of mount and unmount. It's
1007c478bd9Sstevel@tonic-gate * consulted in ufs_update, to allow syncing out all ufs file system instances
1017c478bd9Sstevel@tonic-gate * in a batch.
1027c478bd9Sstevel@tonic-gate *
1037c478bd9Sstevel@tonic-gate * ufsvfs_mutex guards access to this list and to the {,old}ufsvfslist
1047c478bd9Sstevel@tonic-gate * manipulated in ufs_funmount_cleanup. (A given ufs instance is always on
1057c478bd9Sstevel@tonic-gate * exactly one of these lists except while it's being allocated or
1067c478bd9Sstevel@tonic-gate * deallocated.)
1077c478bd9Sstevel@tonic-gate */
1087c478bd9Sstevel@tonic-gate struct ufsvfs *ufs_instances;
1097c478bd9Sstevel@tonic-gate extern kmutex_t ufsvfs_mutex; /* XXX: move this to ufs_inode.h? */
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate /*
1127c478bd9Sstevel@tonic-gate * ufsvfs list manipulation routines
1137c478bd9Sstevel@tonic-gate */
1147c478bd9Sstevel@tonic-gate
1157c478bd9Sstevel@tonic-gate /*
1167c478bd9Sstevel@tonic-gate * Link ufsp in at the head of the list of ufs_instances.
1177c478bd9Sstevel@tonic-gate */
1187c478bd9Sstevel@tonic-gate void
ufs_vfs_add(struct ufsvfs * ufsp)1197c478bd9Sstevel@tonic-gate ufs_vfs_add(struct ufsvfs *ufsp)
1207c478bd9Sstevel@tonic-gate {
1217c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfs_mutex);
1227c478bd9Sstevel@tonic-gate ufsp->vfs_next = ufs_instances;
1237c478bd9Sstevel@tonic-gate ufs_instances = ufsp;
1247c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfs_mutex);
1257c478bd9Sstevel@tonic-gate }
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate /*
1287c478bd9Sstevel@tonic-gate * Remove ufsp from the list of ufs_instances.
1297c478bd9Sstevel@tonic-gate *
1307c478bd9Sstevel@tonic-gate * Does no error checking; ufsp is assumed to actually be on the list.
1317c478bd9Sstevel@tonic-gate */
1327c478bd9Sstevel@tonic-gate void
ufs_vfs_remove(struct ufsvfs * ufsp)1337c478bd9Sstevel@tonic-gate ufs_vfs_remove(struct ufsvfs *ufsp)
1347c478bd9Sstevel@tonic-gate {
1357c478bd9Sstevel@tonic-gate struct ufsvfs **delpt = &ufs_instances;
1367c478bd9Sstevel@tonic-gate
1377c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfs_mutex);
1387c478bd9Sstevel@tonic-gate for (; *delpt != NULL; delpt = &((*delpt)->vfs_next)) {
1397c478bd9Sstevel@tonic-gate if (*delpt == ufsp) {
1407c478bd9Sstevel@tonic-gate *delpt = ufsp->vfs_next;
1417c478bd9Sstevel@tonic-gate ufsp->vfs_next = NULL;
1427c478bd9Sstevel@tonic-gate break;
1437c478bd9Sstevel@tonic-gate }
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfs_mutex);
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate /*
1497c478bd9Sstevel@tonic-gate * Clean up state resulting from a forcible unmount that couldn't be handled
1507c478bd9Sstevel@tonic-gate * directly during the unmount. (See commentary in the unmount code for more
1517c478bd9Sstevel@tonic-gate * info.)
1527c478bd9Sstevel@tonic-gate */
1537c478bd9Sstevel@tonic-gate static void
ufs_funmount_cleanup()1547c478bd9Sstevel@tonic-gate ufs_funmount_cleanup()
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp;
1577c478bd9Sstevel@tonic-gate extern struct ufsvfs *oldufsvfslist, *ufsvfslist;
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate /*
1607c478bd9Sstevel@tonic-gate * Assumption: it's now safe to blow away the entries on
1617c478bd9Sstevel@tonic-gate * oldufsvfslist.
1627c478bd9Sstevel@tonic-gate */
1637c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfs_mutex);
1647c478bd9Sstevel@tonic-gate while ((ufsvfsp = oldufsvfslist) != NULL) {
1657c478bd9Sstevel@tonic-gate oldufsvfslist = ufsvfsp->vfs_next;
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate mutex_destroy(&ufsvfsp->vfs_lock);
1687c478bd9Sstevel@tonic-gate kmem_free(ufsvfsp, sizeof (struct ufsvfs));
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate /*
1717c478bd9Sstevel@tonic-gate * Rotate more recent unmount entries into place in preparation for
1727c478bd9Sstevel@tonic-gate * the next time around.
1737c478bd9Sstevel@tonic-gate */
1747c478bd9Sstevel@tonic-gate oldufsvfslist = ufsvfslist;
1757c478bd9Sstevel@tonic-gate ufsvfslist = NULL;
1767c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfs_mutex);
1777c478bd9Sstevel@tonic-gate }
1787c478bd9Sstevel@tonic-gate
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate /*
1817c478bd9Sstevel@tonic-gate * ufs_update performs the ufs part of `sync'. It goes through the disk
1827c478bd9Sstevel@tonic-gate * queues to initiate sandbagged IO; goes through the inodes to write
1837c478bd9Sstevel@tonic-gate * modified nodes; and it goes through the mount table to initiate
1847c478bd9Sstevel@tonic-gate * the writing of the modified super blocks.
1857c478bd9Sstevel@tonic-gate */
1867c478bd9Sstevel@tonic-gate extern time_t time;
1877c478bd9Sstevel@tonic-gate time_t ufs_sync_time;
1887c478bd9Sstevel@tonic-gate time_t ufs_sync_time_secs = 1;
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate extern kmutex_t ufs_scan_lock;
1917c478bd9Sstevel@tonic-gate
1927c478bd9Sstevel@tonic-gate void
ufs_update(int flag)1937c478bd9Sstevel@tonic-gate ufs_update(int flag)
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate struct vfs *vfsp;
1967c478bd9Sstevel@tonic-gate struct fs *fs;
1977c478bd9Sstevel@tonic-gate struct ufsvfs *ufsp;
1987c478bd9Sstevel@tonic-gate struct ufsvfs *ufsnext;
1997c478bd9Sstevel@tonic-gate struct ufsvfs *update_list = NULL;
2007c478bd9Sstevel@tonic-gate int check_cnt = 0;
2017c478bd9Sstevel@tonic-gate size_t check_size;
2027c478bd9Sstevel@tonic-gate struct check_node *check_list, *ptr;
2037c478bd9Sstevel@tonic-gate int cheap = flag & SYNC_ATTR;
2047c478bd9Sstevel@tonic-gate
2057c478bd9Sstevel@tonic-gate /*
2067c478bd9Sstevel@tonic-gate * This is a hack. A design flaw in the forced unmount protocol
2077c478bd9Sstevel@tonic-gate * could allow a thread to attempt to use a kmem_freed ufsvfs
2087c478bd9Sstevel@tonic-gate * structure in ufs_lockfs_begin/ufs_check_lockfs. This window
2097c478bd9Sstevel@tonic-gate * is difficult to hit, even during the lockfs stress tests.
2107c478bd9Sstevel@tonic-gate * So the hacky fix is to wait awhile before kmem_free'ing the
2117c478bd9Sstevel@tonic-gate * ufsvfs structures for forcibly unmounted file systems. `Awhile'
2127c478bd9Sstevel@tonic-gate * is defined as every other call from fsflush (~60 seconds).
2137c478bd9Sstevel@tonic-gate */
2147c478bd9Sstevel@tonic-gate if (cheap)
2157c478bd9Sstevel@tonic-gate ufs_funmount_cleanup();
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate /*
2187c478bd9Sstevel@tonic-gate * Examine all ufsvfs structures and add those that we can lock to the
2197c478bd9Sstevel@tonic-gate * update list. This is so that we don't hold the list lock for a
2207c478bd9Sstevel@tonic-gate * long time. If vfs_lock fails for a file system instance, then skip
2217c478bd9Sstevel@tonic-gate * it because somebody is doing a unmount on it.
2227c478bd9Sstevel@tonic-gate */
2237c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfs_mutex);
2247c478bd9Sstevel@tonic-gate for (ufsp = ufs_instances; ufsp != NULL; ufsp = ufsp->vfs_next) {
2257c478bd9Sstevel@tonic-gate vfsp = ufsp->vfs_vfs;
2267c478bd9Sstevel@tonic-gate if (vfs_lock(vfsp) != 0)
2277c478bd9Sstevel@tonic-gate continue;
2287c478bd9Sstevel@tonic-gate ufsp->vfs_wnext = update_list;
2297c478bd9Sstevel@tonic-gate update_list = ufsp;
2307c478bd9Sstevel@tonic-gate check_cnt++;
2317c478bd9Sstevel@tonic-gate }
2327c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfs_mutex);
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate if (update_list == NULL)
2357c478bd9Sstevel@tonic-gate return;
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate check_size = sizeof (struct check_node) * check_cnt;
2387c478bd9Sstevel@tonic-gate check_list = ptr = kmem_alloc(check_size, KM_NOSLEEP);
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate /*
2417c478bd9Sstevel@tonic-gate * Write back modified superblocks.
2427c478bd9Sstevel@tonic-gate * Consistency check that the superblock of
2437c478bd9Sstevel@tonic-gate * each file system is still in the buffer cache.
2447c478bd9Sstevel@tonic-gate *
2457c478bd9Sstevel@tonic-gate * Note that the update_list traversal is done without the protection
2467c478bd9Sstevel@tonic-gate * of an overall list lock, so it's necessary to rely on the fact that
2477c478bd9Sstevel@tonic-gate * each entry of the list is vfs_locked when moving from one entry to
2487c478bd9Sstevel@tonic-gate * the next. This works because a concurrent attempt to add an entry
2497c478bd9Sstevel@tonic-gate * to another thread's update_list won't find it, since it'll already
2507c478bd9Sstevel@tonic-gate * be locked.
2517c478bd9Sstevel@tonic-gate */
2527c478bd9Sstevel@tonic-gate check_cnt = 0;
2537c478bd9Sstevel@tonic-gate for (ufsp = update_list; ufsp != NULL; ufsp = ufsnext) {
2547c478bd9Sstevel@tonic-gate /*
2557c478bd9Sstevel@tonic-gate * Need to grab the next ptr before we unlock this one so
2567c478bd9Sstevel@tonic-gate * another thread doesn't grab it and change it before we move
2577c478bd9Sstevel@tonic-gate * on to the next vfs. (Once we unlock it, it's ok if another
2587c478bd9Sstevel@tonic-gate * thread finds it to add it to its own update_list; we don't
2597c478bd9Sstevel@tonic-gate * attempt to refer to it through our list any more.)
2607c478bd9Sstevel@tonic-gate */
2617c478bd9Sstevel@tonic-gate ufsnext = ufsp->vfs_wnext;
2627c478bd9Sstevel@tonic-gate vfsp = ufsp->vfs_vfs;
2637c478bd9Sstevel@tonic-gate
2647c478bd9Sstevel@tonic-gate /*
2657c478bd9Sstevel@tonic-gate * Seems like this can't happen, so perhaps it should become
2667c478bd9Sstevel@tonic-gate * an ASSERT(vfsp->vfs_data != NULL).
2677c478bd9Sstevel@tonic-gate */
2687c478bd9Sstevel@tonic-gate if (!vfsp->vfs_data) {
2697c478bd9Sstevel@tonic-gate vfs_unlock(vfsp);
2707c478bd9Sstevel@tonic-gate continue;
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate
2737c478bd9Sstevel@tonic-gate fs = ufsp->vfs_fs;
2747c478bd9Sstevel@tonic-gate
2757c478bd9Sstevel@tonic-gate /*
2767c478bd9Sstevel@tonic-gate * don't update a locked superblock during a panic; it
2777c478bd9Sstevel@tonic-gate * may be in an inconsistent state
2787c478bd9Sstevel@tonic-gate */
2797c478bd9Sstevel@tonic-gate if (panicstr) {
2807c478bd9Sstevel@tonic-gate if (!mutex_tryenter(&ufsp->vfs_lock)) {
2817c478bd9Sstevel@tonic-gate vfs_unlock(vfsp);
2827c478bd9Sstevel@tonic-gate continue;
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate } else
2857c478bd9Sstevel@tonic-gate mutex_enter(&ufsp->vfs_lock);
2867c478bd9Sstevel@tonic-gate /*
2877c478bd9Sstevel@tonic-gate * Build up the STABLE check list, so we can unlock the vfs
2887c478bd9Sstevel@tonic-gate * until we do the actual checking.
2897c478bd9Sstevel@tonic-gate */
2907c478bd9Sstevel@tonic-gate if (check_list != NULL) {
2917c478bd9Sstevel@tonic-gate if ((fs->fs_ronly == 0) &&
2927c478bd9Sstevel@tonic-gate (fs->fs_clean != FSBAD) &&
2937c478bd9Sstevel@tonic-gate (fs->fs_clean != FSSUSPEND)) {
2947c478bd9Sstevel@tonic-gate ptr->vfsp = vfsp;
2957c478bd9Sstevel@tonic-gate ptr->ufsvfs = ufsp;
2967c478bd9Sstevel@tonic-gate ptr->vfs_dev = vfsp->vfs_dev;
2977c478bd9Sstevel@tonic-gate ptr++;
2987c478bd9Sstevel@tonic-gate check_cnt++;
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate }
3017c478bd9Sstevel@tonic-gate
3027c478bd9Sstevel@tonic-gate /*
3037c478bd9Sstevel@tonic-gate * superblock is not modified
3047c478bd9Sstevel@tonic-gate */
3057c478bd9Sstevel@tonic-gate if (fs->fs_fmod == 0) {
3067c478bd9Sstevel@tonic-gate mutex_exit(&ufsp->vfs_lock);
3077c478bd9Sstevel@tonic-gate vfs_unlock(vfsp);
3087c478bd9Sstevel@tonic-gate continue;
3097c478bd9Sstevel@tonic-gate }
3107c478bd9Sstevel@tonic-gate if (fs->fs_ronly != 0) {
3117c478bd9Sstevel@tonic-gate mutex_exit(&ufsp->vfs_lock);
3127c478bd9Sstevel@tonic-gate vfs_unlock(vfsp);
3137c478bd9Sstevel@tonic-gate (void) ufs_fault(ufsp->vfs_root,
31480d34432Sfrankho "fs = %s update: ro fs mod\n", fs->fs_fsmnt);
3157c478bd9Sstevel@tonic-gate /*
3167c478bd9Sstevel@tonic-gate * XXX: Why is this a return instead of a continue?
3177c478bd9Sstevel@tonic-gate * This may be an attempt to replace a panic with
3187c478bd9Sstevel@tonic-gate * something less drastic, but there's cleanup we
3197c478bd9Sstevel@tonic-gate * should be doing that's not being done (e.g.,
3207c478bd9Sstevel@tonic-gate * unlocking the remaining entries on the list).
3217c478bd9Sstevel@tonic-gate */
3227c478bd9Sstevel@tonic-gate return;
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate fs->fs_fmod = 0;
3257c478bd9Sstevel@tonic-gate mutex_exit(&ufsp->vfs_lock);
3267c478bd9Sstevel@tonic-gate TRANS_SBUPDATE(ufsp, vfsp, TOP_SBUPDATE_UPDATE);
3277c478bd9Sstevel@tonic-gate vfs_unlock(vfsp);
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate
3307c478bd9Sstevel@tonic-gate ufs_sync_time = time;
3317c478bd9Sstevel@tonic-gate
3327c478bd9Sstevel@tonic-gate /*
3337c478bd9Sstevel@tonic-gate * Avoid racing with ufs_unmount() and ufs_sync().
3347c478bd9Sstevel@tonic-gate */
3357c478bd9Sstevel@tonic-gate mutex_enter(&ufs_scan_lock);
3367c478bd9Sstevel@tonic-gate
3377c478bd9Sstevel@tonic-gate (void) ufs_scan_inodes(1, ufs_sync_inode, (void *)(uintptr_t)cheap,
3387c478bd9Sstevel@tonic-gate NULL);
3397c478bd9Sstevel@tonic-gate
3407c478bd9Sstevel@tonic-gate mutex_exit(&ufs_scan_lock);
3417c478bd9Sstevel@tonic-gate
3427c478bd9Sstevel@tonic-gate /*
3437c478bd9Sstevel@tonic-gate * Force stale buffer cache information to be flushed,
3447c478bd9Sstevel@tonic-gate * for all devices. This should cause any remaining control
3457c478bd9Sstevel@tonic-gate * information (e.g., cg and inode info) to be flushed back.
3467c478bd9Sstevel@tonic-gate */
3477c478bd9Sstevel@tonic-gate bflush((dev_t)NODEV);
3487c478bd9Sstevel@tonic-gate
3497c478bd9Sstevel@tonic-gate if (check_list == NULL)
3507c478bd9Sstevel@tonic-gate return;
3517c478bd9Sstevel@tonic-gate
3527c478bd9Sstevel@tonic-gate /*
3537c478bd9Sstevel@tonic-gate * For each UFS filesystem in the STABLE check_list, update
3547c478bd9Sstevel@tonic-gate * the clean flag if warranted.
3557c478bd9Sstevel@tonic-gate */
3567c478bd9Sstevel@tonic-gate for (ptr = check_list; check_cnt > 0; check_cnt--, ptr++) {
3577c478bd9Sstevel@tonic-gate int error;
3587c478bd9Sstevel@tonic-gate
3597c478bd9Sstevel@tonic-gate /*
3607c478bd9Sstevel@tonic-gate * still_mounted() returns with vfsp and the vfs_reflock
3617c478bd9Sstevel@tonic-gate * held if ptr refers to a vfs that is still mounted.
3627c478bd9Sstevel@tonic-gate */
3637c478bd9Sstevel@tonic-gate if ((vfsp = still_mounted(ptr)) == NULL)
3647c478bd9Sstevel@tonic-gate continue;
3657c478bd9Sstevel@tonic-gate ufs_checkclean(vfsp);
3667c478bd9Sstevel@tonic-gate /*
3677c478bd9Sstevel@tonic-gate * commit any outstanding async transactions
3687c478bd9Sstevel@tonic-gate */
3697c478bd9Sstevel@tonic-gate ufsp = (struct ufsvfs *)vfsp->vfs_data;
3707c478bd9Sstevel@tonic-gate curthread->t_flag |= T_DONTBLOCK;
3717c478bd9Sstevel@tonic-gate TRANS_BEGIN_SYNC(ufsp, TOP_COMMIT_UPDATE, TOP_COMMIT_SIZE,
3727c478bd9Sstevel@tonic-gate error);
3737c478bd9Sstevel@tonic-gate if (!error) {
3747c478bd9Sstevel@tonic-gate TRANS_END_SYNC(ufsp, error, TOP_COMMIT_UPDATE,
3757c478bd9Sstevel@tonic-gate TOP_COMMIT_SIZE);
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_DONTBLOCK;
3787c478bd9Sstevel@tonic-gate
3797c478bd9Sstevel@tonic-gate vfs_unlock(vfsp);
3807c478bd9Sstevel@tonic-gate }
3817c478bd9Sstevel@tonic-gate
3827c478bd9Sstevel@tonic-gate kmem_free(check_list, check_size);
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate
3857c478bd9Sstevel@tonic-gate int
ufs_sync_inode(struct inode * ip,void * arg)3867c478bd9Sstevel@tonic-gate ufs_sync_inode(struct inode *ip, void *arg)
3877c478bd9Sstevel@tonic-gate {
3887c478bd9Sstevel@tonic-gate int cheap = (int)(uintptr_t)arg;
3897c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp;
3907c478bd9Sstevel@tonic-gate uint_t flag = ip->i_flag;
3917c478bd9Sstevel@tonic-gate
3927c478bd9Sstevel@tonic-gate if (cheap && ((flag & (IUPD|IACC|ICHG|IMOD|IMODACC|IATTCHG)) == 0))
3937c478bd9Sstevel@tonic-gate return (0);
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate /*
3967c478bd9Sstevel@tonic-gate * if we are panic'ing; then don't update the inode if this
3977c478bd9Sstevel@tonic-gate * file system is FSSTABLE. Otherwise, we would have to
3987c478bd9Sstevel@tonic-gate * force the superblock to FSACTIVE and the superblock
3997c478bd9Sstevel@tonic-gate * may not be in a good state. Also, if the inode is
4007c478bd9Sstevel@tonic-gate * IREF'ed then it may be in an inconsistent state. Don't
4017c478bd9Sstevel@tonic-gate * push it. Finally, don't push the inode if the fs is
4027c478bd9Sstevel@tonic-gate * logging; the transaction will be discarded at boot.
4037c478bd9Sstevel@tonic-gate */
4047c478bd9Sstevel@tonic-gate if (panicstr) {
4057c478bd9Sstevel@tonic-gate
4067c478bd9Sstevel@tonic-gate if (flag & IREF)
4077c478bd9Sstevel@tonic-gate return (0);
4087c478bd9Sstevel@tonic-gate
4097c478bd9Sstevel@tonic-gate if (ip->i_ufsvfs == NULL ||
4107c478bd9Sstevel@tonic-gate (ip->i_fs->fs_clean == FSSTABLE ||
4117c478bd9Sstevel@tonic-gate ip->i_fs->fs_clean == FSLOG))
4127c478bd9Sstevel@tonic-gate return (0);
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate
4157c478bd9Sstevel@tonic-gate ufsvfsp = ip->i_ufsvfs;
4167c478bd9Sstevel@tonic-gate
4177c478bd9Sstevel@tonic-gate /*
4187c478bd9Sstevel@tonic-gate * Limit access time only updates
4197c478bd9Sstevel@tonic-gate */
4207c478bd9Sstevel@tonic-gate if (((flag & (IMOD|IMODACC|IUPD|ICHG|IACC)) == IMODACC) && ufsvfsp) {
4217c478bd9Sstevel@tonic-gate /*
4227c478bd9Sstevel@tonic-gate * if file system has deferred access time turned on and there
4237c478bd9Sstevel@tonic-gate * was no IO recently, don't bother flushing it. It will be
4247c478bd9Sstevel@tonic-gate * flushed when I/Os start again.
4257c478bd9Sstevel@tonic-gate */
4267c478bd9Sstevel@tonic-gate if (cheap && (ufsvfsp->vfs_dfritime & UFS_DFRATIME) &&
427*d3d50737SRafael Vanoni (ufsvfsp->vfs_iotstamp + ufs_iowait < ddi_get_lbolt()))
4287c478bd9Sstevel@tonic-gate return (0);
4297c478bd9Sstevel@tonic-gate /*
4307c478bd9Sstevel@tonic-gate * an app issueing a sync() can take forever on a trans device
4317c478bd9Sstevel@tonic-gate * when NetWorker or find is running because all of the
4327c478bd9Sstevel@tonic-gate * directorys' access times have to be updated. So, we limit
4337c478bd9Sstevel@tonic-gate * the time we spend updating access times per sync.
4347c478bd9Sstevel@tonic-gate */
4357c478bd9Sstevel@tonic-gate if (TRANS_ISTRANS(ufsvfsp) && ((ufs_sync_time +
4367c478bd9Sstevel@tonic-gate ufs_sync_time_secs) < time))
4377c478bd9Sstevel@tonic-gate return (0);
4387c478bd9Sstevel@tonic-gate }
4397c478bd9Sstevel@tonic-gate
4407c478bd9Sstevel@tonic-gate /*
4417c478bd9Sstevel@tonic-gate * if we are running on behalf of the flush thread or this is
4427c478bd9Sstevel@tonic-gate * a swap file, then simply do a delay update of the inode.
4437c478bd9Sstevel@tonic-gate * Otherwise, push the pages and then do a delayed inode update.
4447c478bd9Sstevel@tonic-gate */
4457c478bd9Sstevel@tonic-gate if (cheap || IS_SWAPVP(ITOV(ip))) {
4467c478bd9Sstevel@tonic-gate TRANS_IUPDAT(ip, 0);
4477c478bd9Sstevel@tonic-gate } else {
4487c478bd9Sstevel@tonic-gate (void) TRANS_SYNCIP(ip, B_ASYNC, I_ASYNC, TOP_SYNCIP_SYNC);
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate return (0);
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate
4537c478bd9Sstevel@tonic-gate /*
4547c478bd9Sstevel@tonic-gate * Flush all the pages associated with an inode using the given 'flags',
4557c478bd9Sstevel@tonic-gate * then force inode information to be written back using the given 'waitfor'.
4567c478bd9Sstevel@tonic-gate */
4577c478bd9Sstevel@tonic-gate int
ufs_syncip(struct inode * ip,int flags,int waitfor,top_t topid)4587c478bd9Sstevel@tonic-gate ufs_syncip(struct inode *ip, int flags, int waitfor, top_t topid)
4597c478bd9Sstevel@tonic-gate {
4607c478bd9Sstevel@tonic-gate int error;
4617c478bd9Sstevel@tonic-gate struct vnode *vp = ITOV(ip);
4627c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = ip->i_ufsvfs;
4637c478bd9Sstevel@tonic-gate int dotrans = 0;
4647c478bd9Sstevel@tonic-gate
4657c478bd9Sstevel@tonic-gate /*
4667c478bd9Sstevel@tonic-gate * Return if file system has been forcibly umounted.
4677c478bd9Sstevel@tonic-gate */
4687c478bd9Sstevel@tonic-gate if (ufsvfsp == NULL)
4697c478bd9Sstevel@tonic-gate return (EIO);
4707c478bd9Sstevel@tonic-gate /*
4717c478bd9Sstevel@tonic-gate * don't need to VOP_PUTPAGE if there are no pages
4727c478bd9Sstevel@tonic-gate */
4737c478bd9Sstevel@tonic-gate if (!vn_has_cached_data(vp) || vp->v_type == VCHR) {
4747c478bd9Sstevel@tonic-gate error = 0;
4757c478bd9Sstevel@tonic-gate } else {
4767c478bd9Sstevel@tonic-gate /*
4777c478bd9Sstevel@tonic-gate * if the inode we're working on is a shadow inode
4787c478bd9Sstevel@tonic-gate * or quota inode we need to make sure that the
4797c478bd9Sstevel@tonic-gate * ufs_putpage call is inside a transaction as this
4807c478bd9Sstevel@tonic-gate * could include meta data changes.
4817c478bd9Sstevel@tonic-gate */
4827c478bd9Sstevel@tonic-gate if ((ip->i_mode & IFMT) == IFSHAD ||
4837c478bd9Sstevel@tonic-gate ufsvfsp->vfs_qinod == ip) {
4847c478bd9Sstevel@tonic-gate dotrans = 1;
4857c478bd9Sstevel@tonic-gate curthread->t_flag |= T_DONTBLOCK;
4867c478bd9Sstevel@tonic-gate TRANS_BEGIN_ASYNC(ufsvfsp, TOP_PUTPAGE,
4877c478bd9Sstevel@tonic-gate TOP_PUTPAGE_SIZE(ip));
4887c478bd9Sstevel@tonic-gate }
489da6c28aaSamw error = VOP_PUTPAGE(vp, (offset_t)0, (size_t)0,
490da6c28aaSamw flags, CRED(), NULL);
4917c478bd9Sstevel@tonic-gate if (dotrans) {
4927c478bd9Sstevel@tonic-gate TRANS_END_ASYNC(ufsvfsp, TOP_PUTPAGE,
4937c478bd9Sstevel@tonic-gate TOP_PUTPAGE_SIZE(ip));
4947c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_DONTBLOCK;
4957c478bd9Sstevel@tonic-gate dotrans = 0;
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate }
4987c478bd9Sstevel@tonic-gate if (panicstr && TRANS_ISTRANS(ufsvfsp))
4997c478bd9Sstevel@tonic-gate goto out;
5007c478bd9Sstevel@tonic-gate /*
5017c478bd9Sstevel@tonic-gate * waitfor represents two things -
5027c478bd9Sstevel@tonic-gate * 1. whether data sync or file sync.
5037c478bd9Sstevel@tonic-gate * 2. if file sync then ufs_iupdat should 'waitfor' disk i/o or not.
5047c478bd9Sstevel@tonic-gate */
5057c478bd9Sstevel@tonic-gate if (waitfor == I_DSYNC) {
5067c478bd9Sstevel@tonic-gate /*
5077c478bd9Sstevel@tonic-gate * If data sync, only IATTCHG (size/block change) requires
5087c478bd9Sstevel@tonic-gate * inode update, fdatasync()/FDSYNC implementation.
5097c478bd9Sstevel@tonic-gate */
5107c478bd9Sstevel@tonic-gate if (ip->i_flag & (IBDWRITE|IATTCHG)) {
5117c478bd9Sstevel@tonic-gate /*
5127c478bd9Sstevel@tonic-gate * Enter a transaction to provide mutual exclusion
5137c478bd9Sstevel@tonic-gate * with deltamap_push and avoid a race where
5147c478bd9Sstevel@tonic-gate * the inode flush could get dropped.
5157c478bd9Sstevel@tonic-gate */
5167c478bd9Sstevel@tonic-gate if ((curthread->t_flag & T_DONTBLOCK) == 0) {
5177c478bd9Sstevel@tonic-gate dotrans = 1;
5187c478bd9Sstevel@tonic-gate curthread->t_flag |= T_DONTBLOCK;
5197c478bd9Sstevel@tonic-gate TRANS_BEGIN_ASYNC(ufsvfsp, topid,
5207c478bd9Sstevel@tonic-gate TOP_SYNCIP_SIZE);
5217c478bd9Sstevel@tonic-gate }
5227c478bd9Sstevel@tonic-gate rw_enter(&ip->i_contents, RW_READER);
5237c478bd9Sstevel@tonic-gate mutex_enter(&ip->i_tlock);
5247c478bd9Sstevel@tonic-gate ip->i_flag &= ~IMODTIME;
5257c478bd9Sstevel@tonic-gate mutex_exit(&ip->i_tlock);
5267c478bd9Sstevel@tonic-gate ufs_iupdat(ip, 1);
5277c478bd9Sstevel@tonic-gate rw_exit(&ip->i_contents);
5287c478bd9Sstevel@tonic-gate if (dotrans) {
5297c478bd9Sstevel@tonic-gate TRANS_END_ASYNC(ufsvfsp, topid,
5307c478bd9Sstevel@tonic-gate TOP_SYNCIP_SIZE);
5317c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_DONTBLOCK;
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate }
5347c478bd9Sstevel@tonic-gate } else {
5357c478bd9Sstevel@tonic-gate /* For file sync, any inode change requires inode update */
5367c478bd9Sstevel@tonic-gate if (ip->i_flag & (IBDWRITE|IUPD|IACC|ICHG|IMOD|IMODACC)) {
5377c478bd9Sstevel@tonic-gate /*
5387c478bd9Sstevel@tonic-gate * Enter a transaction to provide mutual exclusion
5397c478bd9Sstevel@tonic-gate * with deltamap_push and avoid a race where
5407c478bd9Sstevel@tonic-gate * the inode flush could get dropped.
5417c478bd9Sstevel@tonic-gate */
5427c478bd9Sstevel@tonic-gate if ((curthread->t_flag & T_DONTBLOCK) == 0) {
5437c478bd9Sstevel@tonic-gate dotrans = 1;
5447c478bd9Sstevel@tonic-gate curthread->t_flag |= T_DONTBLOCK;
5457c478bd9Sstevel@tonic-gate TRANS_BEGIN_ASYNC(ufsvfsp, topid,
5467c478bd9Sstevel@tonic-gate TOP_SYNCIP_SIZE);
5477c478bd9Sstevel@tonic-gate }
5487c478bd9Sstevel@tonic-gate rw_enter(&ip->i_contents, RW_READER);
5497c478bd9Sstevel@tonic-gate mutex_enter(&ip->i_tlock);
5507c478bd9Sstevel@tonic-gate ip->i_flag &= ~IMODTIME;
5517c478bd9Sstevel@tonic-gate mutex_exit(&ip->i_tlock);
5527c478bd9Sstevel@tonic-gate ufs_iupdat(ip, waitfor);
5537c478bd9Sstevel@tonic-gate rw_exit(&ip->i_contents);
5547c478bd9Sstevel@tonic-gate if (dotrans) {
5557c478bd9Sstevel@tonic-gate TRANS_END_ASYNC(ufsvfsp, topid,
5567c478bd9Sstevel@tonic-gate TOP_SYNCIP_SIZE);
5577c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_DONTBLOCK;
5587c478bd9Sstevel@tonic-gate }
5597c478bd9Sstevel@tonic-gate }
5607c478bd9Sstevel@tonic-gate }
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate out:
5637c478bd9Sstevel@tonic-gate return (error);
5647c478bd9Sstevel@tonic-gate }
5657c478bd9Sstevel@tonic-gate /*
5667c478bd9Sstevel@tonic-gate * Flush all indirect blocks related to an inode.
5677c478bd9Sstevel@tonic-gate * Supports triple indirect blocks also.
5687c478bd9Sstevel@tonic-gate */
5697c478bd9Sstevel@tonic-gate int
ufs_sync_indir(struct inode * ip)5707c478bd9Sstevel@tonic-gate ufs_sync_indir(struct inode *ip)
5717c478bd9Sstevel@tonic-gate {
5727c478bd9Sstevel@tonic-gate int i;
5737c478bd9Sstevel@tonic-gate daddr_t blkno;
5747c478bd9Sstevel@tonic-gate daddr_t lbn; /* logical blkno of last blk in file */
5757c478bd9Sstevel@tonic-gate daddr_t clbn; /* current logical blk */
5767c478bd9Sstevel@tonic-gate daddr32_t *bap;
5777c478bd9Sstevel@tonic-gate struct fs *fs;
5787c478bd9Sstevel@tonic-gate struct buf *bp;
5797c478bd9Sstevel@tonic-gate int bsize;
5807c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp;
5817c478bd9Sstevel@tonic-gate int j;
5827c478bd9Sstevel@tonic-gate daddr_t indirect_blkno;
5837c478bd9Sstevel@tonic-gate daddr32_t *indirect_bap;
5847c478bd9Sstevel@tonic-gate struct buf *indirect_bp;
5857c478bd9Sstevel@tonic-gate
5867c478bd9Sstevel@tonic-gate ufsvfsp = ip->i_ufsvfs;
5877c478bd9Sstevel@tonic-gate /*
5887c478bd9Sstevel@tonic-gate * unnecessary when logging; allocation blocks are kept up-to-date
5897c478bd9Sstevel@tonic-gate */
5907c478bd9Sstevel@tonic-gate if (TRANS_ISTRANS(ufsvfsp))
5917c478bd9Sstevel@tonic-gate return (0);
5927c478bd9Sstevel@tonic-gate
5937c478bd9Sstevel@tonic-gate fs = ufsvfsp->vfs_fs;
5947c478bd9Sstevel@tonic-gate bsize = fs->fs_bsize;
5957c478bd9Sstevel@tonic-gate lbn = (daddr_t)lblkno(fs, ip->i_size - 1);
5967c478bd9Sstevel@tonic-gate if (lbn < NDADDR)
5977c478bd9Sstevel@tonic-gate return (0); /* No indirect blocks used */
5987c478bd9Sstevel@tonic-gate if (lbn < NDADDR + NINDIR(fs)) {
5997c478bd9Sstevel@tonic-gate /* File has one indirect block. */
6007c478bd9Sstevel@tonic-gate blkflush(ip->i_dev, (daddr_t)fsbtodb(fs, ip->i_ib[0]));
6017c478bd9Sstevel@tonic-gate return (0);
6027c478bd9Sstevel@tonic-gate }
6037c478bd9Sstevel@tonic-gate
6047c478bd9Sstevel@tonic-gate /* Write out all the first level indirect blocks */
6057c478bd9Sstevel@tonic-gate for (i = 0; i <= NIADDR; i++) {
6067c478bd9Sstevel@tonic-gate if ((blkno = ip->i_ib[i]) == 0)
6077c478bd9Sstevel@tonic-gate continue;
6087c478bd9Sstevel@tonic-gate blkflush(ip->i_dev, (daddr_t)fsbtodb(fs, blkno));
6097c478bd9Sstevel@tonic-gate }
6107c478bd9Sstevel@tonic-gate /* Write out second level of indirect blocks */
6117c478bd9Sstevel@tonic-gate if ((blkno = ip->i_ib[1]) == 0)
6127c478bd9Sstevel@tonic-gate return (0);
6137c478bd9Sstevel@tonic-gate bp = UFS_BREAD(ufsvfsp, ip->i_dev, (daddr_t)fsbtodb(fs, blkno), bsize);
6147c478bd9Sstevel@tonic-gate if (bp->b_flags & B_ERROR) {
6157c478bd9Sstevel@tonic-gate brelse(bp);
6167c478bd9Sstevel@tonic-gate return (EIO);
6177c478bd9Sstevel@tonic-gate }
6187c478bd9Sstevel@tonic-gate bap = bp->b_un.b_daddr;
6197c478bd9Sstevel@tonic-gate clbn = NDADDR + NINDIR(fs);
6207c478bd9Sstevel@tonic-gate for (i = 0; i < NINDIR(fs); i++) {
6217c478bd9Sstevel@tonic-gate if (clbn > lbn)
6227c478bd9Sstevel@tonic-gate break;
6237c478bd9Sstevel@tonic-gate clbn += NINDIR(fs);
6247c478bd9Sstevel@tonic-gate if ((blkno = bap[i]) == 0)
6257c478bd9Sstevel@tonic-gate continue;
6267c478bd9Sstevel@tonic-gate blkflush(ip->i_dev, (daddr_t)fsbtodb(fs, blkno));
6277c478bd9Sstevel@tonic-gate }
6287c478bd9Sstevel@tonic-gate
6297c478bd9Sstevel@tonic-gate brelse(bp);
6307c478bd9Sstevel@tonic-gate /* write out third level indirect blocks */
6317c478bd9Sstevel@tonic-gate
6327c478bd9Sstevel@tonic-gate if ((blkno = ip->i_ib[2]) == 0)
6337c478bd9Sstevel@tonic-gate return (0);
6347c478bd9Sstevel@tonic-gate
6357c478bd9Sstevel@tonic-gate bp = UFS_BREAD(ufsvfsp, ip->i_dev, (daddr_t)fsbtodb(fs, blkno), bsize);
6367c478bd9Sstevel@tonic-gate if (bp->b_flags & B_ERROR) {
6377c478bd9Sstevel@tonic-gate brelse(bp);
6387c478bd9Sstevel@tonic-gate return (EIO);
6397c478bd9Sstevel@tonic-gate }
6407c478bd9Sstevel@tonic-gate bap = bp->b_un.b_daddr;
6417c478bd9Sstevel@tonic-gate clbn = NDADDR + NINDIR(fs) + (NINDIR(fs) * NINDIR(fs));
6427c478bd9Sstevel@tonic-gate
6437c478bd9Sstevel@tonic-gate for (i = 0; i < NINDIR(fs); i++) {
6447c478bd9Sstevel@tonic-gate if (clbn > lbn)
6457c478bd9Sstevel@tonic-gate break;
6467c478bd9Sstevel@tonic-gate if ((indirect_blkno = bap[i]) == 0)
6477c478bd9Sstevel@tonic-gate continue;
6487c478bd9Sstevel@tonic-gate blkflush(ip->i_dev, (daddr_t)fsbtodb(fs, indirect_blkno));
6497c478bd9Sstevel@tonic-gate indirect_bp = UFS_BREAD(ufsvfsp, ip->i_dev,
6507c478bd9Sstevel@tonic-gate (daddr_t)fsbtodb(fs, indirect_blkno), bsize);
6517c478bd9Sstevel@tonic-gate if (indirect_bp->b_flags & B_ERROR) {
6527c478bd9Sstevel@tonic-gate brelse(indirect_bp);
6537c478bd9Sstevel@tonic-gate brelse(bp);
6547c478bd9Sstevel@tonic-gate return (EIO);
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate indirect_bap = indirect_bp->b_un.b_daddr;
6577c478bd9Sstevel@tonic-gate for (j = 0; j < NINDIR(fs); j++) {
6587c478bd9Sstevel@tonic-gate if (clbn > lbn)
6597c478bd9Sstevel@tonic-gate break;
6607c478bd9Sstevel@tonic-gate clbn += NINDIR(fs);
6617c478bd9Sstevel@tonic-gate if ((blkno = indirect_bap[j]) == 0)
6627c478bd9Sstevel@tonic-gate continue;
6637c478bd9Sstevel@tonic-gate blkflush(ip->i_dev, (daddr_t)fsbtodb(fs, blkno));
6647c478bd9Sstevel@tonic-gate }
6657c478bd9Sstevel@tonic-gate brelse(indirect_bp);
6667c478bd9Sstevel@tonic-gate }
6677c478bd9Sstevel@tonic-gate brelse(bp);
6687c478bd9Sstevel@tonic-gate
6697c478bd9Sstevel@tonic-gate return (0);
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate
6727c478bd9Sstevel@tonic-gate /*
6737c478bd9Sstevel@tonic-gate * Flush all indirect blocks related to an offset of a file.
6747c478bd9Sstevel@tonic-gate * read/write in sync mode may have to flush indirect blocks.
6757c478bd9Sstevel@tonic-gate */
6767c478bd9Sstevel@tonic-gate int
ufs_indirblk_sync(struct inode * ip,offset_t off)6777c478bd9Sstevel@tonic-gate ufs_indirblk_sync(struct inode *ip, offset_t off)
6787c478bd9Sstevel@tonic-gate {
6797c478bd9Sstevel@tonic-gate daddr_t lbn;
6807c478bd9Sstevel@tonic-gate struct fs *fs;
6817c478bd9Sstevel@tonic-gate struct buf *bp;
6827c478bd9Sstevel@tonic-gate int i, j, shft;
6837c478bd9Sstevel@tonic-gate daddr_t ob, nb, tbn;
6847c478bd9Sstevel@tonic-gate daddr32_t *bap;
6857c478bd9Sstevel@tonic-gate int nindirshift, nindiroffset;
6867c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp;
6877c478bd9Sstevel@tonic-gate
6887c478bd9Sstevel@tonic-gate ufsvfsp = ip->i_ufsvfs;
6897c478bd9Sstevel@tonic-gate /*
6907c478bd9Sstevel@tonic-gate * unnecessary when logging; allocation blocks are kept up-to-date
6917c478bd9Sstevel@tonic-gate */
6927c478bd9Sstevel@tonic-gate if (TRANS_ISTRANS(ufsvfsp))
6937c478bd9Sstevel@tonic-gate return (0);
6947c478bd9Sstevel@tonic-gate
6957c478bd9Sstevel@tonic-gate fs = ufsvfsp->vfs_fs;
6967c478bd9Sstevel@tonic-gate
6977c478bd9Sstevel@tonic-gate lbn = (daddr_t)lblkno(fs, off);
6987c478bd9Sstevel@tonic-gate if (lbn < 0)
6997c478bd9Sstevel@tonic-gate return (EFBIG);
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate /* The first NDADDR are direct so nothing to do */
7027c478bd9Sstevel@tonic-gate if (lbn < NDADDR)
7037c478bd9Sstevel@tonic-gate return (0);
7047c478bd9Sstevel@tonic-gate
7057c478bd9Sstevel@tonic-gate nindirshift = ip->i_ufsvfs->vfs_nindirshift;
7067c478bd9Sstevel@tonic-gate nindiroffset = ip->i_ufsvfs->vfs_nindiroffset;
7077c478bd9Sstevel@tonic-gate
7087c478bd9Sstevel@tonic-gate /* Determine level of indirect blocks */
7097c478bd9Sstevel@tonic-gate shft = 0;
7107c478bd9Sstevel@tonic-gate tbn = lbn - NDADDR;
7117c478bd9Sstevel@tonic-gate for (j = NIADDR; j > 0; j--) {
7127c478bd9Sstevel@tonic-gate longlong_t sh;
7137c478bd9Sstevel@tonic-gate
7147c478bd9Sstevel@tonic-gate shft += nindirshift;
7157c478bd9Sstevel@tonic-gate sh = 1LL << shft;
7167c478bd9Sstevel@tonic-gate if (tbn < sh)
7177c478bd9Sstevel@tonic-gate break;
7187c478bd9Sstevel@tonic-gate tbn -= (daddr_t)sh;
7197c478bd9Sstevel@tonic-gate }
7207c478bd9Sstevel@tonic-gate
7217c478bd9Sstevel@tonic-gate if (j == 0)
7227c478bd9Sstevel@tonic-gate return (EFBIG);
7237c478bd9Sstevel@tonic-gate
7247c478bd9Sstevel@tonic-gate if ((nb = ip->i_ib[NIADDR - j]) == 0)
7257c478bd9Sstevel@tonic-gate return (0); /* UFS Hole */
7267c478bd9Sstevel@tonic-gate
7277c478bd9Sstevel@tonic-gate /* Flush first level indirect block */
7287c478bd9Sstevel@tonic-gate blkflush(ip->i_dev, fsbtodb(fs, nb));
7297c478bd9Sstevel@tonic-gate
7307c478bd9Sstevel@tonic-gate /* Fetch through next levels */
7317c478bd9Sstevel@tonic-gate for (; j < NIADDR; j++) {
7327c478bd9Sstevel@tonic-gate ob = nb;
7337c478bd9Sstevel@tonic-gate bp = UFS_BREAD(ufsvfsp,
7347c478bd9Sstevel@tonic-gate ip->i_dev, fsbtodb(fs, ob), fs->fs_bsize);
7357c478bd9Sstevel@tonic-gate if (bp->b_flags & B_ERROR) {
7367c478bd9Sstevel@tonic-gate brelse(bp);
7377c478bd9Sstevel@tonic-gate return (EIO);
7387c478bd9Sstevel@tonic-gate }
7397c478bd9Sstevel@tonic-gate bap = bp->b_un.b_daddr;
7407c478bd9Sstevel@tonic-gate shft -= nindirshift; /* sh / nindir */
7417c478bd9Sstevel@tonic-gate i = (tbn >> shft) & nindiroffset; /* (tbn /sh) & nindir */
7427c478bd9Sstevel@tonic-gate nb = bap[i];
7437c478bd9Sstevel@tonic-gate brelse(bp);
7447c478bd9Sstevel@tonic-gate if (nb == 0) {
7457c478bd9Sstevel@tonic-gate return (0); /* UFS hole */
7467c478bd9Sstevel@tonic-gate }
7477c478bd9Sstevel@tonic-gate blkflush(ip->i_dev, fsbtodb(fs, nb));
7487c478bd9Sstevel@tonic-gate }
7497c478bd9Sstevel@tonic-gate return (0);
7507c478bd9Sstevel@tonic-gate }
7517c478bd9Sstevel@tonic-gate
7527c478bd9Sstevel@tonic-gate #ifdef DEBUG
7537c478bd9Sstevel@tonic-gate
7547c478bd9Sstevel@tonic-gate /*
7557c478bd9Sstevel@tonic-gate * The bad block checking routines: ufs_indir_badblock() and ufs_badblock()
7567c478bd9Sstevel@tonic-gate * are very expensive. It's been found from profiling that we're
7577c478bd9Sstevel@tonic-gate * spending 6-7% of our time in ufs_badblock, and another 1-2% in
7587c478bd9Sstevel@tonic-gate * ufs_indir_badblock. They are only called via ASSERTs (from debug kernels).
7597c478bd9Sstevel@tonic-gate * In addition from experience no failures have been found in recent
7607c478bd9Sstevel@tonic-gate * years. So the following tunable can be set to enable checking.
7617c478bd9Sstevel@tonic-gate */
7627c478bd9Sstevel@tonic-gate int ufs_badblock_checks = 0;
7637c478bd9Sstevel@tonic-gate
7647c478bd9Sstevel@tonic-gate /*
7657c478bd9Sstevel@tonic-gate * Check that a given indirect block contains blocks in range
7667c478bd9Sstevel@tonic-gate */
7677c478bd9Sstevel@tonic-gate int
ufs_indir_badblock(struct inode * ip,daddr32_t * bap)7687c478bd9Sstevel@tonic-gate ufs_indir_badblock(struct inode *ip, daddr32_t *bap)
7697c478bd9Sstevel@tonic-gate {
7707c478bd9Sstevel@tonic-gate int i;
7717c478bd9Sstevel@tonic-gate int err = 0;
7727c478bd9Sstevel@tonic-gate
7737c478bd9Sstevel@tonic-gate if (ufs_badblock_checks) {
7747c478bd9Sstevel@tonic-gate for (i = 0; i < NINDIR(ip->i_fs) - 1; i++)
7757c478bd9Sstevel@tonic-gate if (bap[i] != 0 && (err = ufs_badblock(ip, bap[i])))
7767c478bd9Sstevel@tonic-gate break;
7777c478bd9Sstevel@tonic-gate }
7787c478bd9Sstevel@tonic-gate return (err);
7797c478bd9Sstevel@tonic-gate }
7807c478bd9Sstevel@tonic-gate
7817c478bd9Sstevel@tonic-gate /*
7827c478bd9Sstevel@tonic-gate * Check that a specified block number is in range.
7837c478bd9Sstevel@tonic-gate */
7847c478bd9Sstevel@tonic-gate int
ufs_badblock(struct inode * ip,daddr_t bn)7857c478bd9Sstevel@tonic-gate ufs_badblock(struct inode *ip, daddr_t bn)
7867c478bd9Sstevel@tonic-gate {
7877c478bd9Sstevel@tonic-gate long c;
7887c478bd9Sstevel@tonic-gate daddr_t sum;
7897c478bd9Sstevel@tonic-gate
7907c478bd9Sstevel@tonic-gate if (!ufs_badblock_checks)
7917c478bd9Sstevel@tonic-gate return (0);
7927c478bd9Sstevel@tonic-gate ASSERT(bn);
7937c478bd9Sstevel@tonic-gate if (bn <= 0 || bn > ip->i_fs->fs_size)
7947c478bd9Sstevel@tonic-gate return (bn);
7957c478bd9Sstevel@tonic-gate
7967c478bd9Sstevel@tonic-gate sum = 0;
7977c478bd9Sstevel@tonic-gate c = dtog(ip->i_fs, bn);
7987c478bd9Sstevel@tonic-gate if (c == 0) {
7997c478bd9Sstevel@tonic-gate sum = howmany(ip->i_fs->fs_cssize, ip->i_fs->fs_fsize);
8007c478bd9Sstevel@tonic-gate }
8017c478bd9Sstevel@tonic-gate /*
8027c478bd9Sstevel@tonic-gate * if block no. is below this cylinder group,
8037c478bd9Sstevel@tonic-gate * within the space reserved for superblock, inodes, (summary data)
8047c478bd9Sstevel@tonic-gate * or if it is above this cylinder group
8057c478bd9Sstevel@tonic-gate * then its invalid
8067c478bd9Sstevel@tonic-gate * It's hard to see how we'd be outside this cyl, but let's be careful.
8077c478bd9Sstevel@tonic-gate */
8087c478bd9Sstevel@tonic-gate if ((bn < cgbase(ip->i_fs, c)) ||
8097c478bd9Sstevel@tonic-gate (bn >= cgsblock(ip->i_fs, c) && bn < cgdmin(ip->i_fs, c)+sum) ||
8107c478bd9Sstevel@tonic-gate (bn >= (unsigned)cgbase(ip->i_fs, c+1)))
8117c478bd9Sstevel@tonic-gate return (bn);
8127c478bd9Sstevel@tonic-gate
8137c478bd9Sstevel@tonic-gate return (0); /* not a bad block */
8147c478bd9Sstevel@tonic-gate }
8157c478bd9Sstevel@tonic-gate
8167c478bd9Sstevel@tonic-gate #endif /* DEBUG */
8177c478bd9Sstevel@tonic-gate
8187c478bd9Sstevel@tonic-gate /*
8197c478bd9Sstevel@tonic-gate * When i_rwlock is write-locked or has a writer pended, then the inode
8207c478bd9Sstevel@tonic-gate * is going to change in a way that the filesystem will be marked as
8217c478bd9Sstevel@tonic-gate * active. So no need to let the filesystem be mark as stable now.
8227c478bd9Sstevel@tonic-gate * Also to ensure the filesystem consistency during the directory
8237c478bd9Sstevel@tonic-gate * operations, filesystem cannot be marked as stable if i_rwlock of
8247c478bd9Sstevel@tonic-gate * the directory inode is write-locked.
8257c478bd9Sstevel@tonic-gate */
8267c478bd9Sstevel@tonic-gate
8277c478bd9Sstevel@tonic-gate /*
8287c478bd9Sstevel@tonic-gate * Check for busy inodes for this filesystem.
8297c478bd9Sstevel@tonic-gate * NOTE: Needs better way to do this expensive operation in the future.
8307c478bd9Sstevel@tonic-gate */
8317c478bd9Sstevel@tonic-gate static void
ufs_icheck(struct ufsvfs * ufsvfsp,int * isbusyp,int * isreclaimp)8327c478bd9Sstevel@tonic-gate ufs_icheck(struct ufsvfs *ufsvfsp, int *isbusyp, int *isreclaimp)
8337c478bd9Sstevel@tonic-gate {
8347c478bd9Sstevel@tonic-gate union ihead *ih;
8357c478bd9Sstevel@tonic-gate struct inode *ip;
8367c478bd9Sstevel@tonic-gate int i;
8377c478bd9Sstevel@tonic-gate int isnottrans = !TRANS_ISTRANS(ufsvfsp);
8387c478bd9Sstevel@tonic-gate int isbusy = *isbusyp;
8397c478bd9Sstevel@tonic-gate int isreclaim = *isreclaimp;
8407c478bd9Sstevel@tonic-gate
8417c478bd9Sstevel@tonic-gate for (i = 0, ih = ihead; i < inohsz; i++, ih++) {
8427c478bd9Sstevel@tonic-gate mutex_enter(&ih_lock[i]);
8437c478bd9Sstevel@tonic-gate for (ip = ih->ih_chain[0];
8447c478bd9Sstevel@tonic-gate ip != (struct inode *)ih;
8457c478bd9Sstevel@tonic-gate ip = ip->i_forw) {
8467c478bd9Sstevel@tonic-gate /*
8477c478bd9Sstevel@tonic-gate * if inode is busy/modified/deleted, filesystem is busy
8487c478bd9Sstevel@tonic-gate */
8497c478bd9Sstevel@tonic-gate if (ip->i_ufsvfs != ufsvfsp)
8507c478bd9Sstevel@tonic-gate continue;
8517c478bd9Sstevel@tonic-gate if ((ip->i_flag & (IMOD | IUPD | ICHG)) ||
8527c478bd9Sstevel@tonic-gate (RW_ISWRITER(&ip->i_rwlock)))
8537c478bd9Sstevel@tonic-gate isbusy = 1;
8547c478bd9Sstevel@tonic-gate if ((ip->i_nlink <= 0) && (ip->i_flag & IREF))
8557c478bd9Sstevel@tonic-gate isreclaim = 1;
8567c478bd9Sstevel@tonic-gate if (isbusy && (isreclaim || isnottrans))
8577c478bd9Sstevel@tonic-gate break;
8587c478bd9Sstevel@tonic-gate }
8597c478bd9Sstevel@tonic-gate mutex_exit(&ih_lock[i]);
8607c478bd9Sstevel@tonic-gate if (isbusy && (isreclaim || isnottrans))
8617c478bd9Sstevel@tonic-gate break;
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate *isbusyp = isbusy;
8647c478bd9Sstevel@tonic-gate *isreclaimp = isreclaim;
8657c478bd9Sstevel@tonic-gate }
8667c478bd9Sstevel@tonic-gate
8677c478bd9Sstevel@tonic-gate /*
8687c478bd9Sstevel@tonic-gate * As part of the ufs 'sync' operation, this routine is called to mark
8697c478bd9Sstevel@tonic-gate * the filesystem as STABLE if there is no modified metadata in memory.
8707c478bd9Sstevel@tonic-gate */
8717c478bd9Sstevel@tonic-gate void
ufs_checkclean(struct vfs * vfsp)8727c478bd9Sstevel@tonic-gate ufs_checkclean(struct vfs *vfsp)
8737c478bd9Sstevel@tonic-gate {
8747c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = (struct ufsvfs *)vfsp->vfs_data;
8757c478bd9Sstevel@tonic-gate struct fs *fs = ufsvfsp->vfs_fs;
8767c478bd9Sstevel@tonic-gate int isbusy;
8777c478bd9Sstevel@tonic-gate int isreclaim;
8787c478bd9Sstevel@tonic-gate int updatesb;
8797c478bd9Sstevel@tonic-gate
8807c478bd9Sstevel@tonic-gate ASSERT(vfs_lock_held(vfsp));
8817c478bd9Sstevel@tonic-gate
8827c478bd9Sstevel@tonic-gate /*
8837c478bd9Sstevel@tonic-gate * filesystem is stable or cleanflag processing is disabled; do nothing
8847c478bd9Sstevel@tonic-gate * no transitions when panic'ing
8857c478bd9Sstevel@tonic-gate */
8867c478bd9Sstevel@tonic-gate if (fs->fs_ronly ||
8877c478bd9Sstevel@tonic-gate fs->fs_clean == FSBAD ||
8887c478bd9Sstevel@tonic-gate fs->fs_clean == FSSUSPEND ||
8897c478bd9Sstevel@tonic-gate fs->fs_clean == FSSTABLE ||
8907c478bd9Sstevel@tonic-gate panicstr)
8917c478bd9Sstevel@tonic-gate return;
8927c478bd9Sstevel@tonic-gate
8937c478bd9Sstevel@tonic-gate /*
8947c478bd9Sstevel@tonic-gate * if logging and nothing to reclaim; do nothing
8957c478bd9Sstevel@tonic-gate */
8967c478bd9Sstevel@tonic-gate if ((fs->fs_clean == FSLOG) &&
8977c478bd9Sstevel@tonic-gate (((fs->fs_reclaim & FS_RECLAIM) == 0) ||
8987c478bd9Sstevel@tonic-gate (fs->fs_reclaim & FS_RECLAIMING)))
8997c478bd9Sstevel@tonic-gate return;
9007c478bd9Sstevel@tonic-gate
9017c478bd9Sstevel@tonic-gate /*
9027c478bd9Sstevel@tonic-gate * FS_CHECKCLEAN is reset if the file system goes dirty
9037c478bd9Sstevel@tonic-gate * FS_CHECKRECLAIM is reset if a file gets deleted
9047c478bd9Sstevel@tonic-gate */
9057c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfsp->vfs_lock);
9067c478bd9Sstevel@tonic-gate fs->fs_reclaim |= (FS_CHECKCLEAN | FS_CHECKRECLAIM);
9077c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfsp->vfs_lock);
9087c478bd9Sstevel@tonic-gate
9097c478bd9Sstevel@tonic-gate updatesb = 0;
9107c478bd9Sstevel@tonic-gate
9117c478bd9Sstevel@tonic-gate /*
9127c478bd9Sstevel@tonic-gate * if logging or buffers are busy; do nothing
9137c478bd9Sstevel@tonic-gate */
9147c478bd9Sstevel@tonic-gate isbusy = isreclaim = 0;
9157c478bd9Sstevel@tonic-gate if ((fs->fs_clean == FSLOG) ||
9167c478bd9Sstevel@tonic-gate (bcheck(vfsp->vfs_dev, ufsvfsp->vfs_bufp)))
9177c478bd9Sstevel@tonic-gate isbusy = 1;
9187c478bd9Sstevel@tonic-gate
9197c478bd9Sstevel@tonic-gate /*
9207c478bd9Sstevel@tonic-gate * isreclaim == TRUE means can't change the state of fs_reclaim
9217c478bd9Sstevel@tonic-gate */
9227c478bd9Sstevel@tonic-gate isreclaim =
9237c478bd9Sstevel@tonic-gate ((fs->fs_clean == FSLOG) &&
9247c478bd9Sstevel@tonic-gate (((fs->fs_reclaim & FS_RECLAIM) == 0) ||
9257c478bd9Sstevel@tonic-gate (fs->fs_reclaim & FS_RECLAIMING)));
9267c478bd9Sstevel@tonic-gate
9277c478bd9Sstevel@tonic-gate /*
9287c478bd9Sstevel@tonic-gate * if fs is busy or can't change the state of fs_reclaim; do nothing
9297c478bd9Sstevel@tonic-gate */
9307c478bd9Sstevel@tonic-gate if (isbusy && isreclaim)
9317c478bd9Sstevel@tonic-gate return;
9327c478bd9Sstevel@tonic-gate
9337c478bd9Sstevel@tonic-gate /*
9347c478bd9Sstevel@tonic-gate * look for busy or deleted inodes; (deleted == needs reclaim)
9357c478bd9Sstevel@tonic-gate */
9367c478bd9Sstevel@tonic-gate ufs_icheck(ufsvfsp, &isbusy, &isreclaim);
9377c478bd9Sstevel@tonic-gate
9387c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfsp->vfs_lock);
9397c478bd9Sstevel@tonic-gate
9407c478bd9Sstevel@tonic-gate /*
9417c478bd9Sstevel@tonic-gate * IF POSSIBLE, RESET RECLAIM
9427c478bd9Sstevel@tonic-gate */
9437c478bd9Sstevel@tonic-gate /*
9447c478bd9Sstevel@tonic-gate * the reclaim thread is not running
9457c478bd9Sstevel@tonic-gate */
9467c478bd9Sstevel@tonic-gate if ((fs->fs_reclaim & FS_RECLAIMING) == 0)
9477c478bd9Sstevel@tonic-gate /*
9487c478bd9Sstevel@tonic-gate * no files were deleted during the scan
9497c478bd9Sstevel@tonic-gate */
9507c478bd9Sstevel@tonic-gate if (fs->fs_reclaim & FS_CHECKRECLAIM)
9517c478bd9Sstevel@tonic-gate /*
9527c478bd9Sstevel@tonic-gate * no deleted files were found in the inode cache
9537c478bd9Sstevel@tonic-gate */
9547c478bd9Sstevel@tonic-gate if ((isreclaim == 0) && (fs->fs_reclaim & FS_RECLAIM)) {
9557c478bd9Sstevel@tonic-gate fs->fs_reclaim &= ~FS_RECLAIM;
9567c478bd9Sstevel@tonic-gate updatesb = 1;
9577c478bd9Sstevel@tonic-gate }
9587c478bd9Sstevel@tonic-gate /*
9597c478bd9Sstevel@tonic-gate * IF POSSIBLE, SET STABLE
9607c478bd9Sstevel@tonic-gate */
9617c478bd9Sstevel@tonic-gate /*
9627c478bd9Sstevel@tonic-gate * not logging
9637c478bd9Sstevel@tonic-gate */
9647c478bd9Sstevel@tonic-gate if (fs->fs_clean != FSLOG)
9657c478bd9Sstevel@tonic-gate /*
9667c478bd9Sstevel@tonic-gate * file system has not gone dirty since the scan began
9677c478bd9Sstevel@tonic-gate */
9687c478bd9Sstevel@tonic-gate if (fs->fs_reclaim & FS_CHECKCLEAN)
9697c478bd9Sstevel@tonic-gate /*
9707c478bd9Sstevel@tonic-gate * nothing dirty was found in the buffer or inode cache
9717c478bd9Sstevel@tonic-gate */
9727c478bd9Sstevel@tonic-gate if ((isbusy == 0) && (isreclaim == 0) &&
9737c478bd9Sstevel@tonic-gate (fs->fs_clean != FSSTABLE)) {
9747c478bd9Sstevel@tonic-gate fs->fs_clean = FSSTABLE;
9757c478bd9Sstevel@tonic-gate updatesb = 1;
9767c478bd9Sstevel@tonic-gate }
9777c478bd9Sstevel@tonic-gate
9787c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfsp->vfs_lock);
9797c478bd9Sstevel@tonic-gate if (updatesb) {
9807c478bd9Sstevel@tonic-gate TRANS_SBWRITE(ufsvfsp, TOP_SBWRITE_STABLE);
9817c478bd9Sstevel@tonic-gate }
9827c478bd9Sstevel@tonic-gate }
9837c478bd9Sstevel@tonic-gate
9847c478bd9Sstevel@tonic-gate /*
9857c478bd9Sstevel@tonic-gate * called whenever an unlink occurs
9867c478bd9Sstevel@tonic-gate */
9877c478bd9Sstevel@tonic-gate void
ufs_setreclaim(struct inode * ip)9887c478bd9Sstevel@tonic-gate ufs_setreclaim(struct inode *ip)
9897c478bd9Sstevel@tonic-gate {
9907c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = ip->i_ufsvfs;
9917c478bd9Sstevel@tonic-gate struct fs *fs = ufsvfsp->vfs_fs;
9927c478bd9Sstevel@tonic-gate
9937c478bd9Sstevel@tonic-gate if (ip->i_nlink || fs->fs_ronly || (fs->fs_clean != FSLOG))
9947c478bd9Sstevel@tonic-gate return;
9957c478bd9Sstevel@tonic-gate
9967c478bd9Sstevel@tonic-gate /*
9977c478bd9Sstevel@tonic-gate * reclaim-needed bit is already set or we need to tell
9987c478bd9Sstevel@tonic-gate * ufs_checkclean that a file has been deleted
9997c478bd9Sstevel@tonic-gate */
10007c478bd9Sstevel@tonic-gate if ((fs->fs_reclaim & (FS_RECLAIM | FS_CHECKRECLAIM)) == FS_RECLAIM)
10017c478bd9Sstevel@tonic-gate return;
10027c478bd9Sstevel@tonic-gate
10037c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfsp->vfs_lock);
10047c478bd9Sstevel@tonic-gate /*
10057c478bd9Sstevel@tonic-gate * inform ufs_checkclean that the file system has gone dirty
10067c478bd9Sstevel@tonic-gate */
10077c478bd9Sstevel@tonic-gate fs->fs_reclaim &= ~FS_CHECKRECLAIM;
10087c478bd9Sstevel@tonic-gate
10097c478bd9Sstevel@tonic-gate /*
10107c478bd9Sstevel@tonic-gate * set the reclaim-needed bit
10117c478bd9Sstevel@tonic-gate */
10127c478bd9Sstevel@tonic-gate if ((fs->fs_reclaim & FS_RECLAIM) == 0) {
10137c478bd9Sstevel@tonic-gate fs->fs_reclaim |= FS_RECLAIM;
10147c478bd9Sstevel@tonic-gate ufs_sbwrite(ufsvfsp);
10157c478bd9Sstevel@tonic-gate }
10167c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfsp->vfs_lock);
10177c478bd9Sstevel@tonic-gate }
10187c478bd9Sstevel@tonic-gate
10197c478bd9Sstevel@tonic-gate /*
10207c478bd9Sstevel@tonic-gate * Before any modified metadata written back to the disk, this routine
10217c478bd9Sstevel@tonic-gate * is called to mark the filesystem as ACTIVE.
10227c478bd9Sstevel@tonic-gate */
10237c478bd9Sstevel@tonic-gate void
ufs_notclean(struct ufsvfs * ufsvfsp)10247c478bd9Sstevel@tonic-gate ufs_notclean(struct ufsvfs *ufsvfsp)
10257c478bd9Sstevel@tonic-gate {
10267c478bd9Sstevel@tonic-gate struct fs *fs = ufsvfsp->vfs_fs;
10277c478bd9Sstevel@tonic-gate
10287c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ufsvfsp->vfs_lock));
10297c478bd9Sstevel@tonic-gate ULOCKFS_SET_MOD((&ufsvfsp->vfs_ulockfs));
10307c478bd9Sstevel@tonic-gate
10317c478bd9Sstevel@tonic-gate /*
10327c478bd9Sstevel@tonic-gate * inform ufs_checkclean that the file system has gone dirty
10337c478bd9Sstevel@tonic-gate */
10347c478bd9Sstevel@tonic-gate fs->fs_reclaim &= ~FS_CHECKCLEAN;
10357c478bd9Sstevel@tonic-gate
10367c478bd9Sstevel@tonic-gate /*
10377c478bd9Sstevel@tonic-gate * ignore if active or bad or suspended or readonly or logging
10387c478bd9Sstevel@tonic-gate */
10397c478bd9Sstevel@tonic-gate if ((fs->fs_clean == FSACTIVE) || (fs->fs_clean == FSLOG) ||
10407c478bd9Sstevel@tonic-gate (fs->fs_clean == FSBAD) || (fs->fs_clean == FSSUSPEND) ||
10417c478bd9Sstevel@tonic-gate (fs->fs_ronly)) {
10427c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfsp->vfs_lock);
10437c478bd9Sstevel@tonic-gate return;
10447c478bd9Sstevel@tonic-gate }
10457c478bd9Sstevel@tonic-gate fs->fs_clean = FSACTIVE;
10467c478bd9Sstevel@tonic-gate /*
10477c478bd9Sstevel@tonic-gate * write superblock synchronously
10487c478bd9Sstevel@tonic-gate */
10497c478bd9Sstevel@tonic-gate ufs_sbwrite(ufsvfsp);
10507c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfsp->vfs_lock);
10517c478bd9Sstevel@tonic-gate }
10527c478bd9Sstevel@tonic-gate
10537c478bd9Sstevel@tonic-gate /*
10547c478bd9Sstevel@tonic-gate * ufs specific fbwrite()
10557c478bd9Sstevel@tonic-gate */
10567c478bd9Sstevel@tonic-gate int
ufs_fbwrite(struct fbuf * fbp,struct inode * ip)10577c478bd9Sstevel@tonic-gate ufs_fbwrite(struct fbuf *fbp, struct inode *ip)
10587c478bd9Sstevel@tonic-gate {
10597c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = ip->i_ufsvfs;
10607c478bd9Sstevel@tonic-gate
10617c478bd9Sstevel@tonic-gate if (TRANS_ISTRANS(ufsvfsp))
10627c478bd9Sstevel@tonic-gate return (fbwrite(fbp));
10637c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfsp->vfs_lock);
10647c478bd9Sstevel@tonic-gate ufs_notclean(ufsvfsp);
10657c478bd9Sstevel@tonic-gate return ((ufsvfsp->vfs_dio) ? fbdwrite(fbp) : fbwrite(fbp));
10667c478bd9Sstevel@tonic-gate }
10677c478bd9Sstevel@tonic-gate
10687c478bd9Sstevel@tonic-gate /*
10697c478bd9Sstevel@tonic-gate * ufs specific fbiwrite()
10707c478bd9Sstevel@tonic-gate */
10717c478bd9Sstevel@tonic-gate int
ufs_fbiwrite(struct fbuf * fbp,struct inode * ip,daddr_t bn,long bsize)10727c478bd9Sstevel@tonic-gate ufs_fbiwrite(struct fbuf *fbp, struct inode *ip, daddr_t bn, long bsize)
10737c478bd9Sstevel@tonic-gate {
10747c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = ip->i_ufsvfs;
10757c478bd9Sstevel@tonic-gate o_mode_t ifmt = ip->i_mode & IFMT;
10767c478bd9Sstevel@tonic-gate buf_t *bp;
10777c478bd9Sstevel@tonic-gate int error;
10787c478bd9Sstevel@tonic-gate
10797c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfsp->vfs_lock);
10807c478bd9Sstevel@tonic-gate ufs_notclean(ufsvfsp);
10817c478bd9Sstevel@tonic-gate if (ifmt == IFDIR || ifmt == IFSHAD || ifmt == IFATTRDIR ||
10827c478bd9Sstevel@tonic-gate (ip->i_ufsvfs->vfs_qinod == ip)) {
10837c478bd9Sstevel@tonic-gate TRANS_DELTA(ufsvfsp, ldbtob(bn * (offset_t)(btod(bsize))),
10847c478bd9Sstevel@tonic-gate fbp->fb_count, DT_FBI, 0, 0);
10857c478bd9Sstevel@tonic-gate }
10867c478bd9Sstevel@tonic-gate /*
10877c478bd9Sstevel@tonic-gate * Inlined version of fbiwrite()
10887c478bd9Sstevel@tonic-gate */
10897c478bd9Sstevel@tonic-gate bp = pageio_setup((struct page *)NULL, fbp->fb_count,
10907c478bd9Sstevel@tonic-gate ip->i_devvp, B_WRITE);
10917c478bd9Sstevel@tonic-gate bp->b_flags &= ~B_PAGEIO;
10927c478bd9Sstevel@tonic-gate bp->b_un.b_addr = fbp->fb_addr;
10937c478bd9Sstevel@tonic-gate
10947c478bd9Sstevel@tonic-gate bp->b_blkno = bn * btod(bsize);
10957c478bd9Sstevel@tonic-gate bp->b_dev = cmpdev(ip->i_dev); /* store in old dev format */
10967c478bd9Sstevel@tonic-gate bp->b_edev = ip->i_dev;
10977c478bd9Sstevel@tonic-gate bp->b_proc = NULL; /* i.e. the kernel */
10987c478bd9Sstevel@tonic-gate bp->b_file = ip->i_vnode;
10997c478bd9Sstevel@tonic-gate bp->b_offset = -1;
11007c478bd9Sstevel@tonic-gate
11017c478bd9Sstevel@tonic-gate if (ufsvfsp->vfs_log) {
11027c478bd9Sstevel@tonic-gate lufs_write_strategy(ufsvfsp->vfs_log, bp);
11037c478bd9Sstevel@tonic-gate } else if (ufsvfsp->vfs_snapshot) {
11047c478bd9Sstevel@tonic-gate fssnap_strategy(&ufsvfsp->vfs_snapshot, bp);
11057c478bd9Sstevel@tonic-gate } else {
1106*d3d50737SRafael Vanoni ufsvfsp->vfs_iotstamp = ddi_get_lbolt();
11077c478bd9Sstevel@tonic-gate ub.ub_fbiwrites.value.ul++;
11087c478bd9Sstevel@tonic-gate (void) bdev_strategy(bp);
11097c478bd9Sstevel@tonic-gate lwp_stat_update(LWP_STAT_OUBLK, 1);
11107c478bd9Sstevel@tonic-gate }
11117c478bd9Sstevel@tonic-gate error = biowait(bp);
11127c478bd9Sstevel@tonic-gate pageio_done(bp);
11137c478bd9Sstevel@tonic-gate fbrelse(fbp, S_OTHER);
11147c478bd9Sstevel@tonic-gate return (error);
11157c478bd9Sstevel@tonic-gate }
11167c478bd9Sstevel@tonic-gate
11177c478bd9Sstevel@tonic-gate /*
11187c478bd9Sstevel@tonic-gate * Write the ufs superblock only.
11197c478bd9Sstevel@tonic-gate */
11207c478bd9Sstevel@tonic-gate void
ufs_sbwrite(struct ufsvfs * ufsvfsp)11217c478bd9Sstevel@tonic-gate ufs_sbwrite(struct ufsvfs *ufsvfsp)
11227c478bd9Sstevel@tonic-gate {
11237c478bd9Sstevel@tonic-gate char sav_fs_fmod;
11247c478bd9Sstevel@tonic-gate struct fs *fs = ufsvfsp->vfs_fs;
11257c478bd9Sstevel@tonic-gate struct buf *bp = ufsvfsp->vfs_bufp;
11267c478bd9Sstevel@tonic-gate
11277c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ufsvfsp->vfs_lock));
11287c478bd9Sstevel@tonic-gate
11297c478bd9Sstevel@tonic-gate /*
11307c478bd9Sstevel@tonic-gate * for ulockfs processing, limit the superblock writes
11317c478bd9Sstevel@tonic-gate */
11327c478bd9Sstevel@tonic-gate if ((ufsvfsp->vfs_ulockfs.ul_sbowner) &&
11337c478bd9Sstevel@tonic-gate (curthread != ufsvfsp->vfs_ulockfs.ul_sbowner)) {
11347c478bd9Sstevel@tonic-gate /* try again later */
11357c478bd9Sstevel@tonic-gate fs->fs_fmod = 1;
11367c478bd9Sstevel@tonic-gate return;
11377c478bd9Sstevel@tonic-gate }
11387c478bd9Sstevel@tonic-gate
11397c478bd9Sstevel@tonic-gate ULOCKFS_SET_MOD((&ufsvfsp->vfs_ulockfs));
11407c478bd9Sstevel@tonic-gate /*
11417c478bd9Sstevel@tonic-gate * update superblock timestamp and fs_clean checksum
11427c478bd9Sstevel@tonic-gate * if marked FSBAD, we always want an erroneous
11437c478bd9Sstevel@tonic-gate * checksum to force repair
11447c478bd9Sstevel@tonic-gate */
11457c478bd9Sstevel@tonic-gate fs->fs_time = gethrestime_sec();
114680d34432Sfrankho fs->fs_state = (fs->fs_clean != FSBAD) ?
114780d34432Sfrankho FSOKAY - fs->fs_time : -(FSOKAY - fs->fs_time);
11487c478bd9Sstevel@tonic-gate switch (fs->fs_clean) {
11497c478bd9Sstevel@tonic-gate case FSCLEAN:
11507c478bd9Sstevel@tonic-gate case FSSTABLE:
11517c478bd9Sstevel@tonic-gate fs->fs_reclaim &= ~FS_RECLAIM;
11527c478bd9Sstevel@tonic-gate break;
11537c478bd9Sstevel@tonic-gate case FSACTIVE:
11547c478bd9Sstevel@tonic-gate case FSSUSPEND:
11557c478bd9Sstevel@tonic-gate case FSBAD:
11567c478bd9Sstevel@tonic-gate case FSLOG:
11577c478bd9Sstevel@tonic-gate break;
11587c478bd9Sstevel@tonic-gate default:
11597c478bd9Sstevel@tonic-gate fs->fs_clean = FSACTIVE;
11607c478bd9Sstevel@tonic-gate break;
11617c478bd9Sstevel@tonic-gate }
11627c478bd9Sstevel@tonic-gate /*
11637c478bd9Sstevel@tonic-gate * reset incore only bits
11647c478bd9Sstevel@tonic-gate */
11657c478bd9Sstevel@tonic-gate fs->fs_reclaim &= ~(FS_CHECKCLEAN | FS_CHECKRECLAIM);
11667c478bd9Sstevel@tonic-gate
11677c478bd9Sstevel@tonic-gate /*
11687c478bd9Sstevel@tonic-gate * delta the whole superblock
11697c478bd9Sstevel@tonic-gate */
11707c478bd9Sstevel@tonic-gate TRANS_DELTA(ufsvfsp, ldbtob(SBLOCK), sizeof (struct fs),
11717c478bd9Sstevel@tonic-gate DT_SB, NULL, 0);
11727c478bd9Sstevel@tonic-gate /*
11737c478bd9Sstevel@tonic-gate * retain the incore state of fs_fmod; set the ondisk state to 0
11747c478bd9Sstevel@tonic-gate */
11757c478bd9Sstevel@tonic-gate sav_fs_fmod = fs->fs_fmod;
11767c478bd9Sstevel@tonic-gate fs->fs_fmod = 0;
11777c478bd9Sstevel@tonic-gate
11787c478bd9Sstevel@tonic-gate /*
11797c478bd9Sstevel@tonic-gate * Don't release the buffer after written to the disk
11807c478bd9Sstevel@tonic-gate */
11817c478bd9Sstevel@tonic-gate UFS_BWRITE2(ufsvfsp, bp);
11827c478bd9Sstevel@tonic-gate fs->fs_fmod = sav_fs_fmod; /* reset fs_fmod's incore state */
11837c478bd9Sstevel@tonic-gate }
11847c478bd9Sstevel@tonic-gate
11857c478bd9Sstevel@tonic-gate /*
11867c478bd9Sstevel@tonic-gate * Returns vfs pointer if vfs still being mounted. vfs lock is held.
11877c478bd9Sstevel@tonic-gate * Otherwise, returns NULL.
11887c478bd9Sstevel@tonic-gate *
11897c478bd9Sstevel@tonic-gate * For our purposes, "still mounted" means that the file system still appears
11907c478bd9Sstevel@tonic-gate * on the list of UFS file system instances.
11917c478bd9Sstevel@tonic-gate */
11927c478bd9Sstevel@tonic-gate static vfs_t *
still_mounted(struct check_node * checkp)11937c478bd9Sstevel@tonic-gate still_mounted(struct check_node *checkp)
11947c478bd9Sstevel@tonic-gate {
11957c478bd9Sstevel@tonic-gate struct vfs *vfsp;
11967c478bd9Sstevel@tonic-gate struct ufsvfs *ufsp;
11977c478bd9Sstevel@tonic-gate
11987c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfs_mutex);
11997c478bd9Sstevel@tonic-gate for (ufsp = ufs_instances; ufsp != NULL; ufsp = ufsp->vfs_next) {
12007c478bd9Sstevel@tonic-gate if (ufsp != checkp->ufsvfs)
12017c478bd9Sstevel@tonic-gate continue;
12027c478bd9Sstevel@tonic-gate /*
12037c478bd9Sstevel@tonic-gate * Tentative match: verify it and try to lock. (It's not at
12047c478bd9Sstevel@tonic-gate * all clear how the verification could fail, given that we've
12057c478bd9Sstevel@tonic-gate * gotten this far. We would have had to reallocate the
12067c478bd9Sstevel@tonic-gate * ufsvfs struct at hand for a new incarnation; is that really
12077c478bd9Sstevel@tonic-gate * possible in the interval from constructing the check_node
12087c478bd9Sstevel@tonic-gate * to here?)
12097c478bd9Sstevel@tonic-gate */
12107c478bd9Sstevel@tonic-gate vfsp = ufsp->vfs_vfs;
12117c478bd9Sstevel@tonic-gate if (vfsp != checkp->vfsp)
12127c478bd9Sstevel@tonic-gate continue;
12137c478bd9Sstevel@tonic-gate if (vfsp->vfs_dev != checkp->vfs_dev)
12147c478bd9Sstevel@tonic-gate continue;
12157c478bd9Sstevel@tonic-gate if (vfs_lock(vfsp) != 0)
12167c478bd9Sstevel@tonic-gate continue;
12177c478bd9Sstevel@tonic-gate
12187c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfs_mutex);
12197c478bd9Sstevel@tonic-gate return (vfsp);
12207c478bd9Sstevel@tonic-gate }
12217c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfs_mutex);
12227c478bd9Sstevel@tonic-gate return (NULL);
12237c478bd9Sstevel@tonic-gate }
12247c478bd9Sstevel@tonic-gate
12257c478bd9Sstevel@tonic-gate int
ufs_si_io_done(struct buf * bp)12267c478bd9Sstevel@tonic-gate ufs_si_io_done(struct buf *bp)
12277c478bd9Sstevel@tonic-gate {
12287c478bd9Sstevel@tonic-gate sema_v(&bp->b_io);
12297c478bd9Sstevel@tonic-gate return (0);
12307c478bd9Sstevel@tonic-gate }
12317c478bd9Sstevel@tonic-gate
12327c478bd9Sstevel@tonic-gate #define SI_BUFSZ roundup(sizeof (struct cg), DEV_BSIZE)
12337c478bd9Sstevel@tonic-gate #define NSIBUF 32
12347c478bd9Sstevel@tonic-gate
12357c478bd9Sstevel@tonic-gate /*
12367c478bd9Sstevel@tonic-gate * ufs_construct_si()
12377c478bd9Sstevel@tonic-gate * Read each cylinder group in turn and construct the summary information
12387c478bd9Sstevel@tonic-gate */
12397c478bd9Sstevel@tonic-gate static int
ufs_construct_si(dev_t dev,struct fs * fs,struct ufsvfs * ufsvfsp)12407c478bd9Sstevel@tonic-gate ufs_construct_si(dev_t dev, struct fs *fs, struct ufsvfs *ufsvfsp)
12417c478bd9Sstevel@tonic-gate {
12427c478bd9Sstevel@tonic-gate buf_t *bps, *bp;
12437c478bd9Sstevel@tonic-gate char *bufs;
12447c478bd9Sstevel@tonic-gate struct csum *sip = fs->fs_u.fs_csp;
12457c478bd9Sstevel@tonic-gate struct cg *cgp;
12467c478bd9Sstevel@tonic-gate int i, ncg;
12477c478bd9Sstevel@tonic-gate int error = 0, cg = 0;
12487c478bd9Sstevel@tonic-gate
12497c478bd9Sstevel@tonic-gate bps = kmem_alloc(NSIBUF * sizeof (buf_t), KM_SLEEP);
12507c478bd9Sstevel@tonic-gate bufs = kmem_alloc(NSIBUF * SI_BUFSZ, KM_SLEEP);
12517c478bd9Sstevel@tonic-gate
12527c478bd9Sstevel@tonic-gate /*
12537c478bd9Sstevel@tonic-gate * Initialise the buffer headers
12547c478bd9Sstevel@tonic-gate */
12557c478bd9Sstevel@tonic-gate for (bp = bps, i = 0; i < NSIBUF; i++, bp++) {
12567c478bd9Sstevel@tonic-gate bioinit(bp);
12577c478bd9Sstevel@tonic-gate bp->b_iodone = ufs_si_io_done;
12587c478bd9Sstevel@tonic-gate bp->b_bufsize = bp->b_bcount = SI_BUFSZ;
12597c478bd9Sstevel@tonic-gate bp->b_flags = B_READ;
12607c478bd9Sstevel@tonic-gate bp->b_un.b_addr = bufs + (i * SI_BUFSZ);
12617c478bd9Sstevel@tonic-gate bp->b_edev = dev;
12627c478bd9Sstevel@tonic-gate }
12637c478bd9Sstevel@tonic-gate
12647c478bd9Sstevel@tonic-gate /*
12657c478bd9Sstevel@tonic-gate * Repeat while there are cylinder groups left to read.
12667c478bd9Sstevel@tonic-gate */
12677c478bd9Sstevel@tonic-gate do {
12687c478bd9Sstevel@tonic-gate /*
12697c478bd9Sstevel@tonic-gate * Issue upto NSIBUF asynchronous reads
12707c478bd9Sstevel@tonic-gate */
12717c478bd9Sstevel@tonic-gate ncg = MIN(NSIBUF, (fs->fs_ncg - cg));
12727c478bd9Sstevel@tonic-gate for (bp = bps, i = 0; i < ncg; i++, bp++) {
12737c478bd9Sstevel@tonic-gate bp->b_blkno = (daddr_t)fsbtodb(fs, cgtod(fs, cg + i));
12747c478bd9Sstevel@tonic-gate if (ufsvfsp->vfs_log) {
12757c478bd9Sstevel@tonic-gate lufs_read_strategy(ufsvfsp->vfs_log, bp);
12767c478bd9Sstevel@tonic-gate } else {
12777c478bd9Sstevel@tonic-gate (void) bdev_strategy(bp);
12787c478bd9Sstevel@tonic-gate }
12797c478bd9Sstevel@tonic-gate }
12807c478bd9Sstevel@tonic-gate
12817c478bd9Sstevel@tonic-gate /*
12827c478bd9Sstevel@tonic-gate * wait for each read to finish;
12837c478bd9Sstevel@tonic-gate * check for errors and copy the csum info
12847c478bd9Sstevel@tonic-gate */
12857c478bd9Sstevel@tonic-gate for (bp = bps, i = 0; i < ncg; i++, bp++) {
12867c478bd9Sstevel@tonic-gate sema_p(&bp->b_io);
12877c478bd9Sstevel@tonic-gate if (!error) {
12887c478bd9Sstevel@tonic-gate cgp = bp->b_un.b_cg;
12897c478bd9Sstevel@tonic-gate sip[cg + i] = cgp->cg_cs;
12907c478bd9Sstevel@tonic-gate error = geterror(bp);
12917c478bd9Sstevel@tonic-gate }
12927c478bd9Sstevel@tonic-gate }
12937c478bd9Sstevel@tonic-gate if (error) {
12947c478bd9Sstevel@tonic-gate goto err;
12957c478bd9Sstevel@tonic-gate }
12967c478bd9Sstevel@tonic-gate cg += ncg;
12977c478bd9Sstevel@tonic-gate } while (cg < fs->fs_ncg);
12987c478bd9Sstevel@tonic-gate
12997c478bd9Sstevel@tonic-gate err:
13007c478bd9Sstevel@tonic-gate kmem_free(bps, NSIBUF * sizeof (buf_t));
13017c478bd9Sstevel@tonic-gate kmem_free(bufs, NSIBUF * SI_BUFSZ);
13027c478bd9Sstevel@tonic-gate return (error);
13037c478bd9Sstevel@tonic-gate }
13047c478bd9Sstevel@tonic-gate
13057c478bd9Sstevel@tonic-gate /*
13067c478bd9Sstevel@tonic-gate * ufs_getsummaryinfo
13077c478bd9Sstevel@tonic-gate */
13087c478bd9Sstevel@tonic-gate int
ufs_getsummaryinfo(dev_t dev,struct ufsvfs * ufsvfsp,struct fs * fs)13097c478bd9Sstevel@tonic-gate ufs_getsummaryinfo(dev_t dev, struct ufsvfs *ufsvfsp, struct fs *fs)
13107c478bd9Sstevel@tonic-gate {
13117c478bd9Sstevel@tonic-gate int i; /* `for' loop counter */
13127c478bd9Sstevel@tonic-gate ssize_t size; /* bytes of summary info to read */
13137c478bd9Sstevel@tonic-gate daddr_t frags; /* frags of summary info to read */
13147c478bd9Sstevel@tonic-gate caddr_t sip; /* summary info */
13157c478bd9Sstevel@tonic-gate struct buf *tp; /* tmp buf */
13167c478bd9Sstevel@tonic-gate
13177c478bd9Sstevel@tonic-gate /*
13187c478bd9Sstevel@tonic-gate * maintain metadata map for trans device (debug only)
13197c478bd9Sstevel@tonic-gate */
13207c478bd9Sstevel@tonic-gate TRANS_MATA_SI(ufsvfsp, fs);
13217c478bd9Sstevel@tonic-gate
13227c478bd9Sstevel@tonic-gate /*
13237c478bd9Sstevel@tonic-gate * Compute #frags and allocate space for summary info
13247c478bd9Sstevel@tonic-gate */
13257c478bd9Sstevel@tonic-gate frags = howmany(fs->fs_cssize, fs->fs_fsize);
13267c478bd9Sstevel@tonic-gate sip = kmem_alloc((size_t)fs->fs_cssize, KM_SLEEP);
13277c478bd9Sstevel@tonic-gate fs->fs_u.fs_csp = (struct csum *)sip;
13287c478bd9Sstevel@tonic-gate
13297c478bd9Sstevel@tonic-gate if (fs->fs_si == FS_SI_BAD) {
13307c478bd9Sstevel@tonic-gate /*
13317c478bd9Sstevel@tonic-gate * The summary information is unknown, read it in from
13327c478bd9Sstevel@tonic-gate * the cylinder groups.
13337c478bd9Sstevel@tonic-gate */
13347c478bd9Sstevel@tonic-gate if (TRANS_ISTRANS(ufsvfsp) && !TRANS_ISERROR(ufsvfsp) &&
13357c478bd9Sstevel@tonic-gate ufsvfsp->vfs_log->un_logmap) {
13367c478bd9Sstevel@tonic-gate logmap_roll_dev(ufsvfsp->vfs_log); /* flush the log */
13377c478bd9Sstevel@tonic-gate }
13387c478bd9Sstevel@tonic-gate bzero(sip, (size_t)fs->fs_cssize);
13397c478bd9Sstevel@tonic-gate if (ufs_construct_si(dev, fs, ufsvfsp)) {
13407c478bd9Sstevel@tonic-gate kmem_free(fs->fs_u.fs_csp, fs->fs_cssize);
13417c478bd9Sstevel@tonic-gate fs->fs_u.fs_csp = NULL;
13427c478bd9Sstevel@tonic-gate return (EIO);
13437c478bd9Sstevel@tonic-gate }
13447c478bd9Sstevel@tonic-gate } else {
13457c478bd9Sstevel@tonic-gate /* Read summary info a fs block at a time */
13467c478bd9Sstevel@tonic-gate size = fs->fs_bsize;
13477c478bd9Sstevel@tonic-gate for (i = 0; i < frags; i += fs->fs_frag) {
13487c478bd9Sstevel@tonic-gate if (i + fs->fs_frag > frags)
13497c478bd9Sstevel@tonic-gate /*
13507c478bd9Sstevel@tonic-gate * This happens only the last iteration, so
13517c478bd9Sstevel@tonic-gate * don't worry about size being reset
13527c478bd9Sstevel@tonic-gate */
13537c478bd9Sstevel@tonic-gate size = (frags - i) * fs->fs_fsize;
13547c478bd9Sstevel@tonic-gate tp = UFS_BREAD(ufsvfsp, dev,
13557c478bd9Sstevel@tonic-gate (daddr_t)fsbtodb(fs, fs->fs_csaddr+i), size);
13567c478bd9Sstevel@tonic-gate tp->b_flags |= B_STALE | B_AGE;
13577c478bd9Sstevel@tonic-gate if (tp->b_flags & B_ERROR) {
13587c478bd9Sstevel@tonic-gate kmem_free(fs->fs_u.fs_csp, fs->fs_cssize);
13597c478bd9Sstevel@tonic-gate fs->fs_u.fs_csp = NULL;
13607c478bd9Sstevel@tonic-gate brelse(tp);
13617c478bd9Sstevel@tonic-gate return (EIO);
13627c478bd9Sstevel@tonic-gate }
13637c478bd9Sstevel@tonic-gate bcopy(tp->b_un.b_addr, sip, size);
13647c478bd9Sstevel@tonic-gate sip += size;
13657c478bd9Sstevel@tonic-gate brelse(tp);
13667c478bd9Sstevel@tonic-gate }
13677c478bd9Sstevel@tonic-gate }
13687c478bd9Sstevel@tonic-gate bzero((caddr_t)&fs->fs_cstotal, sizeof (fs->fs_cstotal));
13697c478bd9Sstevel@tonic-gate for (i = 0; i < fs->fs_ncg; ++i) {
13707c478bd9Sstevel@tonic-gate fs->fs_cstotal.cs_ndir += fs->fs_cs(fs, i).cs_ndir;
13717c478bd9Sstevel@tonic-gate fs->fs_cstotal.cs_nbfree += fs->fs_cs(fs, i).cs_nbfree;
13727c478bd9Sstevel@tonic-gate fs->fs_cstotal.cs_nifree += fs->fs_cs(fs, i).cs_nifree;
13737c478bd9Sstevel@tonic-gate fs->fs_cstotal.cs_nffree += fs->fs_cs(fs, i).cs_nffree;
13747c478bd9Sstevel@tonic-gate }
13757c478bd9Sstevel@tonic-gate return (0);
13767c478bd9Sstevel@tonic-gate }
13777c478bd9Sstevel@tonic-gate
13787c478bd9Sstevel@tonic-gate /*
13797c478bd9Sstevel@tonic-gate * ufs_putsummaryinfo() stores all the cylinder group summary information
13807c478bd9Sstevel@tonic-gate * This is only used when logging, but the file system may not
13817c478bd9Sstevel@tonic-gate * be logging at the time, eg a read-only mount to flush the log
13827c478bd9Sstevel@tonic-gate * may push the summary info out.
13837c478bd9Sstevel@tonic-gate */
13847c478bd9Sstevel@tonic-gate int
ufs_putsummaryinfo(dev_t dev,struct ufsvfs * ufsvfsp,struct fs * fs)13857c478bd9Sstevel@tonic-gate ufs_putsummaryinfo(dev_t dev, struct ufsvfs *ufsvfsp, struct fs *fs)
13867c478bd9Sstevel@tonic-gate {
13877c478bd9Sstevel@tonic-gate struct buf b, *bp; /* tmp buf */
13887c478bd9Sstevel@tonic-gate caddr_t sip; /* summary info */
13897c478bd9Sstevel@tonic-gate ssize_t size; /* bytes of summary info to write */
13907c478bd9Sstevel@tonic-gate daddr_t frags; /* frags of summary info to write */
13917c478bd9Sstevel@tonic-gate int i; /* `for' loop counter */
13927c478bd9Sstevel@tonic-gate int error; /* error */
13937c478bd9Sstevel@tonic-gate
13947c478bd9Sstevel@tonic-gate if (TRANS_ISERROR(ufsvfsp)) {
13957c478bd9Sstevel@tonic-gate return (EIO);
13967c478bd9Sstevel@tonic-gate }
13977c478bd9Sstevel@tonic-gate
13987c478bd9Sstevel@tonic-gate if ((fs->fs_si != FS_SI_BAD) || !ufsvfsp->vfs_nolog_si) {
13997c478bd9Sstevel@tonic-gate return (0);
14007c478bd9Sstevel@tonic-gate }
14017c478bd9Sstevel@tonic-gate
14027c478bd9Sstevel@tonic-gate bp = &b;
14037c478bd9Sstevel@tonic-gate bioinit(bp);
14047c478bd9Sstevel@tonic-gate bp->b_iodone = ufs_si_io_done;
14057c478bd9Sstevel@tonic-gate bp->b_bufsize = size = fs->fs_bsize;
14067c478bd9Sstevel@tonic-gate bp->b_flags = B_WRITE;
14077c478bd9Sstevel@tonic-gate bp->b_un.b_addr = kmem_alloc(size, KM_SLEEP);
14087c478bd9Sstevel@tonic-gate bp->b_edev = dev;
14097c478bd9Sstevel@tonic-gate frags = howmany(fs->fs_cssize, fs->fs_fsize);
14107c478bd9Sstevel@tonic-gate sip = (caddr_t)fs->fs_u.fs_csp;
14117c478bd9Sstevel@tonic-gate
14127c478bd9Sstevel@tonic-gate /* Write summary info one fs block at a time */
14137c478bd9Sstevel@tonic-gate for (error = 0, i = 0; (i < frags) && (error == 0); i += fs->fs_frag) {
14147c478bd9Sstevel@tonic-gate if (i + fs->fs_frag > frags) {
14157c478bd9Sstevel@tonic-gate /*
14167c478bd9Sstevel@tonic-gate * This happens only the last iteration, so
14177c478bd9Sstevel@tonic-gate * don't worry about size being reset
14187c478bd9Sstevel@tonic-gate */
14197c478bd9Sstevel@tonic-gate size = (frags - i) * fs->fs_fsize;
14207c478bd9Sstevel@tonic-gate }
14217c478bd9Sstevel@tonic-gate bcopy(sip, bp->b_un.b_addr, size);
14227c478bd9Sstevel@tonic-gate bp->b_blkno = (daddr_t)fsbtodb(fs, fs->fs_csaddr+i);
14237c478bd9Sstevel@tonic-gate bp->b_bcount = size;
14247c478bd9Sstevel@tonic-gate (void) bdev_strategy(bp);
14257c478bd9Sstevel@tonic-gate sema_p(&bp->b_io); /* wait for write to complete */
14267c478bd9Sstevel@tonic-gate error = geterror(bp);
14277c478bd9Sstevel@tonic-gate sip += size;
14287c478bd9Sstevel@tonic-gate }
14297c478bd9Sstevel@tonic-gate kmem_free(bp->b_un.b_addr, fs->fs_bsize);
14307c478bd9Sstevel@tonic-gate if (!error) {
14317c478bd9Sstevel@tonic-gate fs->fs_si = FS_SI_OK;
14327c478bd9Sstevel@tonic-gate }
14337c478bd9Sstevel@tonic-gate return (error);
14347c478bd9Sstevel@tonic-gate }
14357c478bd9Sstevel@tonic-gate
14367c478bd9Sstevel@tonic-gate /*
14377c478bd9Sstevel@tonic-gate * Decide whether it is okay to remove within a sticky directory.
14387c478bd9Sstevel@tonic-gate * Two conditions need to be met: write access to the directory
14397c478bd9Sstevel@tonic-gate * is needed. In sticky directories, write access is not sufficient;
14407c478bd9Sstevel@tonic-gate * you can remove entries from a directory only if you own the directory,
14417c478bd9Sstevel@tonic-gate * if you are privileged, if you own the entry or if the entry is
14427c478bd9Sstevel@tonic-gate * a plain file and you have write access to that file.
14437c478bd9Sstevel@tonic-gate * Function returns 0 if remove access is granted.
144460c8e821SFrank Batschulat * Note, the caller is responsible for holding the i_contents lock
144560c8e821SFrank Batschulat * at least as reader on the inquired inode 'ip'.
14467c478bd9Sstevel@tonic-gate */
14477c478bd9Sstevel@tonic-gate int
ufs_sticky_remove_access(struct inode * dp,struct inode * ip,struct cred * cr)14487c478bd9Sstevel@tonic-gate ufs_sticky_remove_access(struct inode *dp, struct inode *ip, struct cred *cr)
14497c478bd9Sstevel@tonic-gate {
14507c478bd9Sstevel@tonic-gate uid_t uid;
145160c8e821SFrank Batschulat
145260c8e821SFrank Batschulat ASSERT(RW_LOCK_HELD(&ip->i_contents));
145360c8e821SFrank Batschulat
14547c478bd9Sstevel@tonic-gate if ((dp->i_mode & ISVTX) &&
14557c478bd9Sstevel@tonic-gate (uid = crgetuid(cr)) != dp->i_uid &&
14567c478bd9Sstevel@tonic-gate uid != ip->i_uid &&
14577c478bd9Sstevel@tonic-gate ((ip->i_mode & IFMT) != IFREG ||
145860c8e821SFrank Batschulat ufs_iaccess(ip, IWRITE, cr, 0) != 0))
14597c478bd9Sstevel@tonic-gate return (secpolicy_vnode_remove(cr));
14607c478bd9Sstevel@tonic-gate
14617c478bd9Sstevel@tonic-gate return (0);
14627c478bd9Sstevel@tonic-gate }
14637c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
14647c478bd9Sstevel@tonic-gate
14657c478bd9Sstevel@tonic-gate extern int around[9];
14667c478bd9Sstevel@tonic-gate extern int inside[9];
14677c478bd9Sstevel@tonic-gate extern uchar_t *fragtbl[];
14687c478bd9Sstevel@tonic-gate
14697c478bd9Sstevel@tonic-gate /*
14707c478bd9Sstevel@tonic-gate * Update the frsum fields to reflect addition or deletion
14717c478bd9Sstevel@tonic-gate * of some frags.
14727c478bd9Sstevel@tonic-gate */
14737c478bd9Sstevel@tonic-gate void
fragacct(struct fs * fs,int fragmap,int32_t * fraglist,int cnt)14747c478bd9Sstevel@tonic-gate fragacct(struct fs *fs, int fragmap, int32_t *fraglist, int cnt)
14757c478bd9Sstevel@tonic-gate {
14767c478bd9Sstevel@tonic-gate int inblk;
14777c478bd9Sstevel@tonic-gate int field, subfield;
14787c478bd9Sstevel@tonic-gate int siz, pos;
14797c478bd9Sstevel@tonic-gate
14807c478bd9Sstevel@tonic-gate /*
14817c478bd9Sstevel@tonic-gate * ufsvfsp->vfs_lock is held when calling this.
14827c478bd9Sstevel@tonic-gate */
14837c478bd9Sstevel@tonic-gate inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
14847c478bd9Sstevel@tonic-gate fragmap <<= 1;
14857c478bd9Sstevel@tonic-gate for (siz = 1; siz < fs->fs_frag; siz++) {
14867c478bd9Sstevel@tonic-gate if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
14877c478bd9Sstevel@tonic-gate continue;
14887c478bd9Sstevel@tonic-gate field = around[siz];
14897c478bd9Sstevel@tonic-gate subfield = inside[siz];
14907c478bd9Sstevel@tonic-gate for (pos = siz; pos <= fs->fs_frag; pos++) {
14917c478bd9Sstevel@tonic-gate if ((fragmap & field) == subfield) {
14927c478bd9Sstevel@tonic-gate fraglist[siz] += cnt;
14937c478bd9Sstevel@tonic-gate ASSERT(fraglist[siz] >= 0);
14947c478bd9Sstevel@tonic-gate pos += siz;
14957c478bd9Sstevel@tonic-gate field <<= siz;
14967c478bd9Sstevel@tonic-gate subfield <<= siz;
14977c478bd9Sstevel@tonic-gate }
14987c478bd9Sstevel@tonic-gate field <<= 1;
14997c478bd9Sstevel@tonic-gate subfield <<= 1;
15007c478bd9Sstevel@tonic-gate }
15017c478bd9Sstevel@tonic-gate }
15027c478bd9Sstevel@tonic-gate }
15037c478bd9Sstevel@tonic-gate
15047c478bd9Sstevel@tonic-gate /*
15057c478bd9Sstevel@tonic-gate * Block operations
15067c478bd9Sstevel@tonic-gate */
15077c478bd9Sstevel@tonic-gate
15087c478bd9Sstevel@tonic-gate /*
15097c478bd9Sstevel@tonic-gate * Check if a block is available
15107c478bd9Sstevel@tonic-gate */
15117c478bd9Sstevel@tonic-gate int
isblock(struct fs * fs,uchar_t * cp,daddr_t h)15127c478bd9Sstevel@tonic-gate isblock(struct fs *fs, uchar_t *cp, daddr_t h)
15137c478bd9Sstevel@tonic-gate {
15147c478bd9Sstevel@tonic-gate uchar_t mask;
15157c478bd9Sstevel@tonic-gate
15167c478bd9Sstevel@tonic-gate ASSERT(fs->fs_frag == 8 || fs->fs_frag == 4 || fs->fs_frag == 2 || \
15177c478bd9Sstevel@tonic-gate fs->fs_frag == 1);
15187c478bd9Sstevel@tonic-gate /*
15197c478bd9Sstevel@tonic-gate * ufsvfsp->vfs_lock is held when calling this.
15207c478bd9Sstevel@tonic-gate */
15217c478bd9Sstevel@tonic-gate switch ((int)fs->fs_frag) {
15227c478bd9Sstevel@tonic-gate case 8:
15237c478bd9Sstevel@tonic-gate return (cp[h] == 0xff);
15247c478bd9Sstevel@tonic-gate case 4:
15257c478bd9Sstevel@tonic-gate mask = 0x0f << ((h & 0x1) << 2);
15267c478bd9Sstevel@tonic-gate return ((cp[h >> 1] & mask) == mask);
15277c478bd9Sstevel@tonic-gate case 2:
15287c478bd9Sstevel@tonic-gate mask = 0x03 << ((h & 0x3) << 1);
15297c478bd9Sstevel@tonic-gate return ((cp[h >> 2] & mask) == mask);
15307c478bd9Sstevel@tonic-gate case 1:
15317c478bd9Sstevel@tonic-gate mask = 0x01 << (h & 0x7);
15327c478bd9Sstevel@tonic-gate return ((cp[h >> 3] & mask) == mask);
15337c478bd9Sstevel@tonic-gate default:
15347c478bd9Sstevel@tonic-gate #ifndef _KERNEL
15357c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "isblock: illegal fs->fs_frag value (%d)",
15367c478bd9Sstevel@tonic-gate fs->fs_frag);
15377c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
15387c478bd9Sstevel@tonic-gate return (0);
15397c478bd9Sstevel@tonic-gate }
15407c478bd9Sstevel@tonic-gate }
15417c478bd9Sstevel@tonic-gate
15427c478bd9Sstevel@tonic-gate /*
15437c478bd9Sstevel@tonic-gate * Take a block out of the map
15447c478bd9Sstevel@tonic-gate */
15457c478bd9Sstevel@tonic-gate void
clrblock(struct fs * fs,uchar_t * cp,daddr_t h)15467c478bd9Sstevel@tonic-gate clrblock(struct fs *fs, uchar_t *cp, daddr_t h)
15477c478bd9Sstevel@tonic-gate {
15487c478bd9Sstevel@tonic-gate ASSERT(fs->fs_frag == 8 || fs->fs_frag == 4 || fs->fs_frag == 2 || \
15497c478bd9Sstevel@tonic-gate fs->fs_frag == 1);
15507c478bd9Sstevel@tonic-gate /*
15517c478bd9Sstevel@tonic-gate * ufsvfsp->vfs_lock is held when calling this.
15527c478bd9Sstevel@tonic-gate */
15537c478bd9Sstevel@tonic-gate switch ((int)fs->fs_frag) {
15547c478bd9Sstevel@tonic-gate case 8:
15557c478bd9Sstevel@tonic-gate cp[h] = 0;
15567c478bd9Sstevel@tonic-gate return;
15577c478bd9Sstevel@tonic-gate case 4:
15587c478bd9Sstevel@tonic-gate cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
15597c478bd9Sstevel@tonic-gate return;
15607c478bd9Sstevel@tonic-gate case 2:
15617c478bd9Sstevel@tonic-gate cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
15627c478bd9Sstevel@tonic-gate return;
15637c478bd9Sstevel@tonic-gate case 1:
15647c478bd9Sstevel@tonic-gate cp[h >> 3] &= ~(0x01 << (h & 0x7));
15657c478bd9Sstevel@tonic-gate return;
15667c478bd9Sstevel@tonic-gate default:
15677c478bd9Sstevel@tonic-gate #ifndef _KERNEL
15687c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "clrblock: illegal fs->fs_frag value (%d)",
15697c478bd9Sstevel@tonic-gate fs->fs_frag);
15707c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
15717c478bd9Sstevel@tonic-gate return;
15727c478bd9Sstevel@tonic-gate }
15737c478bd9Sstevel@tonic-gate }
15747c478bd9Sstevel@tonic-gate
15757c478bd9Sstevel@tonic-gate /*
15767c478bd9Sstevel@tonic-gate * Is block allocated?
15777c478bd9Sstevel@tonic-gate */
15787c478bd9Sstevel@tonic-gate int
isclrblock(struct fs * fs,uchar_t * cp,daddr_t h)15797c478bd9Sstevel@tonic-gate isclrblock(struct fs *fs, uchar_t *cp, daddr_t h)
15807c478bd9Sstevel@tonic-gate {
15817c478bd9Sstevel@tonic-gate uchar_t mask;
15827c478bd9Sstevel@tonic-gate int frag;
15837c478bd9Sstevel@tonic-gate /*
15847c478bd9Sstevel@tonic-gate * ufsvfsp->vfs_lock is held when calling this.
15857c478bd9Sstevel@tonic-gate */
15867c478bd9Sstevel@tonic-gate frag = fs->fs_frag;
15877c478bd9Sstevel@tonic-gate ASSERT(frag == 8 || frag == 4 || frag == 2 || frag == 1);
15887c478bd9Sstevel@tonic-gate switch (frag) {
15897c478bd9Sstevel@tonic-gate case 8:
15907c478bd9Sstevel@tonic-gate return (cp[h] == 0);
15917c478bd9Sstevel@tonic-gate case 4:
15927c478bd9Sstevel@tonic-gate mask = ~(0x0f << ((h & 0x1) << 2));
15937c478bd9Sstevel@tonic-gate return (cp[h >> 1] == (cp[h >> 1] & mask));
15947c478bd9Sstevel@tonic-gate case 2:
15957c478bd9Sstevel@tonic-gate mask = ~(0x03 << ((h & 0x3) << 1));
15967c478bd9Sstevel@tonic-gate return (cp[h >> 2] == (cp[h >> 2] & mask));
15977c478bd9Sstevel@tonic-gate case 1:
15987c478bd9Sstevel@tonic-gate mask = ~(0x01 << (h & 0x7));
15997c478bd9Sstevel@tonic-gate return (cp[h >> 3] == (cp[h >> 3] & mask));
16007c478bd9Sstevel@tonic-gate default:
16017c478bd9Sstevel@tonic-gate #ifndef _KERNEL
16027c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "isclrblock: illegal fs->fs_frag value (%d)",
16037c478bd9Sstevel@tonic-gate fs->fs_frag);
16047c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
16057c478bd9Sstevel@tonic-gate break;
16067c478bd9Sstevel@tonic-gate }
16077c478bd9Sstevel@tonic-gate return (0);
16087c478bd9Sstevel@tonic-gate }
16097c478bd9Sstevel@tonic-gate
16107c478bd9Sstevel@tonic-gate /*
16117c478bd9Sstevel@tonic-gate * Put a block into the map
16127c478bd9Sstevel@tonic-gate */
16137c478bd9Sstevel@tonic-gate void
setblock(struct fs * fs,uchar_t * cp,daddr_t h)16147c478bd9Sstevel@tonic-gate setblock(struct fs *fs, uchar_t *cp, daddr_t h)
16157c478bd9Sstevel@tonic-gate {
16167c478bd9Sstevel@tonic-gate ASSERT(fs->fs_frag == 8 || fs->fs_frag == 4 || fs->fs_frag == 2 || \
16177c478bd9Sstevel@tonic-gate fs->fs_frag == 1);
16187c478bd9Sstevel@tonic-gate /*
16197c478bd9Sstevel@tonic-gate * ufsvfsp->vfs_lock is held when calling this.
16207c478bd9Sstevel@tonic-gate */
16217c478bd9Sstevel@tonic-gate switch ((int)fs->fs_frag) {
16227c478bd9Sstevel@tonic-gate case 8:
16237c478bd9Sstevel@tonic-gate cp[h] = 0xff;
16247c478bd9Sstevel@tonic-gate return;
16257c478bd9Sstevel@tonic-gate case 4:
16267c478bd9Sstevel@tonic-gate cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
16277c478bd9Sstevel@tonic-gate return;
16287c478bd9Sstevel@tonic-gate case 2:
16297c478bd9Sstevel@tonic-gate cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
16307c478bd9Sstevel@tonic-gate return;
16317c478bd9Sstevel@tonic-gate case 1:
16327c478bd9Sstevel@tonic-gate cp[h >> 3] |= (0x01 << (h & 0x7));
16337c478bd9Sstevel@tonic-gate return;
16347c478bd9Sstevel@tonic-gate default:
16357c478bd9Sstevel@tonic-gate #ifndef _KERNEL
16367c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "setblock: illegal fs->fs_frag value (%d)",
16377c478bd9Sstevel@tonic-gate fs->fs_frag);
16387c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
16397c478bd9Sstevel@tonic-gate return;
16407c478bd9Sstevel@tonic-gate }
16417c478bd9Sstevel@tonic-gate }
16427c478bd9Sstevel@tonic-gate
16437c478bd9Sstevel@tonic-gate int
skpc(char c,uint_t len,char * cp)16447c478bd9Sstevel@tonic-gate skpc(char c, uint_t len, char *cp)
16457c478bd9Sstevel@tonic-gate {
16467c478bd9Sstevel@tonic-gate if (len == 0)
16477c478bd9Sstevel@tonic-gate return (0);
16487c478bd9Sstevel@tonic-gate while (*cp++ == c && --len)
16497c478bd9Sstevel@tonic-gate ;
16507c478bd9Sstevel@tonic-gate return (len);
16517c478bd9Sstevel@tonic-gate }
1652