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