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 50209230bSgjelinek * Common Development and Distribution License (the "License"). 60209230bSgjelinek * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*8793b36bSNick Todd * 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 #include <sys/types.h> 277c478bd9Sstevel@tonic-gate #include <sys/param.h> 287c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 297c478bd9Sstevel@tonic-gate #include <sys/systm.h> 307c478bd9Sstevel@tonic-gate #include <sys/time.h> 317c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 327c478bd9Sstevel@tonic-gate #include <sys/proc.h> 337c478bd9Sstevel@tonic-gate #include <sys/disp.h> 347c478bd9Sstevel@tonic-gate #include <sys/user.h> 357c478bd9Sstevel@tonic-gate #include <sys/time.h> 367c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 377c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 387c478bd9Sstevel@tonic-gate #include <sys/stat.h> 397c478bd9Sstevel@tonic-gate #include <sys/mode.h> 407c478bd9Sstevel@tonic-gate #include <sys/errno.h> 417c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 427c478bd9Sstevel@tonic-gate #include <vm/seg.h> 437c478bd9Sstevel@tonic-gate #include <vm/seg_map.h> 447c478bd9Sstevel@tonic-gate #include <vm/anon.h> 457c478bd9Sstevel@tonic-gate #include <vm/page.h> 467c478bd9Sstevel@tonic-gate #include <vm/pvn.h> 477c478bd9Sstevel@tonic-gate #include <sys/fs/tmp.h> 487c478bd9Sstevel@tonic-gate #include <sys/fs/tmpnode.h> 497c478bd9Sstevel@tonic-gate #include <sys/debug.h> 507c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 517c478bd9Sstevel@tonic-gate #include <sys/swap.h> 527c478bd9Sstevel@tonic-gate #include <sys/vtrace.h> 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate /* 557c478bd9Sstevel@tonic-gate * Reserve swap space for the size of the file. 567c478bd9Sstevel@tonic-gate * Called before growing a file (i.e. ftruncate, write) 577c478bd9Sstevel@tonic-gate * Returns 0 on success. 587c478bd9Sstevel@tonic-gate */ 597c478bd9Sstevel@tonic-gate int 607c478bd9Sstevel@tonic-gate tmp_resv( 617c478bd9Sstevel@tonic-gate struct tmount *tm, 627c478bd9Sstevel@tonic-gate struct tmpnode *tp, 637c478bd9Sstevel@tonic-gate size_t delta, /* size needed */ 647c478bd9Sstevel@tonic-gate int pagecreate) /* call anon_resv if set */ 657c478bd9Sstevel@tonic-gate { 667c478bd9Sstevel@tonic-gate pgcnt_t pages = btopr(delta); 670209230bSgjelinek zone_t *zone; 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&tp->tn_rwlock)); 707c478bd9Sstevel@tonic-gate ASSERT(tp->tn_type == VREG); 717c478bd9Sstevel@tonic-gate /* 727c478bd9Sstevel@tonic-gate * pagecreate is set only if we actually need to call anon_resv 737c478bd9Sstevel@tonic-gate * to reserve an additional page of anonymous memory. 747c478bd9Sstevel@tonic-gate * Since anon_resv always reserves a page at a time, 757c478bd9Sstevel@tonic-gate * it should only get called when we know we're growing the 767c478bd9Sstevel@tonic-gate * file into a new page or filling a hole. 777c478bd9Sstevel@tonic-gate * 787c478bd9Sstevel@tonic-gate * Deny if trying to reserve more than tmpfs can allocate 797c478bd9Sstevel@tonic-gate */ 800209230bSgjelinek zone = tm->tm_vfsp->vfs_zone; 817c478bd9Sstevel@tonic-gate if (pagecreate && ((tm->tm_anonmem + pages > tm->tm_anonmax) || 820209230bSgjelinek (!anon_checkspace(ptob(pages + tmpfs_minfree), zone)) || 838c06a490Sjj204856 (anon_try_resv_zone(delta, zone) == 0))) { 847c478bd9Sstevel@tonic-gate return (1); 857c478bd9Sstevel@tonic-gate } 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /* 887c478bd9Sstevel@tonic-gate * update statistics 897c478bd9Sstevel@tonic-gate */ 907c478bd9Sstevel@tonic-gate if (pagecreate) { 917c478bd9Sstevel@tonic-gate mutex_enter(&tm->tm_contents); 927c478bd9Sstevel@tonic-gate tm->tm_anonmem += pages; 937c478bd9Sstevel@tonic-gate mutex_exit(&tm->tm_contents); 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_VM, TR_ANON_TMPFS, "anon tmpfs:%p %lu", 967c478bd9Sstevel@tonic-gate tp, delta); 977c478bd9Sstevel@tonic-gate } 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate return (0); 1007c478bd9Sstevel@tonic-gate } 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate /* 1037c478bd9Sstevel@tonic-gate * tmp_unresv - called when truncating a file 1047c478bd9Sstevel@tonic-gate * Only called if we're freeing at least pagesize bytes 1057c478bd9Sstevel@tonic-gate * because anon_unresv does a btopr(delta) 1067c478bd9Sstevel@tonic-gate */ 1077c478bd9Sstevel@tonic-gate static void 1087c478bd9Sstevel@tonic-gate tmp_unresv( 1097c478bd9Sstevel@tonic-gate struct tmount *tm, 1107c478bd9Sstevel@tonic-gate struct tmpnode *tp, 1117c478bd9Sstevel@tonic-gate size_t delta) 1127c478bd9Sstevel@tonic-gate { 1137c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&tp->tn_rwlock)); 1147c478bd9Sstevel@tonic-gate ASSERT(tp->tn_type == VREG); 1157c478bd9Sstevel@tonic-gate 1160209230bSgjelinek anon_unresv_zone(delta, tm->tm_vfsp->vfs_zone); 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate mutex_enter(&tm->tm_contents); 1197c478bd9Sstevel@tonic-gate tm->tm_anonmem -= btopr(delta); 1207c478bd9Sstevel@tonic-gate mutex_exit(&tm->tm_contents); 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_VM, TR_ANON_TMPFS, "anon tmpfs:%p %lu", tp, delta); 1237c478bd9Sstevel@tonic-gate } 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate #define TMP_INIT_SZ 128 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate /* 1287c478bd9Sstevel@tonic-gate * Grow the anon pointer array to cover 'newsize' bytes plus slack. 1297c478bd9Sstevel@tonic-gate */ 1307c478bd9Sstevel@tonic-gate void 1317c478bd9Sstevel@tonic-gate tmpnode_growmap(struct tmpnode *tp, ulong_t newsize) 1327c478bd9Sstevel@tonic-gate { 1337c478bd9Sstevel@tonic-gate pgcnt_t np = btopr(newsize); 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&tp->tn_rwlock)); 1367c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&tp->tn_contents)); 1377c478bd9Sstevel@tonic-gate ASSERT(tp->tn_type == VREG); 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate if (tp->tn_asize >= np) 1407c478bd9Sstevel@tonic-gate return; 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate if (newsize > MAXOFF_T) 143*8793b36bSNick Todd np = btopr((u_offset_t)MAXOFF_T); 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate if (tp->tn_anon == NULL) { 1467c478bd9Sstevel@tonic-gate tp->tn_anon = anon_create(MAX(np, TMP_INIT_SZ), ANON_SLEEP); 1477c478bd9Sstevel@tonic-gate tp->tn_asize = tp->tn_anon->size; 1487c478bd9Sstevel@tonic-gate return; 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate tp->tn_asize = anon_grow(tp->tn_anon, NULL, tp->tn_asize, 1527c478bd9Sstevel@tonic-gate np - tp->tn_asize, ANON_SLEEP); 1537c478bd9Sstevel@tonic-gate ASSERT(tp->tn_asize >= np); 1547c478bd9Sstevel@tonic-gate } 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate /* 1577c478bd9Sstevel@tonic-gate * Initialize a tmpnode and add it to file list under mount point. 1587c478bd9Sstevel@tonic-gate */ 1597c478bd9Sstevel@tonic-gate void 1607c478bd9Sstevel@tonic-gate tmpnode_init(struct tmount *tm, struct tmpnode *t, vattr_t *vap, cred_t *cred) 1617c478bd9Sstevel@tonic-gate { 1627c478bd9Sstevel@tonic-gate struct vnode *vp; 1637c478bd9Sstevel@tonic-gate timestruc_t now; 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate ASSERT(vap != NULL); 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate rw_init(&t->tn_rwlock, NULL, RW_DEFAULT, NULL); 1687c478bd9Sstevel@tonic-gate mutex_init(&t->tn_tlock, NULL, MUTEX_DEFAULT, NULL); 1697c478bd9Sstevel@tonic-gate t->tn_mode = MAKEIMODE(vap->va_type, vap->va_mode); 1707c478bd9Sstevel@tonic-gate t->tn_mask = 0; 1717c478bd9Sstevel@tonic-gate t->tn_type = vap->va_type; 1727c478bd9Sstevel@tonic-gate t->tn_nodeid = (ino64_t)(uint32_t)((uintptr_t)t >> 3); 1737c478bd9Sstevel@tonic-gate t->tn_nlink = 1; 1747c478bd9Sstevel@tonic-gate t->tn_size = 0; 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate if (cred == NULL) { 1777c478bd9Sstevel@tonic-gate t->tn_uid = vap->va_uid; 1787c478bd9Sstevel@tonic-gate t->tn_gid = vap->va_gid; 1797c478bd9Sstevel@tonic-gate } else { 1807c478bd9Sstevel@tonic-gate t->tn_uid = crgetuid(cred); 1817c478bd9Sstevel@tonic-gate t->tn_gid = crgetgid(cred); 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate t->tn_fsid = tm->tm_dev; 1857c478bd9Sstevel@tonic-gate t->tn_rdev = vap->va_rdev; 1867c478bd9Sstevel@tonic-gate t->tn_blksize = PAGESIZE; 1877c478bd9Sstevel@tonic-gate t->tn_nblocks = 0; 1887c478bd9Sstevel@tonic-gate gethrestime(&now); 1897c478bd9Sstevel@tonic-gate t->tn_atime = now; 1907c478bd9Sstevel@tonic-gate t->tn_mtime = now; 1917c478bd9Sstevel@tonic-gate t->tn_ctime = now; 1927c478bd9Sstevel@tonic-gate t->tn_seq = 0; 1937c478bd9Sstevel@tonic-gate t->tn_dir = NULL; 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate t->tn_vnode = vn_alloc(KM_SLEEP); 1967c478bd9Sstevel@tonic-gate vp = TNTOV(t); 1977c478bd9Sstevel@tonic-gate vn_setops(vp, tmp_vnodeops); 1987c478bd9Sstevel@tonic-gate vp->v_vfsp = tm->tm_vfsp; 1997c478bd9Sstevel@tonic-gate vp->v_type = vap->va_type; 2007c478bd9Sstevel@tonic-gate vp->v_rdev = vap->va_rdev; 2017c478bd9Sstevel@tonic-gate vp->v_data = (caddr_t)t; 2027c478bd9Sstevel@tonic-gate mutex_enter(&tm->tm_contents); 2037c478bd9Sstevel@tonic-gate /* 2047c478bd9Sstevel@tonic-gate * Increment the pseudo generation number for this tmpnode. 2057c478bd9Sstevel@tonic-gate * Since tmpnodes are allocated and freed, there really is no 2067c478bd9Sstevel@tonic-gate * particular generation number for a new tmpnode. Just fake it 2077c478bd9Sstevel@tonic-gate * by using a counter in each file system. 2087c478bd9Sstevel@tonic-gate */ 2097c478bd9Sstevel@tonic-gate t->tn_gen = tm->tm_gen++; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate /* 2127c478bd9Sstevel@tonic-gate * Add new tmpnode to end of linked list of tmpnodes for this tmpfs 2137c478bd9Sstevel@tonic-gate * Root directory is handled specially in tmp_mount. 2147c478bd9Sstevel@tonic-gate */ 2157c478bd9Sstevel@tonic-gate if (tm->tm_rootnode != (struct tmpnode *)NULL) { 2167c478bd9Sstevel@tonic-gate t->tn_forw = NULL; 2177c478bd9Sstevel@tonic-gate t->tn_back = tm->tm_rootnode->tn_back; 2187c478bd9Sstevel@tonic-gate t->tn_back->tn_forw = tm->tm_rootnode->tn_back = t; 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate mutex_exit(&tm->tm_contents); 2217c478bd9Sstevel@tonic-gate vn_exists(vp); 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate /* 2257c478bd9Sstevel@tonic-gate * tmpnode_trunc - set length of tmpnode and deal with resources 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate int 2287c478bd9Sstevel@tonic-gate tmpnode_trunc( 2297c478bd9Sstevel@tonic-gate struct tmount *tm, 2307c478bd9Sstevel@tonic-gate struct tmpnode *tp, 2317c478bd9Sstevel@tonic-gate ulong_t newsize) 2327c478bd9Sstevel@tonic-gate { 2337c478bd9Sstevel@tonic-gate size_t oldsize = tp->tn_size; 2347c478bd9Sstevel@tonic-gate size_t delta; 2357c478bd9Sstevel@tonic-gate struct vnode *vp = TNTOV(tp); 2367c478bd9Sstevel@tonic-gate timestruc_t now; 2377c478bd9Sstevel@tonic-gate int error = 0; 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&tp->tn_rwlock)); 2407c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&tp->tn_contents)); 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate if (newsize == oldsize) { 2437c478bd9Sstevel@tonic-gate /* Required by POSIX */ 2447c478bd9Sstevel@tonic-gate goto stamp_out; 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate switch (tp->tn_type) { 2487c478bd9Sstevel@tonic-gate case VREG: 2497c478bd9Sstevel@tonic-gate /* Growing the file */ 2507c478bd9Sstevel@tonic-gate if (newsize > oldsize) { 2517c478bd9Sstevel@tonic-gate delta = P2ROUNDUP(newsize, PAGESIZE) - 2527c478bd9Sstevel@tonic-gate P2ROUNDUP(oldsize, PAGESIZE); 2537c478bd9Sstevel@tonic-gate /* 2547c478bd9Sstevel@tonic-gate * Grow the size of the anon array to the new size 2557c478bd9Sstevel@tonic-gate * Reserve the space for the growth here. 2567c478bd9Sstevel@tonic-gate * We do it this way for now because this is how 2577c478bd9Sstevel@tonic-gate * tmpfs used to do it, and this way the reserved 2587c478bd9Sstevel@tonic-gate * space is alway equal to the file size. 2597c478bd9Sstevel@tonic-gate * Alternatively, we could wait to reserve space 'til 2607c478bd9Sstevel@tonic-gate * someone tries to store into one of the newly 2617c478bd9Sstevel@tonic-gate * trunc'ed up pages. This would give us behavior 2627c478bd9Sstevel@tonic-gate * identical to ufs; i.e., you could fail a 2637c478bd9Sstevel@tonic-gate * fault on storing into a holey region of a file 2647c478bd9Sstevel@tonic-gate * if there is no space in the filesystem to fill 2657c478bd9Sstevel@tonic-gate * the hole at that time. 2667c478bd9Sstevel@tonic-gate */ 2677c478bd9Sstevel@tonic-gate /* 2687c478bd9Sstevel@tonic-gate * tmp_resv calls anon_resv only if we're extending 2697c478bd9Sstevel@tonic-gate * the file into a new page 2707c478bd9Sstevel@tonic-gate */ 2717c478bd9Sstevel@tonic-gate if (tmp_resv(tm, tp, delta, 2727c478bd9Sstevel@tonic-gate (btopr(newsize) != btopr(oldsize)))) { 2737c478bd9Sstevel@tonic-gate error = ENOSPC; 2747c478bd9Sstevel@tonic-gate goto out; 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate tmpnode_growmap(tp, newsize); 2777c478bd9Sstevel@tonic-gate tp->tn_size = newsize; 2787c478bd9Sstevel@tonic-gate break; 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate /* Free anon pages if shrinking file over page boundary. */ 2827c478bd9Sstevel@tonic-gate if (btopr(newsize) != btopr(oldsize)) { 2837c478bd9Sstevel@tonic-gate pgcnt_t freed; 2847c478bd9Sstevel@tonic-gate delta = P2ROUNDUP(oldsize, PAGESIZE) - 2857c478bd9Sstevel@tonic-gate P2ROUNDUP(newsize, PAGESIZE); 2867c478bd9Sstevel@tonic-gate freed = anon_pages(tp->tn_anon, btopr(newsize), 2877c478bd9Sstevel@tonic-gate btopr(delta)); 2887c478bd9Sstevel@tonic-gate tp->tn_nblocks -= freed; 2897c478bd9Sstevel@tonic-gate anon_free(tp->tn_anon, btopr(newsize), delta); 2907c478bd9Sstevel@tonic-gate tmp_unresv(tm, tp, delta); 2917c478bd9Sstevel@tonic-gate } 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate /* 2947c478bd9Sstevel@tonic-gate * Update the file size now to reflect the pages we just 2957c478bd9Sstevel@tonic-gate * blew away as we're about to drop the 2967c478bd9Sstevel@tonic-gate * contents lock to zero the partial page (which could 2977c478bd9Sstevel@tonic-gate * re-enter tmpfs via getpage and try to reacquire the lock) 2987c478bd9Sstevel@tonic-gate * Once we drop the lock, faulters can fill in holes in 2997c478bd9Sstevel@tonic-gate * the file and if we haven't updated the size they 3007c478bd9Sstevel@tonic-gate * may fill in holes that are beyond EOF, which will then 3017c478bd9Sstevel@tonic-gate * never get cleared. 3027c478bd9Sstevel@tonic-gate */ 3037c478bd9Sstevel@tonic-gate tp->tn_size = newsize; 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate /* Zero new size of file to page boundary. */ 3067c478bd9Sstevel@tonic-gate if (anon_get_ptr(tp->tn_anon, btop(newsize)) != NULL) { 3077c478bd9Sstevel@tonic-gate size_t zlen; 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate zlen = PAGESIZE - ((ulong_t)newsize & PAGEOFFSET); 3107c478bd9Sstevel@tonic-gate rw_exit(&tp->tn_contents); 3117c478bd9Sstevel@tonic-gate pvn_vpzero(TNTOV(tp), (u_offset_t)newsize, zlen); 3127c478bd9Sstevel@tonic-gate rw_enter(&tp->tn_contents, RW_WRITER); 3137c478bd9Sstevel@tonic-gate } 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate if (newsize == 0) { 3167c478bd9Sstevel@tonic-gate /* Delete anon array for tmpnode */ 3177c478bd9Sstevel@tonic-gate ASSERT(tp->tn_nblocks == 0); 3187c478bd9Sstevel@tonic-gate ASSERT(anon_get_ptr(tp->tn_anon, 0) == NULL); 3197c478bd9Sstevel@tonic-gate ASSERT(!vn_has_cached_data(vp)); 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate anon_release(tp->tn_anon, tp->tn_asize); 3227c478bd9Sstevel@tonic-gate tp->tn_anon = NULL; 3237c478bd9Sstevel@tonic-gate tp->tn_asize = 0; 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate break; 3267c478bd9Sstevel@tonic-gate case VLNK: 3277c478bd9Sstevel@tonic-gate /* 3287c478bd9Sstevel@tonic-gate * Don't do anything here 3297c478bd9Sstevel@tonic-gate * tmp_inactive frees the memory 3307c478bd9Sstevel@tonic-gate */ 3317c478bd9Sstevel@tonic-gate if (newsize != 0) 3327c478bd9Sstevel@tonic-gate error = EINVAL; 3337c478bd9Sstevel@tonic-gate goto out; 3347c478bd9Sstevel@tonic-gate case VDIR: 3357c478bd9Sstevel@tonic-gate /* 3367c478bd9Sstevel@tonic-gate * Remove all the directory entries under this directory. 3377c478bd9Sstevel@tonic-gate */ 3387c478bd9Sstevel@tonic-gate if (newsize != 0) { 3397c478bd9Sstevel@tonic-gate error = EINVAL; 3407c478bd9Sstevel@tonic-gate goto out; 3417c478bd9Sstevel@tonic-gate } 3427c478bd9Sstevel@tonic-gate tdirtrunc(tp); 3437c478bd9Sstevel@tonic-gate ASSERT(tp->tn_nlink == 0); 3447c478bd9Sstevel@tonic-gate break; 3457c478bd9Sstevel@tonic-gate default: 3467c478bd9Sstevel@tonic-gate goto out; 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate stamp_out: 3507c478bd9Sstevel@tonic-gate gethrestime(&now); 3517c478bd9Sstevel@tonic-gate tp->tn_mtime = now; 3527c478bd9Sstevel@tonic-gate tp->tn_ctime = now; 3537c478bd9Sstevel@tonic-gate out: 3547c478bd9Sstevel@tonic-gate /* 3557c478bd9Sstevel@tonic-gate * tmpnode_trunc() cannot fail when newsize == 0. 3567c478bd9Sstevel@tonic-gate */ 3577c478bd9Sstevel@tonic-gate ASSERT(error == 0 || newsize != 0); 3587c478bd9Sstevel@tonic-gate return (error); 3597c478bd9Sstevel@tonic-gate } 360