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 /* 22d3d50737SRafael 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 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 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 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 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 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) && 427d3d50737SRafael 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 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 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 */ 605*49a11936SRichard Lowe 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 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 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 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 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 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 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 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 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 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 { 1106d3d50737SRafael 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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