4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Routines to allocate and deallocate data blocks on the disk
30 #include <sys/param.h>
31 #include <sys/errno.h>
34 #include <sys/vnode.h>
35 #include <sys/cmn_err.h>
36 #include <sys/debug.h>
37 #include <sys/sysmacros.h>
38 #include <sys/systm.h>
39 #include <sys/fs/pc_label.h>
40 #include <sys/fs/pc_fs.h>
41 #include <sys/fs/pc_dir.h>
42 #include <sys/fs/pc_node.h>
44 static pc_cluster32_t
pc_getcluster(struct pcfs
*fsp
, pc_cluster32_t cn
);
47 * Convert file logical block (cluster) numbers to disk block numbers.
48 * Also return number of physically contiguous blocks if asked for.
49 * Used for reading only. Use pc_balloc for writing.
53 struct pcnode
*pcp
, /* pcnode for file */
54 daddr_t lcn
, /* logical cluster no */
55 daddr_t
*dbnp
, /* ptr to phys block no */
56 uint_t
*contigbp
) /* ptr to number of contiguous bytes */
57 /* may be zero if not wanted */
59 struct pcfs
*fsp
; /* pcfs that file is in */
61 pc_cluster32_t cn
, ncn
; /* current, next cluster number */
65 fsp
= VFSTOPCFS(vp
->v_vfsp
);
71 * FAT12 / FAT16 root directories are a continuous section on disk
72 * before the actual data clusters. Specialcase this here.
74 if (!IS_FAT32(fsp
) && (vp
->v_flag
& VROOT
)) {
75 daddr_t lbn
; /* logical (disk) block number */
77 lbn
= pc_cltodb(fsp
, lcn
);
78 if (lbn
>= fsp
->pcfs_rdirsec
) {
79 PC_DPRINTF0(2, "pc_bmap: ENOENT1\n");
82 *dbnp
= pc_dbdaddr(fsp
, fsp
->pcfs_rdirstart
+ lbn
);
84 ASSERT (*contigbp
>= fsp
->pcfs_secsize
);
85 *contigbp
= MIN(*contigbp
,
86 fsp
->pcfs_secsize
* (fsp
->pcfs_rdirsec
- lbn
));
91 if (lcn
>= fsp
->pcfs_ncluster
) {
92 PC_DPRINTF0(2, "pc_bmap: ENOENT2\n");
95 if (vp
->v_type
== VREG
&&
97 lcn
>= (daddr_t
)howmany((offset_t
)pcp
->pc_size
,
99 PC_DPRINTF0(2, "pc_bmap: ENOENT3\n");
102 ncn
= pcp
->pc_scluster
;
103 if (IS_FAT32(fsp
) && ncn
== 0)
104 ncn
= fsp
->pcfs_rdirstart
;
106 /* Do we have a cached index/cluster pair? */
107 if (pcp
->pc_lindex
> 0 && lcn
>= pcp
->pc_lindex
) {
108 lcn
-= pcp
->pc_lindex
;
109 ncn
= pcp
->pc_lcluster
;
113 if (!pc_validcl(fsp
, cn
)) {
114 if (IS_FAT32(fsp
) && cn
>= PCF_LASTCLUSTER32
&&
115 vp
->v_type
== VDIR
) {
116 PC_DPRINTF0(2, "pc_bmap: ENOENT4\n");
118 } else if (!IS_FAT32(fsp
) &&
119 cn
>= PCF_LASTCLUSTER
&&
120 vp
->v_type
== VDIR
) {
121 PC_DPRINTF0(2, "pc_bmap: ENOENT5\n");
125 "pc_bmap: badfs cn=%d\n", cn
);
126 (void) pc_badfs(fsp
);
130 ncn
= pc_getcluster(fsp
, cn
);
134 * Cache this cluster, as we'll most likely visit the
135 * one after this next time. Considerably improves
136 * performance on sequential reads and writes.
138 pcp
->pc_lindex
= olcn
;
139 pcp
->pc_lcluster
= cn
;
140 *dbnp
= pc_cldaddr(fsp
, cn
);
142 if (contigbp
&& *contigbp
> fsp
->pcfs_clsize
) {
143 uint_t count
= fsp
->pcfs_clsize
;
145 while ((cn
+ 1) == ncn
&& count
< *contigbp
&&
146 pc_validcl(fsp
, ncn
)) {
147 count
+= fsp
->pcfs_clsize
;
149 ncn
= pc_getcluster(fsp
, ncn
);
157 * Allocate file logical blocks (clusters).
158 * Return disk address of last allocated cluster.
162 struct pcnode
*pcp
, /* pcnode for file */
163 daddr_t lcn
, /* logical cluster no */
164 int zwrite
, /* zerofill blocks? */
165 daddr_t
*dbnp
) /* ptr to phys block no */
167 struct pcfs
*fsp
; /* pcfs that file is in */
169 pc_cluster32_t cn
; /* current cluster number */
170 pc_cluster32_t ncn
; /* next cluster number */
173 fsp
= VFSTOPCFS(vp
-> v_vfsp
);
180 * Again, FAT12/FAT16 root directories are not data clusters.
182 if (!IS_FAT32(fsp
) && (vp
->v_flag
& VROOT
)) {
185 lbn
= pc_cltodb(fsp
, lcn
);
186 if (lbn
>= fsp
->pcfs_rdirsec
)
188 *dbnp
= pc_dbdaddr(fsp
, fsp
->pcfs_rdirstart
+ lbn
);
192 if (lcn
>= fsp
->pcfs_ncluster
)
194 if ((vp
->v_type
== VREG
&& pcp
->pc_size
== 0) ||
195 (vp
->v_type
== VDIR
&& lcn
== 0)) {
196 switch (cn
= pc_alloccluster(fsp
, 1)) {
197 case PCF_FREECLUSTER
:
199 case PCF_ERRORCLUSTER
:
202 pcp
->pc_scluster
= cn
;
204 cn
= pcp
->pc_scluster
;
205 if (IS_FAT32(fsp
) && cn
== 0)
206 cn
= fsp
->pcfs_rdirstart
;
207 if (!pc_validcl(fsp
, cn
)) {
208 PC_DPRINTF1(1, "pc_balloc: badfs cn=%d\n", cn
);
209 (void) pc_badfs(fsp
);
214 if (pcp
->pc_lindex
> 0 && lcn
> pcp
->pc_lindex
) {
215 lcn
-= pcp
->pc_lindex
;
216 cn
= pcp
->pc_lcluster
;
219 ncn
= pc_getcluster(fsp
, cn
);
220 if ((IS_FAT32(fsp
) && ncn
>= PCF_LASTCLUSTER32
) ||
221 (!IS_FAT32(fsp
) && ncn
>= PCF_LASTCLUSTER
)) {
223 * Extend file (no holes).
225 switch (ncn
= pc_alloccluster(fsp
, zwrite
)) {
226 case PCF_FREECLUSTER
:
228 case PCF_ERRORCLUSTER
:
231 pc_setcluster(fsp
, cn
, ncn
);
232 } else if (!pc_validcl(fsp
, ncn
)) {
234 "pc_balloc: badfs ncn=%d\n", ncn
);
235 (void) pc_badfs(fsp
);
241 * Do not cache the new cluster/index values; when
242 * extending the file we're interested in the last
243 * written cluster and not the last cluster allocated.
245 *dbnp
= pc_cldaddr(fsp
, cn
);
251 * Free file cluster chain after the first skipcl clusters.
254 pc_bfree(struct pcnode
*pcp
, pc_cluster32_t skipcl
)
263 fsp
= VFSTOPCFS(vp
->v_vfsp
);
264 if (!IS_FAT32(fsp
) && (vp
->v_flag
& VROOT
)) {
268 if (pcp
->pc_size
== 0 && vp
->v_type
== VREG
) {
271 if (vp
->v_type
== VREG
) {
272 n
= (int)howmany((offset_t
)pcp
->pc_size
, fsp
->pcfs_clsize
);
273 if (n
> fsp
->pcfs_ncluster
) {
274 PC_DPRINTF1(1, "pc_bfree: badfs n=%d\n", n
);
275 (void) pc_badfs(fsp
);
279 n
= fsp
->pcfs_ncluster
;
281 cn
= pcp
->pc_scluster
;
282 if (IS_FAT32(fsp
) && cn
== 0)
283 cn
= fsp
->pcfs_rdirstart
;
286 pcp
->pc_scluster
= PCF_LASTCLUSTERMARK32
;
288 pcp
->pc_scluster
= PCF_LASTCLUSTERMARK
;
291 /* Invalidate last used cluster cache */
293 pcp
->pc_lcluster
= pcp
->pc_scluster
;
296 if (!pc_validcl(fsp
, cn
)) {
297 PC_DPRINTF1(1, "pc_bfree: badfs cn=%d\n", cn
);
298 (void) pc_badfs(fsp
);
301 ncn
= pc_getcluster(fsp
, cn
);
303 pc_setcluster(fsp
, cn
, PCF_FREECLUSTER
);
308 pc_setcluster(fsp
, cn
,
309 PCF_LASTCLUSTERMARK32
);
311 pc_setcluster(fsp
, cn
,
312 PCF_LASTCLUSTERMARK
);
315 if (IS_FAT32(fsp
) && ncn
>= PCF_LASTCLUSTER32
&&
318 if (!IS_FAT32(fsp
) && ncn
>= PCF_LASTCLUSTER
&&
327 * Return the number of free blocks in the filesystem.
330 pc_freeclusters(struct pcfs
*fsp
)
336 fsp
->pcfs_fsinfo
.fs_free_clusters
!= FSINFO_UNKNOWN
)
337 return (fsp
->pcfs_fsinfo
.fs_free_clusters
);
340 * make sure the FAT is in core
342 for (cn
= PCF_FIRSTCLUSTER
; pc_validcl(fsp
, cn
); cn
++) {
343 if (pc_getcluster(fsp
, cn
) == PCF_FREECLUSTER
) {
349 ASSERT(fsp
->pcfs_fsinfo
.fs_free_clusters
== FSINFO_UNKNOWN
);
350 fsp
->pcfs_fsinfo
.fs_free_clusters
= free
;
356 * Cluster manipulation routines.
357 * FAT must be resident.
361 * Get the next cluster in the file cluster chain.
362 * cn = current cluster number in chain
364 static pc_cluster32_t
365 pc_getcluster(struct pcfs
*fsp
, pc_cluster32_t cn
)
369 if (fsp
->pcfs_fatp
== (uchar_t
*)0 || !pc_validcl(fsp
, cn
))
370 panic("pc_getcluster");
372 switch (fsp
->pcfs_fattype
) {
374 fp
= fsp
->pcfs_fatp
+ (cn
<< 2);
375 cn
= ltohi(*(pc_cluster32_t
*)fp
);
378 fp
= fsp
->pcfs_fatp
+ (cn
<< 1);
379 cn
= ltohs(*(pc_cluster16_t
*)fp
);
382 fp
= fsp
->pcfs_fatp
+ (cn
+ (cn
>> 1));
384 cn
= (((unsigned int)*fp
++ & 0xf0) >> 4);
388 cn
+= ((*fp
& 0x0f) << 8);
390 if (cn
>= PCF_12BCLUSTER
)
391 cn
|= PCF_RESCLUSTER
;
394 pc_mark_irrecov(fsp
);
395 cn
= PCF_ERRORCLUSTER
;
401 * Set a cluster in the FAT to a value.
402 * cn = cluster number to be set in FAT
406 pc_setcluster(struct pcfs
*fsp
, pc_cluster32_t cn
, pc_cluster32_t ncn
)
409 pc_cluster16_t ncn16
;
411 if (fsp
->pcfs_fatp
== (uchar_t
*)0 || !pc_validcl(fsp
, cn
))
412 panic("pc_setcluster");
413 fsp
->pcfs_flags
|= PCFS_FATMOD
;
414 pc_mark_fat_updated(fsp
, cn
);
415 switch (fsp
->pcfs_fattype
) {
417 fp
= fsp
->pcfs_fatp
+ (cn
<< 2);
418 *(pc_cluster32_t
*)fp
= htoli(ncn
);
421 fp
= fsp
->pcfs_fatp
+ (cn
<< 1);
422 ncn16
= (pc_cluster16_t
)ncn
;
423 *(pc_cluster16_t
*)fp
= htols(ncn16
);
426 fp
= fsp
->pcfs_fatp
+ (cn
+ (cn
>> 1));
428 *fp
= (*fp
& 0x0f) | ((ncn
<< 4) & 0xf0);
430 *fp
= (ncn
>> 4) & 0xff;
433 *fp
= (*fp
& 0xf0) | ((ncn
>> 8) & 0x0f);
437 pc_mark_irrecov(fsp
);
439 if (ncn
== PCF_FREECLUSTER
) {
440 fsp
->pcfs_nxfrecls
= PCF_FIRSTCLUSTER
;
442 if (fsp
->pcfs_fsinfo
.fs_free_clusters
!=
444 fsp
->pcfs_fsinfo
.fs_free_clusters
++;
450 * Allocate a new cluster.
454 struct pcfs
*fsp
, /* file sys to allocate in */
455 int zwrite
) /* boolean for writing zeroes */
460 if (fsp
->pcfs_fatp
== (uchar_t
*)0)
461 panic("pc_addcluster: no FAT");
463 for (cn
= fsp
->pcfs_nxfrecls
; pc_validcl(fsp
, cn
); cn
++) {
464 if (pc_getcluster(fsp
, cn
) == PCF_FREECLUSTER
) {
468 pc_setcluster(fsp
, cn
, PCF_LASTCLUSTERMARK32
);
469 if (fsp
->pcfs_fsinfo
.fs_free_clusters
!=
471 fsp
->pcfs_fsinfo
.fs_free_clusters
--;
473 pc_setcluster(fsp
, cn
, PCF_LASTCLUSTERMARK
);
476 * zero the new cluster
478 bp
= ngeteblk(fsp
->pcfs_clsize
);
479 bp
->b_edev
= fsp
->pcfs_xdev
;
480 bp
->b_dev
= cmpdev(bp
->b_edev
);
481 bp
->b_blkno
= pc_cldaddr(fsp
, cn
);
484 error
= geterror(bp
);
487 pc_mark_irrecov(fsp
);
488 return (PCF_ERRORCLUSTER
);
491 fsp
->pcfs_nxfrecls
= cn
+ 1;
495 return (PCF_FREECLUSTER
);
499 * Get the number of clusters used by a file or subdirectory
504 pc_cluster32_t startcl
, pc_cluster32_t
*ncl
)
509 for (count
= 0; pc_validcl(fsp
, startcl
);
510 startcl
= pc_getcluster(fsp
, startcl
)) {
511 if (count
++ >= fsp
->pcfs_ncluster
)
514 *ncl
= (pc_cluster32_t
)count
;