Home | History | Annotate | Download | only in pcfs
      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
     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
    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
    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
    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
    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
    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
    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
    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