1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Routines to allocate and deallocate data blocks on the disk
28 */
29
30 #include <sys/param.h>
31 #include <sys/errno.h>
32 #include <sys/buf.h>
33 #include <sys/vfs.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>
43
44 static pc_cluster32_t pc_getcluster(struct pcfs *fsp, pc_cluster32_t cn);
45
46 /*
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.
50 */
51 int
pc_bmap(struct pcnode * pcp,daddr_t lcn,daddr_t * dbnp,uint_t * contigbp)52 pc_bmap(
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 */
58 {
59 struct pcfs *fsp; /* pcfs that file is in */
60 struct vnode *vp;
61 pc_cluster32_t cn, ncn; /* current, next cluster number */
62 daddr_t olcn = lcn;
63
64 vp = PCTOV(pcp);
65 fsp = VFSTOPCFS(vp->v_vfsp);
66
67 if (lcn < 0)
68 return (ENOENT);
69
70 /*
71 * FAT12 / FAT16 root directories are a continuous section on disk
72 * before the actual data clusters. Specialcase this here.
73 */
74 if (!IS_FAT32(fsp) && (vp->v_flag & VROOT)) {
75 daddr_t lbn; /* logical (disk) block number */
76
77 lbn = pc_cltodb(fsp, lcn);
78 if (lbn >= fsp->pcfs_rdirsec) {
79 PC_DPRINTF0(2, "pc_bmap: ENOENT1\n");
80 return (ENOENT);
81 }
82 *dbnp = pc_dbdaddr(fsp, fsp->pcfs_rdirstart + lbn);
83 if (contigbp) {
84 ASSERT (*contigbp >= fsp->pcfs_secsize);
85 *contigbp = MIN(*contigbp,
86 fsp->pcfs_secsize * (fsp->pcfs_rdirsec - lbn));
87 }
88 return (0);
89 }
90
91 if (lcn >= fsp->pcfs_ncluster) {
92 PC_DPRINTF0(2, "pc_bmap: ENOENT2\n");
93 return (ENOENT);
94 }
95 if (vp->v_type == VREG &&
96 (pcp->pc_size == 0 ||
97 lcn >= (daddr_t)howmany((offset_t)pcp->pc_size,
98 fsp->pcfs_clsize))) {
99 PC_DPRINTF0(2, "pc_bmap: ENOENT3\n");
100 return (ENOENT);
101 }
102 ncn = pcp->pc_scluster;
103 if (IS_FAT32(fsp) && ncn == 0)
104 ncn = fsp->pcfs_rdirstart;
105
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;
110 }
111 do {
112 cn = ncn;
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");
117 return (ENOENT);
118 } else if (!IS_FAT32(fsp) &&
119 cn >= PCF_LASTCLUSTER &&
120 vp->v_type == VDIR) {
121 PC_DPRINTF0(2, "pc_bmap: ENOENT5\n");
122 return (ENOENT);
123 } else {
124 PC_DPRINTF1(1,
125 "pc_bmap: badfs cn=%d\n", cn);
126 (void) pc_badfs(fsp);
127 return (EIO);
128 }
129 }
130 ncn = pc_getcluster(fsp, cn);
131 } while (lcn--);
132
133 /*
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.
137 */
138 pcp->pc_lindex = olcn;
139 pcp->pc_lcluster = cn;
140 *dbnp = pc_cldaddr(fsp, cn);
141
142 if (contigbp && *contigbp > fsp->pcfs_clsize) {
143 uint_t count = fsp->pcfs_clsize;
144
145 while ((cn + 1) == ncn && count < *contigbp &&
146 pc_validcl(fsp, ncn)) {
147 count += fsp->pcfs_clsize;
148 cn = ncn;
149 ncn = pc_getcluster(fsp, ncn);
150 }
151 *contigbp = count;
152 }
153 return (0);
154 }
155
156 /*
157 * Allocate file logical blocks (clusters).
158 * Return disk address of last allocated cluster.
159 */
160 int
pc_balloc(struct pcnode * pcp,daddr_t lcn,int zwrite,daddr_t * dbnp)161 pc_balloc(
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 */
166 {
167 struct pcfs *fsp; /* pcfs that file is in */
168 struct vnode *vp;
169 pc_cluster32_t cn; /* current cluster number */
170 pc_cluster32_t ncn; /* next cluster number */
171
172 vp = PCTOV(pcp);
173 fsp = VFSTOPCFS(vp -> v_vfsp);
174
175 if (lcn < 0) {
176 return (EFBIG);
177 }
178
179 /*
180 * Again, FAT12/FAT16 root directories are not data clusters.
181 */
182 if (!IS_FAT32(fsp) && (vp->v_flag & VROOT)) {
183 daddr_t lbn;
184
185 lbn = pc_cltodb(fsp, lcn);
186 if (lbn >= fsp->pcfs_rdirsec)
187 return (ENOSPC);
188 *dbnp = pc_dbdaddr(fsp, fsp->pcfs_rdirstart + lbn);
189 return (0);
190 }
191
192 if (lcn >= fsp->pcfs_ncluster)
193 return (ENOSPC);
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:
198 return (ENOSPC);
199 case PCF_ERRORCLUSTER:
200 return (EIO);
201 }
202 pcp->pc_scluster = cn;
203 } else {
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);
210 return (EIO);
211 }
212 }
213
214 if (pcp->pc_lindex > 0 && lcn > pcp->pc_lindex) {
215 lcn -= pcp->pc_lindex;
216 cn = pcp->pc_lcluster;
217 }
218 while (lcn-- > 0) {
219 ncn = pc_getcluster(fsp, cn);
220 if ((IS_FAT32(fsp) && ncn >= PCF_LASTCLUSTER32) ||
221 (!IS_FAT32(fsp) && ncn >= PCF_LASTCLUSTER)) {
222 /*
223 * Extend file (no holes).
224 */
225 switch (ncn = pc_alloccluster(fsp, zwrite)) {
226 case PCF_FREECLUSTER:
227 return (ENOSPC);
228 case PCF_ERRORCLUSTER:
229 return (EIO);
230 }
231 pc_setcluster(fsp, cn, ncn);
232 } else if (!pc_validcl(fsp, ncn)) {
233 PC_DPRINTF1(1,
234 "pc_balloc: badfs ncn=%d\n", ncn);
235 (void) pc_badfs(fsp);
236 return (EIO);
237 }
238 cn = ncn;
239 }
240 /*
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.
244 */
245 *dbnp = pc_cldaddr(fsp, cn);
246
247 return (0);
248 }
249
250 /*
251 * Free file cluster chain after the first skipcl clusters.
252 */
253 int
pc_bfree(struct pcnode * pcp,pc_cluster32_t skipcl)254 pc_bfree(struct pcnode *pcp, pc_cluster32_t skipcl)
255 {
256 struct pcfs *fsp;
257 pc_cluster32_t cn;
258 pc_cluster32_t ncn;
259 int n;
260 struct vnode *vp;
261
262 vp = PCTOV(pcp);
263 fsp = VFSTOPCFS(vp->v_vfsp);
264 if (!IS_FAT32(fsp) && (vp->v_flag & VROOT)) {
265 panic("pc_bfree");
266 }
267
268 if (pcp->pc_size == 0 && vp->v_type == VREG) {
269 return (0);
270 }
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);
276 return (EIO);
277 }
278 } else {
279 n = fsp->pcfs_ncluster;
280 }
281 cn = pcp->pc_scluster;
282 if (IS_FAT32(fsp) && cn == 0)
283 cn = fsp->pcfs_rdirstart;
284 if (skipcl == 0) {
285 if (IS_FAT32(fsp))
286 pcp->pc_scluster = PCF_LASTCLUSTERMARK32;
287 else
288 pcp->pc_scluster = PCF_LASTCLUSTERMARK;
289 }
290
291 /* Invalidate last used cluster cache */
292 pcp->pc_lindex = 0;
293 pcp->pc_lcluster = pcp->pc_scluster;
294
295 while (n--) {
296 if (!pc_validcl(fsp, cn)) {
297 PC_DPRINTF1(1, "pc_bfree: badfs cn=%d\n", cn);
298 (void) pc_badfs(fsp);
299 return (EIO);
300 }
301 ncn = pc_getcluster(fsp, cn);
302 if (skipcl == 0) {
303 pc_setcluster(fsp, cn, PCF_FREECLUSTER);
304 } else {
305 skipcl--;
306 if (skipcl == 0) {
307 if (IS_FAT32(fsp)) {
308 pc_setcluster(fsp, cn,
309 PCF_LASTCLUSTERMARK32);
310 } else
311 pc_setcluster(fsp, cn,
312 PCF_LASTCLUSTERMARK);
313 }
314 }
315 if (IS_FAT32(fsp) && ncn >= PCF_LASTCLUSTER32 &&
316 vp->v_type == VDIR)
317 break;
318 if (!IS_FAT32(fsp) && ncn >= PCF_LASTCLUSTER &&
319 vp->v_type == VDIR)
320 break;
321 cn = ncn;
322 }
323 return (0);
324 }
325
326 /*
327 * Return the number of free blocks in the filesystem.
328 */
329 int
pc_freeclusters(struct pcfs * fsp)330 pc_freeclusters(struct pcfs *fsp)
331 {
332 pc_cluster32_t cn;
333 int free = 0;
334
335 if (IS_FAT32(fsp) &&
336 fsp->pcfs_fsinfo.fs_free_clusters != FSINFO_UNKNOWN)
337 return (fsp->pcfs_fsinfo.fs_free_clusters);
338
339 /*
340 * make sure the FAT is in core
341 */
342 for (cn = PCF_FIRSTCLUSTER; pc_validcl(fsp, cn); cn++) {
343 if (pc_getcluster(fsp, cn) == PCF_FREECLUSTER) {
344 free++;
345 }
346 }
347
348 if (IS_FAT32(fsp)) {
349 ASSERT(fsp->pcfs_fsinfo.fs_free_clusters == FSINFO_UNKNOWN);
350 fsp->pcfs_fsinfo.fs_free_clusters = free;
351 }
352 return (free);
353 }
354
355 /*
356 * Cluster manipulation routines.
357 * FAT must be resident.
358 */
359
360 /*
361 * Get the next cluster in the file cluster chain.
362 * cn = current cluster number in chain
363 */
364 static pc_cluster32_t
pc_getcluster(struct pcfs * fsp,pc_cluster32_t cn)365 pc_getcluster(struct pcfs *fsp, pc_cluster32_t cn)
366 {
367 unsigned char *fp;
368
369 if (fsp->pcfs_fatp == (uchar_t *)0 || !pc_validcl(fsp, cn))
370 panic("pc_getcluster");
371
372 switch (fsp->pcfs_fattype) {
373 case FAT32:
374 fp = fsp->pcfs_fatp + (cn << 2);
375 cn = ltohi(*(pc_cluster32_t *)fp);
376 break;
377 case FAT16:
378 fp = fsp->pcfs_fatp + (cn << 1);
379 cn = ltohs(*(pc_cluster16_t *)fp);
380 break;
381 case FAT12:
382 fp = fsp->pcfs_fatp + (cn + (cn >> 1));
383 if (cn & 01) {
384 cn = (((unsigned int)*fp++ & 0xf0) >> 4);
385 cn += (*fp << 4);
386 } else {
387 cn = *fp++;
388 cn += ((*fp & 0x0f) << 8);
389 }
390 if (cn >= PCF_12BCLUSTER)
391 cn |= PCF_RESCLUSTER;
392 break;
393 default:
394 pc_mark_irrecov(fsp);
395 cn = PCF_ERRORCLUSTER;
396 }
397 return (cn);
398 }
399
400 /*
401 * Set a cluster in the FAT to a value.
402 * cn = cluster number to be set in FAT
403 * ncn = new value
404 */
405 void
pc_setcluster(struct pcfs * fsp,pc_cluster32_t cn,pc_cluster32_t ncn)406 pc_setcluster(struct pcfs *fsp, pc_cluster32_t cn, pc_cluster32_t ncn)
407 {
408 unsigned char *fp;
409 pc_cluster16_t ncn16;
410
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) {
416 case FAT32:
417 fp = fsp->pcfs_fatp + (cn << 2);
418 *(pc_cluster32_t *)fp = htoli(ncn);
419 break;
420 case FAT16:
421 fp = fsp->pcfs_fatp + (cn << 1);
422 ncn16 = (pc_cluster16_t)ncn;
423 *(pc_cluster16_t *)fp = htols(ncn16);
424 break;
425 case FAT12:
426 fp = fsp->pcfs_fatp + (cn + (cn >> 1));
427 if (cn & 01) {
428 *fp = (*fp & 0x0f) | ((ncn << 4) & 0xf0);
429 fp++;
430 *fp = (ncn >> 4) & 0xff;
431 } else {
432 *fp++ = ncn & 0xff;
433 *fp = (*fp & 0xf0) | ((ncn >> 8) & 0x0f);
434 }
435 break;
436 default:
437 pc_mark_irrecov(fsp);
438 }
439 if (ncn == PCF_FREECLUSTER) {
440 fsp->pcfs_nxfrecls = PCF_FIRSTCLUSTER;
441 if (IS_FAT32(fsp)) {
442 if (fsp->pcfs_fsinfo.fs_free_clusters !=
443 FSINFO_UNKNOWN)
444 fsp->pcfs_fsinfo.fs_free_clusters++;
445 }
446 }
447 }
448
449 /*
450 * Allocate a new cluster.
451 */
452 pc_cluster32_t
pc_alloccluster(struct pcfs * fsp,int zwrite)453 pc_alloccluster(
454 struct pcfs *fsp, /* file sys to allocate in */
455 int zwrite) /* boolean for writing zeroes */
456 {
457 pc_cluster32_t cn;
458 int error;
459
460 if (fsp->pcfs_fatp == (uchar_t *)0)
461 panic("pc_addcluster: no FAT");
462
463 for (cn = fsp->pcfs_nxfrecls; pc_validcl(fsp, cn); cn++) {
464 if (pc_getcluster(fsp, cn) == PCF_FREECLUSTER) {
465 struct buf *bp;
466
467 if (IS_FAT32(fsp)) {
468 pc_setcluster(fsp, cn, PCF_LASTCLUSTERMARK32);
469 if (fsp->pcfs_fsinfo.fs_free_clusters !=
470 FSINFO_UNKNOWN)
471 fsp->pcfs_fsinfo.fs_free_clusters--;
472 } else
473 pc_setcluster(fsp, cn, PCF_LASTCLUSTERMARK);
474 if (zwrite) {
475 /*
476 * zero the new cluster
477 */
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);
482 clrbuf(bp);
483 bwrite2(bp);
484 error = geterror(bp);
485 brelse(bp);
486 if (error) {
487 pc_mark_irrecov(fsp);
488 return (PCF_ERRORCLUSTER);
489 }
490 }
491 fsp->pcfs_nxfrecls = cn + 1;
492 return (cn);
493 }
494 }
495 return (PCF_FREECLUSTER);
496 }
497
498 /*
499 * Get the number of clusters used by a file or subdirectory
500 */
501 int
pc_fileclsize(struct pcfs * fsp,pc_cluster32_t startcl,pc_cluster32_t * ncl)502 pc_fileclsize(
503 struct pcfs *fsp,
504 pc_cluster32_t startcl, pc_cluster32_t *ncl)
505 {
506 int count = 0;
507
508 *ncl = 0;
509 for (count = 0; pc_validcl(fsp, startcl);
510 startcl = pc_getcluster(fsp, startcl)) {
511 if (count++ >= fsp->pcfs_ncluster)
512 return (EIO);
513 }
514 *ncl = (pc_cluster32_t)count;
515
516 return (0);
517 }
518