|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /* $NetBSD: lfs_inode.c,v 1.2 1994/06/29 06:46:57 cgd Exp $ */
23:
24: /*
25: * Copyright (c) 1986, 1989, 1991, 1993
26: * The Regents of the University of California. All rights reserved.
27: *
28: * Redistribution and use in source and binary forms, with or without
29: * modification, are permitted provided that the following conditions
30: * are met:
31: * 1. Redistributions of source code must retain the above copyright
32: * notice, this list of conditions and the following disclaimer.
33: * 2. Redistributions in binary form must reproduce the above copyright
34: * notice, this list of conditions and the following disclaimer in the
35: * documentation and/or other materials provided with the distribution.
36: * 3. All advertising materials mentioning features or use of this software
37: * must display the following acknowledgement:
38: * This product includes software developed by the University of
39: * California, Berkeley and its contributors.
40: * 4. Neither the name of the University nor the names of its contributors
41: * may be used to endorse or promote products derived from this software
42: * without specific prior written permission.
43: *
44: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54: * SUCH DAMAGE.
55: *
56: * @(#)lfs_inode.c 8.5 (Berkeley) 12/30/93
57: */
58:
59: #include <sys/param.h>
60: #include <sys/systm.h>
61: #include <sys/mount.h>
62: #include <sys/proc.h>
63: #include <sys/file.h>
64: #include <sys/buf.h>
65: #include <sys/vnode.h>
66: #include <sys/kernel.h>
67: #include <sys/malloc.h>
68:
69: #include <vm/vm.h>
70:
71: #include <ufs/ufs/quota.h>
72: #include <ufs/ufs/inode.h>
73: #include <ufs/ufs/ufsmount.h>
74: #include <ufs/ufs/ufs_extern.h>
75:
76: #include <ufs/lfs/lfs.h>
77: #include <ufs/lfs/lfs_extern.h>
78:
79: int
80: lfs_init()
81: {
82: return (ufs_init());
83: }
84:
85: /* Search a block for a specific dinode. */
86: struct dinode *
87: lfs_ifind(fs, ino, dip)
88: struct lfs *fs;
89: ino_t ino;
90: register struct dinode *dip;
91: {
92: register int cnt;
93: register struct dinode *ldip;
94:
95: for (cnt = INOPB(fs), ldip = dip + (cnt - 1); cnt--; --ldip)
96: if (ldip->di_inumber == ino)
97: return (ldip);
98:
99: panic("lfs_ifind: dinode %u not found", ino);
100: /* NOTREACHED */
101: }
102:
103: int
104: lfs_update(ap)
105: struct vop_update_args /* {
106: struct vnode *a_vp;
107: struct timeval *a_access;
108: struct timeval *a_modify;
109: int a_waitfor;
110: } */ *ap;
111: {
112: struct vnode *vp = ap->a_vp;
113: struct inode *ip;
114:
115: if (vp->v_mount->mnt_flag & MNT_RDONLY)
116: return (0);
117: ip = VTOI(vp);
118: if ((ip->i_flag &
119: (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0)
120: return (0);
121: if (ip->i_flag & IN_ACCESS)
122: ip->i_atime.tv_sec = ap->a_access->tv_sec;
123: if (ip->i_flag & IN_UPDATE) {
124: ip->i_mtime.tv_sec = ap->a_modify->tv_sec;
125: (ip)->i_modrev++;
126: }
127: if (ip->i_flag & IN_CHANGE)
128: ip->i_ctime.tv_sec = time.tv_sec;
129: ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE);
130:
131: if (!(ip->i_flag & IN_MODIFIED))
132: ++(VFSTOUFS(vp->v_mount)->um_lfs->lfs_uinodes);
133: ip->i_flag |= IN_MODIFIED;
134:
135: /* If sync, push back the vnode and any dirty blocks it may have. */
136: return (ap->a_waitfor & LFS_SYNC ? lfs_vflush(vp) : 0);
137: }
138:
139: /* Update segment usage information when removing a block. */
140: #define UPDATE_SEGUSE \
141: if (lastseg != -1) { \
142: LFS_SEGENTRY(sup, fs, lastseg, sup_bp); \
143: if ((num << fs->lfs_bshift) > sup->su_nbytes) \
144: panic("lfs_truncate: negative bytes in segment %d\n", \
145: lastseg); \
146: sup->su_nbytes -= num << fs->lfs_bshift; \
147: e1 = VOP_BWRITE(sup_bp); \
148: blocksreleased += num; \
149: }
150:
151: #define SEGDEC { \
152: if (daddr != 0) { \
153: if (lastseg != (seg = datosn(fs, daddr))) { \
154: UPDATE_SEGUSE; \
155: num = 1; \
156: lastseg = seg; \
157: } else \
158: ++num; \
159: } \
160: }
161:
162: /*
163: * Truncate the inode ip to at most length size. Update segment usage
164: * table information.
165: */
166: /* ARGSUSED */
167: int
168: lfs_truncate(ap)
169: struct vop_truncate_args /* {
170: struct vnode *a_vp;
171: off_t a_length;
172: int a_flags;
173: struct ucred *a_cred;
174: struct proc *a_p;
175: } */ *ap;
176: {
177: register struct indir *inp;
178: register int i;
179: register daddr_t *daddrp;
180: register struct vnode *vp = ap->a_vp;
181: off_t length = ap->a_length;
182: struct buf *bp, *sup_bp;
183: struct timeval tv;
184: struct ifile *ifp;
185: struct inode *ip;
186: struct lfs *fs;
187: struct indir a[NIADDR + 2], a_end[NIADDR + 2];
188: SEGUSE *sup;
189: daddr_t daddr, lastblock, lbn, olastblock;
190: long off, a_released, blocksreleased, i_released;
191: int e1, e2, depth, lastseg, num, offset, seg, size;
192:
193: ip = VTOI(vp);
194: tv = time;
195: if (vp->v_type == VLNK && vp->v_mount->mnt_maxsymlinklen > 0) {
196: #if DIAGNOSTIC
197: if (length != 0)
198: panic("lfs_truncate: partial truncate of symlink");
199: #endif
200: bzero((char *)&ip->i_shortlink, (u_int)ip->i_size);
201: ip->i_size = 0;
202: ip->i_flag |= IN_CHANGE | IN_UPDATE;
203: return (VOP_UPDATE(vp, &tv, &tv, 0));
204: }
205: vnode_pager_setsize(vp, (u_long)length);
206:
207: fs = ip->i_lfs;
208:
209: /* If length is larger than the file, just update the times. */
210: if (ip->i_size <= length) {
211: ip->i_flag |= IN_CHANGE | IN_UPDATE;
212: return (VOP_UPDATE(vp, &tv, &tv, 0));
213: }
214:
215: /*
216: * Calculate index into inode's block list of last direct and indirect
217: * blocks (if any) which we want to keep. Lastblock is 0 when the
218: * file is truncated to 0.
219: */
220: lastblock = lblkno(fs, length + fs->lfs_bsize - 1);
221: olastblock = lblkno(fs, ip->i_size + fs->lfs_bsize - 1) - 1;
222:
223: /*
224: * Update the size of the file. If the file is not being truncated to
225: * a block boundry, the contents of the partial block following the end
226: * of the file must be zero'ed in case it ever become accessable again
227: * because of subsequent file growth.
228: */
229: offset = blkoff(fs, length);
230: if (offset == 0)
231: ip->i_size = length;
232: else {
233: lbn = lblkno(fs, length);
234: #if QUOTA
235: if (e1 = getinoquota(ip))
236: return (e1);
237: #endif
238: if (e1 = bread(vp, lbn, fs->lfs_bsize, NOCRED, &bp))
239: return (e1);
240: ip->i_size = length;
241: size = blksize(fs);
242: (void)vnode_pager_uncache(vp);
243: bzero((char *)bp->b_data + offset, (u_int)(size - offset));
244: allocbuf(bp, size);
245: if (e1 = VOP_BWRITE(bp))
246: return (e1);
247: }
248: /*
249: * Modify sup->su_nbyte counters for each deleted block; keep track
250: * of number of blocks removed for ip->i_blocks.
251: */
252: blocksreleased = 0;
253: num = 0;
254: lastseg = -1;
255:
256: for (lbn = olastblock; lbn >= lastblock;) {
257: /* XXX use run length from bmap array to make this faster */
258: ufs_bmaparray(vp, lbn, &daddr, a, &depth, NULL);
259: if (lbn == olastblock)
260: for (i = NIADDR + 2; i--;)
261: a_end[i] = a[i];
262: switch (depth) {
263: case 0: /* Direct block. */
264: daddr = ip->i_db[lbn];
265: SEGDEC;
266: ip->i_db[lbn] = 0;
267: --lbn;
268: break;
269: #if DIAGNOSTIC
270: case 1: /* An indirect block. */
271: panic("lfs_truncate: ufs_bmaparray returned depth 1");
272: /* NOTREACHED */
273: #endif
274: default: /* Chain of indirect blocks. */
275: inp = a + --depth;
276: if (inp->in_off > 0 && lbn != lastblock) {
277: lbn -= inp->in_off < lbn - lastblock ?
278: inp->in_off : lbn - lastblock;
279: break;
280: }
281: for (; depth && (inp->in_off == 0 || lbn == lastblock);
282: --inp, --depth) {
283: if (bread(vp,
284: inp->in_lbn, fs->lfs_bsize, NOCRED, &bp))
285: panic("lfs_truncate: bread bno %d",
286: inp->in_lbn);
287: daddrp = (daddr_t *)bp->b_data + inp->in_off;
288: for (i = inp->in_off;
289: i++ <= a_end[depth].in_off;) {
290: daddr = *daddrp++;
291: SEGDEC;
292: }
293: a_end[depth].in_off = NINDIR(fs) - 1;
294: if (inp->in_off == 0)
295: brelse (bp);
296: else {
297: bzero((daddr_t *)bp->b_data +
298: inp->in_off, fs->lfs_bsize -
299: inp->in_off * sizeof(daddr_t));
300: if (e1 = VOP_BWRITE(bp))
301: return (e1);
302: }
303: }
304: if (depth == 0 && a[1].in_off == 0) {
305: off = a[0].in_off;
306: daddr = ip->i_ib[off];
307: SEGDEC;
308: ip->i_ib[off] = 0;
309: }
310: if (lbn == lastblock || lbn <= NDADDR)
311: --lbn;
312: else {
313: lbn -= NINDIR(fs);
314: if (lbn < lastblock)
315: lbn = lastblock;
316: }
317: }
318: }
319: UPDATE_SEGUSE;
320:
321: /* If truncating the file to 0, update the version number. */
322: if (length == 0) {
323: LFS_IENTRY(ifp, fs, ip->i_number, bp);
324: ++ifp->if_version;
325: (void) VOP_BWRITE(bp);
326: }
327:
328: #if DIAGNOSTIC
329: if (ip->i_blocks < fsbtodb(fs, blocksreleased)) {
330: printf("lfs_truncate: block count < 0\n");
331: blocksreleased = ip->i_blocks;
332: }
333: #endif
334: ip->i_blocks -= fsbtodb(fs, blocksreleased);
335: fs->lfs_bfree += fsbtodb(fs, blocksreleased);
336: ip->i_flag |= IN_CHANGE | IN_UPDATE;
337: /*
338: * Traverse dirty block list counting number of dirty buffers
339: * that are being deleted out of the cache, so that the lfs_avail
340: * field can be updated.
341: */
342: a_released = 0;
343: i_released = 0;
344: for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = bp->b_vnbufs.le_next)
345: if (bp->b_flags & B_LOCKED) {
346: ++a_released;
347: /*
348: * XXX
349: * When buffers are created in the cache, their block
350: * number is set equal to their logical block number.
351: * If that is still true, we are assuming that the
352: * blocks are new (not yet on disk) and weren't
353: * counted above. However, there is a slight chance
354: * that a block's disk address is equal to its logical
355: * block number in which case, we'll get an overcounting
356: * here.
357: */
358: if (bp->b_blkno == bp->b_lblkno)
359: ++i_released;
360: }
361: blocksreleased = fsbtodb(fs, i_released);
362: #if DIAGNOSTIC
363: if (blocksreleased > ip->i_blocks) {
364: printf("lfs_inode: Warning! %s\n",
365: "more blocks released from inode than are in inode");
366: blocksreleased = ip->i_blocks;
367: }
368: #endif
369: fs->lfs_bfree += blocksreleased;
370: ip->i_blocks -= blocksreleased;
371: #if DIAGNOSTIC
372: if (length == 0 && ip->i_blocks != 0)
373: printf("lfs_inode: Warning! %s%d%s\n",
374: "Truncation to zero, but ", ip->i_blocks,
375: " blocks left on inode");
376: #endif
377: fs->lfs_avail += fsbtodb(fs, a_released);
378: e1 = vinvalbuf(vp, (length > 0) ? V_SAVE : 0, ap->a_cred, ap->a_p,
379: 0, 0);
380: e2 = VOP_UPDATE(vp, &tv, &tv, 0);
381: return (e1 ? e1 : e2 ? e2 : 0);
382: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.