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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Routines to allocate and deallocate data blocks on the disk 30 */ 31 32 #include <sys/param.h> 33 #include <sys/errno.h> 34 #include <sys/buf.h> 35 #include <sys/vfs.h> 36 #include <sys/vnode.h> 37 #include <sys/cmn_err.h> 38 #include <sys/debug.h> 39 #include <sys/sysmacros.h> 40 #include <sys/systm.h> 41 #include <sys/fs/pc_label.h> 42 #include <sys/fs/pc_fs.h> 43 #include <sys/fs/pc_dir.h> 44 #include <sys/fs/pc_node.h> 45 46 static pc_cluster32_t pc_getcluster(struct pcfs *fsp, pc_cluster32_t cn); 47 48 /* 49 * Convert file logical block (cluster) numbers to disk block numbers. 50 * Also return number of physically contiguous blocks if asked for. 51 * Used for reading only. Use pc_balloc for writing. 52 */ 53 int 54 pc_bmap( 55 struct pcnode *pcp, /* pcnode for file */ 56 daddr_t lcn, /* logical cluster no */ 57 daddr_t *dbnp, /* ptr to phys block no */ 58 uint_t *contigbp) /* ptr to number of contiguous bytes */ 59 /* may be zero if not wanted */ 60 { 61 struct pcfs *fsp; /* pcfs that file is in */ 62 struct vnode *vp; 63 pc_cluster32_t cn, ncn; /* current, next cluster number */ 64 daddr_t olcn = lcn; 65 66 PC_DPRINTF2(6, "pc_bmap: pcp=0x%p, lcn=%ld\n", (void *)pcp, lcn); 67 68 vp = PCTOV(pcp); 69 fsp = VFSTOPCFS(vp->v_vfsp); 70 if (lcn < 0) 71 return (ENOENT); 72 if (!IS_FAT32(fsp) && (vp->v_flag & VROOT)) { 73 daddr_t lbn, bn; /* logical (disk) block number */ 74 75 lbn = pc_cltodb(fsp, lcn); 76 if (lbn >= fsp->pcfs_rdirsec) { 77 PC_DPRINTF0(2, "pc_bmap: ENOENT1\n"); 78 return (ENOENT); 79 } 80 bn = fsp->pcfs_rdirstart + lbn; 81 *dbnp = pc_dbdaddr(fsp, bn); 82 if (contigbp) { 83 ASSERT (*contigbp >= fsp->pcfs_secsize); 84 *contigbp = MIN(*contigbp, 85 fsp->pcfs_secsize * (fsp->pcfs_rdirsec - lbn)); 86 } 87 } else { 88 89 if (lcn >= fsp->pcfs_ncluster) { 90 PC_DPRINTF0(2, "pc_bmap: ENOENT2\n"); 91 return (ENOENT); 92 } 93 if (vp->v_type == VREG && 94 (pcp->pc_size == 0 || 95 lcn >= (daddr_t)howmany((offset_t)pcp->pc_size, 96 fsp->pcfs_clsize))) { 97 PC_DPRINTF0(2, "pc_bmap: ENOENT3\n"); 98 return (ENOENT); 99 } 100 ncn = pcp->pc_scluster; 101 if (IS_FAT32(fsp) && ncn == 0) 102 ncn = fsp->pcfs_rdirstart; 103 104 /* Do we have a cached index/cluster pair? */ 105 if (pcp->pc_lindex > 0 && lcn >= pcp->pc_lindex) { 106 lcn -= pcp->pc_lindex; 107 ncn = pcp->pc_lcluster; 108 } 109 do { 110 cn = ncn; 111 if (!pc_validcl(fsp, cn)) { 112 if (IS_FAT32(fsp) && cn >= PCF_LASTCLUSTER32 && 113 vp->v_type == VDIR) { 114 PC_DPRINTF0(2, "pc_bmap: ENOENT4\n"); 115 return (ENOENT); 116 } else if (!IS_FAT32(fsp) && 117 cn >= PCF_LASTCLUSTER && 118 vp->v_type == VDIR) { 119 PC_DPRINTF0(2, "pc_bmap: ENOENT5\n"); 120 return (ENOENT); 121 } else { 122 PC_DPRINTF1(1, 123 "pc_bmap: badfs cn=%d\n", cn); 124 (void) pc_badfs(fsp); 125 return (EIO); 126 } 127 } 128 ncn = pc_getcluster(fsp, cn); 129 } while (lcn--); 130 131 /* 132 * Cache this cluster, as we'll most likely visit the 133 * one after this next time. Considerably improves 134 * performance on sequential reads and writes. 135 */ 136 pcp->pc_lindex = olcn; 137 pcp->pc_lcluster = cn; 138 *dbnp = pc_cldaddr(fsp, cn); 139 140 if (contigbp && *contigbp > fsp->pcfs_clsize) { 141 uint_t count = fsp->pcfs_clsize; 142 143 while ((cn + 1) == ncn && count < *contigbp && 144 pc_validcl(fsp, ncn)) { 145 count += fsp->pcfs_clsize; 146 cn = ncn; 147 ncn = pc_getcluster(fsp, ncn); 148 } 149 *contigbp = count; 150 } 151 } 152 return (0); 153 } 154 155 /* 156 * Allocate file logical blocks (clusters). 157 * Return disk address of last allocated cluster. 158 */ 159 int 160 pc_balloc( 161 struct pcnode *pcp, /* pcnode for file */ 162 daddr_t lcn, /* logical cluster no */ 163 int zwrite, /* zerofill blocks? */ 164 daddr_t *dbnp) /* ptr to phys block no */ 165 { 166 struct pcfs *fsp; /* pcfs that file is in */ 167 struct vnode *vp; 168 169 PC_DPRINTF2(5, "pc_balloc: pcp=0x%p, lcn=%ld\n", (void *)pcp, lcn); 170 171 vp = PCTOV(pcp); 172 fsp = VFSTOPCFS(vp -> v_vfsp); 173 174 if (lcn < 0) { 175 return (EFBIG); 176 } 177 178 if (!IS_FAT32(fsp) && (vp->v_flag & VROOT)) { 179 daddr_t lbn; 180 181 lbn = pc_cltodb(fsp, lcn); 182 if (lbn >= fsp->pcfs_rdirsec) 183 return (ENOSPC); 184 *dbnp = pc_dbdaddr(fsp, fsp->pcfs_rdirstart + lbn); 185 } else { 186 pc_cluster32_t cn; /* current cluster number */ 187 pc_cluster32_t ncn; /* next cluster number */ 188 189 if (lcn >= fsp->pcfs_ncluster) 190 return (ENOSPC); 191 if ((vp->v_type == VREG && pcp->pc_size == 0) || 192 (vp->v_type == VDIR && lcn == 0)) { 193 switch (cn = pc_alloccluster(fsp, 1)) { 194 case PCF_FREECLUSTER: 195 return (ENOSPC); 196 case PCF_ERRORCLUSTER: 197 return (EIO); 198 } 199 pcp->pc_scluster = cn; 200 } else { 201 cn = pcp->pc_scluster; 202 if (IS_FAT32(fsp) && cn == 0) 203 cn = fsp->pcfs_rdirstart; 204 if (!pc_validcl(fsp, cn)) { 205 PC_DPRINTF1(1, "pc_balloc: badfs cn=%d\n", cn); 206 (void) pc_badfs(fsp); 207 return (EIO); 208 } 209 } 210 211 if (pcp->pc_lindex > 0 && lcn > pcp->pc_lindex) { 212 lcn -= pcp->pc_lindex; 213 cn = pcp->pc_lcluster; 214 } 215 while (lcn-- > 0) { 216 ncn = pc_getcluster(fsp, cn); 217 if ((IS_FAT32(fsp) && ncn >= PCF_LASTCLUSTER32) || 218 (!IS_FAT32(fsp) && ncn >= PCF_LASTCLUSTER)) { 219 /* 220 * Extend file (no holes). 221 */ 222 switch (ncn = pc_alloccluster(fsp, zwrite)) { 223 case PCF_FREECLUSTER: 224 return (ENOSPC); 225 case PCF_ERRORCLUSTER: 226 return (EIO); 227 } 228 pc_setcluster(fsp, cn, ncn); 229 } else if (!pc_validcl(fsp, ncn)) { 230 PC_DPRINTF1(1, 231 "pc_balloc: badfs ncn=%d\n", ncn); 232 (void) pc_badfs(fsp); 233 return (EIO); 234 } 235 cn = ncn; 236 } 237 /* 238 * Do not cache the new cluster/index values; when 239 * extending the file we're interested in the last 240 * written cluster and not the last cluster allocated. 241 */ 242 *dbnp = pc_cldaddr(fsp, cn); 243 } 244 return (0); 245 } 246 247 /* 248 * Free file cluster chain after the first skipcl clusters. 249 */ 250 int 251 pc_bfree(struct pcnode *pcp, pc_cluster32_t skipcl) 252 { 253 struct pcfs *fsp; 254 pc_cluster32_t cn; 255 pc_cluster32_t ncn; 256 int n; 257 struct vnode *vp; 258 259 vp = PCTOV(pcp); 260 fsp = VFSTOPCFS(vp->v_vfsp); 261 if (!IS_FAT32(fsp) && (vp->v_flag & VROOT)) { 262 panic("pc_bfree"); 263 } 264 265 PC_DPRINTF2(5, "pc_bfree: pcp=0x%p, after first %d clusters\n", 266 (void *)pcp, skipcl); 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 330 pc_freeclusters(struct pcfs *fsp) 331 { 332 pc_cluster32_t cn; 333 int free = 0; 334 335 if (IS_FAT32(fsp) && 336 fsp->fsinfo_native.fs_free_clusters != FSINFO_UNKNOWN) 337 return (fsp->fsinfo_native.fs_free_clusters); 338 339 /* 340 * make sure the FAT is in core 341 */ 342 for (cn = PCF_FIRSTCLUSTER; 343 (int)cn < fsp->pcfs_ncluster; cn++) { 344 if (pc_getcluster(fsp, cn) == PCF_FREECLUSTER) { 345 free++; 346 } 347 } 348 349 if (IS_FAT32(fsp)) { 350 ASSERT(fsp->fsinfo_native.fs_free_clusters == FSINFO_UNKNOWN); 351 fsp->fsinfo_native.fs_free_clusters = free; 352 } 353 return (free); 354 } 355 356 /* 357 * Cluster manipulation routines. 358 * FAT must be resident. 359 */ 360 361 /* 362 * Get the next cluster in the file cluster chain. 363 * cn = current cluster number in chain 364 */ 365 static pc_cluster32_t 366 pc_getcluster(struct pcfs *fsp, pc_cluster32_t cn) 367 { 368 unsigned char *fp; 369 370 PC_DPRINTF1(7, "pc_getcluster: cn=%x ", cn); 371 if (fsp->pcfs_fatp == (uchar_t *)0 || !pc_validcl(fsp, cn)) 372 panic("pc_getcluster"); 373 374 if (IS_FAT32(fsp)) { /* 32 bit FAT */ 375 fp = fsp->pcfs_fatp + (cn << 2); 376 cn = ltohi(*(pc_cluster32_t *)fp); 377 } else if (fsp->pcfs_flags & PCFS_FAT16) { /* 16 bit FAT */ 378 fp = fsp->pcfs_fatp + (cn << 1); 379 cn = ltohs(*(pc_cluster16_t *)fp); 380 } else { /* 12 bit FAT */ 381 fp = fsp->pcfs_fatp + (cn + (cn >> 1)); 382 if (cn & 01) { 383 cn = (((unsigned int)*fp++ & 0xf0) >> 4); 384 cn += (*fp << 4); 385 } else { 386 cn = *fp++; 387 cn += ((*fp & 0x0f) << 8); 388 } 389 if (cn >= PCF_12BCLUSTER) 390 cn |= PCF_RESCLUSTER; 391 } 392 PC_DPRINTF1(7, " %x\n", cn); 393 return (cn); 394 } 395 396 /* 397 * Set a cluster in the FAT to a value. 398 * cn = cluster number to be set in FAT 399 * ncn = new value 400 */ 401 void 402 pc_setcluster(struct pcfs *fsp, pc_cluster32_t cn, pc_cluster32_t ncn) 403 { 404 unsigned char *fp; 405 406 PC_DPRINTF2(7, "pc_setcluster: cn=%d ncn=%d\n", cn, ncn); 407 if (fsp->pcfs_fatp == (uchar_t *)0 || !pc_validcl(fsp, cn)) 408 panic("pc_setcluster"); 409 fsp->pcfs_flags |= PCFS_FATMOD; 410 pc_mark_fat_updated(fsp, cn); 411 if (IS_FAT32(fsp)) { /* 32 bit FAT */ 412 fp = fsp->pcfs_fatp + (cn << 2); 413 *(pc_cluster32_t *)fp = htoli(ncn); 414 } else if (fsp->pcfs_flags & PCFS_FAT16) { /* 16 bit FAT */ 415 pc_cluster16_t ncn16; 416 417 fp = fsp->pcfs_fatp + (cn << 1); 418 ncn16 = (pc_cluster16_t)ncn; 419 *(pc_cluster16_t *)fp = htols(ncn16); 420 } else { /* 12 bit FAT */ 421 fp = fsp->pcfs_fatp + (cn + (cn >> 1)); 422 if (cn & 01) { 423 *fp = (*fp & 0x0f) | ((ncn << 4) & 0xf0); 424 fp++; 425 *fp = (ncn >> 4) & 0xff; 426 } else { 427 *fp++ = ncn & 0xff; 428 *fp = (*fp & 0xf0) | ((ncn >> 8) & 0x0f); 429 } 430 } 431 if (ncn == PCF_FREECLUSTER) { 432 fsp->pcfs_nxfrecls = PCF_FIRSTCLUSTER; 433 if (IS_FAT32(fsp)) { 434 if (fsp->fsinfo_native.fs_free_clusters != 435 FSINFO_UNKNOWN) 436 fsp->fsinfo_native.fs_free_clusters++; 437 } 438 } 439 } 440 441 /* 442 * Allocate a new cluster. 443 */ 444 pc_cluster32_t 445 pc_alloccluster( 446 struct pcfs *fsp, /* file sys to allocate in */ 447 int zwrite) /* boolean for writing zeroes */ 448 { 449 pc_cluster32_t cn; 450 int error; 451 452 if (fsp->pcfs_fatp == (uchar_t *)0) 453 panic("pc_addcluster: no FAT"); 454 455 for (cn = fsp->pcfs_nxfrecls; 456 (int)cn < fsp->pcfs_ncluster; cn++) { 457 if (pc_getcluster(fsp, cn) == PCF_FREECLUSTER) { 458 struct buf *bp; 459 460 if (IS_FAT32(fsp)) { 461 pc_setcluster(fsp, cn, PCF_LASTCLUSTERMARK32); 462 if (fsp->fsinfo_native.fs_free_clusters != 463 FSINFO_UNKNOWN) 464 fsp->fsinfo_native.fs_free_clusters--; 465 } else 466 pc_setcluster(fsp, cn, PCF_LASTCLUSTERMARK); 467 if (zwrite) { 468 /* 469 * zero the new cluster 470 */ 471 bp = ngeteblk(fsp->pcfs_clsize); 472 bp->b_edev = fsp->pcfs_xdev; 473 bp->b_dev = cmpdev(bp->b_edev); 474 bp->b_blkno = pc_cldaddr(fsp, cn); 475 clrbuf(bp); 476 bwrite2(bp); 477 error = geterror(bp); 478 brelse(bp); 479 if (error) { 480 PC_DPRINTF0(1, 481 "pc_alloccluster: error\n"); 482 pc_mark_irrecov(fsp); 483 return (PCF_ERRORCLUSTER); 484 } 485 } 486 fsp->pcfs_nxfrecls = cn + 1; 487 PC_DPRINTF1(5, "pc_alloccluster: new cluster = %d\n", 488 cn); 489 return (cn); 490 } 491 } 492 return (PCF_FREECLUSTER); 493 } 494 495 /* 496 * Get the number of clusters used by a file or subdirectory 497 */ 498 int 499 pc_fileclsize( 500 struct pcfs *fsp, 501 pc_cluster32_t startcl, pc_cluster32_t *ncl) 502 { 503 int count = 0; 504 505 *ncl = 0; 506 for (count = 0; pc_validcl(fsp, startcl); 507 startcl = pc_getcluster(fsp, startcl)) { 508 if (count++ >= fsp->pcfs_ncluster) 509 return (EIO); 510 } 511 *ncl = (pc_cluster32_t)count; 512 513 return (0); 514 } 515