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