Annotation of src/sys/ufs/ufs/ufs_inode.c, Revision 1.90.2.2
1.90.2.2! snj 1: /* $NetBSD: ufs_inode.c,v 1.90.2.1 2015/01/28 18:34:11 martin Exp $ */
1.3 cgd 2:
1.1 mycroft 3: /*
4: * Copyright (c) 1991, 1993
5: * The Regents of the University of California. All rights reserved.
6: * (c) UNIX System Laboratories, Inc.
7: * All or some portions of this file are derived from material licensed
8: * to the University of California by American Telephone and Telegraph
9: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10: * the permission of UNIX System Laboratories, Inc.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
1.40 agc 20: * 3. Neither the name of the University nor the names of its contributors
1.1 mycroft 21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
1.10 fvdl 36: * @(#)ufs_inode.c 8.9 (Berkeley) 5/14/95
1.1 mycroft 37: */
1.28 lukem 38:
39: #include <sys/cdefs.h>
1.90.2.2! snj 40: __KERNEL_RCSID(0, "$NetBSD: ufs_inode.c,v 1.90.2.1 2015/01/28 18:34:11 martin Exp $");
1.11 scottr 41:
1.46 dbj 42: #if defined(_KERNEL_OPT)
1.49 thorpej 43: #include "opt_ffs.h"
1.11 scottr 44: #include "opt_quota.h"
1.76 simonb 45: #include "opt_wapbl.h"
1.46 dbj 46: #endif
1.1 mycroft 47:
48: #include <sys/param.h>
49: #include <sys/systm.h>
50: #include <sys/proc.h>
51: #include <sys/vnode.h>
52: #include <sys/mount.h>
53: #include <sys/kernel.h>
1.6 christos 54: #include <sys/namei.h>
1.59 elad 55: #include <sys/kauth.h>
1.76 simonb 56: #include <sys/wapbl.h>
1.63 hannken 57: #include <sys/fstrans.h>
1.68 pooka 58: #include <sys/kmem.h>
1.1 mycroft 59:
60: #include <ufs/ufs/inode.h>
61: #include <ufs/ufs/ufsmount.h>
62: #include <ufs/ufs/ufs_extern.h>
1.76 simonb 63: #include <ufs/ufs/ufs_wapbl.h>
1.47 rumble 64: #ifdef UFS_DIRHASH
65: #include <ufs/ufs/dirhash.h>
66: #endif
1.52 thorpej 67: #ifdef UFS_EXTATTR
68: #include <ufs/ufs/extattr.h>
69: #endif
1.1 mycroft 70:
1.16 chs 71: #include <uvm/uvm.h>
72:
1.19 tsutsui 73: extern int prtactive;
74:
1.1 mycroft 75: /*
76: * Last reference to an inode. If necessary, write or delete it.
77: */
78: int
1.48 thorpej 79: ufs_inactive(void *v)
1.6 christos 80: {
1.1 mycroft 81: struct vop_inactive_args /* {
82: struct vnode *a_vp;
1.72 ad 83: struct bool *a_recycle;
1.6 christos 84: } */ *ap = v;
1.10 fvdl 85: struct vnode *vp = ap->a_vp;
86: struct inode *ip = VTOI(vp);
1.90.2.2! snj 87: struct mount *mp = vp->v_mount;
1.36 fvdl 88: mode_t mode;
1.90.2.2! snj 89: int allerror = 0, error;
! 90: bool wapbl_locked = false;
1.76 simonb 91:
1.90.2.2! snj 92: UFS_WAPBL_JUNLOCK_ASSERT(mp);
1.1 mycroft 93:
1.90.2.2! snj 94: fstrans_start(mp, FSTRANS_LAZY);
1.10 fvdl 95: /*
96: * Ignore inodes related to stale file handles.
97: */
1.36 fvdl 98: if (ip->i_mode == 0)
1.10 fvdl 99: goto out;
1.90.2.2! snj 100: if (ip->i_nlink <= 0 && (mp->mnt_flag & MNT_RDONLY) == 0) {
1.86 manu 101: #ifdef UFS_EXTATTR
102: ufs_extattr_vnode_inactive(vp, curlwp);
103: #endif
1.90.2.1 martin 104: if (ip->i_size != 0)
1.90.2.2! snj 105: allerror = ufs_truncate(vp, 0, NOCRED);
1.84 bouyer 106: #if defined(QUOTA) || defined(QUOTA2)
1.90.2.2! snj 107: error = UFS_WAPBL_BEGIN(mp);
! 108: if (error) {
! 109: allerror = error;
! 110: } else {
! 111: wapbl_locked = true;
! 112: (void)chkiq(ip, -1, NOCRED, 0);
! 113: }
1.84 bouyer 114: #endif
1.37 kristerw 115: DIP_ASSIGN(ip, rdev, 0);
1.36 fvdl 116: mode = ip->i_mode;
117: ip->i_mode = 0;
1.82 hannken 118: ip->i_omode = mode;
1.37 kristerw 119: DIP_ASSIGN(ip, mode, 0);
1.1 mycroft 120: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1.82 hannken 121: /*
122: * Defer final inode free and update to ufs_reclaim().
123: */
1.74 ad 124: }
125:
126: if (ip->i_flag & (IN_CHANGE | IN_UPDATE | IN_MODIFIED)) {
1.90.2.2! snj 127: if (! wapbl_locked) {
! 128: error = UFS_WAPBL_BEGIN(mp);
! 129: if (error) {
! 130: allerror = error;
! 131: goto out;
! 132: }
! 133: wapbl_locked = true;
! 134: }
1.54 yamt 135: UFS_UPDATE(vp, NULL, NULL, 0);
1.90.2.1 martin 136: }
1.10 fvdl 137: out:
1.90.2.2! snj 138: if (wapbl_locked)
! 139: UFS_WAPBL_END(mp);
1.1 mycroft 140: /*
141: * If we are done with the inode, reclaim it
142: * so that it can be reused immediately.
143: */
1.72 ad 144: *ap->a_recycle = (ip->i_mode == 0);
1.81 hannken 145: VOP_UNLOCK(vp);
1.90.2.2! snj 146: fstrans_done(mp);
! 147: return (allerror);
1.1 mycroft 148: }
149:
150: /*
151: * Reclaim an inode so that it can be used for other purposes.
152: */
153: int
1.70 pooka 154: ufs_reclaim(struct vnode *vp)
1.1 mycroft 155: {
1.44 mycroft 156: struct inode *ip = VTOI(vp);
1.1 mycroft 157:
1.72 ad 158: if (prtactive && vp->v_usecount > 1)
1.1 mycroft 159: vprint("ufs_reclaim: pushing active", vp);
1.45 dbj 160:
1.76 simonb 161: if (!UFS_WAPBL_BEGIN(vp->v_mount)) {
162: UFS_UPDATE(vp, NULL, NULL, UPDATE_CLOSE);
163: UFS_WAPBL_END(vp->v_mount);
164: }
1.54 yamt 165: UFS_UPDATE(vp, NULL, NULL, UPDATE_CLOSE);
1.74 ad 166:
167: /*
1.90 hannken 168: * Remove the inode from the vnode cache.
1.74 ad 169: */
1.90 hannken 170: vcache_remove(vp->v_mount, &ip->i_number, sizeof(ip->i_number));
1.85 rmind 171:
1.1 mycroft 172: if (ip->i_devvp) {
173: vrele(ip->i_devvp);
174: ip->i_devvp = 0;
175: }
1.84 bouyer 176: #if defined(QUOTA) || defined(QUOTA2)
1.67 hannken 177: ufsquota_free(ip);
1.1 mycroft 178: #endif
1.47 rumble 179: #ifdef UFS_DIRHASH
180: if (ip->i_dirhash != NULL)
181: ufsdirhash_free(ip);
182: #endif
1.1 mycroft 183: return (0);
1.16 chs 184: }
185:
186: /*
187: * allocate a range of blocks in a file.
188: * after this function returns, any page entirely contained within the range
189: * will map to invalid data and thus must be overwritten before it is made
190: * accessible to others.
191: */
192:
193: int
1.59 elad 194: ufs_balloc_range(struct vnode *vp, off_t off, off_t len, kauth_cred_t cred,
1.48 thorpej 195: int flags)
1.16 chs 196: {
1.58 yamt 197: off_t neweof; /* file size after the operation */
198: off_t neweob; /* offset next to the last block after the operation */
199: off_t pagestart; /* starting offset of range covered by pgs */
200: off_t eob; /* offset next to allocated blocks */
1.16 chs 201: struct uvm_object *uobj;
1.29 chs 202: int i, delta, error, npages;
1.16 chs 203: int bshift = vp->v_mount->mnt_fs_bshift;
204: int bsize = 1 << bshift;
1.22 chs 205: int ppb = MAX(bsize >> PAGE_SHIFT, 1);
1.68 pooka 206: struct vm_page **pgs;
207: size_t pgssize;
1.16 chs 208: UVMHIST_FUNC("ufs_balloc_range"); UVMHIST_CALLED(ubchist);
209: UVMHIST_LOG(ubchist, "vp %p off 0x%x len 0x%x u_size 0x%x",
1.25 chs 210: vp, off, len, vp->v_size);
1.16 chs 211:
1.25 chs 212: neweof = MAX(vp->v_size, off + len);
1.58 yamt 213: GOP_SIZE(vp, neweof, &neweob, 0);
1.16 chs 214:
215: error = 0;
1.25 chs 216: uobj = &vp->v_uobj;
1.16 chs 217:
218: /*
1.29 chs 219: * read or create pages covering the range of the allocation and
220: * keep them locked until the new block is allocated, so there
221: * will be no window where the old contents of the new block are
222: * visible to racing threads.
1.16 chs 223: */
224:
1.29 chs 225: pagestart = trunc_page(off) & ~(bsize - 1);
226: npages = MIN(ppb, (round_page(neweob) - pagestart) >> PAGE_SHIFT);
1.68 pooka 227: pgssize = npages * sizeof(struct vm_page *);
228: pgs = kmem_zalloc(pgssize, KM_SLEEP);
229:
1.77 pooka 230: /*
231: * adjust off to be block-aligned.
232: */
233:
234: delta = off & (bsize - 1);
235: off -= delta;
236: len += delta;
237:
1.83 chs 238: genfs_node_wrlock(vp);
1.87 rmind 239: mutex_enter(uobj->vmobjlock);
1.29 chs 240: error = VOP_GETPAGES(vp, pagestart, pgs, &npages, 0,
1.83 chs 241: VM_PROT_WRITE, 0, PGO_SYNCIO | PGO_PASTEOF | PGO_NOBLOCKALLOC |
242: PGO_NOTIMESTAMP | PGO_GLOCKHELD);
1.29 chs 243: if (error) {
1.90.2.2! snj 244: genfs_node_unlock(vp);
1.68 pooka 245: goto out;
1.16 chs 246: }
247:
248: /*
1.77 pooka 249: * now allocate the range.
1.16 chs 250: */
251:
1.25 chs 252: error = GOP_ALLOC(vp, off, len, flags, cred);
1.61 yamt 253: genfs_node_unlock(vp);
1.16 chs 254:
255: /*
1.88 chs 256: * if the allocation succeeded, clear PG_CLEAN on all the pages
257: * and clear PG_RDONLY on any pages that are now fully backed
258: * by disk blocks. if the allocation failed, we do not invalidate
259: * the pages since they might have already existed and been dirty,
260: * in which case we need to keep them around. if we created the pages,
261: * they will be clean and read-only, and leaving such pages
262: * in the cache won't cause any problems.
1.16 chs 263: */
264:
1.58 yamt 265: GOP_SIZE(vp, off + len, &eob, 0);
1.87 rmind 266: mutex_enter(uobj->vmobjlock);
1.88 chs 267: mutex_enter(&uvm_pageqlock);
1.29 chs 268: for (i = 0; i < npages; i++) {
1.88 chs 269: KASSERT((pgs[i]->flags & PG_RELEASED) == 0);
270: if (!error) {
271: if (off <= pagestart + (i << PAGE_SHIFT) &&
272: pagestart + ((i + 1) << PAGE_SHIFT) <= eob) {
273: pgs[i]->flags &= ~PG_RDONLY;
274: }
275: pgs[i]->flags &= ~PG_CLEAN;
1.24 chs 276: }
1.88 chs 277: uvm_pageactivate(pgs[i]);
1.16 chs 278: }
1.88 chs 279: mutex_exit(&uvm_pageqlock);
280: uvm_page_unbusy(pgs, npages);
1.87 rmind 281: mutex_exit(uobj->vmobjlock);
1.68 pooka 282:
283: out:
1.72 ad 284: kmem_free(pgs, pgssize);
1.16 chs 285: return error;
1.1 mycroft 286: }
1.90.2.1 martin 287:
288: static int
289: ufs_wapbl_truncate(struct vnode *vp, uint64_t newsize, kauth_cred_t cred)
290: {
291: struct inode *ip = VTOI(vp);
292: int error = 0;
293: uint64_t base, incr;
294:
295: base = UFS_NDADDR << vp->v_mount->mnt_fs_bshift;
296: incr = MNINDIR(ip->i_ump) << vp->v_mount->mnt_fs_bshift;/* Power of 2 */
297: while (ip->i_size > base + incr &&
298: (newsize == 0 || ip->i_size > newsize + incr)) {
299: /*
300: * round down to next full indirect
301: * block boundary.
302: */
303: uint64_t nsize = base + ((ip->i_size - base - 1) & ~(incr - 1));
304: error = UFS_TRUNCATE(vp, nsize, 0, cred);
305: if (error)
306: break;
307: UFS_WAPBL_END(vp->v_mount);
308: error = UFS_WAPBL_BEGIN(vp->v_mount);
309: if (error)
310: return error;
311: }
312: return error;
313: }
314:
315: int
316: ufs_truncate(struct vnode *vp, uint64_t newsize, kauth_cred_t cred)
317: {
318: int error;
319:
320: error = UFS_WAPBL_BEGIN(vp->v_mount);
321: if (error)
322: return error;
323:
324: if (vp->v_mount->mnt_wapbl)
325: error = ufs_wapbl_truncate(vp, newsize, cred);
326:
327: if (error == 0)
328: error = UFS_TRUNCATE(vp, newsize, 0, cred);
329: UFS_WAPBL_END(vp->v_mount);
330:
331: return error;
332: }
333:
CVSweb <webmaster@jp.NetBSD.org>