bring up to version 4.1
[unix-history] / usr / src / sys / ufs / ffs / ffs_inode.c
CommitLineData
5485e062 1/* ffs_inode.c 4.9 82/02/27 */
5d5124a1
BJ
2
3#include "../h/param.h"
4#include "../h/systm.h"
5#include "../h/mount.h"
6#include "../h/dir.h"
7#include "../h/user.h"
8#include "../h/inode.h"
9#include "../h/ino.h"
10#include "../h/filsys.h"
11#include "../h/conf.h"
12#include "../h/buf.h"
13#include "../h/inline.h"
14
15#define INOHSZ 63
16#define INOHASH(dev,ino) (((dev)+(ino))%INOHSZ)
17short inohash[INOHSZ];
18short ifreel;
19
20/*
21 * Initialize hash links for inodes
22 * and build inode free list.
23 */
24ihinit()
25{
26 register int i;
75105cf0 27 register struct inode *ip = inode;
5d5124a1
BJ
28
29 ifreel = 0;
75105cf0
BJ
30 for (i = 0; i < ninode-1; i++, ip++)
31 ip->i_hlink = i+1;
32 ip->i_hlink = -1;
5d5124a1
BJ
33 for (i = 0; i < INOHSZ; i++)
34 inohash[i] = -1;
35}
36
37/*
38 * Find an inode if it is incore.
39 * This is the equivalent, for inodes,
40 * of ``incore'' in bio.c or ``pfind'' in subr.c.
41 */
42struct inode *
43ifind(dev, ino)
7494ef16
BJ
44 dev_t dev;
45 ino_t ino;
5d5124a1
BJ
46{
47 register struct inode *ip;
48
49 for (ip = &inode[inohash[INOHASH(dev,ino)]]; ip != &inode[-1];
50 ip = &inode[ip->i_hlink])
51 if (ino==ip->i_number && dev==ip->i_dev)
52 return (ip);
53 return ((struct inode *)0);
54}
55
56/*
57 * Look up an inode by device,inumber.
58 * If it is in core (in the inode structure),
59 * honor the locking protocol.
60 * If it is not in core, read it in from the
61 * specified device.
62 * If the inode is mounted on, perform
63 * the indicated indirection.
64 * In all cases, a pointer to a locked
65 * inode structure is returned.
66 *
5d5124a1
BJ
67 * panic: no imt -- if the mounted file
68 * system is not in the mount table.
69 * "cannot happen"
70 */
71struct inode *
72iget(dev, ino)
7494ef16
BJ
73 dev_t dev;
74 ino_t ino;
5d5124a1
BJ
75{
76 register struct inode *ip;
77 register struct mount *mp;
78 register struct buf *bp;
79 register struct dinode *dp;
80 register int slot;
81
82loop:
83 slot = INOHASH(dev, ino);
84 ip = &inode[inohash[slot]];
85 while (ip != &inode[-1]) {
7494ef16
BJ
86 if (ino == ip->i_number && dev == ip->i_dev) {
87 if ((ip->i_flag&ILOCK) != 0) {
5d5124a1
BJ
88 ip->i_flag |= IWANT;
89 sleep((caddr_t)ip, PINOD);
90 goto loop;
91 }
7494ef16 92 if ((ip->i_flag&IMOUNT) != 0) {
5d5124a1 93 for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
7494ef16 94 if (mp->m_inodp == ip) {
5d5124a1
BJ
95 dev = mp->m_dev;
96 ino = ROOTINO;
97 goto loop;
98 }
99 panic("no imt");
100 }
101 ip->i_count++;
102 ip->i_flag |= ILOCK;
103 return(ip);
104 }
105 ip = &inode[ip->i_hlink];
106 }
7494ef16 107 if (ifreel < 0) {
945fbb1b 108 tablefull("inode");
5d5124a1
BJ
109 u.u_error = ENFILE;
110 return(NULL);
111 }
112 ip = &inode[ifreel];
113 ifreel = ip->i_hlink;
114 ip->i_hlink = inohash[slot];
115 inohash[slot] = ip - inode;
116 ip->i_dev = dev;
117 ip->i_number = ino;
118 ip->i_flag = ILOCK;
119 ip->i_count++;
120 ip->i_un.i_lastr = 0;
121 bp = bread(dev, itod(ino));
122 /*
123 * Check I/O errors
124 */
7494ef16 125 if ((bp->b_flags&B_ERROR) != 0) {
5d5124a1
BJ
126 brelse(bp);
127 iput(ip);
128 return(NULL);
129 }
130 dp = bp->b_un.b_dino;
131 dp += itoo(ino);
132 iexpand(ip, dp);
133 brelse(bp);
134 return(ip);
135}
136
137iexpand(ip, dp)
7494ef16
BJ
138 register struct inode *ip;
139 register struct dinode *dp;
5d5124a1
BJ
140{
141 register char *p1, *p2;
142 register int i;
143
144 ip->i_mode = dp->di_mode;
145 ip->i_nlink = dp->di_nlink;
146 ip->i_uid = dp->di_uid;
147 ip->i_gid = dp->di_gid;
148 ip->i_size = dp->di_size;
149 p1 = (char *)ip->i_un.i_addr;
150 p2 = (char *)dp->di_addr;
151 for(i=0; i<NADDR; i++) {
152 *p1++ = *p2++;
153 *p1++ = *p2++;
154 *p1++ = *p2++;
155 *p1++ = 0;
156 }
157}
158
159/*
160 * Decrement reference count of
161 * an inode structure.
162 * On the last reference,
163 * write the inode out and if necessary,
164 * truncate and deallocate the file.
165 */
166iput(ip)
7494ef16 167 register struct inode *ip;
5d5124a1
BJ
168{
169 register int i, x;
170 register struct inode *jp;
171
7494ef16 172 if (ip->i_count == 1) {
5d5124a1 173 ip->i_flag |= ILOCK;
7494ef16 174 if (ip->i_nlink <= 0) {
5d5124a1
BJ
175 itrunc(ip);
176 ip->i_mode = 0;
177 ip->i_flag |= IUPD|ICHG;
178 ifree(ip->i_dev, ip->i_number);
179 }
c0bb1685 180 IUPDAT(ip, &time, &time, 0);
7494ef16 181 irele(ip);
5d5124a1
BJ
182 i = INOHASH(ip->i_dev, ip->i_number);
183 x = ip - inode;
184 if (inohash[i] == x) {
185 inohash[i] = ip->i_hlink;
186 } else {
187 for (jp = &inode[inohash[i]]; jp != &inode[-1];
188 jp = &inode[jp->i_hlink])
189 if (jp->i_hlink == x) {
190 jp->i_hlink = ip->i_hlink;
191 goto done;
192 }
193 panic("iput");
194 }
195done:
196 ip->i_hlink = ifreel;
197 ifreel = x;
198 ip->i_flag = 0;
199 ip->i_number = 0;
200 } else
7494ef16 201 irele(ip);
5d5124a1
BJ
202 ip->i_count--;
203}
204
205/*
206 * Check accessed and update flags on
207 * an inode structure.
208 * If any is on, update the inode
209 * with the current time.
c0bb1685
BJ
210 * If waitfor is given, then must insure
211 * i/o order so wait for write to complete.
5d5124a1 212 */
c0bb1685 213iupdat(ip, ta, tm, waitfor)
7494ef16
BJ
214 register struct inode *ip;
215 time_t *ta, *tm;
216 int waitfor;
5d5124a1
BJ
217{
218 register struct buf *bp;
219 struct dinode *dp;
220 register char *p1, *p2;
221 register int i;
222
7494ef16
BJ
223 if ((ip->i_flag&(IUPD|IACC|ICHG)) != 0) {
224 if (getfs(ip->i_dev)->s_ronly)
5d5124a1
BJ
225 return;
226 bp = bread(ip->i_dev, itod(ip->i_number));
227 if (bp->b_flags & B_ERROR) {
228 brelse(bp);
229 return;
230 }
231 dp = bp->b_un.b_dino;
232 dp += itoo(ip->i_number);
233 dp->di_mode = ip->i_mode;
234 dp->di_nlink = ip->i_nlink;
235 dp->di_uid = ip->i_uid;
236 dp->di_gid = ip->i_gid;
237 dp->di_size = ip->i_size;
238 p1 = (char *)dp->di_addr;
239 p2 = (char *)ip->i_un.i_addr;
240 for(i=0; i<NADDR; i++) {
241 *p1++ = *p2++;
242 *p1++ = *p2++;
243 *p1++ = *p2++;
7494ef16 244 if (*p2++ != 0)
5d5124a1
BJ
245 printf("iaddress > 2^24\n");
246 }
7494ef16 247 if (ip->i_flag&IACC)
5d5124a1 248 dp->di_atime = *ta;
7494ef16 249 if (ip->i_flag&IUPD)
5d5124a1 250 dp->di_mtime = *tm;
7494ef16 251 if (ip->i_flag&ICHG)
5d5124a1
BJ
252 dp->di_ctime = time;
253 ip->i_flag &= ~(IUPD|IACC|ICHG);
c0bb1685
BJ
254 if (waitfor)
255 bwrite(bp);
256 else
257 bdwrite(bp);
5d5124a1
BJ
258 }
259}
260
261/*
262 * Free all the disk blocks associated
263 * with the specified inode structure.
264 * The blocks of the file are removed
265 * in reverse order. This FILO
266 * algorithm will tend to maintain
267 * a contiguous free list much longer
268 * than FIFO.
269 */
270itrunc(ip)
7494ef16 271 register struct inode *ip;
5d5124a1
BJ
272{
273 register i;
274 dev_t dev;
275 daddr_t bn;
c0bb1685 276 struct inode itmp;
5d5124a1 277
5d5124a1 278 i = ip->i_mode & IFMT;
5485e062 279 if (i!=IFREG && i!=IFDIR && i!=IFLNK)
5d5124a1 280 return;
c0bb1685
BJ
281
282 /*
283 * Clean inode on disk before freeing blocks
284 * to insure no duplicates if system crashes.
285 */
286 itmp = *ip;
287 itmp.i_size = 0;
288 for (i = 0; i < NADDR; i++)
289 itmp.i_un.i_addr[i] = 0;
290 itmp.i_flag |= ICHG|IUPD;
291 iupdat(&itmp, &time, &time, 1);
292 ip->i_flag &= ~(IUPD|IACC|ICHG);
293
294 /*
295 * Now return blocks to free list... if machine
296 * crashes, they will be harmless MISSING blocks.
297 */
5d5124a1
BJ
298 dev = ip->i_dev;
299 for(i=NADDR-1; i>=0; i--) {
300 bn = ip->i_un.i_addr[i];
7494ef16 301 if (bn == (daddr_t)0)
5d5124a1
BJ
302 continue;
303 ip->i_un.i_addr[i] = (daddr_t)0;
304 switch(i) {
305
306 default:
307 free(dev, bn);
308 break;
309
310 case NADDR-3:
311 tloop(dev, bn, 0, 0);
312 break;
313
314 case NADDR-2:
315 tloop(dev, bn, 1, 0);
316 break;
317
318 case NADDR-1:
319 tloop(dev, bn, 1, 1);
320 }
321 }
322 ip->i_size = 0;
c0bb1685
BJ
323 /*
324 * Inode was written and flags updated above.
325 * No need to modify flags here.
326 */
5d5124a1
BJ
327}
328
329tloop(dev, bn, f1, f2)
330dev_t dev;
331daddr_t bn;
332{
333 register i;
334 register struct buf *bp;
335 register daddr_t *bap;
336 daddr_t nb;
337
338 bp = NULL;
339 for(i=NINDIR-1; i>=0; i--) {
7494ef16 340 if (bp == NULL) {
5d5124a1
BJ
341 bp = bread(dev, bn);
342 if (bp->b_flags & B_ERROR) {
343 brelse(bp);
344 return;
345 }
346 bap = bp->b_un.b_daddr;
347 }
348 nb = bap[i];
7494ef16 349 if (nb == (daddr_t)0)
5d5124a1 350 continue;
7494ef16 351 if (f1) {
5d5124a1
BJ
352 brelse(bp);
353 bp = NULL;
354 tloop(dev, nb, f2, 0);
355 } else
356 free(dev, nb);
357 }
7494ef16 358 if (bp != NULL)
5d5124a1
BJ
359 brelse(bp);
360 free(dev, bn);
361}
362
363/*
364 * Make a new file.
365 */
366struct inode *
367maknode(mode)
368{
369 register struct inode *ip;
370
371 ip = ialloc(u.u_pdir->i_dev);
7494ef16 372 if (ip == NULL) {
5d5124a1
BJ
373 iput(u.u_pdir);
374 return(NULL);
375 }
376 ip->i_flag |= IACC|IUPD|ICHG;
7494ef16 377 if ((mode&IFMT) == 0)
5d5124a1
BJ
378 mode |= IFREG;
379 ip->i_mode = mode & ~u.u_cmask;
380 ip->i_nlink = 1;
381 ip->i_uid = u.u_uid;
4f4caf05 382 ip->i_gid = u.u_pdir->i_gid;
c0bb1685
BJ
383
384 /*
385 * Make sure inode goes to disk before directory entry.
386 */
387 iupdat(ip, &time, &time, 1);
388
5d5124a1
BJ
389 wdir(ip);
390 return(ip);
391}
392
393/*
394 * Write a directory entry with
395 * parameters left as side effects
396 * to a call to namei.
397 */
398wdir(ip)
7494ef16 399 struct inode *ip;
5d5124a1
BJ
400{
401
402 u.u_dent.d_ino = ip->i_number;
403 bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_dent.d_name, DIRSIZ);
404 u.u_count = sizeof(struct direct);
405 u.u_segflg = 1;
406 u.u_base = (caddr_t)&u.u_dent;
407 writei(u.u_pdir);
408 iput(u.u_pdir);
409}
d6a210b8 410
7494ef16
BJ
411#ifdef ilock
412#undef ilock
d6a210b8 413#endif
7494ef16
BJ
414#ifdef irele
415#undef irele
d6a210b8
BJ
416#endif
417/*
7494ef16 418 * Lock an inode. If its already locked, set the WANT bit and sleep.
d6a210b8 419 */
7494ef16
BJ
420ilock(ip)
421 register struct inode *ip;
d6a210b8
BJ
422{
423
7494ef16 424 while (ip->i_flag&ILOCK) {
d6a210b8
BJ
425 ip->i_flag |= IWANT;
426 sleep((caddr_t)ip, PINOD);
427 }
428 ip->i_flag |= ILOCK;
429}
430
431/*
7494ef16 432 * Unlock an inode. If WANT bit is on, wakeup.
d6a210b8 433 */
7494ef16
BJ
434irele(ip)
435 register struct inode *ip;
d6a210b8
BJ
436{
437
438 ip->i_flag &= ~ILOCK;
7494ef16 439 if (ip->i_flag&IWANT) {
d6a210b8
BJ
440 ip->i_flag &= ~IWANT;
441 wakeup((caddr_t)ip);
442 }
443}