Made a call which was to sleep() use tsleep() instead.
[unix-history] / sys / pcfs / pcfs_fat.c
CommitLineData
15637ed4
RG
1/*
2 * Written by Paul Popelka (paulp@uts.amdahl.com)
3 *
4 * You can do anything you want with this software,
5 * just don't say you wrote it,
6 * and don't remove this notice.
7 *
8 * This software is provided "as is".
9 *
10 * The author supplies this software to be publicly
11 * redistributed on the understanding that the author
12 * is not responsible for the correct functioning of
13 * this software in any circumstances and is not liable
14 * for any damages caused by this software.
15 *
16 * October 1992
17 *
4c45483e 18 * $Id: pcfs_fat.c,v 1.2 1993/10/16 19:29:34 rgrimes Exp $
15637ed4
RG
19 */
20
21/*
22 * kernel include files.
23 */
24#include "param.h"
25#include "systm.h"
26#include "buf.h"
27#include "file.h"
28#include "namei.h"
29#include "mount.h" /* to define statfs structure */
30#include "vnode.h" /* to define vattr structure */
31#include "errno.h"
32
33/*
34 * pcfs include files.
35 */
36#include "bpb.h"
37#include "pcfsmount.h"
38#include "direntry.h"
39#include "denode.h"
40#include "fat.h"
41
4c45483e
GW
42static void fc_lookup(struct denode *, u_long, u_long *, u_long *);
43
15637ed4
RG
44/*
45 * Fat cache stats.
46 */
47int fc_fileextends; /* # of file extends */
48int fc_lfcempty; /* # of time last file cluster cache entry
49 * was empty */
50int fc_bmapcalls; /* # of times pcbmap was called */
51#define LMMAX 20
52int fc_lmdistance[LMMAX]; /* counters for how far off the last cluster
53 * mapped entry was. */
54int fc_largedistance; /* off by more than LMMAX */
55
56/* Byte offset in FAT on filesystem pmp, cluster cn */
57#define FATOFS(pmp, cn) (FAT12(pmp) ? (cn) * 3 / 2 : (cn) * 2)
58
59
60static void fatblock (pmp, ofs, bnp, sizep, bop)
61 struct pcfsmount *pmp;
62 u_long ofs;
63 u_long *bnp;
64 u_long *sizep;
65 u_long *bop;
66{
67 u_long bn, size;
68
69 bn = ofs / pmp->pm_fatblocksize * pmp->pm_fatblocksec;
70 size = min (pmp->pm_fatblocksec, pmp->pm_FATsecs - bn)
71 * pmp->pm_BytesPerSec;
72 bn += pmp->pm_fatblk;
73 if (bnp)
74 *bnp = bn;
75 if (sizep)
76 *sizep = size;
77 if (bop)
78 *bop = ofs % pmp->pm_fatblocksize;
79}
80
81/*
82 * Map the logical cluster number of a file into
83 * a physical disk sector that is filesystem relative.
84 * dep - address of denode representing the file of interest
85 * findcn - file relative cluster whose filesystem relative
86 * cluster number and/or block number are/is to be found
87 * bnp - address of where to place the file system relative
88 * block number. If this pointer is null then don't return
89 * this quantity.
90 * cnp - address of where to place the file system relative
91 * cluster number. If this pointer is null then don't return
92 * this quantity.
93 * NOTE:
94 * Either bnp or cnp must be non-null.
95 * This function has one side effect. If the requested
96 * file relative cluster is beyond the end of file, then
97 * the actual number of clusters in the file is returned
98 * in *cnp. This is useful for determining how long a
99 * directory is. If cnp is null, nothing is returned.
100 */
101int
102pcbmap(dep, findcn, bnp, cnp)
103 struct denode *dep;
104 u_long findcn; /* file relative cluster to get */
105 daddr_t *bnp; /* returned filesys relative blk number */
106 u_long *cnp; /* returned cluster number */
107{
108 int error;
109 u_long i;
110 u_long cn;
4c45483e 111 u_long prevcn = 0;
15637ed4
RG
112 u_long byteoffset;
113 u_long bn;
114 u_long bo;
115 struct buf *bp = NULL;
116 u_long bp_bn = -1;
117 struct pcfsmount *pmp = dep->de_pmp;
118 u_long bsize;
119 int fat12 = FAT12(pmp); /* 12 bit fat */
120
121 fc_bmapcalls++;
122
123/*
124 * If they don't give us someplace to return a value
125 * then don't bother doing anything.
126 */
127 if (bnp == NULL && cnp == NULL)
128 return 0;
129
130 cn = dep->de_StartCluster;
131/*
132 * The "file" that makes up the root directory is contiguous,
133 * permanently allocated, of fixed size, and is not made up
134 * of clusters. If the cluster number is beyond the end of
135 * the root directory, then return the number of clusters in
136 * the file.
137 */
138 if (cn == PCFSROOT) {
139 if (dep->de_Attributes & ATTR_DIRECTORY) {
140 if (findcn * pmp->pm_SectPerClust > pmp->pm_rootdirsize) {
141 if (cnp)
142 *cnp = pmp->pm_rootdirsize / pmp->pm_SectPerClust;
143 return E2BIG;
144 }
145 if (bnp)
146 *bnp = pmp->pm_rootdirblk + (findcn * pmp->pm_SectPerClust);
147 if (cnp)
148 *cnp = PCFSROOT;
149 return 0;
150 }
151 else { /* just an empty file */
152 if (cnp)
153 *cnp = 0;
154 return E2BIG;
155 }
156 }
157
158/*
159 * Rummage around in the fat cache, maybe we can avoid
160 * tromping thru every fat entry for the file.
161 * And, keep track of how far off the cache was from
162 * where we wanted to be.
163 */
164 i = 0;
165 fc_lookup(dep, findcn, &i, &cn);
166 if ((bn = findcn - i) >= LMMAX)
167 fc_largedistance++;
168 else
169 fc_lmdistance[bn]++;
170
171/*
172 * Handle all other files or directories the normal way.
173 */
174 for (; i < findcn; i++) {
175 if (PCFSEOF(cn))
176 goto hiteof;
177 byteoffset = FATOFS(pmp, cn);
178 fatblock(pmp, byteoffset, &bn, &bsize, &bo);
179 if (bn != bp_bn) {
180 if (bp)
181 brelse(bp);
182 error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
183 if (error)
184 return error;
185 bp_bn = bn;
186 }
187 prevcn = cn;
188 cn = getushort(&bp->b_un.b_addr[bo]);
189 if (fat12) {
190 if (prevcn & 1)
191 cn >>= 4;
192 cn &= 0x0fff;
193/*
194 * Force the special cluster numbers in the range
195 * 0x0ff0-0x0fff to be the same as for 16 bit cluster
196 * numbers to let the rest of pcfs think it is always
197 * dealing with 16 bit fats.
198 */
199 if ((cn & 0x0ff0) == 0x0ff0)
200 cn |= 0xf000;
201 }
202 }
203
204 if (!PCFSEOF(cn)) {
205 if (bp)
206 brelse(bp);
207 if (bnp)
208 *bnp = cntobn(pmp, cn);
209 if (cnp)
210 *cnp = cn;
211 fc_setcache(dep, FC_LASTMAP, i, cn);
212 return 0;
213 }
214
215hiteof:;
216 if (cnp)
217 *cnp = i;
218 if (bp)
219 brelse(bp);
220 /* update last file cluster entry in the fat cache */
221 fc_setcache(dep, FC_LASTFC, i-1, prevcn);
222 return E2BIG;
223}
224
225/*
226 * Find the closest entry in the fat cache to the
227 * cluster we are looking for.
228 */
4c45483e 229static void
15637ed4
RG
230fc_lookup(dep, findcn, frcnp, fsrcnp)
231 struct denode *dep;
232 u_long findcn;
233 u_long *frcnp;
234 u_long *fsrcnp;
235{
236 int i;
237 u_long cn;
238 struct fatcache *closest = 0;
239
240 for (i = 0; i < FC_SIZE; i++) {
241 cn = dep->de_fc[i].fc_frcn;
242 if (cn != FCE_EMPTY && cn <= findcn) {
243 if (closest == 0 || cn > closest->fc_frcn)
244 closest = &dep->de_fc[i];
245 }
246 }
247 if (closest) {
248 *frcnp = closest->fc_frcn;
249 *fsrcnp = closest->fc_fsrcn;
250 }
251}
252
253/*
254 * Purge the fat cache in denode dep of all entries
255 * relating to file relative cluster frcn and beyond.
256 */
4c45483e 257void
15637ed4
RG
258fc_purge(dep, frcn)
259 struct denode *dep;
260 u_int frcn;
261{
262 int i;
263 struct fatcache *fcp;
264
265 fcp = dep->de_fc;
266 for (i = 0; i < FC_SIZE; i++, fcp++) {
267 if (fcp->fc_frcn != FCE_EMPTY && fcp->fc_frcn >= frcn)
268 fcp->fc_frcn = FCE_EMPTY;
269 }
270}
271
272/*
273 * Once the first fat is updated the other copies of
274 * the fat must also be updated. This function does
275 * this.
276 * pmp - pcfsmount structure for filesystem to update
277 * bp - addr of modified fat block
278 * fatbn - block number relative to begin of filesystem
279 * of the modified fat block.
280 */
281void
282updateotherfats(pmp, bp, fatbn)
283 struct pcfsmount *pmp;
284 struct buf *bp;
285 u_long fatbn;
286{
287 int i;
288 struct buf *bpn;
289
290#if defined(PCFSDEBUG)
291printf("updateotherfats(pmp %08x, bp %08x, fatbn %d)\n",
292 pmp, bp, fatbn);
293#endif /* defined(PCFSDEBUG) */
294
295/*
296 * Now copy the block(s) of the modified fat to the other
297 * copies of the fat and write them out. This is faster
298 * than reading in the other fats and then writing them
299 * back out. This could tie up the fat for quite a while.
300 * Preventing others from accessing it. To prevent us
301 * from going after the fat quite so much we use delayed
302 * writes, unless they specfied "synchronous" when the
303 * filesystem was mounted. If synch is asked for then
304 * use bwrite()'s and really slow things down.
305 */
306 for (i = 1; i < pmp->pm_FATs; i++) {
307 fatbn += pmp->pm_FATsecs;
308 /* getblk() never fails */
309 bpn = getblk(pmp->pm_devvp, fatbn, bp->b_bcount);
310 bcopy(bp->b_un.b_addr, bpn->b_un.b_addr,
311 bp->b_bcount);
312 if (pmp->pm_waitonfat)
313 bwrite(bpn);
314 else
315 bdwrite(bpn);
316 }
317}
318
319/*
320 * Updating entries in 12 bit fats is a pain in the butt.
321 *
322 * The following picture shows where nibbles go when
323 * moving from a 12 bit cluster number into the appropriate
324 * bytes in the FAT.
325 *
326 * byte m byte m+1 byte m+2
327 * +----+----+ +----+----+ +----+----+
328 * | 0 1 | | 2 3 | | 4 5 | FAT bytes
329 * +----+----+ +----+----+ +----+----+
330 *
331 * +----+----+----+ +----+----+----+
332 * | 3 0 1 | | 4 5 2 |
333 * +----+----+----+ +----+----+----+
334 * cluster n cluster n+1
335 *
336 * Where n is even.
337 * m = n + (n >> 2)
338 *
339 * (Function no longer used)
340 */
341
342
343extern inline void
344usemap_alloc (struct pcfsmount *pmp, u_long cn)
345{
346 pmp->pm_inusemap[cn / 8] |= 1 << (cn % 8);
347 pmp->pm_freeclustercount--;
348 /* This assumes that the lowest available cluster was allocated */
349 pmp->pm_lookhere = cn + 1;
350}
351
352extern inline void
353usemap_free (struct pcfsmount *pmp, u_long cn)
354{
355 pmp->pm_freeclustercount++;
356 pmp->pm_inusemap[cn / 8] &= ~(1 << (cn % 8));
357 if (pmp->pm_lookhere > cn)
358 pmp->pm_lookhere = cn;
359}
360
361int
362clusterfree(pmp, cluster, oldcnp)
363 struct pcfsmount *pmp;
364 u_long cluster;
365 u_long *oldcnp;
366{
367 int error;
368 u_long oldcn;
369
370 error = fatentry(FAT_GET_AND_SET, pmp, cluster, &oldcn, PCFSFREE);
371 if (error == 0) {
372/*
373 * If the cluster was successfully marked free, then update the count of
374 * free clusters, and turn off the "allocated" bit in the
375 * "in use" cluster bit map.
376 */
377 usemap_free(pmp, cluster);
378 if (oldcnp)
379 *oldcnp = oldcn;
380 }
381 return error;
382}
383
384/*
385 * Get or Set or 'Get and Set' the cluster'th entry in the
386 * fat.
387 * function - whether to get or set a fat entry
388 * pmp - address of the pcfsmount structure for the
389 * filesystem whose fat is to be manipulated.
390 * cluster - which cluster is of interest
391 * oldcontents - address of a word that is to receive
392 * the contents of the cluster'th entry if this is
393 * a get function
394 * newcontents - the new value to be written into the
395 * cluster'th element of the fat if this is a set
396 * function.
397 *
398 * This function can also be used to free a cluster
399 * by setting the fat entry for a cluster to 0.
400 *
401 * All copies of the fat are updated if this is a set
402 * function.
403 * NOTE:
404 * If fatentry() marks a cluster as free it does not
405 * update the inusemap in the pcfsmount structure.
406 * This is left to the caller.
407 */
408int
409fatentry(function, pmp, cn, oldcontents, newcontents)
410 int function;
411 struct pcfsmount *pmp;
412 u_long cn;
413 u_long *oldcontents;
414 u_long newcontents;
415{
416 int error;
417 u_long readcn;
418 u_long bn, bo, bsize, byteoffset;
419 struct buf *bp;
420/*printf("fatentry(func %d, pmp %08x, clust %d, oldcon %08x, newcon %d)\n",
421 function, pmp, cluster, oldcontents, newcontents);*/
422
423#ifdef DIAGNOSTIC
424/*
425 * Be sure they asked us to do something.
426 */
427 if ((function & (FAT_SET | FAT_GET)) == 0) {
428 printf("fatentry(): function code doesn't specify get or set\n");
429 return EINVAL;
430 }
431
432/*
433 * If they asked us to return a cluster number
434 * but didn't tell us where to put it, give them
435 * an error.
436 */
437 if ((function & FAT_GET) && oldcontents == NULL) {
438 printf("fatentry(): get function with no place to put result\n");
439 return EINVAL;
440 }
441#endif
442
443/*
444 * Be sure the requested cluster is in the filesystem.
445 */
446 if (cn < CLUST_FIRST || cn > pmp->pm_maxcluster)
447 return EINVAL;
448
449 byteoffset = FATOFS(pmp, cn);
450 fatblock(pmp, byteoffset, &bn, &bsize, &bo);
451 error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
452 if (function & FAT_GET) {
453 readcn = getushort(&bp->b_un.b_addr[bo]);
454 if (FAT12(pmp)) {
455 if (cn & 1)
456 readcn >>= 4;
457 readcn &= 0x0fff;
458 /* map certain 12 bit fat entries to 16 bit */
459 if ((readcn & 0x0ff0) == 0x0ff0)
460 readcn |= 0xf000;
461 }
462 *oldcontents = readcn;
463 }
464 if (function & FAT_SET) {
465 if (FAT12(pmp)) {
466 readcn = getushort(&bp->b_un.b_addr[bo]);
467 if (cn & 1) {
468 readcn &= 0x000f;
469 readcn |= (newcontents << 4);
470 }
471 else {
472 readcn &= 0xf000;
473 readcn |= (newcontents << 0);
474 }
475 putushort(&bp->b_un.b_addr[bo], readcn);
476 }
477 else
478 putushort(&bp->b_un.b_addr[bo], newcontents);
479 updateotherfats(pmp, bp, bn);
480/*
481 * Write out the first fat last.
482 */
483 if (pmp->pm_waitonfat)
484 bwrite(bp);
485 else
486 bdwrite(bp);
487 bp = NULL;
488 pmp->pm_fmod++;
489 }
490 if (bp)
491 brelse(bp);
492 return 0;
493}
494
495/*
496 * Allocate a free cluster.
497 * pmp -
498 * retcluster - put the allocated cluster's number here.
499 * fillwith - put this value into the fat entry for the
500 * allocated cluster.
501 */
502int
503clusteralloc(pmp, retcluster, fillwith)
504 struct pcfsmount *pmp;
505 u_long *retcluster;
506 u_long fillwith;
507{
508 int error;
509 u_long cn;
510 u_long idx, max_idx, bit, map;
511
512 max_idx = pmp->pm_maxcluster / 8;
513 for (idx = pmp->pm_lookhere / 8; idx <= max_idx; idx++) {
514 map = pmp->pm_inusemap[idx];
515 if (map != 0xff) {
516 for (bit = 0; bit < 8; bit++) {
517 if ((map & (1 << bit)) == 0) {
518 cn = idx * 8 + bit;
519 goto found_one;
520 }
521 }
522 }
523 }
524 return ENOSPC;
525
526found_one:;
527 error = fatentry(FAT_SET, pmp, cn, 0, fillwith);
528 if (error == 0) {
529 usemap_alloc(pmp, cn);
530 *retcluster = cn;
531 }
532#if defined(PCFSDEBUG)
533printf("clusteralloc(): allocated cluster %d\n", cn);
534#endif /* defined(PCFSDEBUG) */
535 return error;
536}
537
538/*
539 * Free a chain of clusters.
540 * pmp - address of the pcfs mount structure for the
541 * filesystem containing the cluster chain to be freed.
542 * startcluster - number of the 1st cluster in the chain
543 * of clusters to be freed.
544 */
545int
546freeclusterchain(pmp, startcluster)
547 struct pcfsmount *pmp;
548 u_long startcluster;
549{
550 u_long nextcluster;
551 int error = 0;
552
553 while (startcluster >= CLUST_FIRST && startcluster <= pmp->pm_maxcluster) {
554 error = clusterfree(pmp, startcluster, &nextcluster);
555 if (error) {
556 printf("freeclusterchain(): free failed, cluster %d\n",
557 startcluster);
558 break;
559 }
560 startcluster = nextcluster;
561 }
562 return error;
563}
564
565/*
566 * Read in fat blocks looking for free clusters.
567 * For every free cluster found turn off its
568 * corresponding bit in the pm_inusemap.
569 */
570int
571fillinusemap(pmp)
572 struct pcfsmount *pmp;
573{
574 struct buf *bp = NULL;
575 u_long cn, readcn;
576 int error;
577 int fat12 = FAT12(pmp);
578 u_long bn, bo, bsize, byteoffset;
579
580/*
581 * Mark all clusters in use, we mark the free ones in the
582 * fat scan loop further down.
583 */
584 for (cn = 0; cn < (pmp->pm_maxcluster >> 3) + 1; cn++)
585 pmp->pm_inusemap[cn] = 0xff;
586
587/*
588 * Figure how many free clusters are in the filesystem
589 * by ripping thougth the fat counting the number of
590 * entries whose content is zero. These represent free
591 * clusters.
592 */
593 pmp->pm_freeclustercount = 0;
594 pmp->pm_lookhere = pmp->pm_maxcluster + 1;
595 for (cn = CLUST_FIRST; cn <= pmp->pm_maxcluster; cn++) {
596 byteoffset = FATOFS(pmp, cn);
597 bo = byteoffset % pmp->pm_fatblocksize;
598 if (!bo || !bp) {
599 /* Read new FAT block */
600 if (bp)
601 brelse(bp);
602 fatblock(pmp, byteoffset, &bn, &bsize, NULL);
603 error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
604 if (error)
605 return error;
606 }
607 readcn = getushort(&bp->b_un.b_addr[bo]);
608 if (fat12) {
609 if (cn & 1)
610 readcn >>= 4;
611 readcn &= 0x0fff;
612 }
613
614 if (readcn == 0)
615 usemap_free(pmp, cn);
616 }
617 brelse(bp);
618 return 0;
619}
620
621/*
622 * Allocate a new cluster and chain it onto the end of the
623 * file.
624 * dep - the file to extend
625 * bpp - where to return the address of the buf header for the
626 * new file block
627 * ncp - where to put cluster number of the newly allocated file block
628 * If this pointer is 0, do not return the cluster number.
629 *
630 * NOTE:
631 * This function is not responsible for turning on the DEUPD
632 * bit if the de_flag field of the denode and it does not
633 * change the de_FileSize field. This is left for the caller
634 * to do.
635 */
636int
637extendfile(dep, bpp, ncp)
638 struct denode *dep;
639 struct buf **bpp;
640 u_int *ncp;
641{
642 int error = 0;
643 u_long frcn;
644 u_long cn;
645 struct pcfsmount *pmp = dep->de_pmp;
646
647/*
648 * Don't try to extend the root directory
649 */
650 if (DETOV(dep)->v_flag & VROOT) {
651 printf("extendfile(): attempt to extend root directory\n");
652 return ENOSPC;
653 }
654
655/*
656 * If the "file's last cluster" cache entry is empty,
657 * and the file is not empty,
658 * then fill the cache entry by calling pcbmap().
659 */
660 fc_fileextends++;
661 if (dep->de_fc[FC_LASTFC].fc_frcn == FCE_EMPTY &&
662 dep->de_StartCluster != 0) {
663 fc_lfcempty++;
664 error = pcbmap(dep, 0xffff, 0, &cn);
665 /* we expect it to return E2BIG */
666 if (error != E2BIG)
667 return error;
668 error = 0;
669 }
670
671/*
672 * Allocate another cluster and chain onto the end of the file.
673 * If the file is empty we make de_StartCluster point to the
674 * new block. Note that de_StartCluster being 0 is sufficient
675 * to be sure the file is empty since we exclude attempts to
676 * extend the root directory above, and the root dir is the
677 * only file with a startcluster of 0 that has blocks allocated
678 * (sort of).
679 */
680 if (error = clusteralloc(pmp, &cn, CLUST_EOFE))
681 return error;
682 if (dep->de_StartCluster == 0) {
683 dep->de_StartCluster = cn;
684 frcn = 0;
685 } else {
686 error = fatentry(FAT_SET, pmp, dep->de_fc[FC_LASTFC].fc_fsrcn,
687 0, cn);
688 if (error) {
689 clusterfree(pmp, cn, NULL);
690 return error;
691 }
692
693 frcn = dep->de_fc[FC_LASTFC].fc_frcn + 1;
694 }
695
696/*
697 * Update the "last cluster of the file" entry in the denode's
698 * fat cache.
699 */
700 fc_setcache(dep, FC_LASTFC, frcn, cn);
701
702/*
703 * Get the buf header for the new block of the file.
704 */
705 if (dep->de_Attributes & ATTR_DIRECTORY) {
706 *bpp = getblk(pmp->pm_devvp, cntobn(pmp, cn),
707 pmp->pm_bpcluster);
708 } else {
709 *bpp = getblk(DETOV(dep), frcn,
710 pmp->pm_bpcluster);
711 }
712 clrbuf(*bpp);
713
714/*
715 * Give them the filesystem relative cluster number
716 * if they want it.
717 */
718 if (ncp)
719 *ncp = cn;
720 return 0;
721}