new itrunc
[unix-history] / usr / src / sys / ufs / lfs / lfs_inode.c
... / ...
CommitLineData
1/* lfs_inode.c 4.22 82/08/03 */
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/fs.h"
10#include "../h/conf.h"
11#include "../h/buf.h"
12#include "../h/inline.h"
13#ifdef QUOTA
14#include "../h/quota.h"
15#endif
16
17#define INOHSZ 63
18#if ((INOHSZ&(INOHSZ-1)) == 0)
19#define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1))
20#else
21#define INOHASH(dev,ino) (((dev)+(ino))%INOHSZ)
22#endif
23
24union ihead { /* inode LRU cache, Chris Maltby */
25 union ihead *ih_head[2];
26 struct inode *ih_chain[2];
27} ihead[INOHSZ];
28
29struct inode *ifreeh, **ifreet;
30
31/*
32 * Initialize hash links for inodes
33 * and build inode free list.
34 */
35ihinit()
36{
37 register int i;
38 register struct inode *ip = inode;
39 register union ihead *ih = ihead;
40
41 for (i = INOHSZ; --i >= 0; ih++) {
42 ih->ih_head[0] = ih;
43 ih->ih_head[1] = ih;
44 }
45 ifreeh = ip;
46 ifreet = &ip->i_freef;
47 ip->i_freeb = &ifreeh;
48 ip->i_forw = ip;
49 ip->i_back = ip;
50 for (i = ninode; --i > 0; ) {
51 ++ip;
52 ip->i_forw = ip;
53 ip->i_back = ip;
54 *ifreet = ip;
55 ip->i_freeb = ifreet;
56 ifreet = &ip->i_freef;
57 }
58 ip->i_freef = NULL;
59}
60
61#ifdef notdef
62/*
63 * Find an inode if it is incore.
64 * This is the equivalent, for inodes,
65 * of ``incore'' in bio.c or ``pfind'' in subr.c.
66 */
67struct inode *
68ifind(dev, ino)
69 dev_t dev;
70 ino_t ino;
71{
72 register struct inode *ip;
73 register union ihead *ih;
74
75 ih = &ihead[INOHASH(dev, ino)];
76 for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
77 if (ino==ip->i_number && dev==ip->i_dev)
78 return (ip);
79 return ((struct inode *)0);
80}
81#endif notdef
82
83/*
84 * Look up an inode by device,inumber.
85 * If it is in core (in the inode structure),
86 * honor the locking protocol.
87 * If it is not in core, read it in from the
88 * specified device.
89 * If the inode is mounted on, perform
90 * the indicated indirection.
91 * In all cases, a pointer to a locked
92 * inode structure is returned.
93 *
94 * panic: no imt -- if the mounted file
95 * system is not in the mount table.
96 * "cannot happen"
97 */
98struct inode *
99iget(dev, fs, ino)
100 dev_t dev;
101 register struct fs *fs;
102 ino_t ino;
103{
104 register struct inode *ip;
105 register union ihead *ih;
106 register struct mount *mp;
107 register struct buf *bp;
108 register struct dinode *dp;
109 register struct inode *iq;
110
111loop:
112 if (getfs(dev) != fs)
113 panic("iget: bad fs");
114 ih = &ihead[INOHASH(dev, ino)];
115 for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw)
116 if (ino == ip->i_number && dev == ip->i_dev) {
117 if ((ip->i_flag&ILOCK) != 0) {
118 ip->i_flag |= IWANT;
119 sleep((caddr_t)ip, PINOD);
120 goto loop;
121 }
122 if ((ip->i_flag&IMOUNT) != 0) {
123 for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
124 if(mp->m_inodp == ip) {
125 dev = mp->m_dev;
126 fs = mp->m_bufp->b_un.b_fs;
127 ino = ROOTINO;
128 goto loop;
129 }
130 panic("no imt");
131 }
132 if (ip->i_count == 0) { /* ino on free list */
133 if (iq = ip->i_freef)
134 iq->i_freeb = ip->i_freeb;
135 else
136 ifreet = ip->i_freeb;
137 *ip->i_freeb = iq;
138 ip->i_freef = NULL;
139 ip->i_freeb = NULL;
140 }
141 ip->i_count++;
142 ip->i_flag |= ILOCK;
143 return(ip);
144 }
145
146 if ((ip = ifreeh) == NULL) {
147 tablefull("inode");
148 u.u_error = ENFILE;
149 return(NULL);
150 }
151 if (iq = ip->i_freef)
152 iq->i_freeb = &ifreeh;
153 ifreeh = iq;
154 ip->i_freef = NULL;
155 ip->i_freeb = NULL;
156 /*
157 * Now to take inode off the hash chain it was on
158 * (initially, or after an iflush, it is on a "hash chain"
159 * consisting entirely of itself, and pointed to by no-one,
160 * but that doesn't matter), and put it on the chain for
161 * its new (ino, dev) pair
162 */
163 remque(ip);
164 insque(ip, ih);
165#ifdef QUOTA
166 dqrele(ip->i_dquot);
167#endif
168 ip->i_dev = dev;
169 ip->i_fs = fs;
170 ip->i_number = ino;
171 ip->i_flag = ILOCK;
172 ip->i_count++;
173 ip->i_lastr = 0;
174 bp = bread(dev, fsbtodb(fs, itod(fs, ino)), fs->fs_bsize);
175 /*
176 * Check I/O errors
177 */
178 if ((bp->b_flags&B_ERROR) != 0) {
179 brelse(bp);
180 /*
181 * the inode doesn't contain anything useful, so it would
182 * be misleading to leave it on its hash chain.
183 * 'iput' will take care of putting it back on the free list.
184 */
185 remque(ip);
186 ip->i_forw = ip;
187 ip->i_back = ip;
188 /*
189 * we also loose its inumber, just in case (as iput
190 * doesn't do that any more) - but as it isn't on its
191 * hash chain, I doubt if this is really necessary .. kre
192 * (probably the two methods are interchangable)
193 */
194 ip->i_number = 0;
195#ifdef QUOTA
196 ip->i_dquot = NODQUOT;
197#endif
198 iput(ip);
199 return(NULL);
200 }
201 dp = bp->b_un.b_dino;
202 dp += itoo(fs, ino);
203 ip->i_ic = dp->di_ic;
204 brelse(bp);
205#ifdef QUOTA
206 if (ip->i_mode == 0)
207 ip->i_dquot = NODQUOT;
208 else
209 ip->i_dquot = inoquota(ip);
210#endif
211 return (ip);
212}
213
214/*
215 * Decrement reference count of
216 * an inode structure.
217 * On the last reference,
218 * write the inode out and if necessary,
219 * truncate and deallocate the file.
220 */
221iput(ip)
222 register struct inode *ip;
223{
224
225 if ((ip->i_flag & ILOCK) == 0)
226 panic("iput");
227 iunlock(ip);
228 irele(ip);
229}
230
231irele(ip)
232 register struct inode *ip;
233{
234 register int i, x;
235 register struct inode *jp;
236 int mode;
237
238 if (ip->i_count == 1) {
239 ip->i_flag |= ILOCK;
240 if (ip->i_nlink <= 0) {
241 itrunc(ip);
242 mode = ip->i_mode;
243 ip->i_mode = 0;
244 ip->i_rdev = 0;
245 ip->i_flag |= IUPD|ICHG;
246 ifree(ip, ip->i_number, mode);
247#ifdef QUOTA
248 chkiq(ip->i_dev, ip, ip->i_uid, 0);
249 dqrele(ip->i_dquot);
250 ip->i_dquot = NODQUOT;
251#endif
252 }
253 IUPDAT(ip, &time, &time, 0);
254 iunlock(ip);
255 ip->i_flag = 0;
256 /*
257 * Put the inode on the end of the free list.
258 * Possibly in some cases it would be better to
259 * put the inode at the head of the free list,
260 * (eg: where i_mode == 0 || i_number == 0)
261 * but I will think about that later .. kre
262 * (i_number is rarely 0 - only after an i/o error in iget,
263 * where i_mode == 0, the inode will probably be wanted
264 * again soon for an ialloc, so possibly we should keep it)
265 */
266 if (ifreeh) {
267 *ifreet = ip;
268 ip->i_freeb = ifreet;
269 } else {
270 ifreeh = ip;
271 ip->i_freeb = &ifreeh;
272 }
273 ip->i_freef = NULL;
274 ifreet = &ip->i_freef;
275 }
276 ip->i_count--;
277}
278
279/*
280 * Check accessed and update flags on
281 * an inode structure.
282 * If any is on, update the inode
283 * with the current time.
284 * If waitfor is given, then must insure
285 * i/o order so wait for write to complete.
286 */
287iupdat(ip, ta, tm, waitfor)
288 register struct inode *ip;
289 time_t *ta, *tm;
290 int waitfor;
291{
292 register struct buf *bp;
293 struct dinode *dp;
294 register struct fs *fp;
295
296 fp = ip->i_fs;
297 if ((ip->i_flag & (IUPD|IACC|ICHG)) != 0) {
298 if (fp->fs_ronly)
299 return;
300 bp = bread(ip->i_dev, fsbtodb(fp, itod(fp, ip->i_number)),
301 fp->fs_bsize);
302 if (bp->b_flags & B_ERROR) {
303 brelse(bp);
304 return;
305 }
306 if (ip->i_flag&IACC)
307 ip->i_atime = *ta;
308 if (ip->i_flag&IUPD)
309 ip->i_mtime = *tm;
310 if (ip->i_flag&ICHG)
311 ip->i_ctime = time;
312 ip->i_flag &= ~(IUPD|IACC|ICHG);
313 dp = bp->b_un.b_dino + itoo(fp, ip->i_number);
314 dp->di_ic = ip->i_ic;
315 if (waitfor)
316 bwrite(bp);
317 else
318 bdwrite(bp);
319 }
320}
321
322/*
323 * Free all the disk blocks associated
324 * with the specified inode structure.
325 * The blocks of the file are removed
326 * in reverse order.
327 */
328itrunc(ip)
329 register struct inode *ip;
330{
331 register i;
332 dev_t dev;
333 daddr_t bn;
334 struct inode itmp;
335 register struct fs *fs;
336#ifdef QUOTA
337 register long cnt = 0;
338 long tloop();
339#endif
340 /*
341 * Only plain files, directories and symbolic
342 * links contain blocks.
343 */
344 i = ip->i_mode & IFMT;
345 if (i != IFREG && i != IFDIR && i != IFLNK)
346 return;
347
348 /*
349 * Clean inode on disk before freeing blocks
350 * to insure no duplicates if system crashes.
351 */
352 itmp = *ip;
353 itmp.i_size = 0;
354 for (i = 0; i < NDADDR; i++)
355 itmp.i_db[i] = 0;
356 for (i = 0; i < NIADDR; i++)
357 itmp.i_ib[i] = 0;
358 itmp.i_flag |= ICHG|IUPD;
359 iupdat(&itmp, &time, &time, 1);
360 ip->i_flag &= ~(IUPD|IACC|ICHG);
361
362 /*
363 * Now return blocks to free list... if machine
364 * crashes, they will be harmless MISSING blocks.
365 */
366 dev = ip->i_dev;
367 fs = ip->i_fs;
368 /*
369 * release double indirect block first
370 */
371 bn = ip->i_ib[NIADDR-1];
372 if (bn != (daddr_t)0) {
373 ip->i_ib[NIADDR - 1] = (daddr_t)0;
374#ifdef QUOTA
375 cnt +=
376#endif
377 tloop(ip, bn, 1);
378 }
379 /*
380 * release single indirect blocks second
381 */
382 for (i = NIADDR - 2; i >= 0; i--) {
383 bn = ip->i_ib[i];
384 if (bn != (daddr_t)0) {
385 ip->i_ib[i] = (daddr_t)0;
386#ifdef QUOTA
387 cnt +=
388#endif
389 tloop(ip, bn, 0);
390 }
391 }
392 /*
393 * finally release direct blocks
394 */
395 for (i = NDADDR - 1; i>=0; i--) {
396 register size;
397
398 bn = ip->i_db[i];
399 if (bn == (daddr_t)0)
400 continue;
401 ip->i_db[i] = (daddr_t)0;
402 fre(ip, bn, size = (off_t)blksize(fs, ip, i));
403#ifdef QUOTA
404 cnt += size / DEV_BSIZE;
405#endif
406 }
407 ip->i_size = 0;
408 /*
409 * Inode was written and flags updated above.
410 * No need to modify flags here.
411 */
412#ifdef QUOTA
413 (void) chkdq(ip, -cnt, 0);
414#endif
415}
416
417#ifdef QUOTA
418long
419#endif
420tloop(ip, bn, indflg)
421 register struct inode *ip;
422 daddr_t bn;
423 int indflg;
424{
425 register i;
426 register struct buf *bp;
427 register daddr_t *bap;
428 register struct fs *fs;
429 daddr_t nb;
430#ifdef QUOTA
431 register long cnt = 0;
432#endif
433
434 bp = NULL;
435 fs = ip->i_fs;
436 for (i = NINDIR(fs) - 1; i >= 0; i--) {
437 if (bp == NULL) {
438 bp = bread(ip->i_dev, fsbtodb(fs, bn), fs->fs_bsize);
439 if (bp->b_flags & B_ERROR) {
440 brelse(bp);
441 return;
442 }
443 bap = bp->b_un.b_daddr;
444 }
445 nb = bap[i];
446 if (nb == (daddr_t)0)
447 continue;
448 if (indflg) {
449#ifdef QUOTA
450 cnt +=
451#endif
452 tloop(ip, nb, 0);
453 } else {
454 fre(ip, nb, fs->fs_bsize);
455#ifdef QUOTA
456 cnt += fs->fs_bsize / DEV_BSIZE;
457#endif
458 }
459 }
460 if (bp != NULL)
461 brelse(bp);
462 fre(ip, bn, fs->fs_bsize);
463#ifdef QUOTA
464 cnt += fs->fs_bsize / DEV_BSIZE;
465 return(cnt);
466#endif
467}
468
469/*
470 * remove any inodes in the inode cache belonging to dev
471 *
472 * There should not be any active ones, return error if any are found
473 * (nb: this is a user error, not a system err)
474 *
475 * Also, count the references to dev by block devices - this really
476 * has nothing to do with the object of the procedure, but as we have
477 * to scan the inode table here anyway, we might as well get the
478 * extra benefit.
479 *
480 * this is called from sumount()/sys3.c when dev is being unmounted
481 */
482#ifdef QUOTA
483iflush(dev, iq)
484 dev_t dev;
485 struct inode *iq;
486#else
487iflush(dev)
488 dev_t dev;
489#endif
490{
491 register struct inode *ip;
492 register open = 0;
493
494 for (ip = inode; ip < inodeNINODE; ip++) {
495#ifdef QUOTA
496 if (ip != iq && ip->i_dev == dev)
497#else
498 if (ip->i_dev == dev)
499#endif
500 if (ip->i_count)
501 return(-1);
502 else {
503 remque(ip);
504 ip->i_forw = ip;
505 ip->i_back = ip;
506 /*
507 * as i_count == 0, the inode was on the free
508 * list already, just leave it there, it will
509 * fall off the bottom eventually. We could
510 * perhaps move it to the head of the free
511 * list, but as umounts are done so
512 * infrequently, we would gain very little,
513 * while making the code bigger.
514 */
515#ifdef QUOTA
516 dqrele(ip->i_dquot);
517 ip->i_dquot = NODQUOT;
518#endif
519 }
520 else if (ip->i_count && (ip->i_mode&IFMT)==IFBLK &&
521 ip->i_rdev == dev)
522 open++;
523 }
524 return (open);
525}
526
527#ifdef ilock
528#undef ilock
529#endif
530#ifdef iunlock
531#undef iunlock
532#endif
533/*
534 * Lock an inode. If its already locked, set the WANT bit and sleep.
535 */
536ilock(ip)
537 register struct inode *ip;
538{
539
540 while (ip->i_flag&ILOCK) {
541 ip->i_flag |= IWANT;
542 sleep((caddr_t)ip, PINOD);
543 }
544 ip->i_flag |= ILOCK;
545}
546
547/*
548 * Unlock an inode. If WANT bit is on, wakeup.
549 */
550iunlock(ip)
551 register struct inode *ip;
552{
553
554 ip->i_flag &= ~ILOCK;
555 if (ip->i_flag&IWANT) {
556 ip->i_flag &= ~IWANT;
557 wakeup((caddr_t)ip);
558 }
559}