remque => ufs_ihashrem
[unix-history] / usr / src / sys / ufs / lfs / lfs_inode.c
CommitLineData
da7c5cc6 1/*
7795cb4d 2 * Copyright (c) 1986, 1989, 1991 Regents of the University of California.
7188ac27 3 * All rights reserved.
da7c5cc6 4 *
b702c21d 5 * %sccs.include.redist.c%
7188ac27 6 *
d942bf69 7 * @(#)lfs_inode.c 7.71 (Berkeley) %G%
da7c5cc6 8 */
5d5124a1 9
29ad237c
KB
10#include <sys/param.h>
11#include <sys/systm.h>
12#include <sys/mount.h>
13#include <sys/proc.h>
14#include <sys/file.h>
15#include <sys/buf.h>
16#include <sys/vnode.h>
17#include <sys/kernel.h>
18#include <sys/malloc.h>
5d5124a1 19
89663819
KM
20#include <vm/vm.h>
21
7795cb4d
KB
22#include <ufs/ufs/quota.h>
23#include <ufs/ufs/inode.h>
24#include <ufs/ufs/ufsmount.h>
25#include <ufs/ufs/ufs_extern.h>
c6f5111d 26
7795cb4d
KB
27#include <ufs/lfs/lfs.h>
28#include <ufs/lfs/lfs_extern.h>
2bf2d153 29
0a0d4fba 30int
0b4d6502 31lfs_init()
5d5124a1 32{
a79b7b81
KB
33#ifdef VERBOSE
34 printf("lfs_init\n");
35#endif
29ad237c 36 return (ufs_init());
5d5124a1
BJ
37}
38
841fa75e 39/* Search a block for a specific dinode. */
b4de8c04 40struct dinode *
841fa75e
KB
41lfs_ifind(fs, ino, dip)
42 struct lfs *fs;
43 ino_t ino;
44 register struct dinode *dip;
45{
46 register int cnt;
3ce71481 47 register struct dinode *ldip;
841fa75e
KB
48
49#ifdef VERBOSE
50 printf("lfs_ifind: inode %d\n", ino);
51#endif
3ce71481
KB
52 for (cnt = INOPB(fs), ldip = dip + (cnt - 1); cnt--; --ldip)
53 if (ldip->di_inum == ino)
54 return (ldip);
841fa75e
KB
55
56 panic("lfs_ifind: dinode %u not found", ino);
57 /* NOTREACHED */
58}
59
0a0d4fba 60int
b4de8c04
KB
61lfs_update(ap)
62 struct vop_update_args /* {
63 struct vnode *a_vp;
64 struct timeval *a_ta;
65 struct timeval *a_tm;
66 int a_waitfor;
67 } */ *ap;
ff56f48a 68{
406c9a0d 69 struct vnode *vp = ap->a_vp;
ffcee610
KM
70 struct inode *ip;
71
a79b7b81
KB
72#ifdef VERBOSE
73 printf("lfs_update\n");
74#endif
406c9a0d 75 if (vp->v_mount->mnt_flag & MNT_RDONLY)
ffcee610 76 return (0);
406c9a0d 77 ip = VTOI(vp);
ffcee610
KM
78 if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0)
79 return (0);
80 if (ip->i_flag&IACC)
7e11a0c9 81 ip->i_atime.ts_sec = ap->a_ta->tv_sec;
5b51b344 82 if (ip->i_flag&IUPD) {
7e11a0c9 83 ip->i_mtime.ts_sec = ap->a_tm->tv_sec;
d9011ad6 84 (ip)->i_modrev++;
5b51b344 85 }
ffcee610 86 if (ip->i_flag&ICHG)
7e11a0c9 87 ip->i_ctime.ts_sec = time.tv_sec;
ffcee610
KM
88 ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD);
89
b3071295 90 /* Push back the vnode and any dirty blocks it may have. */
406c9a0d 91 return (ap->a_waitfor ? lfs_vflush(vp) : 0);
5d5124a1
BJ
92}
93
2c68aab8 94/* Update segment usage information when removing a block. */
4ee2ad24
KB
95#define UPDATE_SEGUSE \
96 if (lastseg != -1) { \
97 LFS_SEGENTRY(sup, fs, lastseg, sup_bp); \
5b792b30 98 sup->su_nbytes -= num << fs->lfs_bshift; \
4ee2ad24
KB
99 LFS_UBWRITE(sup_bp); \
100 blocksreleased += num; \
101 }
2c68aab8
KB
102
103#define SEGDEC { \
104 if (daddr != UNASSIGNED) { \
105 if (lastseg != (seg = datosn(fs, daddr))) { \
106 UPDATE_SEGUSE; \
107 num = 1; \
108 lastseg = seg; \
109 } else \
110 ++num; \
111 } \
112}
113
5d5124a1 114/*
2c68aab8
KB
115 * Truncate the inode ip to at most length size. Update segment usage
116 * table information.
5d5124a1 117 */
29ad237c
KB
118/* ARGSUSED */
119int
b4de8c04
KB
120lfs_truncate(ap)
121 struct vop_truncate_args /* {
122 struct vnode *a_vp;
123 off_t a_length;
124 int a_flags;
125 struct ucred *a_cred;
126 struct proc *a_p;
127 } */ *ap;
5d5124a1 128{
8f42dbe0 129 register INDIR *inp;
2c68aab8
KB
130 register int i;
131 register daddr_t *daddrp;
b4de8c04
KB
132 register struct vnode *vp = ap->a_vp;
133 off_t length = ap->a_length;
4ee2ad24 134 struct buf *bp, *sup_bp;
d942bf69 135 struct timeval tv;
b3071295 136 struct ifile *ifp;
2c68aab8
KB
137 struct inode *ip;
138 struct lfs *fs;
139 INDIR a[NIADDR + 2], a_end[NIADDR + 2];
140 SEGUSE *sup;
141 daddr_t daddr, lastblock, lbn, olastblock;
0308fc84 142 long off, blocksreleased;
b4de8c04 143 int e1, e2, depth, lastseg, num, offset, seg, size;
4f083fd7 144
a79b7b81
KB
145#ifdef VERBOSE
146 printf("lfs_truncate\n");
147#endif
b4de8c04 148 vnode_pager_setsize(vp, (u_long)length);
b3071295 149
b4de8c04 150 ip = VTOI(vp);
b3071295
KB
151 fs = ip->i_lfs;
152
153 /* If truncating the file to 0, update the version number. */
b4de8c04 154 if (length == 0) {
b3071295
KB
155 LFS_IENTRY(ifp, fs, ip->i_number, bp);
156 ++ifp->if_version;
157 LFS_UBWRITE(bp);
158 }
159
b4de8c04 160 /* If length is larger than the file, just update the times. */
d942bf69 161 tv = time;
b4de8c04 162 if (ip->i_size <= length) {
2c68aab8 163 ip->i_flag |= ICHG|IUPD;
d942bf69 164 return (VOP_UPDATE(vp, &tv, &tv, 1));
7b2e4f05 165 }
b3071295 166
2c68aab8
KB
167 /*
168 * Calculate index into inode's block list of last direct and indirect
169 * blocks (if any) which we want to keep. Lastblock is 0 when the
170 * file is truncated to 0.
171 */
b4de8c04 172 lastblock = lblkno(fs, length + fs->lfs_bsize - 1);
2c68aab8 173 olastblock = lblkno(fs, ip->i_size + fs->lfs_bsize - 1) - 1;
29ad237c 174
c0bb1685 175 /*
29ad237c
KB
176 * Update the size of the file. If the file is not being truncated to
177 * a block boundry, the contents of the partial block following the end
178 * of the file must be zero'ed in case it ever become accessable again
179 * because of subsequent file growth.
28821bc5 180 */
b4de8c04 181 offset = blkoff(fs, length);
29ad237c 182 if (offset == 0)
b4de8c04 183 ip->i_size = length;
29ad237c 184 else {
b4de8c04 185 lbn = lblkno(fs, length);
4b61628b 186#ifdef QUOTA
b4de8c04
KB
187 if (e1 = getinoquota(ip))
188 return (e1);
d5075120 189#endif
b4de8c04
KB
190 if (e1 = bread(vp, lbn, fs->lfs_bsize, NOCRED, &bp))
191 return (e1);
192 ip->i_size = length;
a79b7b81 193 size = blksize(fs);
b4de8c04 194 (void)vnode_pager_uncache(vp);
a5e62f37 195 bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset));
9cf42d55 196 allocbuf(bp, size);
f28a1334 197 LFS_UBWRITE(bp);
5d5124a1 198 }
f28a1334 199 /*
2c68aab8
KB
200 * Modify sup->su_nbyte counters for each deleted block; keep track
201 * of number of blocks removed for ip->i_blocks.
202 */
203 blocksreleased = 0;
204 num = 0;
205 lastseg = -1;
206
207 for (lbn = olastblock; lbn >= lastblock;) {
b4de8c04 208 lfs_bmaparray(vp, lbn, &daddr, a, &depth);
2c68aab8
KB
209 if (lbn == olastblock)
210 for (i = NIADDR + 2; i--;)
211 a_end[i] = a[i];
212 switch (depth) {
213 case 0: /* Direct block. */
214 daddr = ip->i_db[lbn];
215 SEGDEC;
216 ip->i_db[lbn] = 0;
217 --lbn;
218 break;
219#ifdef DIAGNOSTIC
220 case 1: /* An indirect block. */
221 panic("lfs_truncate: lfs_bmaparray returned depth 1");
222 /* NOTREACHED */
223#endif
224 default: /* Chain of indirect blocks. */
8f42dbe0
JH
225 inp = a + --depth;
226 if (inp->in_off > 0 && lbn != lastblock) {
227 lbn -= inp->in_off < lbn - lastblock ?
228 inp->in_off : lbn - lastblock;
2c68aab8
KB
229 break;
230 }
8f42dbe0
JH
231 for (; depth && (inp->in_off == 0 || lbn == lastblock);
232 --inp, --depth) {
2c68aab8
KB
233 /*
234 * XXX
235 * The indirect block may not yet exist, so
236 * bread will create one just so we can free
237 * it.
238 */
b4de8c04 239 if (bread(vp,
8f42dbe0 240 inp->in_lbn, fs->lfs_bsize, NOCRED, &bp))
2c68aab8 241 panic("lfs_truncate: bread bno %d",
8f42dbe0
JH
242 inp->in_lbn);
243 daddrp = bp->b_un.b_daddr + inp->in_off;
244 for (i = inp->in_off;
2c68aab8
KB
245 i++ <= a_end[depth].in_off;) {
246 daddr = *daddrp++;
247 SEGDEC;
248 }
c86ca11e 249 a_end[depth].in_off = NINDIR(fs) - 1;
8f42dbe0 250 if (inp->in_off == 0)
c86ca11e
CS
251 brelse (bp);
252 else {
8f42dbe0 253 bzero(bp->b_un.b_daddr + inp->in_off,
2c68aab8 254 fs->lfs_bsize -
8f42dbe0 255 inp->in_off * sizeof(daddr_t));
2c68aab8 256 LFS_UBWRITE(bp);
c86ca11e 257 }
2c68aab8 258 }
c86ca11e 259 if (depth == 0 && a[1].in_off == 0) {
2c68aab8
KB
260 off = a[0].in_off;
261 daddr = ip->i_ib[off];
262 SEGDEC;
263 ip->i_ib[off] = 0;
264 }
5b792b30 265 if (lbn == lastblock || lbn <= NDADDR)
2c68aab8
KB
266 --lbn;
267 else {
268 lbn -= NINDIR(fs);
269 if (lbn < lastblock)
270 lbn = lastblock;
271 }
272 }
273 }
4ee2ad24 274 UPDATE_SEGUSE;
2c68aab8
KB
275 ip->i_blocks -= blocksreleased;
276 /*
f28a1334 277 * XXX
2c68aab8
KB
278 * Currently, we don't know when we allocate an indirect block, so
279 * ip->i_blocks isn't getting incremented appropriately. As a result,
280 * when we delete any indirect blocks, we get a bad number here.
f28a1334 281 */
2c68aab8
KB
282 if (ip->i_blocks < 0)
283 ip->i_blocks = 0;
284 ip->i_flag |= ICHG|IUPD;
b4de8c04 285 e1 = vinvalbuf(vp, length > 0, ap->a_cred, ap->a_p);
d942bf69 286 e2 = VOP_UPDATE(vp, &tv, &tv, MNT_WAIT);
b4de8c04 287 return (e1 ? e1 : e2 ? e2 : 0);
7188ac27 288}