xref: /illumos-gate/usr/src/uts/common/fs/ufs/ufs_thread.c (revision 7da74b76)
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
520a1ae8aSjkennedy  * Common Development and Distribution License (the "License").
620a1ae8aSjkennedy  * 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 
29ade42b55SSebastien Roy /*
30ade42b55SSebastien Roy  * Copyright (c) 2017 by Delphix. All rights reserved.
31ade42b55SSebastien Roy  */
32ade42b55SSebastien Roy 
337c478bd9Sstevel@tonic-gate /*
347c478bd9Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley 4.3 BSD
357c478bd9Sstevel@tonic-gate  * under license from the Regents of the University of California.
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include <sys/types.h>
397c478bd9Sstevel@tonic-gate #include <sys/systm.h>
407c478bd9Sstevel@tonic-gate #include <sys/errno.h>
417c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
427c478bd9Sstevel@tonic-gate #include <sys/buf.h>
437c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
447c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
457c478bd9Sstevel@tonic-gate #include <sys/user.h>
467c478bd9Sstevel@tonic-gate #include <sys/callb.h>
477c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
487c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
497c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_log.h>
507c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_trans.h>
517c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_acl.h>
527c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_bio.h>
537c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fsdir.h>
547c478bd9Sstevel@tonic-gate #include <sys/debug.h>
557c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
567c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
57b7deb15bSWolfgang Schremser #include <vm/pvn.h>
587c478bd9Sstevel@tonic-gate 
59ade42b55SSebastien Roy extern pri_t			minclsyspri;
607c478bd9Sstevel@tonic-gate extern int			hash2ints();
617c478bd9Sstevel@tonic-gate extern struct kmem_cache	*inode_cache;	/* cache of free inodes */
627c478bd9Sstevel@tonic-gate extern int			ufs_idle_waiters;
637c478bd9Sstevel@tonic-gate extern struct instats		ins;
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate static void ufs_attr_purge(struct inode *);
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate /*
687c478bd9Sstevel@tonic-gate  * initialize a thread's queue struct
697c478bd9Sstevel@tonic-gate  */
707c478bd9Sstevel@tonic-gate void
ufs_thread_init(struct ufs_q * uq,int lowat)717c478bd9Sstevel@tonic-gate ufs_thread_init(struct ufs_q *uq, int lowat)
727c478bd9Sstevel@tonic-gate {
737c478bd9Sstevel@tonic-gate 	bzero((caddr_t)uq, sizeof (*uq));
747c478bd9Sstevel@tonic-gate 	cv_init(&uq->uq_cv, NULL, CV_DEFAULT, NULL);
757c478bd9Sstevel@tonic-gate 	mutex_init(&uq->uq_mutex, NULL, MUTEX_DEFAULT, NULL);
767c478bd9Sstevel@tonic-gate 	uq->uq_lowat = lowat;
777c478bd9Sstevel@tonic-gate 	uq->uq_hiwat = 2 * lowat;
787c478bd9Sstevel@tonic-gate 	uq->uq_threadp = NULL;
797c478bd9Sstevel@tonic-gate }
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate /*
827c478bd9Sstevel@tonic-gate  * start a thread for a queue (assumes success)
837c478bd9Sstevel@tonic-gate  */
847c478bd9Sstevel@tonic-gate void
ufs_thread_start(struct ufs_q * uq,void (* func)(),struct vfs * vfsp)857c478bd9Sstevel@tonic-gate ufs_thread_start(struct ufs_q *uq, void (*func)(), struct vfs *vfsp)
867c478bd9Sstevel@tonic-gate {
877c478bd9Sstevel@tonic-gate 	mutex_enter(&uq->uq_mutex);
887c478bd9Sstevel@tonic-gate 	if (uq->uq_threadp == NULL) {
897c478bd9Sstevel@tonic-gate 		uq->uq_threadp = thread_create(NULL, 0, func, vfsp, 0, &p0,
907c478bd9Sstevel@tonic-gate 		    TS_RUN, minclsyspri);
917c478bd9Sstevel@tonic-gate 		uq->uq_flags = 0;
927c478bd9Sstevel@tonic-gate 	}
937c478bd9Sstevel@tonic-gate 	mutex_exit(&uq->uq_mutex);
947c478bd9Sstevel@tonic-gate }
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate /*
977c478bd9Sstevel@tonic-gate  * wait for the thread to exit
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate void
ufs_thread_exit(struct ufs_q * uq)1007c478bd9Sstevel@tonic-gate ufs_thread_exit(struct ufs_q *uq)
1017c478bd9Sstevel@tonic-gate {
1027c478bd9Sstevel@tonic-gate 	kt_did_t ufs_thread_did = 0;
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	mutex_enter(&uq->uq_mutex);
1057c478bd9Sstevel@tonic-gate 	uq->uq_flags &= ~(UQ_SUSPEND | UQ_SUSPENDED);
1067c478bd9Sstevel@tonic-gate 	if (uq->uq_threadp != NULL) {
1077c478bd9Sstevel@tonic-gate 		ufs_thread_did = uq->uq_threadp->t_did;
1087c478bd9Sstevel@tonic-gate 		uq->uq_flags |= (UQ_EXIT|UQ_WAIT);
1097c478bd9Sstevel@tonic-gate 		cv_broadcast(&uq->uq_cv);
1107c478bd9Sstevel@tonic-gate 	}
1117c478bd9Sstevel@tonic-gate 	mutex_exit(&uq->uq_mutex);
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	/*
1147c478bd9Sstevel@tonic-gate 	 * It's safe to call thread_join() with an already-gone
1157c478bd9Sstevel@tonic-gate 	 * t_did, but we have to obtain it before the kernel
1167c478bd9Sstevel@tonic-gate 	 * thread structure is freed. We do so above under the
1177c478bd9Sstevel@tonic-gate 	 * protection of the uq_mutex when we're sure the thread
1187c478bd9Sstevel@tonic-gate 	 * still exists and it's save to de-reference it.
1197c478bd9Sstevel@tonic-gate 	 * We also have to check if ufs_thread_did is != 0
1207c478bd9Sstevel@tonic-gate 	 * before calling thread_join() since thread 0 in the system
1217c478bd9Sstevel@tonic-gate 	 * gets a t_did of 0.
1227c478bd9Sstevel@tonic-gate 	 */
1237c478bd9Sstevel@tonic-gate 	if (ufs_thread_did)
1247c478bd9Sstevel@tonic-gate 		thread_join(ufs_thread_did);
1257c478bd9Sstevel@tonic-gate }
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate /*
1287c478bd9Sstevel@tonic-gate  * wait for a thread to suspend itself on the caller's behalf
1297c478bd9Sstevel@tonic-gate  *	the caller is responsible for continuing the thread
1307c478bd9Sstevel@tonic-gate  */
1317c478bd9Sstevel@tonic-gate void
ufs_thread_suspend(struct ufs_q * uq)1327c478bd9Sstevel@tonic-gate ufs_thread_suspend(struct ufs_q *uq)
1337c478bd9Sstevel@tonic-gate {
1347c478bd9Sstevel@tonic-gate 	mutex_enter(&uq->uq_mutex);
1357c478bd9Sstevel@tonic-gate 	if (uq->uq_threadp != NULL) {
1367c478bd9Sstevel@tonic-gate 		/*
1377c478bd9Sstevel@tonic-gate 		 * wait while another thread is suspending this thread.
1387c478bd9Sstevel@tonic-gate 		 * no need to do a cv_broadcast(), as whoever suspended
139121be23bSjkennedy 		 * the thread must continue it at some point.
1407c478bd9Sstevel@tonic-gate 		 */
1417c478bd9Sstevel@tonic-gate 		while ((uq->uq_flags & UQ_SUSPEND) &&
1427c478bd9Sstevel@tonic-gate 		    (uq->uq_threadp != NULL)) {
143121be23bSjkennedy 			/*
144121be23bSjkennedy 			 * We can't use cv_signal() because if our
145121be23bSjkennedy 			 * signal doesn't happen to hit the desired
146121be23bSjkennedy 			 * thread but instead some other waiter like
147121be23bSjkennedy 			 * ourselves, we'll wait forever for a
148121be23bSjkennedy 			 * response.  Well, at least an indeterminate
149121be23bSjkennedy 			 * amount of time until we just happen to get
150121be23bSjkennedy 			 * lucky from whomever did get signalled doing
151121be23bSjkennedy 			 * a cv_signal() of their own.  This is an
152121be23bSjkennedy 			 * unfortunate performance lossage.
153121be23bSjkennedy 			 */
1547c478bd9Sstevel@tonic-gate 			uq->uq_flags |= UQ_WAIT;
1557c478bd9Sstevel@tonic-gate 			cv_wait(&uq->uq_cv, &uq->uq_mutex);
1567c478bd9Sstevel@tonic-gate 		}
1577c478bd9Sstevel@tonic-gate 
1588db829a5Smishra 		uq->uq_flags |= (UQ_SUSPEND | UQ_WAIT);
1598db829a5Smishra 
1607c478bd9Sstevel@tonic-gate 		/*
1617c478bd9Sstevel@tonic-gate 		 * wait for the thread to suspend itself
1627c478bd9Sstevel@tonic-gate 		 */
1638db829a5Smishra 		if ((uq->uq_flags & UQ_SUSPENDED) == 0 &&
1647c478bd9Sstevel@tonic-gate 		    (uq->uq_threadp != NULL)) {
1657c478bd9Sstevel@tonic-gate 			cv_broadcast(&uq->uq_cv);
1668db829a5Smishra 		}
1678db829a5Smishra 
1688db829a5Smishra 		while (((uq->uq_flags & UQ_SUSPENDED) == 0) &&
1698db829a5Smishra 		    (uq->uq_threadp != NULL)) {
1707c478bd9Sstevel@tonic-gate 			cv_wait(&uq->uq_cv, &uq->uq_mutex);
1717c478bd9Sstevel@tonic-gate 		}
1727c478bd9Sstevel@tonic-gate 	}
1737c478bd9Sstevel@tonic-gate 	mutex_exit(&uq->uq_mutex);
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate /*
1777c478bd9Sstevel@tonic-gate  * allow a thread to continue from a ufs_thread_suspend()
1787c478bd9Sstevel@tonic-gate  *	This thread must be the same as the thread that called
1797c478bd9Sstevel@tonic-gate  *	ufs_thread_suspend.
1807c478bd9Sstevel@tonic-gate  */
1817c478bd9Sstevel@tonic-gate void
ufs_thread_continue(struct ufs_q * uq)1827c478bd9Sstevel@tonic-gate ufs_thread_continue(struct ufs_q *uq)
1837c478bd9Sstevel@tonic-gate {
1847c478bd9Sstevel@tonic-gate 	mutex_enter(&uq->uq_mutex);
1857c478bd9Sstevel@tonic-gate 	uq->uq_flags &= ~(UQ_SUSPEND | UQ_SUSPENDED);
1867c478bd9Sstevel@tonic-gate 	cv_broadcast(&uq->uq_cv);
1877c478bd9Sstevel@tonic-gate 	mutex_exit(&uq->uq_mutex);
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate /*
1917c478bd9Sstevel@tonic-gate  * some common code for managing a threads execution
1927c478bd9Sstevel@tonic-gate  *	uq is locked at entry and return
1937c478bd9Sstevel@tonic-gate  *	may sleep
1947c478bd9Sstevel@tonic-gate  *	may exit
1957c478bd9Sstevel@tonic-gate  */
1967c478bd9Sstevel@tonic-gate /*
1977c478bd9Sstevel@tonic-gate  * Kind of a hack passing in the callb_cpr_t * here.
1987c478bd9Sstevel@tonic-gate  * It should really be part of the ufs_q structure.
1997c478bd9Sstevel@tonic-gate  * I did not put it in there because we are already in beta
2007c478bd9Sstevel@tonic-gate  * and I was concerned that changing ufs_inode.h to include
2017c478bd9Sstevel@tonic-gate  * callb.h might break something.
2027c478bd9Sstevel@tonic-gate  */
2037c478bd9Sstevel@tonic-gate int
ufs_thread_run(struct ufs_q * uq,callb_cpr_t * cprinfop)2047c478bd9Sstevel@tonic-gate ufs_thread_run(struct ufs_q *uq, callb_cpr_t *cprinfop)
2057c478bd9Sstevel@tonic-gate {
2067c478bd9Sstevel@tonic-gate again:
2077c478bd9Sstevel@tonic-gate 	ASSERT(uq->uq_ne >= 0);
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	if (uq->uq_flags & UQ_SUSPEND) {
2107c478bd9Sstevel@tonic-gate 		uq->uq_flags |= UQ_SUSPENDED;
2117c478bd9Sstevel@tonic-gate 	} else if (uq->uq_flags & UQ_EXIT) {
2127c478bd9Sstevel@tonic-gate 		/*
2137c478bd9Sstevel@tonic-gate 		 * exiting; empty the queue (may infinite loop)
2147c478bd9Sstevel@tonic-gate 		 */
2157c478bd9Sstevel@tonic-gate 		if (uq->uq_ne)
2167c478bd9Sstevel@tonic-gate 			return (uq->uq_ne);
2177c478bd9Sstevel@tonic-gate 		uq->uq_threadp = NULL;
218121be23bSjkennedy 		if (uq->uq_flags & UQ_WAIT) {
2197c478bd9Sstevel@tonic-gate 			cv_broadcast(&uq->uq_cv);
220121be23bSjkennedy 		}
2217c478bd9Sstevel@tonic-gate 		uq->uq_flags &= ~(UQ_EXIT | UQ_WAIT);
2227c478bd9Sstevel@tonic-gate 		CALLB_CPR_EXIT(cprinfop);
2237c478bd9Sstevel@tonic-gate 		thread_exit();
2247c478bd9Sstevel@tonic-gate 	} else if (uq->uq_ne >= uq->uq_lowat) {
2257c478bd9Sstevel@tonic-gate 		/*
2267c478bd9Sstevel@tonic-gate 		 * process a block of entries until below high water mark
2277c478bd9Sstevel@tonic-gate 		 */
2287c478bd9Sstevel@tonic-gate 		return (uq->uq_ne - (uq->uq_lowat >> 1));
2297c478bd9Sstevel@tonic-gate 	}
2307c478bd9Sstevel@tonic-gate 	if (uq->uq_flags & UQ_WAIT) {
2317c478bd9Sstevel@tonic-gate 		uq->uq_flags &= ~UQ_WAIT;
2327c478bd9Sstevel@tonic-gate 		cv_broadcast(&uq->uq_cv);
2337c478bd9Sstevel@tonic-gate 	}
2347c478bd9Sstevel@tonic-gate 	CALLB_CPR_SAFE_BEGIN(cprinfop);
2357c478bd9Sstevel@tonic-gate 	cv_wait(&uq->uq_cv, &uq->uq_mutex);
2367c478bd9Sstevel@tonic-gate 	CALLB_CPR_SAFE_END(cprinfop, &uq->uq_mutex);
2377c478bd9Sstevel@tonic-gate 	goto again;
2387c478bd9Sstevel@tonic-gate }
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate /*
2417c478bd9Sstevel@tonic-gate  * DELETE INODE
2427c478bd9Sstevel@tonic-gate  * The following routines implement the protocol for freeing the resources
2437c478bd9Sstevel@tonic-gate  * held by an idle and deleted inode.
2447c478bd9Sstevel@tonic-gate  */
2457c478bd9Sstevel@tonic-gate void
ufs_delete(struct ufsvfs * ufsvfsp,struct inode * ip,int dolockfs)2467c478bd9Sstevel@tonic-gate ufs_delete(struct ufsvfs *ufsvfsp, struct inode *ip, int dolockfs)
2477c478bd9Sstevel@tonic-gate {
2487c478bd9Sstevel@tonic-gate 	ushort_t	mode;
2497c478bd9Sstevel@tonic-gate 	struct vnode	*vp	= ITOV(ip);
2507c478bd9Sstevel@tonic-gate 	struct ulockfs	*ulp;
2517c478bd9Sstevel@tonic-gate 	int		trans_size;
2527c478bd9Sstevel@tonic-gate 	int		dorwlock = ((ip->i_mode & IFMT) == IFREG);
2537c478bd9Sstevel@tonic-gate 	int		issync;
2547c478bd9Sstevel@tonic-gate 	int		err;
2557c478bd9Sstevel@tonic-gate 	struct inode	*dp;
256121be23bSjkennedy 	struct ufs_q    *delq = &ufsvfsp->vfs_delete;
257121be23bSjkennedy 	struct ufs_delq_info *delq_info = &ufsvfsp->vfs_delete_info;
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	/*
2607c478bd9Sstevel@tonic-gate 	 * Ignore if deletes are not allowed (wlock/hlock)
2617c478bd9Sstevel@tonic-gate 	 */
2627c478bd9Sstevel@tonic-gate 	if (ULOCKFS_IS_NOIDEL(ITOUL(ip))) {
263d13c09a7Svk 		mutex_enter(&delq->uq_mutex);
264d13c09a7Svk 		delq_info->delq_unreclaimed_blocks -= ip->i_blocks;
265d13c09a7Svk 		delq_info->delq_unreclaimed_files--;
266d13c09a7Svk 		mutex_exit(&delq->uq_mutex);
2677c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
2687c478bd9Sstevel@tonic-gate 		return;
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	if ((vp->v_count > 1) || (ip->i_mode == 0)) {
272d13c09a7Svk 		mutex_enter(&delq->uq_mutex);
273d13c09a7Svk 		delq_info->delq_unreclaimed_blocks -= ip->i_blocks;
274d13c09a7Svk 		delq_info->delq_unreclaimed_files--;
275d13c09a7Svk 		mutex_exit(&delq->uq_mutex);
2767c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
2777c478bd9Sstevel@tonic-gate 		return;
2787c478bd9Sstevel@tonic-gate 	}
2797c478bd9Sstevel@tonic-gate 	/*
2807c478bd9Sstevel@tonic-gate 	 * If we are called as part of setting a fs lock, then only
2817c478bd9Sstevel@tonic-gate 	 * do part of the lockfs protocol.  In other words, don't hang.
2827c478bd9Sstevel@tonic-gate 	 */
2837c478bd9Sstevel@tonic-gate 	if (dolockfs) {
2847c478bd9Sstevel@tonic-gate 		if (ufs_lockfs_begin(ufsvfsp, &ulp, ULOCKFS_DELETE_MASK))
2857c478bd9Sstevel@tonic-gate 			return;
2867c478bd9Sstevel@tonic-gate 	} else {
2877c478bd9Sstevel@tonic-gate 		/*
2887c478bd9Sstevel@tonic-gate 		 * check for recursive VOP call
2897c478bd9Sstevel@tonic-gate 		 */
2907c478bd9Sstevel@tonic-gate 		if (curthread->t_flag & T_DONTBLOCK) {
2917c478bd9Sstevel@tonic-gate 			ulp = NULL;
2927c478bd9Sstevel@tonic-gate 		} else {
2937c478bd9Sstevel@tonic-gate 			ulp = &ufsvfsp->vfs_ulockfs;
2947c478bd9Sstevel@tonic-gate 			curthread->t_flag |= T_DONTBLOCK;
2957c478bd9Sstevel@tonic-gate 		}
2967c478bd9Sstevel@tonic-gate 	}
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	/*
2997c478bd9Sstevel@tonic-gate 	 * Hold rwlock to synchronize with (nfs) writes
3007c478bd9Sstevel@tonic-gate 	 */
3017c478bd9Sstevel@tonic-gate 	if (dorwlock)
3027c478bd9Sstevel@tonic-gate 		rw_enter(&ip->i_rwlock, RW_WRITER);
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	/*
3057c478bd9Sstevel@tonic-gate 	 * Delete the attribute directory.
3067c478bd9Sstevel@tonic-gate 	 */
3077c478bd9Sstevel@tonic-gate 	if (ip->i_oeftflag != 0) {
3087c478bd9Sstevel@tonic-gate 		TRANS_BEGIN_CSYNC(ufsvfsp, issync, TOP_REMOVE,
3097c478bd9Sstevel@tonic-gate 		    trans_size = (int)TOP_REMOVE_SIZE(ip));
3107c478bd9Sstevel@tonic-gate 		rw_enter(&ip->i_contents, RW_WRITER);
3117c478bd9Sstevel@tonic-gate 		err = ufs_iget(ip->i_vfs, ip->i_oeftflag,
3127c478bd9Sstevel@tonic-gate 		    &dp, CRED());
3137c478bd9Sstevel@tonic-gate 		if (err == 0) {
3147c478bd9Sstevel@tonic-gate 			rw_enter(&dp->i_rwlock, RW_WRITER);
3157c478bd9Sstevel@tonic-gate 			rw_enter(&dp->i_contents, RW_WRITER);
3167c478bd9Sstevel@tonic-gate 			dp->i_flag |= IUPD|ICHG;
3177c478bd9Sstevel@tonic-gate 			dp->i_seq++;
3187c478bd9Sstevel@tonic-gate 			TRANS_INODE(dp->i_ufsvfs, dp);
3197c478bd9Sstevel@tonic-gate 			dp->i_nlink -= 2;
3207c478bd9Sstevel@tonic-gate 			ufs_setreclaim(dp);
3217c478bd9Sstevel@tonic-gate 			/*
3227c478bd9Sstevel@tonic-gate 			 * Should get rid of any negative cache entries that
3237c478bd9Sstevel@tonic-gate 			 * might be lingering, as well as ``.'' and
3247c478bd9Sstevel@tonic-gate 			 * ``..''.  If we don't, the VN_RELE() below
3257c478bd9Sstevel@tonic-gate 			 * won't actually put dp on the delete queue
3267c478bd9Sstevel@tonic-gate 			 * and it'll hang out until someone forces it
3277c478bd9Sstevel@tonic-gate 			 * (lockfs -f, umount, ...).  The only reliable
3287c478bd9Sstevel@tonic-gate 			 * way of doing this at the moment is to call
3297c478bd9Sstevel@tonic-gate 			 * dnlc_purge_vp(ITOV(dp)), which is unacceptably
3307c478bd9Sstevel@tonic-gate 			 * slow, so we'll just note the problem in this
3317c478bd9Sstevel@tonic-gate 			 * comment for now.
3327c478bd9Sstevel@tonic-gate 			 */
3337c478bd9Sstevel@tonic-gate 			dnlc_remove(ITOV(dp), ".");
3347c478bd9Sstevel@tonic-gate 			dnlc_remove(ITOV(dp), "..");
3357c478bd9Sstevel@tonic-gate 			ITIMES_NOLOCK(dp);
3367c478bd9Sstevel@tonic-gate 			if (!TRANS_ISTRANS(ufsvfsp)) {
3377c478bd9Sstevel@tonic-gate 				ufs_iupdat(dp, I_SYNC);
3387c478bd9Sstevel@tonic-gate 			}
3397c478bd9Sstevel@tonic-gate 			rw_exit(&dp->i_contents);
3407c478bd9Sstevel@tonic-gate 			rw_exit(&dp->i_rwlock);
3417c478bd9Sstevel@tonic-gate 			VN_RELE(ITOV(dp));
3427c478bd9Sstevel@tonic-gate 		}
3437c478bd9Sstevel@tonic-gate 		/*
3447c478bd9Sstevel@tonic-gate 		 * Clear out attribute pointer
3457c478bd9Sstevel@tonic-gate 		 */
3467c478bd9Sstevel@tonic-gate 		ip->i_oeftflag = 0;
3477c478bd9Sstevel@tonic-gate 		rw_exit(&ip->i_contents);
3487c478bd9Sstevel@tonic-gate 		TRANS_END_CSYNC(ufsvfsp, err, issync,
3497c478bd9Sstevel@tonic-gate 		    TOP_REMOVE, trans_size);
3507c478bd9Sstevel@tonic-gate 		dnlc_remove(ITOV(ip), XATTR_DIR_NAME);
3517c478bd9Sstevel@tonic-gate 	}
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	if ((ip->i_mode & IFMT) == IFATTRDIR) {
3547c478bd9Sstevel@tonic-gate 		ufs_attr_purge(ip);
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 
357121be23bSjkennedy 	(void) TRANS_ITRUNC(ip, (u_offset_t)0, I_FREE | I_ACCT, CRED());
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	/*
3607c478bd9Sstevel@tonic-gate 	 * the inode's space has been freed; now free the inode
3617c478bd9Sstevel@tonic-gate 	 */
3627c478bd9Sstevel@tonic-gate 	if (ulp) {
3637c478bd9Sstevel@tonic-gate 		trans_size = TOP_IFREE_SIZE(ip);
3647c478bd9Sstevel@tonic-gate 		TRANS_BEGIN_ASYNC(ufsvfsp, TOP_IFREE, trans_size);
3657c478bd9Sstevel@tonic-gate 	}
3667c478bd9Sstevel@tonic-gate 	rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER);
3677c478bd9Sstevel@tonic-gate 	rw_enter(&ip->i_contents, RW_WRITER);
3687c478bd9Sstevel@tonic-gate 	TRANS_INODE(ufsvfsp, ip);
3697c478bd9Sstevel@tonic-gate 	mode = ip->i_mode;
3707c478bd9Sstevel@tonic-gate 	ip->i_mode = 0;
3717c478bd9Sstevel@tonic-gate 	ip->i_rdev = 0;
3727c478bd9Sstevel@tonic-gate 	ip->i_ordev = 0;
3737c478bd9Sstevel@tonic-gate 	ip->i_flag |= IMOD;
3747c478bd9Sstevel@tonic-gate 	if (ip->i_ufs_acl) {
3757c478bd9Sstevel@tonic-gate 		(void) ufs_si_free(ip->i_ufs_acl, vp->v_vfsp, CRED());
3767c478bd9Sstevel@tonic-gate 		ip->i_ufs_acl = NULL;
3777c478bd9Sstevel@tonic-gate 		ip->i_shadow = 0;
3787c478bd9Sstevel@tonic-gate 	}
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	/*
3817c478bd9Sstevel@tonic-gate 	 * This inode is torn down but still retains it's identity
3827c478bd9Sstevel@tonic-gate 	 * (inode number).  It could get recycled soon so it's best
3837c478bd9Sstevel@tonic-gate 	 * to clean up the vnode just in case.
3847c478bd9Sstevel@tonic-gate 	 */
3857c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
3867c478bd9Sstevel@tonic-gate 	vn_recycle(vp);
3877c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	/*
3907c478bd9Sstevel@tonic-gate 	 * free the inode
3917c478bd9Sstevel@tonic-gate 	 */
3927c478bd9Sstevel@tonic-gate 	ufs_ifree(ip, ip->i_number, mode);
3937c478bd9Sstevel@tonic-gate 	/*
3947c478bd9Sstevel@tonic-gate 	 * release quota resources; can't fail
3957c478bd9Sstevel@tonic-gate 	 */
3967c478bd9Sstevel@tonic-gate 	(void) chkiq((struct ufsvfs *)vp->v_vfsp->vfs_data,
39780d34432Sfrankho 	    /* change */ -1, ip, (uid_t)ip->i_uid, 0, CRED(),
39880d34432Sfrankho 	    (char **)NULL, (size_t *)NULL);
3997c478bd9Sstevel@tonic-gate 	dqrele(ip->i_dquot);
4007c478bd9Sstevel@tonic-gate 	ip->i_dquot = NULL;
4017c478bd9Sstevel@tonic-gate 	ip->i_flag &= ~(IDEL | IDIRECTIO);
4027c478bd9Sstevel@tonic-gate 	ip->i_cflags = 0;
4037c478bd9Sstevel@tonic-gate 	if (!TRANS_ISTRANS(ufsvfsp)) {
4047c478bd9Sstevel@tonic-gate 		ufs_iupdat(ip, I_SYNC);
405121be23bSjkennedy 	} else {
406121be23bSjkennedy 		mutex_enter(&delq->uq_mutex);
407121be23bSjkennedy 		delq_info->delq_unreclaimed_files--;
408121be23bSjkennedy 		mutex_exit(&delq->uq_mutex);
4097c478bd9Sstevel@tonic-gate 	}
4107c478bd9Sstevel@tonic-gate 	rw_exit(&ip->i_contents);
4117c478bd9Sstevel@tonic-gate 	rw_exit(&ufsvfsp->vfs_dqrwlock);
4127c478bd9Sstevel@tonic-gate 	if (dorwlock)
4137c478bd9Sstevel@tonic-gate 		rw_exit(&ip->i_rwlock);
4147c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	/*
4177c478bd9Sstevel@tonic-gate 	 * End of transaction
4187c478bd9Sstevel@tonic-gate 	 */
4197c478bd9Sstevel@tonic-gate 	if (ulp) {
4207c478bd9Sstevel@tonic-gate 		TRANS_END_ASYNC(ufsvfsp, TOP_IFREE, trans_size);
4217c478bd9Sstevel@tonic-gate 		if (dolockfs)
4227c478bd9Sstevel@tonic-gate 			ufs_lockfs_end(ulp);
4237c478bd9Sstevel@tonic-gate 		else
4247c478bd9Sstevel@tonic-gate 			curthread->t_flag &= ~T_DONTBLOCK;
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate }
4277c478bd9Sstevel@tonic-gate 
428121be23bSjkennedy /*
429121be23bSjkennedy  * Create the delete thread and init the delq_info for this fs
430121be23bSjkennedy  */
431121be23bSjkennedy void
ufs_delete_init(struct ufsvfs * ufsvfsp,int lowat)432121be23bSjkennedy ufs_delete_init(struct ufsvfs *ufsvfsp, int lowat)
433121be23bSjkennedy {
434121be23bSjkennedy 	struct ufs_delq_info *delq_info = &ufsvfsp->vfs_delete_info;
435121be23bSjkennedy 
436121be23bSjkennedy 	ufs_thread_init(&ufsvfsp->vfs_delete, lowat);
437a135774bSjkennedy 	(void) memset((void *)delq_info, 0, sizeof (*delq_info));
438121be23bSjkennedy }
439121be23bSjkennedy 
4407c478bd9Sstevel@tonic-gate /*
4417c478bd9Sstevel@tonic-gate  * thread that frees up deleted inodes
4427c478bd9Sstevel@tonic-gate  */
4437c478bd9Sstevel@tonic-gate void
ufs_thread_delete(struct vfs * vfsp)4447c478bd9Sstevel@tonic-gate ufs_thread_delete(struct vfs *vfsp)
4457c478bd9Sstevel@tonic-gate {
4467c478bd9Sstevel@tonic-gate 	struct ufsvfs	*ufsvfsp = (struct ufsvfs *)vfsp->vfs_data;
447121be23bSjkennedy 	struct ufs_q	*uq = &ufsvfsp->vfs_delete;
4487c478bd9Sstevel@tonic-gate 	struct inode	*ip;
4497c478bd9Sstevel@tonic-gate 	long		ne;
4507c478bd9Sstevel@tonic-gate 	callb_cpr_t	cprinfo;
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &uq->uq_mutex, callb_generic_cpr,
4537c478bd9Sstevel@tonic-gate 	    "ufsdelete");
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	mutex_enter(&uq->uq_mutex);
4567c478bd9Sstevel@tonic-gate again:
4577c478bd9Sstevel@tonic-gate 	/*
458121be23bSjkennedy 	 * Sleep until there is work to do.  Only do one entry at
459121be23bSjkennedy 	 * a time, to reduce the wait time for checking for a suspend
460709bb9d7Svk 	 * request.  The ?: is for pedantic portability.
4617c478bd9Sstevel@tonic-gate 	 */
462121be23bSjkennedy 	ne = ufs_thread_run(uq, &cprinfo) ? 1 : 0;
463121be23bSjkennedy 
4647c478bd9Sstevel@tonic-gate 	/*
465121be23bSjkennedy 	 * process an entry, if there are any
4667c478bd9Sstevel@tonic-gate 	 */
467121be23bSjkennedy 	if (ne && (ip = uq->uq_ihead)) {
4687c478bd9Sstevel@tonic-gate 		/*
4697c478bd9Sstevel@tonic-gate 		 * process first entry on queue.  Assumed conditions are:
4707c478bd9Sstevel@tonic-gate 		 *	ip is held (v_count >= 1)
4717c478bd9Sstevel@tonic-gate 		 *	ip is referenced (i_flag & IREF)
4727c478bd9Sstevel@tonic-gate 		 *	ip is free (i_nlink <= 0)
4737c478bd9Sstevel@tonic-gate 		 */
4747c478bd9Sstevel@tonic-gate 		if ((uq->uq_ihead = ip->i_freef) == ip)
4757c478bd9Sstevel@tonic-gate 			uq->uq_ihead = NULL;
4767c478bd9Sstevel@tonic-gate 		ip->i_freef->i_freeb = ip->i_freeb;
4777c478bd9Sstevel@tonic-gate 		ip->i_freeb->i_freef = ip->i_freef;
4787c478bd9Sstevel@tonic-gate 		ip->i_freef = ip;
4797c478bd9Sstevel@tonic-gate 		ip->i_freeb = ip;
4807c478bd9Sstevel@tonic-gate 		uq->uq_ne--;
4817c478bd9Sstevel@tonic-gate 		mutex_exit(&uq->uq_mutex);
4827c478bd9Sstevel@tonic-gate 		ufs_delete(ufsvfsp, ip, 1);
4837c478bd9Sstevel@tonic-gate 		mutex_enter(&uq->uq_mutex);
4847c478bd9Sstevel@tonic-gate 	}
4857c478bd9Sstevel@tonic-gate 	goto again;
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate /*
4897c478bd9Sstevel@tonic-gate  * drain ne entries off the delete queue.  As new queue entries may
4907c478bd9Sstevel@tonic-gate  * be added while we're working, ne is interpreted as follows:
4917c478bd9Sstevel@tonic-gate  *
4927c478bd9Sstevel@tonic-gate  * ne > 0   => remove up to ne entries
4937c478bd9Sstevel@tonic-gate  * ne == 0  => remove all entries currently on the queue
4947c478bd9Sstevel@tonic-gate  * ne == -1 => remove entries until the queue is empty
4957c478bd9Sstevel@tonic-gate  */
4967c478bd9Sstevel@tonic-gate void
ufs_delete_drain(struct vfs * vfsp,int ne,int dolockfs)4977c478bd9Sstevel@tonic-gate ufs_delete_drain(struct vfs *vfsp, int ne, int dolockfs)
4987c478bd9Sstevel@tonic-gate {
4997c478bd9Sstevel@tonic-gate 	struct ufsvfs	*ufsvfsp = (struct ufsvfs *)vfsp->vfs_data;
5007c478bd9Sstevel@tonic-gate 	struct ufs_q	*uq;
5017c478bd9Sstevel@tonic-gate 	struct inode	*ip;
5027c478bd9Sstevel@tonic-gate 	int		drain_cnt = 0;
5037c478bd9Sstevel@tonic-gate 	int		done;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	/*
5067c478bd9Sstevel@tonic-gate 	 * if forcibly unmounted; ignore
5077c478bd9Sstevel@tonic-gate 	 */
5087c478bd9Sstevel@tonic-gate 	if (ufsvfsp == NULL)
5097c478bd9Sstevel@tonic-gate 		return;
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	uq = &ufsvfsp->vfs_delete;
5127c478bd9Sstevel@tonic-gate 	mutex_enter(&uq->uq_mutex);
5137c478bd9Sstevel@tonic-gate 	if (ne == 0)
5147c478bd9Sstevel@tonic-gate 		drain_cnt = uq->uq_ne;
5157c478bd9Sstevel@tonic-gate 	else if (ne > 0)
5167c478bd9Sstevel@tonic-gate 		drain_cnt = ne;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	/*
5197c478bd9Sstevel@tonic-gate 	 * process up to ne entries
5207c478bd9Sstevel@tonic-gate 	 */
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	done = 0;
5237c478bd9Sstevel@tonic-gate 	while (!done && (ip = uq->uq_ihead)) {
5247c478bd9Sstevel@tonic-gate 		if (ne != -1)
5257c478bd9Sstevel@tonic-gate 			drain_cnt--;
5267c478bd9Sstevel@tonic-gate 		if (ne != -1 && drain_cnt == 0)
5277c478bd9Sstevel@tonic-gate 			done = 1;
5287c478bd9Sstevel@tonic-gate 		if ((uq->uq_ihead = ip->i_freef) == ip)
5297c478bd9Sstevel@tonic-gate 			uq->uq_ihead = NULL;
5307c478bd9Sstevel@tonic-gate 		ip->i_freef->i_freeb = ip->i_freeb;
5317c478bd9Sstevel@tonic-gate 		ip->i_freeb->i_freef = ip->i_freef;
5327c478bd9Sstevel@tonic-gate 		ip->i_freef = ip;
5337c478bd9Sstevel@tonic-gate 		ip->i_freeb = ip;
5347c478bd9Sstevel@tonic-gate 		uq->uq_ne--;
5357c478bd9Sstevel@tonic-gate 		mutex_exit(&uq->uq_mutex);
5367c478bd9Sstevel@tonic-gate 		ufs_delete(ufsvfsp, ip, dolockfs);
5377c478bd9Sstevel@tonic-gate 		mutex_enter(&uq->uq_mutex);
5387c478bd9Sstevel@tonic-gate 	}
5397c478bd9Sstevel@tonic-gate 	mutex_exit(&uq->uq_mutex);
5407c478bd9Sstevel@tonic-gate }
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate void
ufs_sync_with_thread(struct ufs_q * uq)5437c478bd9Sstevel@tonic-gate ufs_sync_with_thread(struct ufs_q *uq)
5447c478bd9Sstevel@tonic-gate {
5457c478bd9Sstevel@tonic-gate 	mutex_enter(&uq->uq_mutex);
5468db829a5Smishra 
5477c478bd9Sstevel@tonic-gate 	/*
5488db829a5Smishra 	 * Wake up delete thread to free up space.
5497c478bd9Sstevel@tonic-gate 	 */
5508db829a5Smishra 	if ((uq->uq_flags & UQ_WAIT) == 0) {
5518db829a5Smishra 		uq->uq_flags |= UQ_WAIT;
5527c478bd9Sstevel@tonic-gate 		cv_broadcast(&uq->uq_cv);
5538db829a5Smishra 	}
5548db829a5Smishra 
5558db829a5Smishra 	while ((uq->uq_threadp != NULL) && (uq->uq_flags & UQ_WAIT)) {
5567c478bd9Sstevel@tonic-gate 		cv_wait(&uq->uq_cv, &uq->uq_mutex);
5577c478bd9Sstevel@tonic-gate 	}
5588db829a5Smishra 
5597c478bd9Sstevel@tonic-gate 	mutex_exit(&uq->uq_mutex);
5607c478bd9Sstevel@tonic-gate }
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate /*
5637c478bd9Sstevel@tonic-gate  * Get rid of everything that's currently in the delete queue,
5647c478bd9Sstevel@tonic-gate  * plus whatever the delete thread is working on at the moment.
5657c478bd9Sstevel@tonic-gate  *
5667c478bd9Sstevel@tonic-gate  * This ability is required for providing true POSIX semantics
5677c478bd9Sstevel@tonic-gate  * regarding close(2), unlink(2), etc, even when logging is enabled.
5687c478bd9Sstevel@tonic-gate  * The standard requires that the released space be immediately
5697c478bd9Sstevel@tonic-gate  * observable (statvfs(2)) and allocatable (e.g., write(2)).
5707c478bd9Sstevel@tonic-gate  */
5717c478bd9Sstevel@tonic-gate void
ufs_delete_drain_wait(struct ufsvfs * ufsvfsp,int dolockfs)5727c478bd9Sstevel@tonic-gate ufs_delete_drain_wait(struct ufsvfs *ufsvfsp, int dolockfs)
5737c478bd9Sstevel@tonic-gate {
5747c478bd9Sstevel@tonic-gate 	struct ufs_q *uq = &ufsvfsp->vfs_delete;
5757c478bd9Sstevel@tonic-gate 	int	error;
5768db829a5Smishra 	struct ufs_q    *delq = &ufsvfsp->vfs_delete;
5778db829a5Smishra 	struct ufs_delq_info *delq_info = &ufsvfsp->vfs_delete_info;
5787c478bd9Sstevel@tonic-gate 
5798db829a5Smishra 	/*
5808db829a5Smishra 	 * If there is something on delq or delete thread
5818db829a5Smishra 	 * working on delq.
5828db829a5Smishra 	 */
5838db829a5Smishra 	mutex_enter(&delq->uq_mutex);
5848db829a5Smishra 	if (delq_info->delq_unreclaimed_files > 0) {
5858db829a5Smishra 		mutex_exit(&delq->uq_mutex);
5868db829a5Smishra 		(void) ufs_delete_drain(ufsvfsp->vfs_vfs, 0, dolockfs);
5878db829a5Smishra 		ufs_sync_with_thread(uq);
5888db829a5Smishra 	} else {
5898db829a5Smishra 		ASSERT(delq_info->delq_unreclaimed_files == 0);
5908db829a5Smishra 		mutex_exit(&delq->uq_mutex);
5918db829a5Smishra 		return;
5928db829a5Smishra 	}
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	/*
5957c478bd9Sstevel@tonic-gate 	 * Commit any outstanding transactions to make sure
5967c478bd9Sstevel@tonic-gate 	 * any canceled freed blocks are available for allocation.
5977c478bd9Sstevel@tonic-gate 	 */
5987c478bd9Sstevel@tonic-gate 	curthread->t_flag |= T_DONTBLOCK;
5997c478bd9Sstevel@tonic-gate 	TRANS_BEGIN_SYNC(ufsvfsp, TOP_COMMIT_UPDATE, TOP_COMMIT_SIZE, error);
6007c478bd9Sstevel@tonic-gate 	if (!error) {
6017c478bd9Sstevel@tonic-gate 		TRANS_END_SYNC(ufsvfsp, error, TOP_COMMIT_UPDATE,
60280d34432Sfrankho 		    TOP_COMMIT_SIZE);
6037c478bd9Sstevel@tonic-gate 	}
6047c478bd9Sstevel@tonic-gate 	curthread->t_flag &= ~T_DONTBLOCK;
6057c478bd9Sstevel@tonic-gate }
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate /*
6087c478bd9Sstevel@tonic-gate  * Adjust the resource usage in a struct statvfs based on
609121be23bSjkennedy  * what's in the delete queue.
6107c478bd9Sstevel@tonic-gate  *
6117c478bd9Sstevel@tonic-gate  * We do not consider the impact of ACLs or extended attributes
6127c478bd9Sstevel@tonic-gate  * that may be deleted as a side-effect of deleting a file.
6137c478bd9Sstevel@tonic-gate  * Those are metadata, and their sizes aren't reflected in the
6147c478bd9Sstevel@tonic-gate  * sizes returned by stat(), so this is not a problem.
6157c478bd9Sstevel@tonic-gate  */
6167c478bd9Sstevel@tonic-gate void
ufs_delete_adjust_stats(struct ufsvfs * ufsvfsp,struct statvfs64 * sp)6177c478bd9Sstevel@tonic-gate ufs_delete_adjust_stats(struct ufsvfs *ufsvfsp, struct statvfs64 *sp)
6187c478bd9Sstevel@tonic-gate {
6197c478bd9Sstevel@tonic-gate 	struct ufs_q *uq = &ufsvfsp->vfs_delete;
620121be23bSjkennedy 	struct ufs_delq_info *delq_info = &ufsvfsp->vfs_delete_info;
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	mutex_enter(&uq->uq_mutex);
62320a1ae8aSjkennedy 	/*
62420a1ae8aSjkennedy 	 * The blocks accounted for in the delete queue info are
62520a1ae8aSjkennedy 	 * counted in DEV_BSIZE chunks, but ufs_statvfs counts in
62620a1ae8aSjkennedy 	 * filesystem fragments, so a conversion is required here.
62720a1ae8aSjkennedy 	 */
62820a1ae8aSjkennedy 	sp->f_bfree += dbtofsb(ufsvfsp->vfs_fs,
62920a1ae8aSjkennedy 	    delq_info->delq_unreclaimed_blocks);
630121be23bSjkennedy 	sp->f_ffree += delq_info->delq_unreclaimed_files;
6317c478bd9Sstevel@tonic-gate 	mutex_exit(&uq->uq_mutex);
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate /*
6357c478bd9Sstevel@tonic-gate  * IDLE INODE
6367c478bd9Sstevel@tonic-gate  * The following routines implement the protocol for maintaining an
6377c478bd9Sstevel@tonic-gate  * LRU list of idle inodes and for moving the idle inodes to the
6387c478bd9Sstevel@tonic-gate  * reuse list when the number of allocated inodes exceeds the user
6397c478bd9Sstevel@tonic-gate  * tunable high-water mark (ufs_ninode).
6407c478bd9Sstevel@tonic-gate  */
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate /*
6437c478bd9Sstevel@tonic-gate  * clean an idle inode and move it to the reuse list
6447c478bd9Sstevel@tonic-gate  */
6457c478bd9Sstevel@tonic-gate static void
ufs_idle_free(struct inode * ip)6467c478bd9Sstevel@tonic-gate ufs_idle_free(struct inode *ip)
6477c478bd9Sstevel@tonic-gate {
6487c478bd9Sstevel@tonic-gate 	int			pages;
6497c478bd9Sstevel@tonic-gate 	int			hno;
6507c478bd9Sstevel@tonic-gate 	kmutex_t		*ihm;
6517c478bd9Sstevel@tonic-gate 	struct ufsvfs		*ufsvfsp	= ip->i_ufsvfs;
6527c478bd9Sstevel@tonic-gate 	struct vnode		*vp		= ITOV(ip);
653b7deb15bSWolfgang Schremser 	int			vn_has_data, vn_modified;
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	/*
6567c478bd9Sstevel@tonic-gate 	 * inode is held
6577c478bd9Sstevel@tonic-gate 	 */
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 	/*
6607c478bd9Sstevel@tonic-gate 	 * remember `pages' for stats below
6617c478bd9Sstevel@tonic-gate 	 */
6627c478bd9Sstevel@tonic-gate 	pages = (ip->i_mode && vn_has_cached_data(vp) && vp->v_type != VCHR);
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	/*
6657c478bd9Sstevel@tonic-gate 	 * start the dirty pages to disk and then invalidate them
6667c478bd9Sstevel@tonic-gate 	 * unless the inode is invalid (ISTALE)
6677c478bd9Sstevel@tonic-gate 	 */
6687c478bd9Sstevel@tonic-gate 	if ((ip->i_flag & ISTALE) == 0) {
6697c478bd9Sstevel@tonic-gate 		(void) TRANS_SYNCIP(ip, B_ASYNC, I_ASYNC, TOP_SYNCIP_FREE);
6707c478bd9Sstevel@tonic-gate 		(void) TRANS_SYNCIP(ip,
67180d34432Sfrankho 		    (TRANS_ISERROR(ufsvfsp)) ? B_INVAL | B_FORCE : B_INVAL,
67280d34432Sfrankho 		    I_ASYNC, TOP_SYNCIP_FREE);
6737c478bd9Sstevel@tonic-gate 	}
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	/*
6767c478bd9Sstevel@tonic-gate 	 * wait for any current ufs_iget to finish and block future ufs_igets
6777c478bd9Sstevel@tonic-gate 	 */
6787c478bd9Sstevel@tonic-gate 	ASSERT(ip->i_number != 0);
6797c478bd9Sstevel@tonic-gate 	hno = INOHASH(ip->i_number);
6807c478bd9Sstevel@tonic-gate 	ihm = &ih_lock[hno];
6817c478bd9Sstevel@tonic-gate 	mutex_enter(ihm);
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	/*
6847c478bd9Sstevel@tonic-gate 	 * It must be guaranteed that v_count >= 2, otherwise
6857c478bd9Sstevel@tonic-gate 	 * something must be wrong with this vnode already.
686ade42b55SSebastien Roy 	 * That is why we use VN_RELE_LOCKED() instead of VN_RELE().
6877c478bd9Sstevel@tonic-gate 	 * Acquire the vnode lock in case another thread is in
6887c478bd9Sstevel@tonic-gate 	 * VN_RELE().
6897c478bd9Sstevel@tonic-gate 	 */
6907c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
6917c478bd9Sstevel@tonic-gate 
692*7da74b76SPrakash Surya 	VERIFY3U(vp->v_count, >=, 2);
6937c478bd9Sstevel@tonic-gate 
694ade42b55SSebastien Roy 	VN_RELE_LOCKED(vp);
695b7deb15bSWolfgang Schremser 
696b7deb15bSWolfgang Schremser 	vn_has_data = (vp->v_type != VCHR && vn_has_cached_data(vp));
697b7deb15bSWolfgang Schremser 	vn_modified = (ip->i_flag & (IMOD|IMODACC|IACC|ICHG|IUPD|IATTCHG));
698b7deb15bSWolfgang Schremser 
699b7deb15bSWolfgang Schremser 	if (vp->v_count != 1 ||
700b7deb15bSWolfgang Schremser 	    ((vn_has_data || vn_modified) &&
701b7deb15bSWolfgang Schremser 	    ((ip->i_flag & ISTALE) == 0))) {
70280d34432Sfrankho 		/*
70380d34432Sfrankho 		 * Another thread has referenced this inode while
704b7deb15bSWolfgang Schremser 		 * we are trying  to free  it.  Call VN_RELE() to
705b7deb15bSWolfgang Schremser 		 * release our reference, if v_count > 1  data is
706b7deb15bSWolfgang Schremser 		 * present  or one of the modified etc. flags was
707b7deb15bSWolfgang Schremser 		 * set, whereby ISTALE wasn't set.
708b7deb15bSWolfgang Schremser 		 * If we'd proceed with ISTALE set here, we might
709b7deb15bSWolfgang Schremser 		 * get ourselves into a deadlock situation.
71080d34432Sfrankho 		 */
71180d34432Sfrankho 		mutex_exit(&vp->v_lock);
71280d34432Sfrankho 		mutex_exit(ihm);
71380d34432Sfrankho 		VN_RELE(vp);
7147c478bd9Sstevel@tonic-gate 	} else {
7157c478bd9Sstevel@tonic-gate 		/*
7167c478bd9Sstevel@tonic-gate 		 * The inode is currently unreferenced and can not
7177c478bd9Sstevel@tonic-gate 		 * acquire further references because it has no pages
7187c478bd9Sstevel@tonic-gate 		 * and the hash is locked.  Inodes acquire references
7197c478bd9Sstevel@tonic-gate 		 * via the hash list or via their pages.
7207c478bd9Sstevel@tonic-gate 		 */
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 		/*
7257c478bd9Sstevel@tonic-gate 		 * remove it from the cache
7267c478bd9Sstevel@tonic-gate 		 */
7277c478bd9Sstevel@tonic-gate 		remque(ip);
7287c478bd9Sstevel@tonic-gate 		mutex_exit(ihm);
7297c478bd9Sstevel@tonic-gate 		/*
7307c478bd9Sstevel@tonic-gate 		 * Stale inodes have no valid ufsvfs
7317c478bd9Sstevel@tonic-gate 		 */
7327c478bd9Sstevel@tonic-gate 		if ((ip->i_flag & ISTALE) == 0 && ip->i_dquot) {
7337c478bd9Sstevel@tonic-gate 			TRANS_DQRELE(ufsvfsp, ip->i_dquot);
7347c478bd9Sstevel@tonic-gate 			ip->i_dquot = NULL;
7357c478bd9Sstevel@tonic-gate 		}
736b7deb15bSWolfgang Schremser 		if ((ip->i_flag & ISTALE) &&
737b7deb15bSWolfgang Schremser 		    vn_has_data) {
738b7deb15bSWolfgang Schremser 			/*
739b7deb15bSWolfgang Schremser 			 * ISTALE inodes may have data
740b7deb15bSWolfgang Schremser 			 * and  this data needs  to be
741b7deb15bSWolfgang Schremser 			 * cleaned up.
742b7deb15bSWolfgang Schremser 			 */
743b7deb15bSWolfgang Schremser 			(void) pvn_vplist_dirty(vp, (u_offset_t)0,
744b7deb15bSWolfgang Schremser 			    ufs_putapage, B_INVAL | B_TRUNC,
745b7deb15bSWolfgang Schremser 			    (struct cred *)NULL);
746b7deb15bSWolfgang Schremser 		}
7477c478bd9Sstevel@tonic-gate 		ufs_si_del(ip);
7487c478bd9Sstevel@tonic-gate 		if (pages) {
7497c478bd9Sstevel@tonic-gate 			CPU_STATS_ADDQ(CPU, sys, ufsipage, 1);
7507c478bd9Sstevel@tonic-gate 		} else {
7517c478bd9Sstevel@tonic-gate 			CPU_STATS_ADDQ(CPU, sys, ufsinopage, 1);
7527c478bd9Sstevel@tonic-gate 		}
7537c478bd9Sstevel@tonic-gate 		ASSERT((vp->v_type == VCHR) || !vn_has_cached_data(vp));
7545bde59abSbatschul 
7555bde59abSbatschul 		/*
7565bde59abSbatschul 		 * We had better not have a vnode reference count > 1
7575bde59abSbatschul 		 * at this point, if we do then something is broken as
7585bde59abSbatschul 		 * this inode/vnode acquired a reference underneath of us.
7595bde59abSbatschul 		 */
7605bde59abSbatschul 		ASSERT(vp->v_count == 1);
7615bde59abSbatschul 
7627c478bd9Sstevel@tonic-gate 		ufs_free_inode(ip);
7637c478bd9Sstevel@tonic-gate 	}
7647c478bd9Sstevel@tonic-gate }
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate /*
7677c478bd9Sstevel@tonic-gate  * this thread processes the global idle queue
7687c478bd9Sstevel@tonic-gate  */
7697c478bd9Sstevel@tonic-gate iqhead_t *ufs_junk_iq;
7707c478bd9Sstevel@tonic-gate iqhead_t *ufs_useful_iq;
7717c478bd9Sstevel@tonic-gate int ufs_njunk_iq = 0;
7727c478bd9Sstevel@tonic-gate int ufs_nuseful_iq = 0;
7737c478bd9Sstevel@tonic-gate int ufs_niqhash;
7747c478bd9Sstevel@tonic-gate int ufs_iqhashmask;
7757c478bd9Sstevel@tonic-gate struct ufs_q	ufs_idle_q;
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate void
ufs_thread_idle(void)7787c478bd9Sstevel@tonic-gate ufs_thread_idle(void)
7797c478bd9Sstevel@tonic-gate {
7807c478bd9Sstevel@tonic-gate 	callb_cpr_t cprinfo;
7817c478bd9Sstevel@tonic-gate 	int i;
7827c478bd9Sstevel@tonic-gate 	int ne;
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 	ufs_niqhash = (ufs_idle_q.uq_lowat >> 1) / IQHASHQLEN;
7857c478bd9Sstevel@tonic-gate 	ufs_niqhash = 1 << highbit(ufs_niqhash); /* round up to power of 2 */
7867c478bd9Sstevel@tonic-gate 	ufs_iqhashmask = ufs_niqhash - 1;
7877c478bd9Sstevel@tonic-gate 	ufs_junk_iq = kmem_alloc(ufs_niqhash * sizeof (*ufs_junk_iq),
7887c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
7897c478bd9Sstevel@tonic-gate 	ufs_useful_iq = kmem_alloc(ufs_niqhash * sizeof (*ufs_useful_iq),
7907c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	/* Initialize hash queue headers */
7937c478bd9Sstevel@tonic-gate 	for (i = 0; i < ufs_niqhash; i++) {
7947c478bd9Sstevel@tonic-gate 		ufs_junk_iq[i].i_freef = (inode_t *)&ufs_junk_iq[i];
7957c478bd9Sstevel@tonic-gate 		ufs_junk_iq[i].i_freeb = (inode_t *)&ufs_junk_iq[i];
7967c478bd9Sstevel@tonic-gate 		ufs_useful_iq[i].i_freef = (inode_t *)&ufs_useful_iq[i];
7977c478bd9Sstevel@tonic-gate 		ufs_useful_iq[i].i_freeb = (inode_t *)&ufs_useful_iq[i];
7987c478bd9Sstevel@tonic-gate 	}
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &ufs_idle_q.uq_mutex, callb_generic_cpr,
8017c478bd9Sstevel@tonic-gate 	    "ufsidle");
8027c478bd9Sstevel@tonic-gate again:
8037c478bd9Sstevel@tonic-gate 	/*
8047c478bd9Sstevel@tonic-gate 	 * Whenever the idle thread is awakened, it repeatedly gives
8057c478bd9Sstevel@tonic-gate 	 * back half of the idle queue until the idle queue falls
8067c478bd9Sstevel@tonic-gate 	 * below lowat.
8077c478bd9Sstevel@tonic-gate 	 */
8087c478bd9Sstevel@tonic-gate 	mutex_enter(&ufs_idle_q.uq_mutex);
8097c478bd9Sstevel@tonic-gate 	if (ufs_idle_q.uq_ne < ufs_idle_q.uq_lowat) {
8107c478bd9Sstevel@tonic-gate 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
8117c478bd9Sstevel@tonic-gate 		cv_wait(&ufs_idle_q.uq_cv, &ufs_idle_q.uq_mutex);
8127c478bd9Sstevel@tonic-gate 		CALLB_CPR_SAFE_END(&cprinfo, &ufs_idle_q.uq_mutex);
8137c478bd9Sstevel@tonic-gate 	}
8147c478bd9Sstevel@tonic-gate 	mutex_exit(&ufs_idle_q.uq_mutex);
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 	/*
8177c478bd9Sstevel@tonic-gate 	 * Give back 1/2 of the idle queue
8187c478bd9Sstevel@tonic-gate 	 */
8197c478bd9Sstevel@tonic-gate 	ne = ufs_idle_q.uq_ne >> 1;
8207c478bd9Sstevel@tonic-gate 	ins.in_tidles.value.ul += ne;
8217c478bd9Sstevel@tonic-gate 	ufs_idle_some(ne);
8227c478bd9Sstevel@tonic-gate 	goto again;
8237c478bd9Sstevel@tonic-gate }
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate /*
8267c478bd9Sstevel@tonic-gate  * Reclaim callback for ufs inode cache.
8277c478bd9Sstevel@tonic-gate  * Invoked by the kernel memory allocator when memory gets tight.
8287c478bd9Sstevel@tonic-gate  */
8297c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8307c478bd9Sstevel@tonic-gate void
ufs_inode_cache_reclaim(void * cdrarg)8317c478bd9Sstevel@tonic-gate ufs_inode_cache_reclaim(void *cdrarg)
8327c478bd9Sstevel@tonic-gate {
8337c478bd9Sstevel@tonic-gate 	/*
8347c478bd9Sstevel@tonic-gate 	 * If we are low on memory and the idle queue is over its
8357c478bd9Sstevel@tonic-gate 	 * halfway mark, then free 50% of the idle q
8367c478bd9Sstevel@tonic-gate 	 *
8377c478bd9Sstevel@tonic-gate 	 * We don't free all of the idle inodes because the inodes
8387c478bd9Sstevel@tonic-gate 	 * for popular NFS files may have been kicked from the dnlc.
8397c478bd9Sstevel@tonic-gate 	 * The inodes for these files will end up on the idle queue
8407c478bd9Sstevel@tonic-gate 	 * after every NFS access.
8417c478bd9Sstevel@tonic-gate 	 *
8427c478bd9Sstevel@tonic-gate 	 * If we repeatedly push them from the idle queue then
8437c478bd9Sstevel@tonic-gate 	 * NFS users may be unhappy as an extra buf cache operation
8447c478bd9Sstevel@tonic-gate 	 * is incurred for every NFS operation to these files.
8457c478bd9Sstevel@tonic-gate 	 *
8467c478bd9Sstevel@tonic-gate 	 * It's not common, but I have seen it happen.
8477c478bd9Sstevel@tonic-gate 	 *
8487c478bd9Sstevel@tonic-gate 	 */
8497c478bd9Sstevel@tonic-gate 	if (ufs_idle_q.uq_ne < (ufs_idle_q.uq_lowat >> 1))
8507c478bd9Sstevel@tonic-gate 		return;
8517c478bd9Sstevel@tonic-gate 	mutex_enter(&ufs_idle_q.uq_mutex);
8527c478bd9Sstevel@tonic-gate 	cv_broadcast(&ufs_idle_q.uq_cv);
8537c478bd9Sstevel@tonic-gate 	mutex_exit(&ufs_idle_q.uq_mutex);
8547c478bd9Sstevel@tonic-gate }
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate /*
8577c478bd9Sstevel@tonic-gate  * Free up some idle inodes
8587c478bd9Sstevel@tonic-gate  */
8597c478bd9Sstevel@tonic-gate void
ufs_idle_some(int ne)8607c478bd9Sstevel@tonic-gate ufs_idle_some(int ne)
8617c478bd9Sstevel@tonic-gate {
8627c478bd9Sstevel@tonic-gate 	int i;
8637c478bd9Sstevel@tonic-gate 	struct inode *ip;
8647c478bd9Sstevel@tonic-gate 	struct vnode *vp;
8657c478bd9Sstevel@tonic-gate 	static int junk_rotor = 0;
8667c478bd9Sstevel@tonic-gate 	static int useful_rotor = 0;
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	for (i = 0; i < ne; ++i) {
8697c478bd9Sstevel@tonic-gate 		mutex_enter(&ufs_idle_q.uq_mutex);
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 		if (ufs_njunk_iq) {
8727c478bd9Sstevel@tonic-gate 			while (ufs_junk_iq[junk_rotor].i_freef ==
8737c478bd9Sstevel@tonic-gate 			    (inode_t *)&ufs_junk_iq[junk_rotor]) {
8747c478bd9Sstevel@tonic-gate 				junk_rotor = IQNEXT(junk_rotor);
8757c478bd9Sstevel@tonic-gate 			}
8767c478bd9Sstevel@tonic-gate 			ip = ufs_junk_iq[junk_rotor].i_freef;
8777c478bd9Sstevel@tonic-gate 			ASSERT(ip->i_flag & IJUNKIQ);
8787c478bd9Sstevel@tonic-gate 		} else if (ufs_nuseful_iq) {
8797c478bd9Sstevel@tonic-gate 			while (ufs_useful_iq[useful_rotor].i_freef ==
8807c478bd9Sstevel@tonic-gate 			    (inode_t *)&ufs_useful_iq[useful_rotor]) {
8817c478bd9Sstevel@tonic-gate 				useful_rotor = IQNEXT(useful_rotor);
8827c478bd9Sstevel@tonic-gate 			}
8837c478bd9Sstevel@tonic-gate 			ip = ufs_useful_iq[useful_rotor].i_freef;
8847c478bd9Sstevel@tonic-gate 			ASSERT(!(ip->i_flag & IJUNKIQ));
8857c478bd9Sstevel@tonic-gate 		} else {
8867c478bd9Sstevel@tonic-gate 			mutex_exit(&ufs_idle_q.uq_mutex);
8877c478bd9Sstevel@tonic-gate 			return;
8887c478bd9Sstevel@tonic-gate 		}
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 		/*
8917c478bd9Sstevel@tonic-gate 		 * emulate ufs_iget
8927c478bd9Sstevel@tonic-gate 		 */
8937c478bd9Sstevel@tonic-gate 		vp = ITOV(ip);
8947c478bd9Sstevel@tonic-gate 		VN_HOLD(vp);
8957c478bd9Sstevel@tonic-gate 		mutex_exit(&ufs_idle_q.uq_mutex);
8967c478bd9Sstevel@tonic-gate 		rw_enter(&ip->i_contents, RW_WRITER);
8977c478bd9Sstevel@tonic-gate 		/*
8987c478bd9Sstevel@tonic-gate 		 * VN_RELE should not be called if
8997c478bd9Sstevel@tonic-gate 		 * ufs_rmidle returns true, as it will
9007c478bd9Sstevel@tonic-gate 		 * effectively be done in ufs_idle_free.
9017c478bd9Sstevel@tonic-gate 		 */
9027c478bd9Sstevel@tonic-gate 		if (ufs_rmidle(ip)) {
9037c478bd9Sstevel@tonic-gate 			rw_exit(&ip->i_contents);
9047c478bd9Sstevel@tonic-gate 			ufs_idle_free(ip);
9057c478bd9Sstevel@tonic-gate 		} else {
9067c478bd9Sstevel@tonic-gate 			rw_exit(&ip->i_contents);
9077c478bd9Sstevel@tonic-gate 			VN_RELE(vp);
9087c478bd9Sstevel@tonic-gate 		}
9097c478bd9Sstevel@tonic-gate 	}
9107c478bd9Sstevel@tonic-gate }
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate /*
9137c478bd9Sstevel@tonic-gate  * drain entries for vfsp from the idle queue
9147c478bd9Sstevel@tonic-gate  * vfsp == NULL means drain the entire thing
9157c478bd9Sstevel@tonic-gate  */
9167c478bd9Sstevel@tonic-gate void
ufs_idle_drain(struct vfs * vfsp)9177c478bd9Sstevel@tonic-gate ufs_idle_drain(struct vfs *vfsp)
9187c478bd9Sstevel@tonic-gate {
9197c478bd9Sstevel@tonic-gate 	struct inode	*ip, *nip;
9207c478bd9Sstevel@tonic-gate 	struct inode	*ianchor = NULL;
9217c478bd9Sstevel@tonic-gate 	int		i;
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 	mutex_enter(&ufs_idle_q.uq_mutex);
9247c478bd9Sstevel@tonic-gate 	if (ufs_njunk_iq) {
9257c478bd9Sstevel@tonic-gate 		/* for each hash q */
9267c478bd9Sstevel@tonic-gate 		for (i = 0; i < ufs_niqhash; i++) {
9277c478bd9Sstevel@tonic-gate 			/* search down the hash q */
9287c478bd9Sstevel@tonic-gate 			for (ip = ufs_junk_iq[i].i_freef;
9297c478bd9Sstevel@tonic-gate 			    ip != (inode_t *)&ufs_junk_iq[i];
9307c478bd9Sstevel@tonic-gate 			    ip = ip->i_freef) {
9317c478bd9Sstevel@tonic-gate 				if (ip->i_vfs == vfsp || vfsp == NULL) {
9327c478bd9Sstevel@tonic-gate 					/* found a matching entry */
9337c478bd9Sstevel@tonic-gate 					VN_HOLD(ITOV(ip));
9347c478bd9Sstevel@tonic-gate 					mutex_exit(&ufs_idle_q.uq_mutex);
9357c478bd9Sstevel@tonic-gate 					rw_enter(&ip->i_contents, RW_WRITER);
9367c478bd9Sstevel@tonic-gate 					/*
9377c478bd9Sstevel@tonic-gate 					 * See comments in ufs_idle_some()
9387c478bd9Sstevel@tonic-gate 					 * as we will call ufs_idle_free()
9397c478bd9Sstevel@tonic-gate 					 * after scanning both queues.
9407c478bd9Sstevel@tonic-gate 					 */
9417c478bd9Sstevel@tonic-gate 					if (ufs_rmidle(ip)) {
9427c478bd9Sstevel@tonic-gate 						rw_exit(&ip->i_contents);
9437c478bd9Sstevel@tonic-gate 						ip->i_freef = ianchor;
9447c478bd9Sstevel@tonic-gate 						ianchor = ip;
9457c478bd9Sstevel@tonic-gate 					} else {
9467c478bd9Sstevel@tonic-gate 						rw_exit(&ip->i_contents);
9477c478bd9Sstevel@tonic-gate 						VN_RELE(ITOV(ip));
9487c478bd9Sstevel@tonic-gate 					}
9497c478bd9Sstevel@tonic-gate 					/* restart this hash q */
9507c478bd9Sstevel@tonic-gate 					ip = (inode_t *)&ufs_junk_iq[i];
9517c478bd9Sstevel@tonic-gate 					mutex_enter(&ufs_idle_q.uq_mutex);
9527c478bd9Sstevel@tonic-gate 				}
9537c478bd9Sstevel@tonic-gate 			}
9547c478bd9Sstevel@tonic-gate 		}
9557c478bd9Sstevel@tonic-gate 	}
9567c478bd9Sstevel@tonic-gate 	if (ufs_nuseful_iq) {
9577c478bd9Sstevel@tonic-gate 		/* for each hash q */
9587c478bd9Sstevel@tonic-gate 		for (i = 0; i < ufs_niqhash; i++) {
9597c478bd9Sstevel@tonic-gate 			/* search down the hash q */
9607c478bd9Sstevel@tonic-gate 			for (ip = ufs_useful_iq[i].i_freef;
9617c478bd9Sstevel@tonic-gate 			    ip != (inode_t *)&ufs_useful_iq[i];
9627c478bd9Sstevel@tonic-gate 			    ip = ip->i_freef) {
9637c478bd9Sstevel@tonic-gate 				if (ip->i_vfs == vfsp || vfsp == NULL) {
9647c478bd9Sstevel@tonic-gate 					/* found a matching entry */
9657c478bd9Sstevel@tonic-gate 					VN_HOLD(ITOV(ip));
9667c478bd9Sstevel@tonic-gate 					mutex_exit(&ufs_idle_q.uq_mutex);
9677c478bd9Sstevel@tonic-gate 					rw_enter(&ip->i_contents, RW_WRITER);
9687c478bd9Sstevel@tonic-gate 					/*
9697c478bd9Sstevel@tonic-gate 					 * See comments in ufs_idle_some()
9707c478bd9Sstevel@tonic-gate 					 * as we will call ufs_idle_free()
9717c478bd9Sstevel@tonic-gate 					 * after scanning both queues.
9727c478bd9Sstevel@tonic-gate 					 */
9737c478bd9Sstevel@tonic-gate 					if (ufs_rmidle(ip)) {
9747c478bd9Sstevel@tonic-gate 						rw_exit(&ip->i_contents);
9757c478bd9Sstevel@tonic-gate 						ip->i_freef = ianchor;
9767c478bd9Sstevel@tonic-gate 						ianchor = ip;
9777c478bd9Sstevel@tonic-gate 					} else {
9787c478bd9Sstevel@tonic-gate 						rw_exit(&ip->i_contents);
9797c478bd9Sstevel@tonic-gate 						VN_RELE(ITOV(ip));
9807c478bd9Sstevel@tonic-gate 					}
9817c478bd9Sstevel@tonic-gate 					/* restart this hash q */
9827c478bd9Sstevel@tonic-gate 					ip = (inode_t *)&ufs_useful_iq[i];
9837c478bd9Sstevel@tonic-gate 					mutex_enter(&ufs_idle_q.uq_mutex);
9847c478bd9Sstevel@tonic-gate 				}
9857c478bd9Sstevel@tonic-gate 			}
9867c478bd9Sstevel@tonic-gate 		}
9877c478bd9Sstevel@tonic-gate 	}
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 	mutex_exit(&ufs_idle_q.uq_mutex);
9907c478bd9Sstevel@tonic-gate 	/* no more matching entries, release those we have found (if any) */
9917c478bd9Sstevel@tonic-gate 	for (ip = ianchor; ip; ip = nip) {
9927c478bd9Sstevel@tonic-gate 		nip = ip->i_freef;
9937c478bd9Sstevel@tonic-gate 		ip->i_freef = ip;
9947c478bd9Sstevel@tonic-gate 		ufs_idle_free(ip);
9957c478bd9Sstevel@tonic-gate 	}
9967c478bd9Sstevel@tonic-gate }
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate /*
9997c478bd9Sstevel@tonic-gate  * RECLAIM DELETED INODES
10007c478bd9Sstevel@tonic-gate  * The following thread scans the file system once looking for deleted files
10017c478bd9Sstevel@tonic-gate  */
10027c478bd9Sstevel@tonic-gate void
ufs_thread_reclaim(struct vfs * vfsp)10037c478bd9Sstevel@tonic-gate ufs_thread_reclaim(struct vfs *vfsp)
10047c478bd9Sstevel@tonic-gate {
10057c478bd9Sstevel@tonic-gate 	struct ufsvfs		*ufsvfsp = (struct ufsvfs *)vfsp->vfs_data;
10067c478bd9Sstevel@tonic-gate 	struct ufs_q		*uq	= &ufsvfsp->vfs_reclaim;
10077c478bd9Sstevel@tonic-gate 	struct fs		*fs	= ufsvfsp->vfs_fs;
10087c478bd9Sstevel@tonic-gate 	struct buf		*bp	= 0;
10097c478bd9Sstevel@tonic-gate 	int			err	= 0;
10107c478bd9Sstevel@tonic-gate 	daddr_t			bno;
10117c478bd9Sstevel@tonic-gate 	ino_t			ino;
10127c478bd9Sstevel@tonic-gate 	struct dinode		*dp;
10137c478bd9Sstevel@tonic-gate 	struct inode		*ip;
10147c478bd9Sstevel@tonic-gate 	callb_cpr_t		cprinfo;
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &uq->uq_mutex, callb_generic_cpr,
10177c478bd9Sstevel@tonic-gate 	    "ufsreclaim");
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 	/*
10207c478bd9Sstevel@tonic-gate 	 * mount decided that we don't need a reclaim thread
10217c478bd9Sstevel@tonic-gate 	 */
10227c478bd9Sstevel@tonic-gate 	if ((fs->fs_reclaim & FS_RECLAIMING) == 0)
10237c478bd9Sstevel@tonic-gate 		err++;
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 	/*
10267c478bd9Sstevel@tonic-gate 	 * don't reclaim if readonly
10277c478bd9Sstevel@tonic-gate 	 */
10287c478bd9Sstevel@tonic-gate 	if (fs->fs_ronly)
10297c478bd9Sstevel@tonic-gate 		err++;
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 	for (ino = 0; ino < (fs->fs_ncg * fs->fs_ipg) && !err; ++ino) {
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 		/*
10347c478bd9Sstevel@tonic-gate 		 * Check whether we are the target of another
10357c478bd9Sstevel@tonic-gate 		 * thread having called ufs_thread_exit() or
10367c478bd9Sstevel@tonic-gate 		 * ufs_thread_suspend().
10377c478bd9Sstevel@tonic-gate 		 */
10387c478bd9Sstevel@tonic-gate 		mutex_enter(&uq->uq_mutex);
10397c478bd9Sstevel@tonic-gate again:
10407c478bd9Sstevel@tonic-gate 		if (uq->uq_flags & UQ_EXIT) {
10417c478bd9Sstevel@tonic-gate 			err++;
10427c478bd9Sstevel@tonic-gate 			mutex_exit(&uq->uq_mutex);
10437c478bd9Sstevel@tonic-gate 			break;
10447c478bd9Sstevel@tonic-gate 		} else if (uq->uq_flags & UQ_SUSPEND) {
10457c478bd9Sstevel@tonic-gate 			uq->uq_flags |= UQ_SUSPENDED;
10467c478bd9Sstevel@tonic-gate 			/*
10477c478bd9Sstevel@tonic-gate 			 * Release the buf before we cv_wait()
10487c478bd9Sstevel@tonic-gate 			 * otherwise we may deadlock with the
10497c478bd9Sstevel@tonic-gate 			 * thread that called ufs_thread_suspend().
10507c478bd9Sstevel@tonic-gate 			 */
10517c478bd9Sstevel@tonic-gate 			if (bp) {
10527c478bd9Sstevel@tonic-gate 				brelse(bp);
10537c478bd9Sstevel@tonic-gate 				bp = 0;
10547c478bd9Sstevel@tonic-gate 			}
10557c478bd9Sstevel@tonic-gate 			if (uq->uq_flags & UQ_WAIT) {
10567c478bd9Sstevel@tonic-gate 				uq->uq_flags &= ~UQ_WAIT;
10577c478bd9Sstevel@tonic-gate 				cv_broadcast(&uq->uq_cv);
10587c478bd9Sstevel@tonic-gate 			}
10597c478bd9Sstevel@tonic-gate 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
10607c478bd9Sstevel@tonic-gate 			cv_wait(&uq->uq_cv, &uq->uq_mutex);
10617c478bd9Sstevel@tonic-gate 			CALLB_CPR_SAFE_END(&cprinfo, &uq->uq_mutex);
10627c478bd9Sstevel@tonic-gate 			goto again;
10637c478bd9Sstevel@tonic-gate 		}
10647c478bd9Sstevel@tonic-gate 		mutex_exit(&uq->uq_mutex);
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 		/*
10677c478bd9Sstevel@tonic-gate 		 * if we don't already have the buf; get it
10687c478bd9Sstevel@tonic-gate 		 */
10697c478bd9Sstevel@tonic-gate 		bno = fsbtodb(fs, itod(fs, ino));
10707c478bd9Sstevel@tonic-gate 		if ((bp == 0) || (bp->b_blkno != bno)) {
10717c478bd9Sstevel@tonic-gate 			if (bp)
10727c478bd9Sstevel@tonic-gate 				brelse(bp);
10737c478bd9Sstevel@tonic-gate 			bp = UFS_BREAD(ufsvfsp,
107480d34432Sfrankho 			    ufsvfsp->vfs_dev, bno, fs->fs_bsize);
10757c478bd9Sstevel@tonic-gate 			bp->b_flags |= B_AGE;
10767c478bd9Sstevel@tonic-gate 		}
10777c478bd9Sstevel@tonic-gate 		if (bp->b_flags & B_ERROR) {
10787c478bd9Sstevel@tonic-gate 			err++;
10797c478bd9Sstevel@tonic-gate 			continue;
10807c478bd9Sstevel@tonic-gate 		}
10817c478bd9Sstevel@tonic-gate 		/*
10827c478bd9Sstevel@tonic-gate 		 * nlink <= 0 and mode != 0 means deleted
10837c478bd9Sstevel@tonic-gate 		 */
10847c478bd9Sstevel@tonic-gate 		dp = (struct dinode *)bp->b_un.b_addr + itoo(fs, ino);
10857c478bd9Sstevel@tonic-gate 		if ((dp->di_nlink <= 0) && (dp->di_mode != 0)) {
10867c478bd9Sstevel@tonic-gate 			/*
10877c478bd9Sstevel@tonic-gate 			 * can't hold the buf (deadlock)
10887c478bd9Sstevel@tonic-gate 			 */
10897c478bd9Sstevel@tonic-gate 			brelse(bp);
10907c478bd9Sstevel@tonic-gate 			bp = 0;
10917c478bd9Sstevel@tonic-gate 			rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER);
10927c478bd9Sstevel@tonic-gate 			/*
10937c478bd9Sstevel@tonic-gate 			 * iget/iput sequence will put inode on ifree
10947c478bd9Sstevel@tonic-gate 			 * thread queue if it is idle.  This is a nop
10957c478bd9Sstevel@tonic-gate 			 * for busy (open, deleted) inodes
10967c478bd9Sstevel@tonic-gate 			 */
10977c478bd9Sstevel@tonic-gate 			if (ufs_iget(vfsp, ino, &ip, CRED()))
10987c478bd9Sstevel@tonic-gate 				err++;
10997c478bd9Sstevel@tonic-gate 			else
11007c478bd9Sstevel@tonic-gate 				VN_RELE(ITOV(ip));
11017c478bd9Sstevel@tonic-gate 			rw_exit(&ufsvfsp->vfs_dqrwlock);
11027c478bd9Sstevel@tonic-gate 		}
11037c478bd9Sstevel@tonic-gate 	}
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 	if (bp)
11067c478bd9Sstevel@tonic-gate 		brelse(bp);
11077c478bd9Sstevel@tonic-gate 	if (!err) {
11087c478bd9Sstevel@tonic-gate 		/*
11097c478bd9Sstevel@tonic-gate 		 * reset the reclaiming-bit
11107c478bd9Sstevel@tonic-gate 		 */
11117c478bd9Sstevel@tonic-gate 		mutex_enter(&ufsvfsp->vfs_lock);
11127c478bd9Sstevel@tonic-gate 		fs->fs_reclaim &= ~FS_RECLAIMING;
11137c478bd9Sstevel@tonic-gate 		mutex_exit(&ufsvfsp->vfs_lock);
11147c478bd9Sstevel@tonic-gate 		TRANS_SBWRITE(ufsvfsp, TOP_SBWRITE_RECLAIM);
11157c478bd9Sstevel@tonic-gate 	}
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 	/*
11187c478bd9Sstevel@tonic-gate 	 * exit the reclaim thread
11197c478bd9Sstevel@tonic-gate 	 */
11207c478bd9Sstevel@tonic-gate 	mutex_enter(&uq->uq_mutex);
11217c478bd9Sstevel@tonic-gate 	uq->uq_threadp = NULL;
11227c478bd9Sstevel@tonic-gate 	uq->uq_flags &= ~UQ_WAIT;
11237c478bd9Sstevel@tonic-gate 	cv_broadcast(&uq->uq_cv);
11247c478bd9Sstevel@tonic-gate 	CALLB_CPR_EXIT(&cprinfo);
11257c478bd9Sstevel@tonic-gate 	thread_exit();
11267c478bd9Sstevel@tonic-gate }
11277c478bd9Sstevel@tonic-gate /*
11287c478bd9Sstevel@tonic-gate  * HLOCK FILE SYSTEM
11297c478bd9Sstevel@tonic-gate  *	hlock the file system's whose logs have device errors
11307c478bd9Sstevel@tonic-gate  */
11317c478bd9Sstevel@tonic-gate struct ufs_q	ufs_hlock;
11327c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11337c478bd9Sstevel@tonic-gate void
ufs_thread_hlock(void * ignore)11347c478bd9Sstevel@tonic-gate ufs_thread_hlock(void *ignore)
11357c478bd9Sstevel@tonic-gate {
11367c478bd9Sstevel@tonic-gate 	int		retry;
11377c478bd9Sstevel@tonic-gate 	callb_cpr_t	cprinfo;
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &ufs_hlock.uq_mutex, callb_generic_cpr,
11407c478bd9Sstevel@tonic-gate 	    "ufshlock");
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 	for (;;) {
11437c478bd9Sstevel@tonic-gate 		/*
11447c478bd9Sstevel@tonic-gate 		 * sleep until there is work to do
11457c478bd9Sstevel@tonic-gate 		 */
11467c478bd9Sstevel@tonic-gate 		mutex_enter(&ufs_hlock.uq_mutex);
11477c478bd9Sstevel@tonic-gate 		(void) ufs_thread_run(&ufs_hlock, &cprinfo);
11487c478bd9Sstevel@tonic-gate 		ufs_hlock.uq_ne = 0;
11497c478bd9Sstevel@tonic-gate 		mutex_exit(&ufs_hlock.uq_mutex);
11507c478bd9Sstevel@tonic-gate 		/*
11517c478bd9Sstevel@tonic-gate 		 * hlock the error'ed fs's
11527c478bd9Sstevel@tonic-gate 		 *	retry after a bit if another app is doing lockfs stuff
11537c478bd9Sstevel@tonic-gate 		 */
11547c478bd9Sstevel@tonic-gate 		do {
11557c478bd9Sstevel@tonic-gate 			retry = ufs_trans_hlock();
11567c478bd9Sstevel@tonic-gate 			if (retry) {
11577c478bd9Sstevel@tonic-gate 				mutex_enter(&ufs_hlock.uq_mutex);
11587c478bd9Sstevel@tonic-gate 				CALLB_CPR_SAFE_BEGIN(&cprinfo);
1159d3d50737SRafael Vanoni 				(void) cv_reltimedwait(&ufs_hlock.uq_cv,
1160d3d50737SRafael Vanoni 				    &ufs_hlock.uq_mutex, hz, TR_CLOCK_TICK);
11617c478bd9Sstevel@tonic-gate 				CALLB_CPR_SAFE_END(&cprinfo,
11627c478bd9Sstevel@tonic-gate 				    &ufs_hlock.uq_mutex);
11637c478bd9Sstevel@tonic-gate 				mutex_exit(&ufs_hlock.uq_mutex);
11647c478bd9Sstevel@tonic-gate 			}
11657c478bd9Sstevel@tonic-gate 		} while (retry);
11667c478bd9Sstevel@tonic-gate 	}
11677c478bd9Sstevel@tonic-gate }
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate static void
ufs_attr_purge(struct inode * dp)11707c478bd9Sstevel@tonic-gate ufs_attr_purge(struct inode *dp)
11717c478bd9Sstevel@tonic-gate {
11727c478bd9Sstevel@tonic-gate 	int	err;
11737c478bd9Sstevel@tonic-gate 	int	error;
11747c478bd9Sstevel@tonic-gate 	off_t 	dirsize;			/* size of the directory */
11757c478bd9Sstevel@tonic-gate 	off_t 	offset;	/* offset in the directory */
11767c478bd9Sstevel@tonic-gate 	int entryoffsetinblk;		/* offset of ep in fbp's buffer */
11777c478bd9Sstevel@tonic-gate 	struct inode *tp;
11787c478bd9Sstevel@tonic-gate 	struct fbuf *fbp;	/* pointer to directory block */
11797c478bd9Sstevel@tonic-gate 	struct direct *ep;	/* directory entry */
11807c478bd9Sstevel@tonic-gate 	int trans_size;
11817c478bd9Sstevel@tonic-gate 	int issync;
11827c478bd9Sstevel@tonic-gate 	struct ufsvfs	*ufsvfsp = dp->i_ufsvfs;
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 	rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER);
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 	fbp = NULL;
11877c478bd9Sstevel@tonic-gate 	dirsize = roundup(dp->i_size, DIRBLKSIZ);
11887c478bd9Sstevel@tonic-gate 	offset = 0;
11897c478bd9Sstevel@tonic-gate 	entryoffsetinblk = 0;
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 	/*
11927c478bd9Sstevel@tonic-gate 	 * Purge directory cache
11937c478bd9Sstevel@tonic-gate 	 */
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 	dnlc_dir_purge(&dp->i_danchor);
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 	while (offset < dirsize) {
11987c478bd9Sstevel@tonic-gate 		/*
11997c478bd9Sstevel@tonic-gate 		 * If offset is on a block boundary,
12007c478bd9Sstevel@tonic-gate 		 * read the next directory block.
12017c478bd9Sstevel@tonic-gate 		 * Release previous if it exists.
12027c478bd9Sstevel@tonic-gate 		 */
12037c478bd9Sstevel@tonic-gate 		if (blkoff(dp->i_fs, offset) == 0) {
12047c478bd9Sstevel@tonic-gate 			if (fbp != NULL) {
12057c478bd9Sstevel@tonic-gate 				fbrelse(fbp, S_OTHER);
12067c478bd9Sstevel@tonic-gate 			}
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate 			err = blkatoff(dp, offset, (char **)0, &fbp);
12097c478bd9Sstevel@tonic-gate 			if (err) {
12107c478bd9Sstevel@tonic-gate 				goto out;
12117c478bd9Sstevel@tonic-gate 			}
12127c478bd9Sstevel@tonic-gate 			entryoffsetinblk = 0;
12137c478bd9Sstevel@tonic-gate 		}
12147c478bd9Sstevel@tonic-gate 		ep = (struct direct *)(fbp->fb_addr + entryoffsetinblk);
12157c478bd9Sstevel@tonic-gate 		if (ep->d_ino == 0 || (ep->d_name[0] == '.' &&
12167c478bd9Sstevel@tonic-gate 		    ep->d_name[1] == '\0') ||
12177c478bd9Sstevel@tonic-gate 		    (ep->d_name[0] == '.' && ep->d_name[1] == '.' &&
12187c478bd9Sstevel@tonic-gate 		    ep->d_name[2] == '\0')) {
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate 			entryoffsetinblk += ep->d_reclen;
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 		} else {
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 			if ((err = ufs_iget(dp->i_vfs, ep->d_ino,
12257c478bd9Sstevel@tonic-gate 			    &tp, CRED())) != 0) {
12267c478bd9Sstevel@tonic-gate 				goto out;
12277c478bd9Sstevel@tonic-gate 			}
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 			TRANS_BEGIN_CSYNC(ufsvfsp, issync, TOP_REMOVE,
12307c478bd9Sstevel@tonic-gate 			    trans_size = (int)TOP_REMOVE_SIZE(tp));
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate 			/*
12337c478bd9Sstevel@tonic-gate 			 * Delete inode.
12347c478bd9Sstevel@tonic-gate 			 */
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 			dnlc_remove(ITOV(dp), ep->d_name);
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 			rw_enter(&tp->i_contents, RW_WRITER);
12397c478bd9Sstevel@tonic-gate 			tp->i_flag |= ICHG;
12407c478bd9Sstevel@tonic-gate 			tp->i_seq++;
12417c478bd9Sstevel@tonic-gate 			TRANS_INODE(tp->i_ufsvfs, tp);
12427c478bd9Sstevel@tonic-gate 			tp->i_nlink--;
12437c478bd9Sstevel@tonic-gate 			ufs_setreclaim(tp);
12447c478bd9Sstevel@tonic-gate 			ITIMES_NOLOCK(tp);
12457c478bd9Sstevel@tonic-gate 			rw_exit(&tp->i_contents);
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 			VN_RELE(ITOV(tp));
12487c478bd9Sstevel@tonic-gate 			entryoffsetinblk += ep->d_reclen;
12497c478bd9Sstevel@tonic-gate 			TRANS_END_CSYNC(ufsvfsp, error,
12507c478bd9Sstevel@tonic-gate 			    issync, TOP_REMOVE, trans_size);
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 		}
12537c478bd9Sstevel@tonic-gate 		offset += ep->d_reclen;
12547c478bd9Sstevel@tonic-gate 	}
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	if (fbp) {
12577c478bd9Sstevel@tonic-gate 		fbrelse(fbp, S_OTHER);
12587c478bd9Sstevel@tonic-gate 	}
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate out:
12617c478bd9Sstevel@tonic-gate 	rw_exit(&ufsvfsp->vfs_dqrwlock);
12627c478bd9Sstevel@tonic-gate }
1263