]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/fsck_ffs/inode.c
This commit was generated by cvs2svn to compensate for changes in r132722,
[FreeBSD/FreeBSD.git] / sbin / fsck_ffs / inode.c
1 /*
2  * Copyright (c) 1980, 1986, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #if 0
31 #ifndef lint
32 static const char sccsid[] = "@(#)inode.c       8.8 (Berkeley) 4/28/95";
33 #endif /* not lint */
34 #endif
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 #include <sys/param.h>
39 #include <sys/stdint.h>
40 #include <sys/time.h>
41 #include <sys/sysctl.h>
42
43 #include <ufs/ufs/dinode.h>
44 #include <ufs/ufs/dir.h>
45 #include <ufs/ffs/fs.h>
46
47 #include <err.h>
48 #include <pwd.h>
49 #include <string.h>
50
51 #include "fsck.h"
52
53 static ino_t startinum;
54
55 static int iblock(struct inodesc *, long ilevel, off_t isize);
56
57 int
58 ckinode(union dinode *dp, struct inodesc *idesc)
59 {
60         off_t remsize, sizepb;
61         int i, offset, ret;
62         union dinode dino;
63         ufs2_daddr_t ndb;
64         mode_t mode;
65         char pathbuf[MAXPATHLEN + 1];
66
67         if (idesc->id_fix != IGNORE)
68                 idesc->id_fix = DONTKNOW;
69         idesc->id_lbn = -1;
70         idesc->id_entryno = 0;
71         idesc->id_filesize = DIP(dp, di_size);
72         mode = DIP(dp, di_mode) & IFMT;
73         if (mode == IFBLK || mode == IFCHR || (mode == IFLNK &&
74             DIP(dp, di_size) < (unsigned)sblock.fs_maxsymlinklen))
75                 return (KEEPON);
76         if (sblock.fs_magic == FS_UFS1_MAGIC)
77                 dino.dp1 = dp->dp1;
78         else
79                 dino.dp2 = dp->dp2;
80         ndb = howmany(DIP(&dino, di_size), sblock.fs_bsize);
81         for (i = 0; i < NDADDR; i++) {
82                 idesc->id_lbn++;
83                 if (--ndb == 0 &&
84                     (offset = blkoff(&sblock, DIP(&dino, di_size))) != 0)
85                         idesc->id_numfrags =
86                                 numfrags(&sblock, fragroundup(&sblock, offset));
87                 else
88                         idesc->id_numfrags = sblock.fs_frag;
89                 if (DIP(&dino, di_db[i]) == 0) {
90                         if (idesc->id_type == DATA && ndb >= 0) {
91                                 /* An empty block in a directory XXX */
92                                 getpathname(pathbuf, idesc->id_number,
93                                                 idesc->id_number);
94                                 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
95                                         pathbuf);
96                                 if (reply("ADJUST LENGTH") == 1) {
97                                         dp = ginode(idesc->id_number);
98                                         DIP(dp, di_size) = i * sblock.fs_bsize;
99                                         printf(
100                                             "YOU MUST RERUN FSCK AFTERWARDS\n");
101                                         rerun = 1;
102                                         inodirty();
103                                         
104                                 }
105                         }
106                         continue;
107                 }
108                 idesc->id_blkno = DIP(&dino, di_db[i]);
109                 if (idesc->id_type != DATA)
110                         ret = (*idesc->id_func)(idesc);
111                 else
112                         ret = dirscan(idesc);
113                 if (ret & STOP)
114                         return (ret);
115         }
116         idesc->id_numfrags = sblock.fs_frag;
117         remsize = DIP(&dino, di_size) - sblock.fs_bsize * NDADDR;
118         sizepb = sblock.fs_bsize;
119         for (i = 0; i < NIADDR; i++) {
120                 sizepb *= NINDIR(&sblock);
121                 if (DIP(&dino, di_ib[i])) {
122                         idesc->id_blkno = DIP(&dino, di_ib[i]);
123                         ret = iblock(idesc, i + 1, remsize);
124                         if (ret & STOP)
125                                 return (ret);
126                 } else {
127                         idesc->id_lbn += sizepb / sblock.fs_bsize;
128                         if (idesc->id_type == DATA && remsize > 0) {
129                                 /* An empty block in a directory XXX */
130                                 getpathname(pathbuf, idesc->id_number,
131                                                 idesc->id_number);
132                                 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
133                                         pathbuf);
134                                 if (reply("ADJUST LENGTH") == 1) {
135                                         dp = ginode(idesc->id_number);
136                                         DIP(dp, di_size) -= remsize;
137                                         remsize = 0;
138                                         printf(
139                                             "YOU MUST RERUN FSCK AFTERWARDS\n");
140                                         rerun = 1;
141                                         inodirty();
142                                         break;
143                                 }
144                         }
145                 }
146                 remsize -= sizepb;
147         }
148         return (KEEPON);
149 }
150
151 static int
152 iblock(struct inodesc *idesc, long ilevel, off_t isize)
153 {
154         struct bufarea *bp;
155         int i, n, (*func)(struct inodesc *), nif;
156         off_t sizepb;
157         char buf[BUFSIZ];
158         char pathbuf[MAXPATHLEN + 1];
159         union dinode *dp;
160
161         if (idesc->id_type != DATA) {
162                 func = idesc->id_func;
163                 if (((n = (*func)(idesc)) & KEEPON) == 0)
164                         return (n);
165         } else
166                 func = dirscan;
167         if (chkrange(idesc->id_blkno, idesc->id_numfrags))
168                 return (SKIP);
169         bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
170         ilevel--;
171         for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
172                 sizepb *= NINDIR(&sblock);
173         if (howmany(isize, sizepb) > NINDIR(&sblock))
174                 nif = NINDIR(&sblock);
175         else
176                 nif = howmany(isize, sizepb);
177         if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
178                 for (i = nif; i < NINDIR(&sblock); i++) {
179                         if (IBLK(bp, i) == 0)
180                                 continue;
181                         (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu",
182                             (u_long)idesc->id_number);
183                         if (preen) {
184                                 pfatal("%s", buf);
185                         } else if (dofix(idesc, buf)) {
186                                 IBLK(bp, i) = 0;
187                                 dirty(bp);
188                         }
189                 }
190                 flush(fswritefd, bp);
191         }
192         for (i = 0; i < nif; i++) {
193                 if (ilevel == 0)
194                         idesc->id_lbn++;
195                 if (IBLK(bp, i)) {
196                         idesc->id_blkno = IBLK(bp, i);
197                         if (ilevel == 0)
198                                 n = (*func)(idesc);
199                         else
200                                 n = iblock(idesc, ilevel, isize);
201                         if (n & STOP) {
202                                 bp->b_flags &= ~B_INUSE;
203                                 return (n);
204                         }
205                 } else {
206                         if (idesc->id_type == DATA && isize > 0) {
207                                 /* An empty block in a directory XXX */
208                                 getpathname(pathbuf, idesc->id_number,
209                                                 idesc->id_number);
210                                 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
211                                         pathbuf);
212                                 if (reply("ADJUST LENGTH") == 1) {
213                                         dp = ginode(idesc->id_number);
214                                         DIP(dp, di_size) -= isize;
215                                         isize = 0;
216                                         printf(
217                                             "YOU MUST RERUN FSCK AFTERWARDS\n");
218                                         rerun = 1;
219                                         inodirty();
220                                         bp->b_flags &= ~B_INUSE;
221                                         return(STOP);
222                                 }
223                         }
224                 }
225                 isize -= sizepb;
226         }
227         bp->b_flags &= ~B_INUSE;
228         return (KEEPON);
229 }
230
231 /*
232  * Check that a block in a legal block number.
233  * Return 0 if in range, 1 if out of range.
234  */
235 int
236 chkrange(ufs2_daddr_t blk, int cnt)
237 {
238         int c;
239
240         if (cnt <= 0 || blk <= 0 || blk > maxfsblock ||
241             cnt - 1 > maxfsblock - blk)
242                 return (1);
243         if (cnt > sblock.fs_frag ||
244             fragnum(&sblock, blk) + cnt > sblock.fs_frag) {
245                 if (debug)
246                         printf("bad size: blk %ld, offset %i, size %d\n",
247                             (long)blk, (int)fragnum(&sblock, blk), cnt);
248                 return (1);
249         }
250         c = dtog(&sblock, blk);
251         if (blk < cgdmin(&sblock, c)) {
252                 if ((blk + cnt) > cgsblock(&sblock, c)) {
253                         if (debug) {
254                                 printf("blk %ld < cgdmin %ld;",
255                                     (long)blk, (long)cgdmin(&sblock, c));
256                                 printf(" blk + cnt %ld > cgsbase %ld\n",
257                                     (long)(blk + cnt),
258                                     (long)cgsblock(&sblock, c));
259                         }
260                         return (1);
261                 }
262         } else {
263                 if ((blk + cnt) > cgbase(&sblock, c+1)) {
264                         if (debug)  {
265                                 printf("blk %ld >= cgdmin %ld;",
266                                     (long)blk, (long)cgdmin(&sblock, c));
267                                 printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
268                                     (long)(blk + cnt), (long)sblock.fs_fpg);
269                         }
270                         return (1);
271                 }
272         }
273         return (0);
274 }
275
276 /*
277  * General purpose interface for reading inodes.
278  */
279 union dinode *
280 ginode(ino_t inumber)
281 {
282         ufs2_daddr_t iblk;
283
284         if (inumber < ROOTINO || inumber > maxino)
285                 errx(EEXIT, "bad inode number %d to ginode", inumber);
286         if (startinum == 0 ||
287             inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
288                 iblk = ino_to_fsba(&sblock, inumber);
289                 if (pbp != 0)
290                         pbp->b_flags &= ~B_INUSE;
291                 pbp = getdatablk(iblk, sblock.fs_bsize);
292                 startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
293         }
294         if (sblock.fs_magic == FS_UFS1_MAGIC)
295                 return ((union dinode *)
296                     &pbp->b_un.b_dinode1[inumber % INOPB(&sblock)]);
297         return ((union dinode *)&pbp->b_un.b_dinode2[inumber % INOPB(&sblock)]);
298 }
299
300 /*
301  * Special purpose version of ginode used to optimize first pass
302  * over all the inodes in numerical order.
303  */
304 static ino_t nextino, lastinum, lastvalidinum;
305 static long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
306 static caddr_t inodebuf;
307
308 union dinode *
309 getnextinode(ino_t inumber)
310 {
311         long size;
312         ufs2_daddr_t dblk;
313         union dinode *dp;
314         static caddr_t nextinop;
315
316         if (inumber != nextino++ || inumber > lastvalidinum)
317                 errx(EEXIT, "bad inode number %d to nextinode", inumber);
318         if (inumber >= lastinum) {
319                 readcnt++;
320                 dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));
321                 if (readcnt % readpercg == 0) {
322                         size = partialsize;
323                         lastinum += partialcnt;
324                 } else {
325                         size = inobufsize;
326                         lastinum += fullcnt;
327                 }
328                 /*
329                  * If bread returns an error, it will already have zeroed
330                  * out the buffer, so we do not need to do so here.
331                  */
332                 (void)bread(fsreadfd, inodebuf, dblk, size);
333                 nextinop = inodebuf;
334         }
335         dp = (union dinode *)nextinop;
336         if (sblock.fs_magic == FS_UFS1_MAGIC)
337                 nextinop += sizeof(struct ufs1_dinode);
338         else
339                 nextinop += sizeof(struct ufs2_dinode);
340         return (dp);
341 }
342
343 void
344 setinodebuf(ino_t inum)
345 {
346
347         if (inum % sblock.fs_ipg != 0)
348                 errx(EEXIT, "bad inode number %d to setinodebuf", inum);
349         lastvalidinum = inum + sblock.fs_ipg - 1;
350         startinum = 0;
351         nextino = inum;
352         lastinum = inum;
353         readcnt = 0;
354         if (inodebuf != NULL)
355                 return;
356         inobufsize = blkroundup(&sblock, INOBUFSIZE);
357         fullcnt = inobufsize / ((sblock.fs_magic == FS_UFS1_MAGIC) ?
358             sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode));
359         readpercg = sblock.fs_ipg / fullcnt;
360         partialcnt = sblock.fs_ipg % fullcnt;
361         partialsize = partialcnt * ((sblock.fs_magic == FS_UFS1_MAGIC) ?
362             sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode));
363         if (partialcnt != 0) {
364                 readpercg++;
365         } else {
366                 partialcnt = fullcnt;
367                 partialsize = inobufsize;
368         }
369         if ((inodebuf = malloc((unsigned)inobufsize)) == NULL)
370                 errx(EEXIT, "cannot allocate space for inode buffer");
371 }
372
373 void
374 freeinodebuf(void)
375 {
376
377         if (inodebuf != NULL)
378                 free((char *)inodebuf);
379         inodebuf = NULL;
380 }
381
382 /*
383  * Routines to maintain information about directory inodes.
384  * This is built during the first pass and used during the
385  * second and third passes.
386  *
387  * Enter inodes into the cache.
388  */
389 void
390 cacheino(union dinode *dp, ino_t inumber)
391 {
392         struct inoinfo *inp, **inpp;
393         int i, blks;
394
395         if (howmany(DIP(dp, di_size), sblock.fs_bsize) > NDADDR)
396                 blks = NDADDR + NIADDR;
397         else
398                 blks = howmany(DIP(dp, di_size), sblock.fs_bsize);
399         inp = (struct inoinfo *)
400                 malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs2_daddr_t));
401         if (inp == NULL)
402                 errx(EEXIT, "cannot increase directory list");
403         inpp = &inphead[inumber % dirhash];
404         inp->i_nexthash = *inpp;
405         *inpp = inp;
406         inp->i_parent = inumber == ROOTINO ? ROOTINO : (ino_t)0;
407         inp->i_dotdot = (ino_t)0;
408         inp->i_number = inumber;
409         inp->i_isize = DIP(dp, di_size);
410         inp->i_numblks = blks;
411         for (i = 0; i < (blks < NDADDR ? blks : NDADDR); i++)
412                 inp->i_blks[i] = DIP(dp, di_db[i]);
413         if (blks > NDADDR)
414                 for (i = 0; i < NIADDR; i++)
415                         inp->i_blks[NDADDR + i] = DIP(dp, di_ib[i]);
416         if (inplast == listmax) {
417                 listmax += 100;
418                 inpsort = (struct inoinfo **)realloc((char *)inpsort,
419                     (unsigned)listmax * sizeof(struct inoinfo *));
420                 if (inpsort == NULL)
421                         errx(EEXIT, "cannot increase directory list");
422         }
423         inpsort[inplast++] = inp;
424 }
425
426 /*
427  * Look up an inode cache structure.
428  */
429 struct inoinfo *
430 getinoinfo(ino_t inumber)
431 {
432         struct inoinfo *inp;
433
434         for (inp = inphead[inumber % dirhash]; inp; inp = inp->i_nexthash) {
435                 if (inp->i_number != inumber)
436                         continue;
437                 return (inp);
438         }
439         errx(EEXIT, "cannot find inode %d", inumber);
440         return ((struct inoinfo *)0);
441 }
442
443 /*
444  * Clean up all the inode cache structure.
445  */
446 void
447 inocleanup(void)
448 {
449         struct inoinfo **inpp;
450
451         if (inphead == NULL)
452                 return;
453         for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
454                 free((char *)(*inpp));
455         free((char *)inphead);
456         free((char *)inpsort);
457         inphead = inpsort = NULL;
458 }
459
460 void
461 inodirty(void)
462 {
463
464         dirty(pbp);
465 }
466
467 void
468 clri(struct inodesc *idesc, const char *type, int flag)
469 {
470         union dinode *dp;
471
472         dp = ginode(idesc->id_number);
473         if (flag == 1) {
474                 pwarn("%s %s", type,
475                     (DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE");
476                 pinode(idesc->id_number);
477         }
478         if (preen || reply("CLEAR") == 1) {
479                 if (preen)
480                         printf(" (CLEARED)\n");
481                 n_files--;
482                 if (bkgrdflag == 0) {
483                         (void)ckinode(dp, idesc);
484                         inoinfo(idesc->id_number)->ino_state = USTATE;
485                         clearinode(dp);
486                         inodirty();
487                 } else {
488                         cmd.value = idesc->id_number;
489                         cmd.size = -DIP(dp, di_nlink);
490                         if (debug)
491                                 printf("adjrefcnt ino %ld amt %lld\n",
492                                     (long)cmd.value, (long long)cmd.size);
493                         if (sysctl(adjrefcnt, MIBSIZE, 0, 0,
494                             &cmd, sizeof cmd) == -1)
495                                 rwerror("ADJUST INODE", cmd.value);
496                 }
497         }
498 }
499
500 int
501 findname(struct inodesc *idesc)
502 {
503         struct direct *dirp = idesc->id_dirp;
504
505         if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
506                 idesc->id_entryno++;
507                 return (KEEPON);
508         }
509         memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
510         return (STOP|FOUND);
511 }
512
513 int
514 findino(struct inodesc *idesc)
515 {
516         struct direct *dirp = idesc->id_dirp;
517
518         if (dirp->d_ino == 0)
519                 return (KEEPON);
520         if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
521             dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
522                 idesc->id_parent = dirp->d_ino;
523                 return (STOP|FOUND);
524         }
525         return (KEEPON);
526 }
527
528 int
529 clearentry(struct inodesc *idesc)
530 {
531         struct direct *dirp = idesc->id_dirp;
532
533         if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
534                 idesc->id_entryno++;
535                 return (KEEPON);
536         }
537         dirp->d_ino = 0;
538         return (STOP|FOUND|ALTERED);
539 }
540
541 void
542 pinode(ino_t ino)
543 {
544         union dinode *dp;
545         char *p;
546         struct passwd *pw;
547         time_t t;
548
549         printf(" I=%lu ", (u_long)ino);
550         if (ino < ROOTINO || ino > maxino)
551                 return;
552         dp = ginode(ino);
553         printf(" OWNER=");
554         if ((pw = getpwuid((int)DIP(dp, di_uid))) != 0)
555                 printf("%s ", pw->pw_name);
556         else
557                 printf("%u ", (unsigned)DIP(dp, di_uid));
558         printf("MODE=%o\n", DIP(dp, di_mode));
559         if (preen)
560                 printf("%s: ", cdevname);
561         printf("SIZE=%ju ", (uintmax_t)DIP(dp, di_size));
562         t = DIP(dp, di_mtime);
563         p = ctime(&t);
564         printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
565 }
566
567 void
568 blkerror(ino_t ino, const char *type, ufs2_daddr_t blk)
569 {
570
571         pfatal("%jd %s I=%ju", (intmax_t)blk, type, (uintmax_t)ino);
572         printf("\n");
573         switch (inoinfo(ino)->ino_state) {
574
575         case FSTATE:
576                 inoinfo(ino)->ino_state = FCLEAR;
577                 return;
578
579         case DSTATE:
580                 inoinfo(ino)->ino_state = DCLEAR;
581                 return;
582
583         case FCLEAR:
584         case DCLEAR:
585                 return;
586
587         default:
588                 errx(EEXIT, "BAD STATE %d TO BLKERR", inoinfo(ino)->ino_state);
589                 /* NOTREACHED */
590         }
591 }
592
593 /*
594  * allocate an unused inode
595  */
596 ino_t
597 allocino(ino_t request, int type)
598 {
599         ino_t ino;
600         union dinode *dp;
601         struct cg *cgp = &cgrp;
602         int cg;
603
604         if (request == 0)
605                 request = ROOTINO;
606         else if (inoinfo(request)->ino_state != USTATE)
607                 return (0);
608         for (ino = request; ino < maxino; ino++)
609                 if (inoinfo(ino)->ino_state == USTATE)
610                         break;
611         if (ino == maxino)
612                 return (0);
613         cg = ino_to_cg(&sblock, ino);
614         getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
615         if (!cg_chkmagic(cgp))
616                 pfatal("CG %d: BAD MAGIC NUMBER\n", cg);
617         setbit(cg_inosused(cgp), ino % sblock.fs_ipg);
618         cgp->cg_cs.cs_nifree--;
619         switch (type & IFMT) {
620         case IFDIR:
621                 inoinfo(ino)->ino_state = DSTATE;
622                 cgp->cg_cs.cs_ndir++;
623                 break;
624         case IFREG:
625         case IFLNK:
626                 inoinfo(ino)->ino_state = FSTATE;
627                 break;
628         default:
629                 return (0);
630         }
631         cgdirty();
632         dp = ginode(ino);
633         DIP(dp, di_db[0]) = allocblk((long)1);
634         if (DIP(dp, di_db[0]) == 0) {
635                 inoinfo(ino)->ino_state = USTATE;
636                 return (0);
637         }
638         DIP(dp, di_mode) = type;
639         DIP(dp, di_flags) = 0;
640         DIP(dp, di_atime) = time(NULL);
641         DIP(dp, di_mtime) = DIP(dp, di_ctime) = DIP(dp, di_atime);
642         DIP(dp, di_mtimensec) = 0;
643         DIP(dp, di_ctimensec) = 0;
644         DIP(dp, di_atimensec) = 0;
645         DIP(dp, di_size) = sblock.fs_fsize;
646         DIP(dp, di_blocks) = btodb(sblock.fs_fsize);
647         n_files++;
648         inodirty();
649         inoinfo(ino)->ino_type = IFTODT(type);
650         return (ino);
651 }
652
653 /*
654  * deallocate an inode
655  */
656 void
657 freeino(ino_t ino)
658 {
659         struct inodesc idesc;
660         union dinode *dp;
661
662         memset(&idesc, 0, sizeof(struct inodesc));
663         idesc.id_type = ADDR;
664         idesc.id_func = pass4check;
665         idesc.id_number = ino;
666         dp = ginode(ino);
667         (void)ckinode(dp, &idesc);
668         clearinode(dp);
669         inodirty();
670         inoinfo(ino)->ino_state = USTATE;
671         n_files--;
672 }