kernel - Greatly improve shared memory fault rate concurrency / shared tokens
[dragonfly.git] / sys / vfs / hpfs / hpfs_subr.c
1 /*-
2  * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
3  * 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  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sys/fs/hpfs/hpfs_subr.c,v 1.1 1999/12/09 19:09:59 semenu Exp $
27  * $DragonFly: src/sys/vfs/hpfs/hpfs_subr.c,v 1.8 2006/12/23 00:41:29 swildner Exp $
28  */
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/proc.h>
34 #include <sys/time.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/vnode.h>
38 #include <sys/mount.h>
39 #include <sys/namei.h>
40 #include <sys/malloc.h>
41 #include <sys/buf.h>
42
43 #include <sys/buf2.h>
44
45 #include "hpfs.h"
46 #include "hpfsmount.h"
47 #include "hpfs_subr.h"
48
49 u_long
50 hpfs_checksum(
51         u_int8_t *object,
52         int size)
53 {
54         int i;
55         u_long csum=0L;
56         for (i=0; i < size; i++) {
57                 csum += (u_long) *object++;
58                 csum = (csum << 7) + (csum >> (25));
59         }
60         return (csum);
61 }
62
63 void
64 hpfs_bmdeinit(
65         struct hpfsmount *hpmp)
66 {
67         struct buf *bp;
68         int i;
69
70         dprintf(("hpmp_bmdeinit: "));
71
72         if (!(hpmp->hpm_mp->mnt_flag & MNT_RDONLY)) {
73                 /*
74                  * Write down BitMap.
75                  */
76                 for (i=0; i<hpmp->hpm_dbnum; i++) {
77                         dprintf(("[%d: 0x%x] ", i, hpmp->hpm_bmind[i]));
78
79                         bp = getblk(hpmp->hpm_devvp,
80                                     dbtodoff(hpmp->hpm_bmind[i]),
81                                     BMSIZE, 0, 0);
82                         clrbuf(bp);
83
84                         bcopy(hpmp->hpm_bitmap + BMSIZE * i, bp->b_data,
85                               BMSIZE);
86
87                         bwrite(bp);
88                 }
89         }
90
91         FREE(hpmp->hpm_bitmap,M_HPFSMNT);
92         FREE(hpmp->hpm_bmind,M_HPFSMNT);
93
94         dprintf(("\n"));
95 }
96
97 /*
98  * Initialize BitMap management, includes calculation of
99  * available blocks number.
100  */
101 int
102 hpfs_bminit(
103         struct hpfsmount *hpmp)
104 {
105         struct buf *bp;
106         int error, i, k;
107         u_long dbavail;
108
109         dprintf(("hpfs_bminit: "));
110
111         hpmp->hpm_dbnum = (hpmp->hpm_su.su_btotal + 0x3FFF) / 0x4000;
112
113         dprintf(("0x%lx data bands, ", hpmp->hpm_dbnum));
114
115         MALLOC(hpmp->hpm_bmind, lsn_t *, hpmp->hpm_dbnum * sizeof(lsn_t),
116                 M_HPFSMNT, M_WAITOK);
117
118         MALLOC(hpmp->hpm_bitmap, u_int8_t *, hpmp->hpm_dbnum * BMSIZE,
119                 M_HPFSMNT, M_WAITOK);
120
121         error = bread(hpmp->hpm_devvp, dbtodoff(hpmp->hpm_su.su_bitmap.lsn1),
122                 ((hpmp->hpm_dbnum + 0x7F) & ~(0x7F)) << 2, &bp);
123         if (error) {
124                 brelse(bp);
125                 FREE(hpmp->hpm_bitmap, M_HPFSMNT);
126                 FREE(hpmp->hpm_bmind, M_HPFSMNT);
127                 dprintf((" error %d\n", error));
128                 return (error);
129         }
130         bcopy(bp->b_data, hpmp->hpm_bmind, hpmp->hpm_dbnum * sizeof(lsn_t));
131         
132         brelse(bp);
133
134         /*
135          * Read in all BitMap
136          */
137         for (i=0; i<hpmp->hpm_dbnum; i++) {
138                 dprintf(("[%d: 0x%x] ", i, hpmp->hpm_bmind[i]));
139
140                 error = bread(hpmp->hpm_devvp, dbtodoff(hpmp->hpm_bmind[i]),
141                                 BMSIZE, &bp);
142                 if (error) {
143                         brelse(bp);
144                         FREE(hpmp->hpm_bitmap, M_HPFSMNT);
145                         FREE(hpmp->hpm_bmind, M_HPFSMNT);
146                         dprintf((" error %d\n", error));
147                         return (error);
148                 }
149                 bcopy(bp->b_data, hpmp->hpm_bitmap + BMSIZE * i, BMSIZE);
150
151                 brelse(bp);
152         }
153
154         /*
155          * Look througth BitMap and count free bits
156          */
157         dbavail = 0;
158         for (i=0; i < hpmp->hpm_su.su_btotal >> 5; i++) {
159                 u_int32_t mask;
160                 for (k=0, mask=1; k < 32; k++, mask<<=1)
161                         if(((u_int32_t *)hpmp->hpm_bitmap)[i] & mask) 
162                                 dbavail ++;
163
164         }
165         hpmp->hpm_bavail = dbavail;
166
167         return (0);
168 }
169
170 int
171 hpfs_cmpfname (
172         struct hpfsmount *hpmp,
173         char * uname,
174         int ulen,
175         char * dname,
176         int dlen,
177         u_int16_t cp)
178 {
179         int i, res;
180
181         for (i = 0; i < ulen && i < dlen; i++) {
182                 res = hpfs_toupper(hpmp, hpfs_u2d(hpmp, uname[i]), cp) - 
183                       hpfs_toupper(hpmp, dname[i], cp);
184                 if (res)
185                         return res;
186         }
187         return (ulen - dlen);
188 }
189
190 int
191 hpfs_cpstrnnicmp (
192         struct hpfsmount *hpmp,
193         char * str1,
194         int str1len,
195         u_int16_t str1cp,
196         char * str2,
197         int str2len,
198         u_int16_t str2cp)
199 {
200         int i, res;
201
202         for (i = 0; i < str1len && i < str2len; i++) {
203                 res = (int)hpfs_toupper(hpmp, ((u_char *)str1)[i], str1cp) - 
204                       (int)hpfs_toupper(hpmp, ((u_char *)str2)[i], str2cp);
205                 if (res)
206                         return res;
207         }
208         return (str1len - str2len);
209 }
210
211
212 int
213 hpfs_cpload (
214         struct hpfsmount *hpmp,
215         struct cpiblk *cpibp,
216         struct cpdblk *cpdbp)
217 {
218         struct buf *bp;
219         struct cpdsec * cpdsp;
220         int error, i;
221
222         error = bread(hpmp->hpm_devvp, dbtodoff(cpibp->b_cpdsec), DEV_BSIZE, &bp);
223         if (error) {
224                 brelse(bp);
225                 return (error);
226         }
227
228         cpdsp = (struct cpdsec *)bp->b_data;
229
230         for (i=cpdsp->d_cpfirst; i<cpdsp->d_cpcnt; i++) {
231                 if (cpdsp->d_cpdblk[i].b_cpid == cpibp->b_cpid) {
232                         bcopy(cpdsp->d_cpdblk + i, cpdbp, 
233                               sizeof(struct cpdblk));
234
235                         brelse(bp);
236
237                         return (0);
238                 }
239         }
240
241         brelse(bp);
242
243         return (ENOENT);
244 }
245
246
247 /*
248  * Initialize Code Page information management.
249  * Load all copdepages in memory.
250  */
251 int
252 hpfs_cpinit (
253         struct hpfsmount *hpmp,
254         struct hpfs_args *argsp)
255 {
256         struct buf *bp;
257         int error, i;
258         lsn_t lsn;
259         int cpicnt;
260         struct cpisec * cpisp;
261         struct cpiblk * cpibp;
262         struct cpdblk * cpdbp;
263
264         dprintf(("hpfs_cpinit: \n"));
265
266         if (argsp->flags & HPFSMNT_TABLES) {
267                 bcopy(argsp->d2u, hpmp->hpm_d2u, sizeof(u_char) * 0x80);
268                 bcopy(argsp->u2d, hpmp->hpm_u2d, sizeof(u_char) * 0x80);
269         } else {
270                 for (i=0x0; i<0x80;i++) {
271                         hpmp->hpm_d2u[i] = i + 0x80;
272                         hpmp->hpm_u2d[i] = i + 0x80;
273                 }
274         }
275
276         cpicnt = hpmp->hpm_sp.sp_cpinum;
277
278         MALLOC(hpmp->hpm_cpdblk, struct cpdblk *,       
279                 cpicnt * sizeof(struct cpdblk), M_HPFSMNT, M_WAITOK);
280
281         cpdbp = hpmp->hpm_cpdblk;
282         lsn = hpmp->hpm_sp.sp_cpi;
283
284         while (cpicnt > 0) {
285                 error = bread(hpmp->hpm_devvp, dbtodoff(lsn), DEV_BSIZE, &bp);
286                 if (error) {
287                         brelse(bp);
288                         return (error);
289                 }
290
291                 cpisp = (struct cpisec *)bp->b_data;
292
293                 cpibp = cpisp->s_cpi;
294                 for (i=0; i<cpisp->s_cpicnt; i++, cpicnt --, cpdbp++, cpibp++) {
295                         dprintf(("hpfs_cpinit: Country: %d, CP: %d (%d)\n",
296                                  cpibp->b_country, cpibp->b_cpid, 
297                                  cpibp->b_vcpid));
298
299                         error = hpfs_cpload(hpmp, cpibp, cpdbp);
300                         if (error) {
301                                 brelse(bp);
302                                 return (error);
303                         }
304                 }
305                 lsn = cpisp->s_next;
306                 brelse(bp);
307         }
308
309         return (0);
310 }
311
312 int
313 hpfs_cpdeinit (
314         struct hpfsmount *hpmp)
315 {
316         dprintf(("hpmp_cpdeinit: "));
317         FREE(hpmp->hpm_cpdblk,M_HPFSMNT);
318         return (0);
319 }
320
321 /*
322  * Lookup for a run of blocks.
323  */
324 int
325 hpfs_bmlookup (
326         struct hpfsmount *hpmp,
327         u_long flags,   /* 1 means we want right len blocks in run, not less */
328         lsn_t lsn,              /* We want near this one */
329         u_long len,             /* We want such long */
330         lsn_t *lsnp,    /* We got here */
331         u_long *lenp)   /* We got this long */
332 {
333         u_int32_t * bitmap;
334         u_int32_t mask;
335         int i,k;
336         int cband, vcband;
337         u_int bandsz;
338         int count;
339
340         dprintf(("hpfs_bmlookup: lsn: 0x%x, len 0x%lx | Step1\n", lsn, len));
341
342         if (lsn > hpmp->hpm_su.su_btotal) {
343                 kprintf("hpfs_bmlookup: OUT OF VOLUME\n");
344                 return ENOSPC;
345         }
346         if (len > hpmp->hpm_bavail) {
347                 kprintf("hpfs_bmlookup: OUT OF SPACE\n");
348                 return ENOSPC;
349         }
350         i = lsn >> 5;
351         k = lsn & 0x1F;
352         mask = 1 << k;
353         bitmap = (u_int32_t *)hpmp->hpm_bitmap + i;
354
355         if (*bitmap & mask) {
356                 *lsnp = lsn;
357                 *lenp = 0;
358                 for (; k < 32; k++, mask<<=1) {
359                         if (*bitmap & mask)
360                                 (*lenp) ++;
361                         else {
362                                 if (flags & 1)
363                                         goto step2;
364                                 else 
365                                         return (0);
366                         }
367
368                         if (*lenp == len)
369                                 return (0);
370                 }
371
372                 bitmap++;
373                 i++;
374                 for (; i < hpmp->hpm_su.su_btotal >> 5; i++, bitmap++) {
375                         for (k=0, mask=1; k < 32; k++, mask<<=1) {
376                                 if (*bitmap & mask)
377                                         (*lenp) ++;
378                                 else {
379                                         if (flags & 1)
380                                                 goto step2;
381                                         else 
382                                                 return (0);
383                                 }
384
385                                 if (*lenp == len)
386                                         return (0);
387                         }
388                 }
389                 return (0);
390         }
391
392 step2:
393         /*
394          * Lookup all bands begining from cband, lookup for first block
395          */
396         cband = (lsn >> 14);
397         dprintf(("hpfs_bmlookup: Step2: band 0x%x (0x%lx)\n",
398                  cband, hpmp->hpm_dbnum));
399         for (vcband = 0; vcband < hpmp->hpm_dbnum; vcband ++, cband++) {
400                 cband = cband % hpmp->hpm_dbnum;
401                 bandsz = min (hpmp->hpm_su.su_btotal - (cband << 14), 0x4000);
402                 dprintf(("hpfs_bmlookup: band: %d, sz: 0x%x\n", cband, bandsz));
403
404                 bitmap = (u_int32_t *)hpmp->hpm_bitmap + (cband << 9);
405                 *lsnp = cband << 14;
406                 *lenp = 0;
407                 count = 0;
408                 for (i=0; i < bandsz >> 5; i++, bitmap++) {
409                         for (k=0, mask=1; k < 32; k++, mask<<=1) {
410                                 if (*bitmap & mask) {
411                                         if (count) {
412                                                 (*lenp) ++;
413                                         } else {
414                                                 count = 1;
415                                                 *lsnp = (cband << 14) + (i << 5) + k;
416                                                 *lenp = 1;
417                                         }
418                                 } else {
419                                         if ((*lenp) && !(flags & 1)) {
420                                                 return (0);
421                                         } else {
422                                                 count = 0;
423                                         }
424                                 }
425
426                                 if (*lenp == len)
427                                         return (0);
428                         }
429                 }
430                 if (cband == hpmp->hpm_dbnum - 1)  {
431                         if ((*lenp) && !(flags & 1)) {
432                                 return (0);
433                         } else {
434                                 count = 0;
435                         }
436                 }
437         }
438
439         return (ENOSPC);
440 }
441
442 /*
443  * Lookup a single free block.  XXX Need locking on BitMap operations
444  * VERY STUPID ROUTINE!!!
445  */
446 int
447 hpfs_bmfblookup (
448         struct hpfsmount *hpmp,
449         lsn_t *lp)
450 {
451         u_int32_t * bitmap;
452         int i,k;
453
454         dprintf(("hpfs_bmfblookup: "));
455
456         bitmap = (u_int32_t *)hpmp->hpm_bitmap;
457         for (i=0; i < hpmp->hpm_su.su_btotal >> 5; i++, bitmap++) {
458                 k = ffs(*bitmap);
459                 if (k) {
460                         *lp = (i << 5) + k - 1;
461                         dprintf((" found: 0x%x\n",*lp));
462                         return (0);
463                 }
464         }
465
466         return (ENOSPC);
467 }
468
469 /*
470  * Mark contignous block of blocks.
471  */
472 int
473 hpfs_bmmark (
474         struct hpfsmount *hpmp,
475         lsn_t bn,
476         u_long bl,
477         int state)
478 {
479         u_int32_t * bitmap;
480         int i, didprint = 0;
481
482         dprintf(("hpfs_bmmark(0x%x, 0x%lx, %d): \n",bn,bl, state));
483
484         if ((bn > hpmp->hpm_su.su_btotal) || (bn+bl > hpmp->hpm_su.su_btotal)) {
485                 kprintf("hpfs_bmmark: MARKING OUT OF VOLUME\n");
486                 return 0;
487         }
488         bitmap = (u_int32_t *)hpmp->hpm_bitmap;
489         bitmap += bn >> 5;
490
491         while (bl > 0) {
492                 for (i = bn & 0x1F; (i < 0x20) && (bl > 0) ; i++, bl--) {
493                         if (state) {
494                                 if ( *bitmap & (1 << i)) {
495                                         if (!didprint) {
496                                                 kprintf("hpfs_bmmark: ALREADY FREE\n");
497                                                 didprint = 1;
498                                         }
499                                 } else 
500                                         hpmp->hpm_bavail++;
501
502                                 *bitmap |= (1 << i);
503                         } else {
504                                 if ((~(*bitmap)) & (1 << i)) {
505                                         if (!didprint) {
506                                                 kprintf("hpfs_bmmark: ALREADY BUSY\n");
507                                                 didprint = 1;
508                                         }
509                                 } else 
510                                         hpmp->hpm_bavail--;
511
512                                 *bitmap &= ~(1 << i);
513                         }
514                 }
515                 bn = 0;
516                 bitmap++;
517         }
518
519         return (0);
520 }
521
522
523 int
524 hpfs_validateparent (
525         struct hpfsnode *hp)
526 {
527         struct hpfsnode *dhp;
528         struct vnode *dvp;
529         struct hpfsmount *hpmp = hp->h_hpmp;
530         struct buf *bp;
531         struct dirblk *dp;
532         struct hpfsdirent *dep;
533         lsn_t lsn, olsn;
534         int level, error;
535
536         dprintf(("hpfs_validatetimes(0x%x): [parent: 0x%x] ",
537                 hp->h_no, hp->h_fn.fn_parent));
538
539         if (hp->h_no == hp->h_fn.fn_parent) {
540                 dhp = hp;
541         } else {
542                 error = VFS_VGET(hpmp->hpm_mp, NULL, hp->h_fn.fn_parent, &dvp);
543                 if (error)
544                         return (error);
545                 dhp = VTOHP(dvp);
546         }
547
548         lsn = ((alleaf_t *)dhp->h_fn.fn_abd)->al_lsn;
549
550         olsn = 0;
551         level = 1;
552         bp = NULL;
553
554 dive:
555         dprintf(("[dive 0x%x] ", lsn));
556         if (bp != NULL)
557                 brelse(bp);
558         error = bread(dhp->h_devvp, dbtodoff(lsn), D_BSIZE, &bp);
559         if (error)
560                 goto failed;
561
562         dp = (struct dirblk *) bp->b_data;
563         if (dp->d_magic != D_MAGIC) {
564                 kprintf("hpfs_validatetimes: magic doesn't match\n");
565                 error = EINVAL;
566                 goto failed;
567         }
568
569         dep = D_DIRENT(dp);
570
571         if (olsn) {
572                 dprintf(("[restore 0x%x] ", olsn));
573
574                 while(!(dep->de_flag & DE_END) ) {
575                         if((dep->de_flag & DE_DOWN) &&
576                            (olsn == DE_DOWNLSN(dep)))
577                                          break;
578                         dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
579                 }
580
581                 if((dep->de_flag & DE_DOWN) && (olsn == DE_DOWNLSN(dep))) {
582                         if (dep->de_flag & DE_END)
583                                 goto blockdone;
584
585                         if (hp->h_no == dep->de_fnode) {
586                                 dprintf(("[found] "));
587                                 goto readdone;
588                         }
589
590                         dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
591                 } else {
592                         kprintf("hpfs_validatetimes: ERROR! oLSN not found\n");
593                         error = EINVAL;
594                         goto failed;
595                 }
596         }
597
598         olsn = 0;
599
600         while(!(dep->de_flag & DE_END)) {
601                 if(dep->de_flag & DE_DOWN) {
602                         lsn = DE_DOWNLSN(dep);
603                         level++;
604                         goto dive;
605                 }
606
607                 if (hp->h_no == dep->de_fnode) {
608                         dprintf(("[found] "));
609                         goto readdone;
610                 }
611
612                 dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
613         }
614
615         if(dep->de_flag & DE_DOWN) {
616                 dprintf(("[enddive] "));
617                 lsn = DE_DOWNLSN(dep);
618                 level++;
619                 goto dive;
620         }
621
622 blockdone:
623         dprintf(("[EOB] "));
624         olsn = lsn;
625         lsn = dp->d_parent;
626         level--;
627         dprintf(("[level %d] ", level));
628         if (level > 0)
629                 goto dive;      /* undive really */
630
631         goto failed;
632
633 readdone:
634         bcopy(dep->de_name,hp->h_name,dep->de_namelen);
635         hp->h_name[dep->de_namelen] = '\0';
636         hp->h_namelen = dep->de_namelen;
637         hp->h_ctime = dep->de_ctime;
638         hp->h_atime = dep->de_atime;
639         hp->h_mtime = dep->de_mtime;
640         hp->h_flag |= H_PARVALID;
641
642         dprintf(("[readdone]"));
643
644 failed:
645         dprintf(("\n"));
646         if (bp != NULL)
647                 brelse(bp);
648         if (hp != dhp)
649                 vput(dvp);
650
651         return (error);
652 }
653
654 struct timespec
655 hpfstimetounix (
656         u_long hptime)
657 {
658         struct timespec t;
659
660         t.tv_nsec = 0;
661         t.tv_sec = hptime;
662
663         return t;
664 }
665
666 /*
667  * Write down changes done to parent dir, these are only times for now. 
668  * hpfsnode have to be locked.
669  */
670 int
671 hpfs_updateparent (
672         struct hpfsnode *hp)
673 {
674         struct hpfsnode *dhp;
675         struct vnode *dvp;
676         struct hpfsdirent *dep;
677         struct buf * bp;
678         int error;
679
680         dprintf(("hpfs_updateparent(0x%x): \n", hp->h_no));
681
682         if (!(hp->h_flag & H_PARCHANGE))
683                 return (0);
684
685         if (!(hp->h_flag & H_PARVALID)) {
686                 error = hpfs_validateparent (hp);
687                 if (error)
688                         return (error);
689         }
690
691         if (hp->h_no == hp->h_fn.fn_parent) {
692                 dhp = hp;
693         } else {
694                 error = VFS_VGET(hp->h_hpmp->hpm_mp, NULL,
695                                  hp->h_fn.fn_parent, &dvp);
696                 if (error)
697                         return (error);
698                 dhp = VTOHP(dvp);
699         }
700
701         error = hpfs_genlookupbyname (dhp, hp->h_name, hp->h_namelen,
702                                         &bp, &dep);
703         if (error) {
704                 goto failed;
705         }
706
707         dep->de_atime = hp->h_atime;
708         dep->de_mtime = hp->h_mtime;
709         dep->de_size = hp->h_fn.fn_size;
710
711         bdwrite (bp);
712
713         hp->h_flag &= ~H_PARCHANGE;
714
715         error = 0;
716 failed:
717         if (hp != dhp)
718                 vput(dvp);
719
720         return (0);
721 }
722
723 /*
724  * Write down on disk changes done to fnode. hpfsnode have to be locked.
725  */
726 int
727 hpfs_update (
728         struct hpfsnode *hp)
729 {
730         struct buf * bp;
731
732         dprintf(("hpfs_update(0x%x): \n", hp->h_no));
733
734         if (!(hp->h_flag & H_CHANGE))
735                 return (0);
736
737         bp = getblk(hp->h_devvp, dbtodoff(hp->h_no), FNODESIZE, 0, 0);
738         clrbuf(bp);
739
740         bcopy (&hp->h_fn, bp->b_data, sizeof(struct fnode));
741         bdwrite (bp);
742
743         hp->h_flag &= ~H_CHANGE;
744
745         if (hp->h_flag & H_PARCHANGE)
746                 return (hpfs_updateparent(hp));
747
748         return (0);
749 }
750
751 /*
752  * Truncate file to specifed size. hpfsnode have to be locked.
753  */
754 int
755 hpfs_truncate (
756         struct hpfsnode *hp,
757         u_long size)
758 {
759         struct hpfsmount *hpmp = hp->h_hpmp;
760         lsn_t newblen, oldblen;
761         int error, pf;
762
763         dprintf(("hpfs_truncate(0x%x, 0x%x -> 0x%lx): ",
764                 hp->h_no, hp->h_fn.fn_size, size));
765
766         newblen = (size + DEV_BSIZE - 1) >> DEV_BSHIFT;
767         oldblen = (hp->h_fn.fn_size + DEV_BSIZE - 1) >> DEV_BSHIFT;
768
769         dprintf(("blen: 0x%x -> 0x%x\n", oldblen, newblen));
770
771         error = hpfs_truncatealblk (hpmp, &hp->h_fn.fn_ab, newblen, &pf);
772         if (error)
773                 return (error);
774         if (pf) {
775                 hp->h_fn.fn_ab.ab_flag = 0;
776                 hp->h_fn.fn_ab.ab_freecnt = 0x8;
777                 hp->h_fn.fn_ab.ab_busycnt = 0x0;
778                 hp->h_fn.fn_ab.ab_freeoff = sizeof(alblk_t);
779         }
780
781         hp->h_fn.fn_size = size;
782
783         hp->h_flag |= (H_CHANGE | H_PARCHANGE);
784
785         dprintf(("hpfs_truncate: successful\n"));
786
787         return (0);
788 }
789
790 /*
791  * Enlarge file to specifed size. hpfsnode have to be locked.
792  */
793 int
794 hpfs_extend (
795         struct hpfsnode *hp,
796         u_long size)
797 {
798         struct hpfsmount *hpmp = hp->h_hpmp;
799         lsn_t newblen, oldblen;
800         int error;
801
802         dprintf(("hpfs_extend(0x%x, 0x%x -> 0x%lx): ",
803                 hp->h_no, hp->h_fn.fn_size, size));
804
805         if (hpmp->hpm_bavail < 0x10) 
806                 return (ENOSPC);
807
808         newblen = (size + DEV_BSIZE - 1) >> DEV_BSHIFT;
809         oldblen = (hp->h_fn.fn_size + DEV_BSIZE - 1) >> DEV_BSHIFT;
810
811         dprintf(("blen: 0x%x -> 0x%x\n", oldblen, newblen));
812
813         error = hpfs_addextent(hpmp, hp, newblen - oldblen);
814         if (error) {
815                 kprintf("hpfs_extend: FAILED TO ADD EXTENT %d\n", error);
816                 return (error);
817         }
818
819         hp->h_fn.fn_size = size;
820
821         hp->h_flag |= (H_CHANGE | H_PARCHANGE);
822
823         dprintf(("hpfs_extend: successful\n"));
824
825         return (0);
826 }
827
828 /*
829  * Read AlSec structure, and check if magic is valid.
830  * You don't need to brelse buf on error.
831  */
832 int
833 hpfs_breadstruct (
834         struct hpfsmount *hpmp,
835         lsn_t lsn,
836         u_int len,
837         u_int32_t magic,
838         struct buf **bpp)
839 {
840         struct buf *bp;
841         u_int32_t *mp;
842         int error;
843
844         dprintf(("hpfs_breadstruct: reading at 0x%x\n", lsn));
845
846         *bpp = NULL;
847
848         error = bread(hpmp->hpm_devvp, dbtodoff(lsn), len, &bp);
849         if (error) {
850                 brelse(bp);
851                 return (error);
852         }
853         mp = (u_int32_t *) bp->b_data;
854         if (*mp != magic) {
855                 brelse(bp);
856                 kprintf("hpfs_breadstruct: MAGIC DOESN'T MATCH (0x%08x != 0x%08x)\n",
857                         *mp, magic);
858                 return (EINVAL);
859         }
860
861         *bpp = bp;
862
863         return (0);
864 }
865