ilock/irele and get rid of FPORT and FNET stuff
[unix-history] / usr / src / sys / ufs / ffs / ffs_inode.c
CommitLineData
231ed58b 1/* ffs_inode.c 4.6 81/10/11 */
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)
44dev_t dev;
45ino_t ino;
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)
73dev_t dev;
74ino_t ino;
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]) {
86 if(ino == ip->i_number && dev == ip->i_dev) {
87 if((ip->i_flag&ILOCK) != 0) {
88 ip->i_flag |= IWANT;
89 sleep((caddr_t)ip, PINOD);
90 goto loop;
91 }
92 if((ip->i_flag&IMOUNT) != 0) {
93 for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
94 if(mp->m_inodp == ip) {
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 }
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 */
125 if((bp->b_flags&B_ERROR) != 0) {
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)
138register struct inode *ip;
139register struct dinode *dp;
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)
167register struct inode *ip;
168{
169 register int i, x;
170 register struct inode *jp;
171
172 if(ip->i_count == 1) {
173 ip->i_flag |= ILOCK;
174 if(ip->i_nlink <= 0) {
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);
5d5124a1
BJ
181 prele(ip);
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
201 prele(ip);
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)
5d5124a1
BJ
214register struct inode *ip;
215time_t *ta, *tm;
c0bb1685 216int waitfor;
5d5124a1
BJ
217{
218 register struct buf *bp;
219 struct dinode *dp;
220 register char *p1, *p2;
221 register int i;
222
223 if((ip->i_flag&(IUPD|IACC|ICHG)) != 0) {
224 if(getfs(ip->i_dev)->s_ronly)
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++;
231ed58b 244 if(*p2++ != 0)
5d5124a1
BJ
245 printf("iaddress > 2^24\n");
246 }
247 if(ip->i_flag&IACC)
248 dp->di_atime = *ta;
249 if(ip->i_flag&IUPD)
250 dp->di_mtime = *tm;
251 if(ip->i_flag&ICHG)
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)
271register struct inode *ip;
272{
273 register i;
274 dev_t dev;
275 daddr_t bn;
c0bb1685 276 struct inode itmp;
5d5124a1
BJ
277
278 if (ip->i_vfdcnt)
279 panic("itrunc");
280 i = ip->i_mode & IFMT;
281 if (i!=IFREG && i!=IFDIR)
282 return;
c0bb1685
BJ
283
284 /*
285 * Clean inode on disk before freeing blocks
286 * to insure no duplicates if system crashes.
287 */
288 itmp = *ip;
289 itmp.i_size = 0;
290 for (i = 0; i < NADDR; i++)
291 itmp.i_un.i_addr[i] = 0;
292 itmp.i_flag |= ICHG|IUPD;
293 iupdat(&itmp, &time, &time, 1);
294 ip->i_flag &= ~(IUPD|IACC|ICHG);
295
296 /*
297 * Now return blocks to free list... if machine
298 * crashes, they will be harmless MISSING blocks.
299 */
5d5124a1
BJ
300 dev = ip->i_dev;
301 for(i=NADDR-1; i>=0; i--) {
302 bn = ip->i_un.i_addr[i];
303 if(bn == (daddr_t)0)
304 continue;
305 ip->i_un.i_addr[i] = (daddr_t)0;
306 switch(i) {
307
308 default:
309 free(dev, bn);
310 break;
311
312 case NADDR-3:
313 tloop(dev, bn, 0, 0);
314 break;
315
316 case NADDR-2:
317 tloop(dev, bn, 1, 0);
318 break;
319
320 case NADDR-1:
321 tloop(dev, bn, 1, 1);
322 }
323 }
324 ip->i_size = 0;
c0bb1685
BJ
325 /*
326 * Inode was written and flags updated above.
327 * No need to modify flags here.
328 */
5d5124a1
BJ
329}
330
331tloop(dev, bn, f1, f2)
332dev_t dev;
333daddr_t bn;
334{
335 register i;
336 register struct buf *bp;
337 register daddr_t *bap;
338 daddr_t nb;
339
340 bp = NULL;
341 for(i=NINDIR-1; i>=0; i--) {
342 if(bp == NULL) {
343 bp = bread(dev, bn);
344 if (bp->b_flags & B_ERROR) {
345 brelse(bp);
346 return;
347 }
348 bap = bp->b_un.b_daddr;
349 }
350 nb = bap[i];
351 if(nb == (daddr_t)0)
352 continue;
353 if(f1) {
354 brelse(bp);
355 bp = NULL;
356 tloop(dev, nb, f2, 0);
357 } else
358 free(dev, nb);
359 }
360 if(bp != NULL)
361 brelse(bp);
362 free(dev, bn);
363}
364
365/*
366 * Make a new file.
367 */
368struct inode *
369maknode(mode)
370{
371 register struct inode *ip;
372
373 ip = ialloc(u.u_pdir->i_dev);
374 if(ip == NULL) {
375 iput(u.u_pdir);
376 return(NULL);
377 }
378 ip->i_flag |= IACC|IUPD|ICHG;
379 if((mode&IFMT) == 0)
380 mode |= IFREG;
381 ip->i_mode = mode & ~u.u_cmask;
382 ip->i_nlink = 1;
383 ip->i_uid = u.u_uid;
384 ip->i_gid = u.u_gid;
c0bb1685
BJ
385
386 /*
387 * Make sure inode goes to disk before directory entry.
388 */
389 iupdat(ip, &time, &time, 1);
390
5d5124a1
BJ
391 wdir(ip);
392 return(ip);
393}
394
395/*
396 * Write a directory entry with
397 * parameters left as side effects
398 * to a call to namei.
399 */
400wdir(ip)
401struct inode *ip;
402{
403
404 u.u_dent.d_ino = ip->i_number;
405 bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_dent.d_name, DIRSIZ);
406 u.u_count = sizeof(struct direct);
407 u.u_segflg = 1;
408 u.u_base = (caddr_t)&u.u_dent;
409 writei(u.u_pdir);
410 iput(u.u_pdir);
411}
d6a210b8
BJ
412
413#ifdef plock
414#undef plock
415#endif
416#ifdef prele
417#undef prele
418#endif
419/*
420 * Lock an inode (should be called ilock).
421 * If its already locked,
422 * set the WANT bit and sleep.
423 */
424plock(ip)
425register struct inode *ip;
426{
427
428 while(ip->i_flag&ILOCK) {
429 ip->i_flag |= IWANT;
430 sleep((caddr_t)ip, PINOD);
431 }
432 ip->i_flag |= ILOCK;
433}
434
435/*
436 * Unlock an inode.
437 * If WANT bit is on,
438 * wakeup.
439 */
440prele(ip)
441register struct inode *ip;
442{
443
444 ip->i_flag &= ~ILOCK;
445 if(ip->i_flag&IWANT) {
446 ip->i_flag &= ~IWANT;
447 wakeup((caddr_t)ip);
448 }
449}