%H%->%G%
[unix-history] / usr / src / sys / ufs / ffs / ufs_inode.c
CommitLineData
f86df66c 1/* ufs_inode.c 3.3 %G% */
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;
27
28 ifreel = 0;
29 for (i = 0; i < NINODE - 1; i++)
30 inode[i].i_hlink = i+1;
31 inode[NINODE - 1].i_hlink = -1;
32 for (i = 0; i < INOHSZ; i++)
33 inohash[i] = -1;
34}
35
36/*
37 * Find an inode if it is incore.
38 * This is the equivalent, for inodes,
39 * of ``incore'' in bio.c or ``pfind'' in subr.c.
40 */
41struct inode *
42ifind(dev, ino)
43dev_t dev;
44ino_t ino;
45{
46 register struct inode *ip;
47
48 for (ip = &inode[inohash[INOHASH(dev,ino)]]; ip != &inode[-1];
49 ip = &inode[ip->i_hlink])
50 if (ino==ip->i_number && dev==ip->i_dev)
51 return (ip);
52 return ((struct inode *)0);
53}
54
55/*
56 * Look up an inode by device,inumber.
57 * If it is in core (in the inode structure),
58 * honor the locking protocol.
59 * If it is not in core, read it in from the
60 * specified device.
61 * If the inode is mounted on, perform
62 * the indicated indirection.
63 * In all cases, a pointer to a locked
64 * inode structure is returned.
65 *
66 * printf warning: no inodes -- if the inode
67 * structure is full
68 * panic: no imt -- if the mounted file
69 * system is not in the mount table.
70 * "cannot happen"
71 */
72struct inode *
73iget(dev, ino)
74dev_t dev;
75ino_t ino;
76{
77 register struct inode *ip;
78 register struct mount *mp;
79 register struct buf *bp;
80 register struct dinode *dp;
81 register int slot;
82
83loop:
84 slot = INOHASH(dev, ino);
85 ip = &inode[inohash[slot]];
86 while (ip != &inode[-1]) {
87 if(ino == ip->i_number && dev == ip->i_dev) {
88 if((ip->i_flag&ILOCK) != 0) {
89 ip->i_flag |= IWANT;
90 sleep((caddr_t)ip, PINOD);
91 goto loop;
92 }
93 if((ip->i_flag&IMOUNT) != 0) {
94 for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
95 if(mp->m_inodp == ip) {
96 dev = mp->m_dev;
97 ino = ROOTINO;
98 goto loop;
99 }
100 panic("no imt");
101 }
102 ip->i_count++;
103 ip->i_flag |= ILOCK;
104 return(ip);
105 }
106 ip = &inode[ip->i_hlink];
107 }
108 if(ifreel < 0) {
109 printf("Inode table overflow\n");
110 u.u_error = ENFILE;
111 return(NULL);
112 }
113 ip = &inode[ifreel];
114 ifreel = ip->i_hlink;
115 ip->i_hlink = inohash[slot];
116 inohash[slot] = ip - inode;
117 ip->i_dev = dev;
118 ip->i_number = ino;
119 ip->i_flag = ILOCK;
120 ip->i_count++;
121 ip->i_un.i_lastr = 0;
122 bp = bread(dev, itod(ino));
123 /*
124 * Check I/O errors
125 */
126 if((bp->b_flags&B_ERROR) != 0) {
127 brelse(bp);
128 iput(ip);
129 return(NULL);
130 }
131 dp = bp->b_un.b_dino;
132 dp += itoo(ino);
133 iexpand(ip, dp);
134 brelse(bp);
135 return(ip);
136}
137
138iexpand(ip, dp)
139register struct inode *ip;
140register struct dinode *dp;
141{
142 register char *p1, *p2;
143 register int i;
144
145 ip->i_mode = dp->di_mode;
146 ip->i_nlink = dp->di_nlink;
147 ip->i_uid = dp->di_uid;
148 ip->i_gid = dp->di_gid;
149 ip->i_size = dp->di_size;
150 p1 = (char *)ip->i_un.i_addr;
151 p2 = (char *)dp->di_addr;
152 for(i=0; i<NADDR; i++) {
153 *p1++ = *p2++;
154 *p1++ = *p2++;
155 *p1++ = *p2++;
156 *p1++ = 0;
157 }
158}
159
160/*
161 * Decrement reference count of
162 * an inode structure.
163 * On the last reference,
164 * write the inode out and if necessary,
165 * truncate and deallocate the file.
166 */
167iput(ip)
168register struct inode *ip;
169{
170 register int i, x;
171 register struct inode *jp;
172
173 if(ip->i_count == 1) {
174 ip->i_flag |= ILOCK;
175 if(ip->i_nlink <= 0) {
176 itrunc(ip);
177 ip->i_mode = 0;
178 ip->i_flag |= IUPD|ICHG;
179 ifree(ip->i_dev, ip->i_number);
180 }
5074594f 181 IUPDAT(ip, &time, &time);
5d5124a1
BJ
182 prele(ip);
183 i = INOHASH(ip->i_dev, ip->i_number);
184 x = ip - inode;
185 if (inohash[i] == x) {
186 inohash[i] = ip->i_hlink;
187 } else {
188 for (jp = &inode[inohash[i]]; jp != &inode[-1];
189 jp = &inode[jp->i_hlink])
190 if (jp->i_hlink == x) {
191 jp->i_hlink = ip->i_hlink;
192 goto done;
193 }
194 panic("iput");
195 }
196done:
197 ip->i_hlink = ifreel;
198 ifreel = x;
199 ip->i_flag = 0;
200 ip->i_number = 0;
201 } else
202 prele(ip);
203 ip->i_count--;
204}
205
206/*
207 * Check accessed and update flags on
208 * an inode structure.
209 * If any is on, update the inode
210 * with the current time.
211 */
212iupdat(ip, ta, tm)
213register struct inode *ip;
214time_t *ta, *tm;
215{
216 register struct buf *bp;
217 struct dinode *dp;
218 register char *p1, *p2;
219 register int i;
220
221 if((ip->i_flag&(IUPD|IACC|ICHG)) != 0) {
222 if(getfs(ip->i_dev)->s_ronly)
223 return;
224 bp = bread(ip->i_dev, itod(ip->i_number));
225 if (bp->b_flags & B_ERROR) {
226 brelse(bp);
227 return;
228 }
229 dp = bp->b_un.b_dino;
230 dp += itoo(ip->i_number);
231 dp->di_mode = ip->i_mode;
232 dp->di_nlink = ip->i_nlink;
233 dp->di_uid = ip->i_uid;
234 dp->di_gid = ip->i_gid;
235 dp->di_size = ip->i_size;
236 p1 = (char *)dp->di_addr;
237 p2 = (char *)ip->i_un.i_addr;
238 for(i=0; i<NADDR; i++) {
239 *p1++ = *p2++;
240 *p1++ = *p2++;
241 *p1++ = *p2++;
242 if(*p2++ != 0 && (ip->i_mode&IFMT)!=IFMPC
243 && (ip->i_mode&IFMT)!=IFMPB)
244 printf("iaddress > 2^24\n");
245 }
246 if(ip->i_flag&IACC)
247 dp->di_atime = *ta;
248 if(ip->i_flag&IUPD)
249 dp->di_mtime = *tm;
250 if(ip->i_flag&ICHG)
251 dp->di_ctime = time;
252 ip->i_flag &= ~(IUPD|IACC|ICHG);
253 bdwrite(bp);
254 }
255}
256
257/*
258 * Free all the disk blocks associated
259 * with the specified inode structure.
260 * The blocks of the file are removed
261 * in reverse order. This FILO
262 * algorithm will tend to maintain
263 * a contiguous free list much longer
264 * than FIFO.
265 */
266itrunc(ip)
267register struct inode *ip;
268{
269 register i;
270 dev_t dev;
271 daddr_t bn;
272
273 if (ip->i_vfdcnt)
274 panic("itrunc");
275 i = ip->i_mode & IFMT;
276 if (i!=IFREG && i!=IFDIR)
277 return;
278 dev = ip->i_dev;
279 for(i=NADDR-1; i>=0; i--) {
280 bn = ip->i_un.i_addr[i];
281 if(bn == (daddr_t)0)
282 continue;
283 ip->i_un.i_addr[i] = (daddr_t)0;
284 switch(i) {
285
286 default:
287 free(dev, bn);
288 break;
289
290 case NADDR-3:
291 tloop(dev, bn, 0, 0);
292 break;
293
294 case NADDR-2:
295 tloop(dev, bn, 1, 0);
296 break;
297
298 case NADDR-1:
299 tloop(dev, bn, 1, 1);
300 }
301 }
302 ip->i_size = 0;
303 ip->i_flag |= ICHG|IUPD;
304}
305
306tloop(dev, bn, f1, f2)
307dev_t dev;
308daddr_t bn;
309{
310 register i;
311 register struct buf *bp;
312 register daddr_t *bap;
313 daddr_t nb;
314
315 bp = NULL;
316 for(i=NINDIR-1; i>=0; i--) {
317 if(bp == NULL) {
318 bp = bread(dev, bn);
319 if (bp->b_flags & B_ERROR) {
320 brelse(bp);
321 return;
322 }
323 bap = bp->b_un.b_daddr;
324 }
325 nb = bap[i];
326 if(nb == (daddr_t)0)
327 continue;
328 if(f1) {
329 brelse(bp);
330 bp = NULL;
331 tloop(dev, nb, f2, 0);
332 } else
333 free(dev, nb);
334 }
335 if(bp != NULL)
336 brelse(bp);
337 free(dev, bn);
338}
339
340/*
341 * Make a new file.
342 */
343struct inode *
344maknode(mode)
345{
346 register struct inode *ip;
347
348 ip = ialloc(u.u_pdir->i_dev);
349 if(ip == NULL) {
350 iput(u.u_pdir);
351 return(NULL);
352 }
353 ip->i_flag |= IACC|IUPD|ICHG;
354 if((mode&IFMT) == 0)
355 mode |= IFREG;
356 ip->i_mode = mode & ~u.u_cmask;
357 ip->i_nlink = 1;
358 ip->i_uid = u.u_uid;
359 ip->i_gid = u.u_gid;
360 wdir(ip);
361 return(ip);
362}
363
364/*
365 * Write a directory entry with
366 * parameters left as side effects
367 * to a call to namei.
368 */
369wdir(ip)
370struct inode *ip;
371{
372
373 u.u_dent.d_ino = ip->i_number;
374 bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_dent.d_name, DIRSIZ);
375 u.u_count = sizeof(struct direct);
376 u.u_segflg = 1;
377 u.u_base = (caddr_t)&u.u_dent;
378 writei(u.u_pdir);
379 iput(u.u_pdir);
380}