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 /* 221e13ea4bSvsakar * Copyright 2008 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 * Portions of this source code were derived from Berkeley 4.3 BSD 317c478bd9Sstevel@tonic-gate * under license from the Regents of the University of California. 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 357c478bd9Sstevel@tonic-gate #include <sys/param.h> 367c478bd9Sstevel@tonic-gate #include <sys/types.h> 377c478bd9Sstevel@tonic-gate #include <sys/systm.h> 387c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 397c478bd9Sstevel@tonic-gate #include <sys/uio.h> 407c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 417c478bd9Sstevel@tonic-gate #include <sys/thread.h> 427c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 437c478bd9Sstevel@tonic-gate #include <sys/errno.h> 447c478bd9Sstevel@tonic-gate #include <sys/buf.h> 457c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 467c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_trans.h> 477c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h> 487c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h> 497c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fsdir.h> 507c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_quota.h> 517c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_panic.h> 527c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_bio.h> 537c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_log.h> 547c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 557c478bd9Sstevel@tonic-gate #include <sys/file.h> 567c478bd9Sstevel@tonic-gate #include <sys/debug.h> 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate extern kmutex_t ufsvfs_mutex; 607c478bd9Sstevel@tonic-gate extern struct ufsvfs *ufs_instances; 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate /* 637c478bd9Sstevel@tonic-gate * hlock any file systems w/errored logs 647c478bd9Sstevel@tonic-gate */ 657c478bd9Sstevel@tonic-gate int 667c478bd9Sstevel@tonic-gate ufs_trans_hlock() 677c478bd9Sstevel@tonic-gate { 687c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp; 697c478bd9Sstevel@tonic-gate struct lockfs lockfs; 707c478bd9Sstevel@tonic-gate int error; 717c478bd9Sstevel@tonic-gate int retry = 0; 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate /* 747c478bd9Sstevel@tonic-gate * find fs's that paniced or have errored logging devices 757c478bd9Sstevel@tonic-gate */ 767c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfs_mutex); 777c478bd9Sstevel@tonic-gate for (ufsvfsp = ufs_instances; ufsvfsp; ufsvfsp = ufsvfsp->vfs_next) { 787c478bd9Sstevel@tonic-gate /* 797c478bd9Sstevel@tonic-gate * not mounted; continue 807c478bd9Sstevel@tonic-gate */ 817c478bd9Sstevel@tonic-gate if ((ufsvfsp->vfs_vfs == NULL) || 827c478bd9Sstevel@tonic-gate (ufsvfsp->vfs_validfs == UT_UNMOUNTED)) 837c478bd9Sstevel@tonic-gate continue; 847c478bd9Sstevel@tonic-gate /* 857c478bd9Sstevel@tonic-gate * disallow unmounts (hlock occurs below) 867c478bd9Sstevel@tonic-gate */ 877c478bd9Sstevel@tonic-gate if (TRANS_ISERROR(ufsvfsp)) 887c478bd9Sstevel@tonic-gate ufsvfsp->vfs_validfs = UT_HLOCKING; 897c478bd9Sstevel@tonic-gate } 907c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfs_mutex); 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* 937c478bd9Sstevel@tonic-gate * hlock the fs's that paniced or have errored logging devices 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate again: 967c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfs_mutex); 977c478bd9Sstevel@tonic-gate for (ufsvfsp = ufs_instances; ufsvfsp; ufsvfsp = ufsvfsp->vfs_next) 987c478bd9Sstevel@tonic-gate if (ufsvfsp->vfs_validfs == UT_HLOCKING) 997c478bd9Sstevel@tonic-gate break; 1007c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfs_mutex); 1017c478bd9Sstevel@tonic-gate if (ufsvfsp == NULL) 1027c478bd9Sstevel@tonic-gate return (retry); 1037c478bd9Sstevel@tonic-gate /* 1047c478bd9Sstevel@tonic-gate * hlock the file system 1057c478bd9Sstevel@tonic-gate */ 1067c478bd9Sstevel@tonic-gate (void) ufs_fiolfss(ufsvfsp->vfs_root, &lockfs); 1077c478bd9Sstevel@tonic-gate if (!LOCKFS_IS_ELOCK(&lockfs)) { 1087c478bd9Sstevel@tonic-gate lockfs.lf_lock = LOCKFS_HLOCK; 1097c478bd9Sstevel@tonic-gate lockfs.lf_flags = 0; 1107c478bd9Sstevel@tonic-gate lockfs.lf_comlen = 0; 1117c478bd9Sstevel@tonic-gate lockfs.lf_comment = NULL; 1127c478bd9Sstevel@tonic-gate error = ufs_fiolfs(ufsvfsp->vfs_root, &lockfs, 0); 1137c478bd9Sstevel@tonic-gate /* 1147c478bd9Sstevel@tonic-gate * retry after awhile; another app currently doing lockfs 1157c478bd9Sstevel@tonic-gate */ 1167c478bd9Sstevel@tonic-gate if (error == EBUSY || error == EINVAL) 1177c478bd9Sstevel@tonic-gate retry = 1; 1187c478bd9Sstevel@tonic-gate } else { 1197c478bd9Sstevel@tonic-gate if (ufsfx_get_failure_qlen() > 0) { 1207c478bd9Sstevel@tonic-gate if (mutex_tryenter(&ufs_fix.uq_mutex)) { 1217c478bd9Sstevel@tonic-gate ufs_fix.uq_lowat = ufs_fix.uq_ne; 1227c478bd9Sstevel@tonic-gate cv_broadcast(&ufs_fix.uq_cv); 1237c478bd9Sstevel@tonic-gate mutex_exit(&ufs_fix.uq_mutex); 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate } 1267c478bd9Sstevel@tonic-gate retry = 1; 1277c478bd9Sstevel@tonic-gate } 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate /* 1307c478bd9Sstevel@tonic-gate * allow unmounts 1317c478bd9Sstevel@tonic-gate */ 1327c478bd9Sstevel@tonic-gate ufsvfsp->vfs_validfs = UT_MOUNTED; 1337c478bd9Sstevel@tonic-gate goto again; 1347c478bd9Sstevel@tonic-gate } 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1377c478bd9Sstevel@tonic-gate void 1387c478bd9Sstevel@tonic-gate ufs_trans_onerror() 1397c478bd9Sstevel@tonic-gate { 1407c478bd9Sstevel@tonic-gate mutex_enter(&ufs_hlock.uq_mutex); 1417c478bd9Sstevel@tonic-gate ufs_hlock.uq_ne = ufs_hlock.uq_lowat; 1427c478bd9Sstevel@tonic-gate cv_broadcast(&ufs_hlock.uq_cv); 1437c478bd9Sstevel@tonic-gate mutex_exit(&ufs_hlock.uq_mutex); 1447c478bd9Sstevel@tonic-gate } 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate void 1477c478bd9Sstevel@tonic-gate ufs_trans_sbupdate(struct ufsvfs *ufsvfsp, struct vfs *vfsp, top_t topid) 1487c478bd9Sstevel@tonic-gate { 1497c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_DONTBLOCK) { 1507c478bd9Sstevel@tonic-gate sbupdate(vfsp); 1517c478bd9Sstevel@tonic-gate return; 1527c478bd9Sstevel@tonic-gate } else { 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate if (panicstr && TRANS_ISTRANS(ufsvfsp)) 1557c478bd9Sstevel@tonic-gate return; 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate curthread->t_flag |= T_DONTBLOCK; 1587c478bd9Sstevel@tonic-gate TRANS_BEGIN_ASYNC(ufsvfsp, topid, TOP_SBUPDATE_SIZE); 1597c478bd9Sstevel@tonic-gate sbupdate(vfsp); 1607c478bd9Sstevel@tonic-gate TRANS_END_ASYNC(ufsvfsp, topid, TOP_SBUPDATE_SIZE); 1617c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_DONTBLOCK; 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate void 1667c478bd9Sstevel@tonic-gate ufs_trans_iupdat(struct inode *ip, int waitfor) 1677c478bd9Sstevel@tonic-gate { 1687c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp; 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_DONTBLOCK) { 1717c478bd9Sstevel@tonic-gate rw_enter(&ip->i_contents, RW_READER); 1727c478bd9Sstevel@tonic-gate ufs_iupdat(ip, waitfor); 1737c478bd9Sstevel@tonic-gate rw_exit(&ip->i_contents); 1747c478bd9Sstevel@tonic-gate return; 1757c478bd9Sstevel@tonic-gate } else { 1767c478bd9Sstevel@tonic-gate ufsvfsp = ip->i_ufsvfs; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate if (panicstr && TRANS_ISTRANS(ufsvfsp)) 1797c478bd9Sstevel@tonic-gate return; 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate curthread->t_flag |= T_DONTBLOCK; 1827c478bd9Sstevel@tonic-gate TRANS_BEGIN_ASYNC(ufsvfsp, TOP_IUPDAT, TOP_IUPDAT_SIZE(ip)); 1837c478bd9Sstevel@tonic-gate rw_enter(&ip->i_contents, RW_READER); 1847c478bd9Sstevel@tonic-gate ufs_iupdat(ip, waitfor); 1857c478bd9Sstevel@tonic-gate rw_exit(&ip->i_contents); 1867c478bd9Sstevel@tonic-gate TRANS_END_ASYNC(ufsvfsp, TOP_IUPDAT, TOP_IUPDAT_SIZE(ip)); 1877c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_DONTBLOCK; 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate void 1927c478bd9Sstevel@tonic-gate ufs_trans_sbwrite(struct ufsvfs *ufsvfsp, top_t topid) 1937c478bd9Sstevel@tonic-gate { 1947c478bd9Sstevel@tonic-gate if (curthread->t_flag & T_DONTBLOCK) { 1957c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfsp->vfs_lock); 1967c478bd9Sstevel@tonic-gate ufs_sbwrite(ufsvfsp); 1977c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfsp->vfs_lock); 1987c478bd9Sstevel@tonic-gate return; 1997c478bd9Sstevel@tonic-gate } else { 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate if (panicstr && TRANS_ISTRANS(ufsvfsp)) 2027c478bd9Sstevel@tonic-gate return; 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate curthread->t_flag |= T_DONTBLOCK; 2057c478bd9Sstevel@tonic-gate TRANS_BEGIN_ASYNC(ufsvfsp, topid, TOP_SBWRITE_SIZE); 2067c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfsp->vfs_lock); 2077c478bd9Sstevel@tonic-gate ufs_sbwrite(ufsvfsp); 2087c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfsp->vfs_lock); 2097c478bd9Sstevel@tonic-gate TRANS_END_ASYNC(ufsvfsp, topid, TOP_SBWRITE_SIZE); 2107c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_DONTBLOCK; 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2157c478bd9Sstevel@tonic-gate int 2167c478bd9Sstevel@tonic-gate ufs_trans_push_si(ufsvfs_t *ufsvfsp, delta_t dtyp, int ignore) 2177c478bd9Sstevel@tonic-gate { 2187c478bd9Sstevel@tonic-gate struct fs *fs; 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate fs = ufsvfsp->vfs_fs; 2217c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfsp->vfs_lock); 2227c478bd9Sstevel@tonic-gate TRANS_LOG(ufsvfsp, (char *)fs->fs_u.fs_csp, 2237c478bd9Sstevel@tonic-gate ldbtob(fsbtodb(fs, fs->fs_csaddr)), fs->fs_cssize, 2247c478bd9Sstevel@tonic-gate (caddr_t)fs->fs_u.fs_csp, fs->fs_cssize); 2257c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfsp->vfs_lock); 2267c478bd9Sstevel@tonic-gate return (0); 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2307c478bd9Sstevel@tonic-gate int 2317c478bd9Sstevel@tonic-gate ufs_trans_push_buf(ufsvfs_t *ufsvfsp, delta_t dtyp, daddr_t bno) 2327c478bd9Sstevel@tonic-gate { 2337c478bd9Sstevel@tonic-gate struct buf *bp; 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate bp = (struct buf *)UFS_GETBLK(ufsvfsp, ufsvfsp->vfs_dev, bno, 1); 2367c478bd9Sstevel@tonic-gate if (bp == NULL) 2377c478bd9Sstevel@tonic-gate return (ENOENT); 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate if (bp->b_flags & B_DELWRI) { 2407c478bd9Sstevel@tonic-gate /* 2417c478bd9Sstevel@tonic-gate * Do not use brwrite() here since the buffer is already 2427c478bd9Sstevel@tonic-gate * marked for retry or not by the code that called 2437c478bd9Sstevel@tonic-gate * TRANS_BUF(). 2447c478bd9Sstevel@tonic-gate */ 2457c478bd9Sstevel@tonic-gate UFS_BWRITE(ufsvfsp, bp); 2467c478bd9Sstevel@tonic-gate return (0); 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate /* 2497c478bd9Sstevel@tonic-gate * If we did not find the real buf for this block above then 2507c478bd9Sstevel@tonic-gate * clear the dev so the buf won't be found by mistake 2517c478bd9Sstevel@tonic-gate * for this block later. We had to allocate at least a 1 byte 2527c478bd9Sstevel@tonic-gate * buffer to keep brelse happy. 2537c478bd9Sstevel@tonic-gate */ 2547c478bd9Sstevel@tonic-gate if (bp->b_bufsize == 1) { 2557c478bd9Sstevel@tonic-gate bp->b_dev = (o_dev_t)NODEV; 2567c478bd9Sstevel@tonic-gate bp->b_edev = NODEV; 2577c478bd9Sstevel@tonic-gate bp->b_flags = 0; 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate brelse(bp); 2607c478bd9Sstevel@tonic-gate return (ENOENT); 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2647c478bd9Sstevel@tonic-gate int 2657c478bd9Sstevel@tonic-gate ufs_trans_push_inode(ufsvfs_t *ufsvfsp, delta_t dtyp, ino_t ino) 2667c478bd9Sstevel@tonic-gate { 2677c478bd9Sstevel@tonic-gate int error; 2687c478bd9Sstevel@tonic-gate struct inode *ip; 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate /* 2717c478bd9Sstevel@tonic-gate * Grab the quota lock (if the file system has not been forcibly 2727c478bd9Sstevel@tonic-gate * unmounted). 2737c478bd9Sstevel@tonic-gate */ 2747c478bd9Sstevel@tonic-gate if (ufsvfsp) 2757c478bd9Sstevel@tonic-gate rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER); 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate error = ufs_iget(ufsvfsp->vfs_vfs, ino, &ip, kcred); 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate if (ufsvfsp) 2807c478bd9Sstevel@tonic-gate rw_exit(&ufsvfsp->vfs_dqrwlock); 2817c478bd9Sstevel@tonic-gate if (error) 2827c478bd9Sstevel@tonic-gate return (ENOENT); 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate if (ip->i_flag & (IUPD|IACC|ICHG|IMOD|IMODACC|IATTCHG)) { 2857c478bd9Sstevel@tonic-gate rw_enter(&ip->i_contents, RW_READER); 2867c478bd9Sstevel@tonic-gate ufs_iupdat(ip, 1); 2877c478bd9Sstevel@tonic-gate rw_exit(&ip->i_contents); 2887c478bd9Sstevel@tonic-gate VN_RELE(ITOV(ip)); 2897c478bd9Sstevel@tonic-gate return (0); 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate VN_RELE(ITOV(ip)); 2927c478bd9Sstevel@tonic-gate return (ENOENT); 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate #ifdef DEBUG 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * These routines maintain the metadata map (matamap) 2987c478bd9Sstevel@tonic-gate */ 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate /* 3017c478bd9Sstevel@tonic-gate * update the metadata map at mount 3027c478bd9Sstevel@tonic-gate */ 3037c478bd9Sstevel@tonic-gate static int 3047c478bd9Sstevel@tonic-gate ufs_trans_mata_mount_scan(struct inode *ip, void *arg) 3057c478bd9Sstevel@tonic-gate { 3067c478bd9Sstevel@tonic-gate /* 3077c478bd9Sstevel@tonic-gate * wrong file system; keep looking 3087c478bd9Sstevel@tonic-gate */ 3097c478bd9Sstevel@tonic-gate if (ip->i_ufsvfs != (struct ufsvfs *)arg) 3107c478bd9Sstevel@tonic-gate return (0); 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate /* 3137c478bd9Sstevel@tonic-gate * load the metadata map 3147c478bd9Sstevel@tonic-gate */ 3157c478bd9Sstevel@tonic-gate rw_enter(&ip->i_contents, RW_WRITER); 3167c478bd9Sstevel@tonic-gate ufs_trans_mata_iget(ip); 3177c478bd9Sstevel@tonic-gate rw_exit(&ip->i_contents); 3187c478bd9Sstevel@tonic-gate return (0); 3197c478bd9Sstevel@tonic-gate } 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate void 3227c478bd9Sstevel@tonic-gate ufs_trans_mata_mount(struct ufsvfs *ufsvfsp) 3237c478bd9Sstevel@tonic-gate { 3247c478bd9Sstevel@tonic-gate struct fs *fs = ufsvfsp->vfs_fs; 3257c478bd9Sstevel@tonic-gate ino_t ino; 3267c478bd9Sstevel@tonic-gate int i; 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate /* 3297c478bd9Sstevel@tonic-gate * put static metadata into matamap 3307c478bd9Sstevel@tonic-gate * superblock 3317c478bd9Sstevel@tonic-gate * cylinder groups 3327c478bd9Sstevel@tonic-gate * inode groups 3337c478bd9Sstevel@tonic-gate * existing inodes 3347c478bd9Sstevel@tonic-gate */ 3357c478bd9Sstevel@tonic-gate TRANS_MATAADD(ufsvfsp, ldbtob(SBLOCK), fs->fs_sbsize); 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate for (ino = i = 0; i < fs->fs_ncg; ++i, ino += fs->fs_ipg) { 3387c478bd9Sstevel@tonic-gate TRANS_MATAADD(ufsvfsp, 3397c478bd9Sstevel@tonic-gate ldbtob(fsbtodb(fs, cgtod(fs, i))), fs->fs_cgsize); 3407c478bd9Sstevel@tonic-gate TRANS_MATAADD(ufsvfsp, 3417c478bd9Sstevel@tonic-gate ldbtob(fsbtodb(fs, itod(fs, ino))), 3427c478bd9Sstevel@tonic-gate fs->fs_ipg * sizeof (struct dinode)); 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate (void) ufs_scan_inodes(0, ufs_trans_mata_mount_scan, ufsvfsp, ufsvfsp); 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate /* 3487c478bd9Sstevel@tonic-gate * clear the metadata map at umount 3497c478bd9Sstevel@tonic-gate */ 3507c478bd9Sstevel@tonic-gate void 3517c478bd9Sstevel@tonic-gate ufs_trans_mata_umount(struct ufsvfs *ufsvfsp) 3527c478bd9Sstevel@tonic-gate { 3537c478bd9Sstevel@tonic-gate top_mataclr(ufsvfsp); 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate /* 3577c478bd9Sstevel@tonic-gate * summary info (may be extended during growfs test) 3587c478bd9Sstevel@tonic-gate */ 3597c478bd9Sstevel@tonic-gate void 3607c478bd9Sstevel@tonic-gate ufs_trans_mata_si(struct ufsvfs *ufsvfsp, struct fs *fs) 3617c478bd9Sstevel@tonic-gate { 3627c478bd9Sstevel@tonic-gate TRANS_MATAADD(ufsvfsp, ldbtob(fsbtodb(fs, fs->fs_csaddr)), 3637c478bd9Sstevel@tonic-gate fs->fs_cssize); 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate /* 3677c478bd9Sstevel@tonic-gate * scan an allocation block (either inode or true block) 3687c478bd9Sstevel@tonic-gate */ 3697c478bd9Sstevel@tonic-gate static void 3707c478bd9Sstevel@tonic-gate ufs_trans_mata_direct( 3717c478bd9Sstevel@tonic-gate struct inode *ip, 3727c478bd9Sstevel@tonic-gate daddr_t *fragsp, 3737c478bd9Sstevel@tonic-gate daddr32_t *blkp, 3747c478bd9Sstevel@tonic-gate unsigned int nblk) 3757c478bd9Sstevel@tonic-gate { 3767c478bd9Sstevel@tonic-gate int i; 3777c478bd9Sstevel@tonic-gate daddr_t frag; 3787c478bd9Sstevel@tonic-gate ulong_t nb; 3797c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = ip->i_ufsvfs; 3807c478bd9Sstevel@tonic-gate struct fs *fs = ufsvfsp->vfs_fs; 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate for (i = 0; i < nblk && *fragsp; ++i, ++blkp) 3837c478bd9Sstevel@tonic-gate if ((frag = *blkp) != 0) { 3847c478bd9Sstevel@tonic-gate if (*fragsp > fs->fs_frag) { 3857c478bd9Sstevel@tonic-gate nb = fs->fs_bsize; 3867c478bd9Sstevel@tonic-gate *fragsp -= fs->fs_frag; 3877c478bd9Sstevel@tonic-gate } else { 3887c478bd9Sstevel@tonic-gate nb = *fragsp * fs->fs_fsize; 3897c478bd9Sstevel@tonic-gate *fragsp = 0; 3907c478bd9Sstevel@tonic-gate } 3917c478bd9Sstevel@tonic-gate TRANS_MATAADD(ufsvfsp, ldbtob(fsbtodb(fs, frag)), nb); 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate /* 3967c478bd9Sstevel@tonic-gate * scan an indirect allocation block (either inode or true block) 3977c478bd9Sstevel@tonic-gate */ 3987c478bd9Sstevel@tonic-gate static void 3997c478bd9Sstevel@tonic-gate ufs_trans_mata_indir( 4007c478bd9Sstevel@tonic-gate struct inode *ip, 4017c478bd9Sstevel@tonic-gate daddr_t *fragsp, 4027c478bd9Sstevel@tonic-gate daddr_t frag, 4037c478bd9Sstevel@tonic-gate int level) 4047c478bd9Sstevel@tonic-gate { 4057c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = ip->i_ufsvfs; 4067c478bd9Sstevel@tonic-gate struct fs *fs = ufsvfsp->vfs_fs; 4077c478bd9Sstevel@tonic-gate int ne = fs->fs_bsize / (int)sizeof (daddr32_t); 4087c478bd9Sstevel@tonic-gate int i; 4097c478bd9Sstevel@tonic-gate struct buf *bp; 4107c478bd9Sstevel@tonic-gate daddr32_t *blkp; 4117c478bd9Sstevel@tonic-gate o_mode_t ifmt = ip->i_mode & IFMT; 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate bp = UFS_BREAD(ufsvfsp, ip->i_dev, fsbtodb(fs, frag), fs->fs_bsize); 4147c478bd9Sstevel@tonic-gate if (bp->b_flags & B_ERROR) { 4157c478bd9Sstevel@tonic-gate brelse(bp); 4167c478bd9Sstevel@tonic-gate return; 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate blkp = bp->b_un.b_daddr; 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate if (level || (ifmt == IFDIR) || (ifmt == IFSHAD) || 4217c478bd9Sstevel@tonic-gate (ifmt == IFATTRDIR) || (ip == ip->i_ufsvfs->vfs_qinod)) 4227c478bd9Sstevel@tonic-gate ufs_trans_mata_direct(ip, fragsp, blkp, ne); 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate if (level) 4257c478bd9Sstevel@tonic-gate for (i = 0; i < ne && *fragsp; ++i, ++blkp) 4267c478bd9Sstevel@tonic-gate ufs_trans_mata_indir(ip, fragsp, *blkp, level-1); 4277c478bd9Sstevel@tonic-gate brelse(bp); 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate /* 4317c478bd9Sstevel@tonic-gate * put appropriate metadata into matamap for this inode 4327c478bd9Sstevel@tonic-gate */ 4337c478bd9Sstevel@tonic-gate void 4347c478bd9Sstevel@tonic-gate ufs_trans_mata_iget(struct inode *ip) 4357c478bd9Sstevel@tonic-gate { 4367c478bd9Sstevel@tonic-gate int i; 4377c478bd9Sstevel@tonic-gate daddr_t frags = dbtofsb(ip->i_fs, ip->i_blocks); 4387c478bd9Sstevel@tonic-gate o_mode_t ifmt = ip->i_mode & IFMT; 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate if (frags && ((ifmt == IFDIR) || (ifmt == IFSHAD) || 4417c478bd9Sstevel@tonic-gate (ifmt == IFATTRDIR) || (ip == ip->i_ufsvfs->vfs_qinod))) 4427c478bd9Sstevel@tonic-gate ufs_trans_mata_direct(ip, &frags, &ip->i_db[0], NDADDR); 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate if (frags) 4457c478bd9Sstevel@tonic-gate ufs_trans_mata_direct(ip, &frags, &ip->i_ib[0], NIADDR); 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate for (i = 0; i < NIADDR && frags; ++i) 4487c478bd9Sstevel@tonic-gate if (ip->i_ib[i]) 4497c478bd9Sstevel@tonic-gate ufs_trans_mata_indir(ip, &frags, ip->i_ib[i], i); 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate /* 4537c478bd9Sstevel@tonic-gate * freeing possible metadata (block of user data) 4547c478bd9Sstevel@tonic-gate */ 4557c478bd9Sstevel@tonic-gate void 4567c478bd9Sstevel@tonic-gate ufs_trans_mata_free(struct ufsvfs *ufsvfsp, offset_t mof, off_t nb) 4577c478bd9Sstevel@tonic-gate { 4587c478bd9Sstevel@tonic-gate top_matadel(ufsvfsp, mof, nb); 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate /* 4637c478bd9Sstevel@tonic-gate * allocating metadata 4647c478bd9Sstevel@tonic-gate */ 4657c478bd9Sstevel@tonic-gate void 4667c478bd9Sstevel@tonic-gate ufs_trans_mata_alloc( 4677c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp, 4687c478bd9Sstevel@tonic-gate struct inode *ip, 4697c478bd9Sstevel@tonic-gate daddr_t frag, 4707c478bd9Sstevel@tonic-gate ulong_t nb, 4717c478bd9Sstevel@tonic-gate int indir) 4727c478bd9Sstevel@tonic-gate { 4737c478bd9Sstevel@tonic-gate struct fs *fs = ufsvfsp->vfs_fs; 4747c478bd9Sstevel@tonic-gate o_mode_t ifmt = ip->i_mode & IFMT; 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate if (indir || ((ifmt == IFDIR) || (ifmt == IFSHAD) || 4777c478bd9Sstevel@tonic-gate (ifmt == IFATTRDIR) || (ip == ip->i_ufsvfs->vfs_qinod))) 4787c478bd9Sstevel@tonic-gate TRANS_MATAADD(ufsvfsp, ldbtob(fsbtodb(fs, frag)), nb); 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate /* 4847c478bd9Sstevel@tonic-gate * ufs_trans_dir is used to declare a directory delta 4857c478bd9Sstevel@tonic-gate */ 4867c478bd9Sstevel@tonic-gate int 4877c478bd9Sstevel@tonic-gate ufs_trans_dir(struct inode *ip, off_t offset) 4887c478bd9Sstevel@tonic-gate { 4897c478bd9Sstevel@tonic-gate daddr_t bn; 4907c478bd9Sstevel@tonic-gate int contig = 0, error; 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate ASSERT(ip); 4937c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&ip->i_contents)); 4947c478bd9Sstevel@tonic-gate error = bmap_read(ip, (u_offset_t)offset, &bn, &contig); 4957c478bd9Sstevel@tonic-gate if (error || (bn == UFS_HOLE)) { 4967c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "ufs_trans_dir - could not get block" 4977c478bd9Sstevel@tonic-gate " number error = %d bn = %d\n", error, (int)bn); 4987c478bd9Sstevel@tonic-gate if (error == 0) /* treat UFS_HOLE as an I/O error */ 4997c478bd9Sstevel@tonic-gate error = EIO; 5007c478bd9Sstevel@tonic-gate return (error); 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate TRANS_DELTA(ip->i_ufsvfs, ldbtob(bn), DIRBLKSIZ, DT_DIR, 0, 0); 5037c478bd9Sstevel@tonic-gate return (error); 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5077c478bd9Sstevel@tonic-gate int 5087c478bd9Sstevel@tonic-gate ufs_trans_push_quota(ufsvfs_t *ufsvfsp, delta_t dtyp, struct dquot *dqp) 5097c478bd9Sstevel@tonic-gate { 5107c478bd9Sstevel@tonic-gate /* 5117c478bd9Sstevel@tonic-gate * Lock the quota subsystem (ufsvfsp can be NULL 5127c478bd9Sstevel@tonic-gate * if the DQ_ERROR is set). 5137c478bd9Sstevel@tonic-gate */ 5147c478bd9Sstevel@tonic-gate if (ufsvfsp) 5157c478bd9Sstevel@tonic-gate rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER); 5167c478bd9Sstevel@tonic-gate mutex_enter(&dqp->dq_lock); 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate /* 5197c478bd9Sstevel@tonic-gate * If this transaction has been cancelled by closedq_scan_inode(), 5207c478bd9Sstevel@tonic-gate * then bail out now. We don't call dqput() in this case because 5217c478bd9Sstevel@tonic-gate * it has already been done. 5227c478bd9Sstevel@tonic-gate */ 5237c478bd9Sstevel@tonic-gate if ((dqp->dq_flags & DQ_TRANS) == 0) { 5247c478bd9Sstevel@tonic-gate mutex_exit(&dqp->dq_lock); 5257c478bd9Sstevel@tonic-gate if (ufsvfsp) 5267c478bd9Sstevel@tonic-gate rw_exit(&ufsvfsp->vfs_dqrwlock); 5277c478bd9Sstevel@tonic-gate return (0); 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate if (dqp->dq_flags & DQ_ERROR) { 5317c478bd9Sstevel@tonic-gate /* 5327c478bd9Sstevel@tonic-gate * Paranoia to make sure that there is at least one 5337c478bd9Sstevel@tonic-gate * reference to the dquot struct. We are done with 5347c478bd9Sstevel@tonic-gate * the dquot (due to an error) so clear logging 5357c478bd9Sstevel@tonic-gate * specific markers. 5367c478bd9Sstevel@tonic-gate */ 5377c478bd9Sstevel@tonic-gate ASSERT(dqp->dq_cnt >= 1); 5387c478bd9Sstevel@tonic-gate dqp->dq_flags &= ~DQ_TRANS; 5397c478bd9Sstevel@tonic-gate dqput(dqp); 5407c478bd9Sstevel@tonic-gate mutex_exit(&dqp->dq_lock); 5417c478bd9Sstevel@tonic-gate if (ufsvfsp) 5427c478bd9Sstevel@tonic-gate rw_exit(&ufsvfsp->vfs_dqrwlock); 5437c478bd9Sstevel@tonic-gate return (1); 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate if (dqp->dq_flags & (DQ_MOD | DQ_BLKS | DQ_FILES)) { 5477c478bd9Sstevel@tonic-gate ASSERT((dqp->dq_mof != UFS_HOLE) && (dqp->dq_mof != 0)); 5487c478bd9Sstevel@tonic-gate TRANS_LOG(ufsvfsp, (caddr_t)&dqp->dq_dqb, 5497c478bd9Sstevel@tonic-gate dqp->dq_mof, (int)sizeof (struct dqblk), NULL, 0); 5507c478bd9Sstevel@tonic-gate /* 5517c478bd9Sstevel@tonic-gate * Paranoia to make sure that there is at least one 5527c478bd9Sstevel@tonic-gate * reference to the dquot struct. Clear the 5537c478bd9Sstevel@tonic-gate * modification flag because the operation is now in 5547c478bd9Sstevel@tonic-gate * the log. Also clear the logging specific markers 5557c478bd9Sstevel@tonic-gate * that were set in ufs_trans_quota(). 5567c478bd9Sstevel@tonic-gate */ 5577c478bd9Sstevel@tonic-gate ASSERT(dqp->dq_cnt >= 1); 5587c478bd9Sstevel@tonic-gate dqp->dq_flags &= ~(DQ_MOD | DQ_TRANS); 5597c478bd9Sstevel@tonic-gate dqput(dqp); 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate /* 5637c478bd9Sstevel@tonic-gate * At this point, the logging specific flag should be clear, 5647c478bd9Sstevel@tonic-gate * but add paranoia just in case something has gone wrong. 5657c478bd9Sstevel@tonic-gate */ 5667c478bd9Sstevel@tonic-gate ASSERT((dqp->dq_flags & DQ_TRANS) == 0); 5677c478bd9Sstevel@tonic-gate mutex_exit(&dqp->dq_lock); 5687c478bd9Sstevel@tonic-gate if (ufsvfsp) 5697c478bd9Sstevel@tonic-gate rw_exit(&ufsvfsp->vfs_dqrwlock); 5707c478bd9Sstevel@tonic-gate return (0); 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate /* 5747c478bd9Sstevel@tonic-gate * ufs_trans_quota take in a uid, allocates the disk space, placing the 5757c478bd9Sstevel@tonic-gate * quota record into the metamap, then declares the delta. 5767c478bd9Sstevel@tonic-gate */ 5777c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5787c478bd9Sstevel@tonic-gate void 5797c478bd9Sstevel@tonic-gate ufs_trans_quota(struct dquot *dqp) 5807c478bd9Sstevel@tonic-gate { 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate struct inode *qip = dqp->dq_ufsvfsp->vfs_qinod; 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate ASSERT(qip); 5857c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dqp->dq_lock)); 5867c478bd9Sstevel@tonic-gate ASSERT(dqp->dq_flags & DQ_MOD); 5877c478bd9Sstevel@tonic-gate ASSERT(dqp->dq_mof != 0); 5887c478bd9Sstevel@tonic-gate ASSERT(dqp->dq_mof != UFS_HOLE); 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate /* 5917c478bd9Sstevel@tonic-gate * Mark this dquot to indicate that we are starting a logging 5927c478bd9Sstevel@tonic-gate * file system operation for this dquot. Also increment the 5937c478bd9Sstevel@tonic-gate * reference count so that the dquot does not get reused while 5947c478bd9Sstevel@tonic-gate * it is on the mapentry_t list. DQ_TRANS is cleared and the 5957c478bd9Sstevel@tonic-gate * reference count is decremented by ufs_trans_push_quota. 5967c478bd9Sstevel@tonic-gate * 5977c478bd9Sstevel@tonic-gate * If the file system is force-unmounted while there is a 5987c478bd9Sstevel@tonic-gate * pending quota transaction, then closedq_scan_inode() will 5997c478bd9Sstevel@tonic-gate * clear the DQ_TRANS flag and decrement the reference count. 6007c478bd9Sstevel@tonic-gate * 6017c478bd9Sstevel@tonic-gate * Since deltamap_add() drops multiple transactions to the 6027c478bd9Sstevel@tonic-gate * same dq_mof and ufs_trans_push_quota() won't get called, 6037c478bd9Sstevel@tonic-gate * we use DQ_TRANS to prevent repeat transactions from 6047c478bd9Sstevel@tonic-gate * incrementing the reference count (or calling TRANS_DELTA()). 6057c478bd9Sstevel@tonic-gate */ 6067c478bd9Sstevel@tonic-gate if ((dqp->dq_flags & DQ_TRANS) == 0) { 6077c478bd9Sstevel@tonic-gate dqp->dq_flags |= DQ_TRANS; 6087c478bd9Sstevel@tonic-gate dqp->dq_cnt++; 6097c478bd9Sstevel@tonic-gate TRANS_DELTA(qip->i_ufsvfs, dqp->dq_mof, sizeof (struct dqblk), 6107c478bd9Sstevel@tonic-gate DT_QR, ufs_trans_push_quota, (ulong_t)dqp); 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate void 6157c478bd9Sstevel@tonic-gate ufs_trans_dqrele(struct dquot *dqp) 6167c478bd9Sstevel@tonic-gate { 6177c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = dqp->dq_ufsvfsp; 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate curthread->t_flag |= T_DONTBLOCK; 6207c478bd9Sstevel@tonic-gate TRANS_BEGIN_ASYNC(ufsvfsp, TOP_QUOTA, TOP_QUOTA_SIZE); 6217c478bd9Sstevel@tonic-gate rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER); 6227c478bd9Sstevel@tonic-gate dqrele(dqp); 6237c478bd9Sstevel@tonic-gate rw_exit(&ufsvfsp->vfs_dqrwlock); 6247c478bd9Sstevel@tonic-gate TRANS_END_ASYNC(ufsvfsp, TOP_QUOTA, TOP_QUOTA_SIZE); 6257c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_DONTBLOCK; 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate int ufs_trans_max_resv = TOP_MAX_RESV; /* will be adjusted for testing */ 6297c478bd9Sstevel@tonic-gate long ufs_trans_avgbfree = 0; /* will be adjusted for testing */ 6307c478bd9Sstevel@tonic-gate #define TRANS_MAX_WRITE (1024 * 1024) 6317c478bd9Sstevel@tonic-gate size_t ufs_trans_max_resid = TRANS_MAX_WRITE; 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate /* 6347c478bd9Sstevel@tonic-gate * Calculate the log reservation for the given write or truncate 6357c478bd9Sstevel@tonic-gate */ 6367c478bd9Sstevel@tonic-gate static ulong_t 6377c478bd9Sstevel@tonic-gate ufs_log_amt(struct inode *ip, offset_t offset, ssize_t resid, int trunc) 6387c478bd9Sstevel@tonic-gate { 6397c478bd9Sstevel@tonic-gate long ncg, last2blk; 6407c478bd9Sstevel@tonic-gate long niblk = 0; 6417c478bd9Sstevel@tonic-gate u_offset_t writeend, offblk; 6427c478bd9Sstevel@tonic-gate int resv; 6437c478bd9Sstevel@tonic-gate daddr_t nblk, maxfblk; 6447c478bd9Sstevel@tonic-gate long avgbfree; 6457c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = ip->i_ufsvfs; 6467c478bd9Sstevel@tonic-gate struct fs *fs = ufsvfsp->vfs_fs; 6477c478bd9Sstevel@tonic-gate long fni = NINDIR(fs); 6487c478bd9Sstevel@tonic-gate int bsize = fs->fs_bsize; 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate /* 6517c478bd9Sstevel@tonic-gate * Assume that the request will fit in 1 or 2 cg's, 6527c478bd9Sstevel@tonic-gate * resv is the amount of log space to reserve (in bytes). 6537c478bd9Sstevel@tonic-gate */ 6547c478bd9Sstevel@tonic-gate resv = SIZECG(ip) * 2 + INODESIZE + 1024; 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate /* 6577c478bd9Sstevel@tonic-gate * get max position of write in fs blocks 6587c478bd9Sstevel@tonic-gate */ 6597c478bd9Sstevel@tonic-gate writeend = offset + resid; 6607c478bd9Sstevel@tonic-gate maxfblk = lblkno(fs, writeend); 6617c478bd9Sstevel@tonic-gate offblk = lblkno(fs, offset); 6627c478bd9Sstevel@tonic-gate /* 6637c478bd9Sstevel@tonic-gate * request size in fs blocks 6647c478bd9Sstevel@tonic-gate */ 6657c478bd9Sstevel@tonic-gate nblk = lblkno(fs, blkroundup(fs, resid)); 6667c478bd9Sstevel@tonic-gate /* 6677c478bd9Sstevel@tonic-gate * Adjust for sparse files 6687c478bd9Sstevel@tonic-gate */ 6697c478bd9Sstevel@tonic-gate if (trunc) 6707c478bd9Sstevel@tonic-gate nblk = MIN(nblk, ip->i_blocks); 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate /* 6737c478bd9Sstevel@tonic-gate * Adjust avgbfree (for testing) 6747c478bd9Sstevel@tonic-gate */ 6757c478bd9Sstevel@tonic-gate avgbfree = (ufs_trans_avgbfree) ? 1 : ufsvfsp->vfs_avgbfree + 1; 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate /* 6787c478bd9Sstevel@tonic-gate * Calculate maximum number of blocks of triple indirect 6797c478bd9Sstevel@tonic-gate * pointers to write. 6807c478bd9Sstevel@tonic-gate */ 6817c478bd9Sstevel@tonic-gate last2blk = NDADDR + fni + fni * fni; 6827c478bd9Sstevel@tonic-gate if (maxfblk > last2blk) { 6837c478bd9Sstevel@tonic-gate long nl2ptr; 6847c478bd9Sstevel@tonic-gate long n3blk; 6857c478bd9Sstevel@tonic-gate 6867c478bd9Sstevel@tonic-gate if (offblk > last2blk) 6877c478bd9Sstevel@tonic-gate n3blk = maxfblk - offblk; 6887c478bd9Sstevel@tonic-gate else 6897c478bd9Sstevel@tonic-gate n3blk = maxfblk - last2blk; 6907c478bd9Sstevel@tonic-gate niblk += roundup(n3blk * sizeof (daddr_t), bsize) / bsize + 1; 6917c478bd9Sstevel@tonic-gate nl2ptr = roundup(niblk, fni) / fni + 1; 6927c478bd9Sstevel@tonic-gate niblk += roundup(nl2ptr * sizeof (daddr_t), bsize) / bsize + 2; 6937c478bd9Sstevel@tonic-gate maxfblk -= n3blk; 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate /* 6967c478bd9Sstevel@tonic-gate * calculate maximum number of blocks of double indirect 6977c478bd9Sstevel@tonic-gate * pointers to write. 6987c478bd9Sstevel@tonic-gate */ 6997c478bd9Sstevel@tonic-gate if (maxfblk > NDADDR + fni) { 7007c478bd9Sstevel@tonic-gate long n2blk; 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate if (offblk > NDADDR + fni) 7037c478bd9Sstevel@tonic-gate n2blk = maxfblk - offblk; 7047c478bd9Sstevel@tonic-gate else 7057c478bd9Sstevel@tonic-gate n2blk = maxfblk - NDADDR + fni; 7067c478bd9Sstevel@tonic-gate niblk += roundup(n2blk * sizeof (daddr_t), bsize) / bsize + 2; 7077c478bd9Sstevel@tonic-gate maxfblk -= n2blk; 7087c478bd9Sstevel@tonic-gate } 7097c478bd9Sstevel@tonic-gate /* 7107c478bd9Sstevel@tonic-gate * Add in indirect pointer block write 7117c478bd9Sstevel@tonic-gate */ 7127c478bd9Sstevel@tonic-gate if (maxfblk > NDADDR) { 7137c478bd9Sstevel@tonic-gate niblk += 1; 7147c478bd9Sstevel@tonic-gate } 7157c478bd9Sstevel@tonic-gate /* 7167c478bd9Sstevel@tonic-gate * Calculate deltas for indirect pointer writes 7177c478bd9Sstevel@tonic-gate */ 7187c478bd9Sstevel@tonic-gate resv += niblk * (fs->fs_bsize + sizeof (struct delta)); 7197c478bd9Sstevel@tonic-gate /* 7207c478bd9Sstevel@tonic-gate * maximum number of cg's needed for request 7217c478bd9Sstevel@tonic-gate */ 7227c478bd9Sstevel@tonic-gate ncg = nblk / avgbfree; 7237c478bd9Sstevel@tonic-gate if (ncg > fs->fs_ncg) 7247c478bd9Sstevel@tonic-gate ncg = fs->fs_ncg; 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate /* 7277c478bd9Sstevel@tonic-gate * maximum amount of log space needed for request 7287c478bd9Sstevel@tonic-gate */ 7297c478bd9Sstevel@tonic-gate if (ncg > 2) 7307c478bd9Sstevel@tonic-gate resv += (ncg - 2) * SIZECG(ip); 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate return (resv); 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate /* 7367c478bd9Sstevel@tonic-gate * Calculate the amount of log space that needs to be reserved for this 7377c478bd9Sstevel@tonic-gate * trunc request. If the amount of log space is too large, then 7387c478bd9Sstevel@tonic-gate * calculate the the size that the requests needs to be split into. 7397c478bd9Sstevel@tonic-gate */ 740303bf60bSsdebnath void 7417c478bd9Sstevel@tonic-gate ufs_trans_trunc_resv( 7427c478bd9Sstevel@tonic-gate struct inode *ip, 7437c478bd9Sstevel@tonic-gate u_offset_t length, 7447c478bd9Sstevel@tonic-gate int *resvp, 7457c478bd9Sstevel@tonic-gate u_offset_t *residp) 7467c478bd9Sstevel@tonic-gate { 7477c478bd9Sstevel@tonic-gate ulong_t resv; 7487c478bd9Sstevel@tonic-gate u_offset_t size, offset, resid; 749*8388e56eSViswanathan Kannappan int nchunks, flag; 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate /* 7527c478bd9Sstevel@tonic-gate * *resvp is the amount of log space to reserve (in bytes). 7537c478bd9Sstevel@tonic-gate * when nonzero, *residp is the number of bytes to truncate. 7547c478bd9Sstevel@tonic-gate */ 7557c478bd9Sstevel@tonic-gate *residp = 0; 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate if (length < ip->i_size) { 7587c478bd9Sstevel@tonic-gate size = ip->i_size - length; 7597c478bd9Sstevel@tonic-gate } else { 7607c478bd9Sstevel@tonic-gate resv = SIZECG(ip) * 2 + INODESIZE + 1024; 7617c478bd9Sstevel@tonic-gate /* 7627c478bd9Sstevel@tonic-gate * truncate up, doesn't really use much space, 7637c478bd9Sstevel@tonic-gate * the default above should be sufficient. 7647c478bd9Sstevel@tonic-gate */ 7657c478bd9Sstevel@tonic-gate goto done; 7667c478bd9Sstevel@tonic-gate } 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate offset = length; 7697c478bd9Sstevel@tonic-gate resid = size; 7707c478bd9Sstevel@tonic-gate nchunks = 1; 771*8388e56eSViswanathan Kannappan flag = 0; 7721e13ea4bSvsakar 7737c478bd9Sstevel@tonic-gate /* 774*8388e56eSViswanathan Kannappan * If this request takes too much log space, it will be split into 775*8388e56eSViswanathan Kannappan * "nchunks". If this split is not enough, linearly increment the 776*8388e56eSViswanathan Kannappan * nchunks in the next iteration. 7777c478bd9Sstevel@tonic-gate */ 778*8388e56eSViswanathan Kannappan for (; (resv = ufs_log_amt(ip, offset, resid, 1)) > ufs_trans_max_resv; 779*8388e56eSViswanathan Kannappan offset = length + (nchunks - 1) * resid) { 780*8388e56eSViswanathan Kannappan if (!flag) { 781*8388e56eSViswanathan Kannappan nchunks = roundup(resv, ufs_trans_max_resv) / 782*8388e56eSViswanathan Kannappan ufs_trans_max_resv; 783*8388e56eSViswanathan Kannappan flag = 1; 7841e13ea4bSvsakar } else { 785*8388e56eSViswanathan Kannappan nchunks++; 7861e13ea4bSvsakar } 7871e13ea4bSvsakar resid = size / nchunks; 788*8388e56eSViswanathan Kannappan } 7891e13ea4bSvsakar 7907c478bd9Sstevel@tonic-gate if (nchunks > 1) { 7917c478bd9Sstevel@tonic-gate *residp = resid; 7927c478bd9Sstevel@tonic-gate } 7937c478bd9Sstevel@tonic-gate done: 7947c478bd9Sstevel@tonic-gate *resvp = resv; 7957c478bd9Sstevel@tonic-gate } 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate int 7987c478bd9Sstevel@tonic-gate ufs_trans_itrunc(struct inode *ip, u_offset_t length, int flags, cred_t *cr) 7997c478bd9Sstevel@tonic-gate { 8007c478bd9Sstevel@tonic-gate int err, issync, resv; 8017c478bd9Sstevel@tonic-gate u_offset_t resid; 8027c478bd9Sstevel@tonic-gate int do_block = 0; 8037c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = ip->i_ufsvfs; 8047c478bd9Sstevel@tonic-gate struct fs *fs = ufsvfsp->vfs_fs; 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate /* 8077c478bd9Sstevel@tonic-gate * Not logging; just do the trunc 8087c478bd9Sstevel@tonic-gate */ 8097c478bd9Sstevel@tonic-gate if (!TRANS_ISTRANS(ufsvfsp)) { 8107c478bd9Sstevel@tonic-gate rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER); 8117c478bd9Sstevel@tonic-gate rw_enter(&ip->i_contents, RW_WRITER); 8127c478bd9Sstevel@tonic-gate err = ufs_itrunc(ip, length, flags, cr); 8137c478bd9Sstevel@tonic-gate rw_exit(&ip->i_contents); 8147c478bd9Sstevel@tonic-gate rw_exit(&ufsvfsp->vfs_dqrwlock); 8157c478bd9Sstevel@tonic-gate return (err); 8167c478bd9Sstevel@tonic-gate } 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate /* 8197c478bd9Sstevel@tonic-gate * within the lockfs protocol but *not* part of a transaction 8207c478bd9Sstevel@tonic-gate */ 8217c478bd9Sstevel@tonic-gate do_block = curthread->t_flag & T_DONTBLOCK; 8227c478bd9Sstevel@tonic-gate curthread->t_flag |= T_DONTBLOCK; 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate /* 8257c478bd9Sstevel@tonic-gate * Trunc the file (in pieces, if necessary) 8267c478bd9Sstevel@tonic-gate */ 8277c478bd9Sstevel@tonic-gate again: 8287c478bd9Sstevel@tonic-gate ufs_trans_trunc_resv(ip, length, &resv, &resid); 8297c478bd9Sstevel@tonic-gate TRANS_BEGIN_CSYNC(ufsvfsp, issync, TOP_ITRUNC, resv); 8307c478bd9Sstevel@tonic-gate rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER); 8317c478bd9Sstevel@tonic-gate rw_enter(&ip->i_contents, RW_WRITER); 8327c478bd9Sstevel@tonic-gate if (resid) { 8337c478bd9Sstevel@tonic-gate /* 8347c478bd9Sstevel@tonic-gate * resid is only set if we have to truncate in chunks 8357c478bd9Sstevel@tonic-gate */ 8367c478bd9Sstevel@tonic-gate ASSERT(length + resid < ip->i_size); 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate /* 8397c478bd9Sstevel@tonic-gate * Partially trunc file down to desired size (length). 8407c478bd9Sstevel@tonic-gate * Only retain I_FREE on the last partial trunc. 8417c478bd9Sstevel@tonic-gate * Round up size to a block boundary, to ensure the truncate 8427c478bd9Sstevel@tonic-gate * doesn't have to allocate blocks. This is done both for 8437c478bd9Sstevel@tonic-gate * performance and to fix a bug where if the block can't be 8447c478bd9Sstevel@tonic-gate * allocated then the inode delete fails, but the inode 8457c478bd9Sstevel@tonic-gate * is still freed with attached blocks and non-zero size 8467c478bd9Sstevel@tonic-gate * (bug 4348738). 8477c478bd9Sstevel@tonic-gate */ 8487c478bd9Sstevel@tonic-gate err = ufs_itrunc(ip, blkroundup(fs, (ip->i_size - resid)), 8497c478bd9Sstevel@tonic-gate flags & ~I_FREE, cr); 8507c478bd9Sstevel@tonic-gate ASSERT(ip->i_size != length); 8517c478bd9Sstevel@tonic-gate } else 8527c478bd9Sstevel@tonic-gate err = ufs_itrunc(ip, length, flags, cr); 8537c478bd9Sstevel@tonic-gate if (!do_block) 8547c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_DONTBLOCK; 8557c478bd9Sstevel@tonic-gate rw_exit(&ip->i_contents); 8567c478bd9Sstevel@tonic-gate rw_exit(&ufsvfsp->vfs_dqrwlock); 8577c478bd9Sstevel@tonic-gate TRANS_END_CSYNC(ufsvfsp, err, issync, TOP_ITRUNC, resv); 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate if ((err == 0) && resid) { 8607c478bd9Sstevel@tonic-gate ufsvfsp->vfs_avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; 8617c478bd9Sstevel@tonic-gate goto again; 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate return (err); 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate /* 8677c478bd9Sstevel@tonic-gate * Calculate the amount of log space that needs to be reserved for this 8687c478bd9Sstevel@tonic-gate * write request. If the amount of log space is too large, then 8697c478bd9Sstevel@tonic-gate * calculate the size that the requests needs to be split into. 8707c478bd9Sstevel@tonic-gate * First try fixed chunks of size ufs_trans_max_resid. If that 8717c478bd9Sstevel@tonic-gate * is too big, iterate down to the largest size that will fit. 8727c478bd9Sstevel@tonic-gate * Pagein the pages in the first chunk here, so that the pagein is 8737c478bd9Sstevel@tonic-gate * avoided later when the transaction is open. 8747c478bd9Sstevel@tonic-gate */ 8757c478bd9Sstevel@tonic-gate void 8767c478bd9Sstevel@tonic-gate ufs_trans_write_resv( 8777c478bd9Sstevel@tonic-gate struct inode *ip, 8787c478bd9Sstevel@tonic-gate struct uio *uio, 8797c478bd9Sstevel@tonic-gate int *resvp, 8807c478bd9Sstevel@tonic-gate int *residp) 8817c478bd9Sstevel@tonic-gate { 8827c478bd9Sstevel@tonic-gate ulong_t resv; 8837c478bd9Sstevel@tonic-gate offset_t offset; 8847c478bd9Sstevel@tonic-gate ssize_t resid; 8857c478bd9Sstevel@tonic-gate int nchunks; 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate *residp = 0; 8887c478bd9Sstevel@tonic-gate offset = uio->uio_offset; 8897c478bd9Sstevel@tonic-gate resid = MIN(uio->uio_resid, ufs_trans_max_resid); 8907c478bd9Sstevel@tonic-gate resv = ufs_log_amt(ip, offset, resid, 0); 8917c478bd9Sstevel@tonic-gate if (resv <= ufs_trans_max_resv) { 8926f5f1c63SDonghai Qiao uio_prefaultpages(resid, uio); 8937c478bd9Sstevel@tonic-gate if (resid != uio->uio_resid) 8947c478bd9Sstevel@tonic-gate *residp = resid; 8957c478bd9Sstevel@tonic-gate *resvp = resv; 8967c478bd9Sstevel@tonic-gate return; 8977c478bd9Sstevel@tonic-gate } 8987c478bd9Sstevel@tonic-gate 8997c478bd9Sstevel@tonic-gate resid = uio->uio_resid; 9007c478bd9Sstevel@tonic-gate nchunks = 1; 9017c478bd9Sstevel@tonic-gate for (; (resv = ufs_log_amt(ip, offset, resid, 0)) > ufs_trans_max_resv; 9027c478bd9Sstevel@tonic-gate offset = uio->uio_offset + (nchunks - 1) * resid) { 9037c478bd9Sstevel@tonic-gate nchunks++; 9047c478bd9Sstevel@tonic-gate resid = uio->uio_resid / nchunks; 9057c478bd9Sstevel@tonic-gate } 9066f5f1c63SDonghai Qiao uio_prefaultpages(resid, uio); 9077c478bd9Sstevel@tonic-gate /* 9087c478bd9Sstevel@tonic-gate * If this request takes too much log space, it will be split 9097c478bd9Sstevel@tonic-gate */ 9107c478bd9Sstevel@tonic-gate if (nchunks > 1) 9117c478bd9Sstevel@tonic-gate *residp = resid; 9127c478bd9Sstevel@tonic-gate *resvp = resv; 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate /* 9167c478bd9Sstevel@tonic-gate * Issue write request. 9177c478bd9Sstevel@tonic-gate * 9187c478bd9Sstevel@tonic-gate * Split a large request into smaller chunks. 9197c478bd9Sstevel@tonic-gate */ 9207c478bd9Sstevel@tonic-gate int 9217c478bd9Sstevel@tonic-gate ufs_trans_write( 9227c478bd9Sstevel@tonic-gate struct inode *ip, 9237c478bd9Sstevel@tonic-gate struct uio *uio, 9247c478bd9Sstevel@tonic-gate int ioflag, 9257c478bd9Sstevel@tonic-gate cred_t *cr, 9267c478bd9Sstevel@tonic-gate int resv, 9277c478bd9Sstevel@tonic-gate long resid) 9287c478bd9Sstevel@tonic-gate { 9297c478bd9Sstevel@tonic-gate long realresid; 9307c478bd9Sstevel@tonic-gate int err; 9317c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = ip->i_ufsvfs; 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate /* 9347c478bd9Sstevel@tonic-gate * since the write is too big and would "HOG THE LOG" it needs to 9357c478bd9Sstevel@tonic-gate * be broken up and done in pieces. NOTE, the caller will 9367c478bd9Sstevel@tonic-gate * issue the EOT after the request has been completed 9377c478bd9Sstevel@tonic-gate */ 9387c478bd9Sstevel@tonic-gate realresid = uio->uio_resid; 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate again: 9417c478bd9Sstevel@tonic-gate /* 9427c478bd9Sstevel@tonic-gate * Perform partial request (uiomove will update uio for us) 9437c478bd9Sstevel@tonic-gate * Request is split up into "resid" size chunks until 9447c478bd9Sstevel@tonic-gate * "realresid" bytes have been transferred. 9457c478bd9Sstevel@tonic-gate */ 9467c478bd9Sstevel@tonic-gate uio->uio_resid = MIN(resid, realresid); 9477c478bd9Sstevel@tonic-gate realresid -= uio->uio_resid; 9487c478bd9Sstevel@tonic-gate err = wrip(ip, uio, ioflag, cr); 9497c478bd9Sstevel@tonic-gate 9507c478bd9Sstevel@tonic-gate /* 9517c478bd9Sstevel@tonic-gate * Error or request is done; caller issues final EOT 9527c478bd9Sstevel@tonic-gate */ 9537c478bd9Sstevel@tonic-gate if (err || uio->uio_resid || (realresid == 0)) { 9547c478bd9Sstevel@tonic-gate uio->uio_resid += realresid; 9557c478bd9Sstevel@tonic-gate return (err); 9567c478bd9Sstevel@tonic-gate } 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate /* 9597c478bd9Sstevel@tonic-gate * Generate EOT for this part of the request 9607c478bd9Sstevel@tonic-gate */ 9617c478bd9Sstevel@tonic-gate rw_exit(&ip->i_contents); 9627c478bd9Sstevel@tonic-gate rw_exit(&ufsvfsp->vfs_dqrwlock); 9637c478bd9Sstevel@tonic-gate if (ioflag & (FSYNC|FDSYNC)) { 9647c478bd9Sstevel@tonic-gate TRANS_END_SYNC(ufsvfsp, err, TOP_WRITE_SYNC, resv); 9657c478bd9Sstevel@tonic-gate } else { 9667c478bd9Sstevel@tonic-gate TRANS_END_ASYNC(ufsvfsp, TOP_WRITE, resv); 9677c478bd9Sstevel@tonic-gate } 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate /* 9707c478bd9Sstevel@tonic-gate * Make sure the input buffer is resident before starting 9717c478bd9Sstevel@tonic-gate * the next transaction. 9727c478bd9Sstevel@tonic-gate */ 9736f5f1c63SDonghai Qiao uio_prefaultpages(MIN(resid, realresid), uio); 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate /* 9767c478bd9Sstevel@tonic-gate * Generate BOT for next part of the request 9777c478bd9Sstevel@tonic-gate */ 9787c478bd9Sstevel@tonic-gate if (ioflag & (FSYNC|FDSYNC)) { 9797c478bd9Sstevel@tonic-gate int error; 9807c478bd9Sstevel@tonic-gate TRANS_BEGIN_SYNC(ufsvfsp, TOP_WRITE_SYNC, resv, error); 9817c478bd9Sstevel@tonic-gate ASSERT(!error); 9827c478bd9Sstevel@tonic-gate } else { 9837c478bd9Sstevel@tonic-gate TRANS_BEGIN_ASYNC(ufsvfsp, TOP_WRITE, resv); 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER); 9867c478bd9Sstevel@tonic-gate rw_enter(&ip->i_contents, RW_WRITER); 9877c478bd9Sstevel@tonic-gate /* 9887c478bd9Sstevel@tonic-gate * Error during EOT (probably device error while writing commit rec) 9897c478bd9Sstevel@tonic-gate */ 9907c478bd9Sstevel@tonic-gate if (err) 9917c478bd9Sstevel@tonic-gate return (err); 9927c478bd9Sstevel@tonic-gate goto again; 9937c478bd9Sstevel@tonic-gate } 994