xref: /illumos-gate/usr/src/uts/common/sys/fs/pc_fs.h (revision 264a6e74)
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 #ifndef	_SYS_FS_PC_FS_H
27 #define	_SYS_FS_PC_FS_H
28 
29 #pragma ident	"%Z%%M%	%I%	%E% SMI"
30 
31 #include <sys/thread.h>
32 
33 #ifdef	__cplusplus
34 extern "C" {
35 #endif
36 
37 typedef	uint16_t	pc_cluster16_t;
38 typedef	uint32_t	pc_cluster32_t;
39 
40 /*
41  * PC (MSDOS) compatible virtual file system.
42  *
43  * A main goal of the implementation was to maintain statelessness
44  * except while files are open. Thus mounting and unmounting merely
45  * declared the file system name. The user may change disks at almost
46  * any time without concern (just like the PC). It is assumed that when
47  * files are open for writing the disk access light will be on, as a
48  * warning not to change disks. The implementation must, however, detect
49  * disk change and recover gracefully. It does this by comparing the
50  * in core entry for a directory to the on disk entry whenever a directory
51  * is searched. If a discrepancy is found active directories become root and
52  * active files are marked invalid.
53  *
54  * There are only two type of nodes on the PC file system; files and
55  * directories. These are represented by two separate vnode op vectors,
56  * and they are kept in two separate tables. Files are known by the
57  * disk block number and block (cluster) offset of the files directory
58  * entry. Directories are known by the starting cluster number.
59  *
60  * The file system is locked for during each user operation. This is
61  * done to simplify disk verification error conditions.
62  *
63  * Notes on FAT32 support
64  * ----------------------
65  * The basic difference between FAT32 and FAT16 is that cluster numbers are now
66  * 32-bit instead of 16-bit. The FAT is thus an array of 32-bit cluster numbers,
67  * and because of this the cluster size can be much smaller on a large disk
68  * (4k, say, on a 1 Gig drive instead of 16k). Unfortunately, the FAT is not
69  * the only place cluster numbers are stored - the starting cluster is stored
70  * in the directory entry for a file, and of course it's only 16-bit. Luckily,
71  * there's a 16-bit OS/2 Extended Attribute field that is now used to store the
72  * upper 16-bits of the starting cluster number.
73  *
74  * Most of the FAT32 changes to pcfs are under 'if it's FAT32' to minimize the
75  * effect on non-FAT32 filesystems (and still share the code), except for the
76  * starting cluster changes. It seemed easier to make common functions to
77  * handle that.
78  *
79  * Other changes:
80  *
81  *     1. FAT32 partitions are indicated by partition types 0xB and 0xC.
82  *     2. The boot sector is now 2 sectors, to make room for FAT32 extensions.
83  *     3. The root directory is no longer stored in a fixed location. Its'
84  *        starting cluster is stored in the extended boot sector.
85  *     4. "Summary information" is now stored and we need to (at least) maintain
86  *        the number of free clusters or scandisk will be upset. Though the
87  *        sector this info is in is pointed to by the extensions in the boot
88  *        sector, the magic offset of this information is just that so
89  *        far - magic. 0x1e0.
90  *     5. FAT32 can use the alternate FAT. But we don't.
91  *
92  * FAT32 also exposed a latent bug: we bread() each copy of the FAT in one
93  * big chunk.  This is not good on a large FAT32 drive, such as a 1 Gig
94  * Jaz drive that has 4k clusters, since the FAT becomes 1 Meg in size and
95  * bread blocks forever. So now we read the FAT in chunks.
96  */
97 
98 /*
99  * pre-FAT32 boot sector.
100  */
101 struct bootsec {
102 	uchar_t	instr[3];
103 	uchar_t	version[8];
104 	uchar_t	bps[2];			/* bytes per sector */
105 	uchar_t	spcl;			/* sectors per allocation unit */
106 	uchar_t	res_sec[2];		/* reserved sectors, starting at 0 */
107 	uchar_t	nfat;			/* number of FATs */
108 	uchar_t	rdirents[2];		/* number of root directory entries */
109 	uchar_t	numsect[2];		/* old total sectors in logical image */
110 	uchar_t	mediadesriptor;		/* media descriptor byte */
111 	ushort_t fatsec;		/* number of sectors per FAT */
112 	ushort_t spt;			/* sectors per track */
113 	ushort_t nhead;			/* number of heads */
114 	uint_t	hiddensec;		/* number of hidden sectors */
115 	uint_t	totalsec;		/* total sectors in logical image */
116 };
117 
118 /*
119  * FAT32 volumes have a bigger boot sector. They include the normal
120  * boot sector.
121  */
122 struct fat32_bootsec {
123 	struct bootsec	f_bs;
124 	uint32_t	f_fatlength;	/* size of FAT */
125 	uint16_t	f_flags;
126 	uint8_t		f_major;	/* major filesystem version #? */
127 	uint8_t		f_minor;	/* minor filesystem version #? */
128 	uint32_t	f_rootcluster;	/* first cluster in root directory */
129 	uint16_t	f_infosector;	/* where summary info is */
130 	uint16_t	f_backupboot;	/* backup boot sector */
131 	uint16_t	f_reserved2[6];
132 };
133 
134 #define	FAT32_FS_SIGN	0x61417272
135 #define	FAT32_BOOT_FSINFO_OFF	0x1e0
136 
137 /*
138  * summary information for fat32 volumes. We need to maintain fs_free_clusters
139  * or Microsoft Scandisk will be upset.
140  */
141 struct fat32_boot_fsinfo {
142 	uint32_t	fs_reserved1;
143 	uint32_t	fs_signature;	/* 0x61417272 */
144 	uint32_t	fs_free_clusters;  /* # free clusters. -1 if unknown */
145 	uint32_t	fs_next_cluster;   /* unused by pcfs */
146 	uint32_t	fs_reserved2[4];
147 };
148 
149 #define	FSINFO_UNKNOWN	(-1)
150 
151 struct pcfs {
152 	struct vfs *pcfs_vfs;		/* vfs for this fs */
153 	int pcfs_flags;			/* flags */
154 	int pcfs_ldrv;			/* logical DOS drive number */
155 	dev_t pcfs_xdev;		/* actual device that is mounted */
156 	struct vnode *pcfs_devvp;	/*   and a vnode for it */
157 	int pcfs_secsize;		/* sector size in bytes */
158 	int pcfs_spcl;			/* sectors per cluster */
159 	int pcfs_spt;			/* sectors per track */
160 	int pcfs_sdshift;		/* shift to convert sector into */
161 					/* DEV_BSIZE "sectors"; assume */
162 					/* pcfs_secsize is 2**n times of */
163 					/* DEV_BSIZE */
164 	int pcfs_fatsec;		/* number of sec per FAT */
165 	int pcfs_numfat;		/* number of FAT copies */
166 	int pcfs_rdirsec;		/* number of sec in root dir */
167 	daddr_t pcfs_dosstart;		/* start blkno of DOS partition */
168 	daddr_t pcfs_fatstart;		/* start blkno of first FAT */
169 	daddr_t pcfs_rdirstart;		/* start blkno of root dir */
170 	daddr_t pcfs_datastart;		/* start blkno of data area */
171 	int pcfs_clsize;		/* cluster size in bytes */
172 	int pcfs_ncluster;		/* number of clusters in fs */
173 	int pcfs_entps;			/* number of dir entry per sector */
174 	int pcfs_nrefs;			/* number of active pcnodes */
175 	int pcfs_frefs;			/* number of active file pcnodes */
176 	int pcfs_nxfrecls;		/* next free cluster */
177 	uchar_t *pcfs_fatp;		/* ptr to FAT data */
178 	uchar_t *pcfs_fat_changemap;	/* map of changed fat data */
179 	int pcfs_fatsize;		/* size of FAT data */
180 	int pcfs_fat_changemapsize;	/* size of FAT changemap */
181 	time_t pcfs_fattime;		/* time FAT becomes invalid */
182 	time_t pcfs_verifytime;		/* time to reverify disk */
183 	kmutex_t	pcfs_lock;		/* per filesystem lock */
184 	kthread_id_t pcfs_owner;		/* id of thread locking pcfs */
185 	int pcfs_count;			/* # of pcfs locks for pcfs_owner */
186 	struct fat32_boot_fsinfo fsinfo_native; /* native fsinfo for fat32 */
187 	uint32_t	f32fsinfo_sector; /* where to read/write fsinfo */
188 	struct pcfs *pcfs_nxt;		/* linked list of all mounts */
189 	int pcfs_fatjustread;		/* Used to flag a freshly found FAT */
190 	struct vnode *pcfs_root;	/* vnode for the root dir of the fs */
191 };
192 
193 /*
194  * flags
195  */
196 #define	PCFS_FATMOD		0x01	/* FAT has been modified */
197 #define	PCFS_LOCKED		0x02	/* fs is locked */
198 #define	PCFS_WANTED		0x04	/* locked fs is wanted */
199 #define	PCFS_FAT16		0x400	/* 16 bit FAT */
200 #define	PCFS_NOCHK		0x800	/* don't resync fat on error */
201 #define	PCFS_BOOTPART		0x1000	/* boot partition type */
202 #define	PCFS_HIDDEN		0x2000	/* show hidden files */
203 #define	PCFS_PCMCIA_NO_CIS	0x4000	/* PCMCIA psuedo floppy */
204 #define	PCFS_FOLDCASE		0x8000	/* fold filenames to lowercase */
205 #define	PCFS_FAT32		0x10000	/* 32 bit FAT */
206 #define	PCFS_IRRECOV		0x20000	/* FS was messed with during write */
207 #define	PCFS_NOCLAMPTIME	0x40000	/* expose full FAT timestamp range */
208 
209 /* for compatibility */
210 struct old_pcfs_args {
211 	int	secondswest;	/* seconds west of Greenwich */
212 	int	dsttime;    	/* type of dst correction */
213 };
214 
215 struct pcfs_args {
216 	int	secondswest;	/* seconds west of Greenwich */
217 	int	dsttime;    	/* type of dst correction */
218 	int	flags;
219 };
220 
221 /*
222  * flags for the pcfs_args 'flags' field.
223  *
224  * Note that these two macros are obsolete - do not use them.
225  */
226 #define	PCFS_MNT_HIDDEN		0x01	/* show hidden files */
227 #define	PCFS_MNT_FOLDCASE	0x02	/* fold all names from media to */
228 					/* lowercase */
229 #define	PCFS_MNT_NOCLAMPTIME	0x04	/* expose full FAT timestamp range */
230 
231 /*
232  * pcfs mount options.
233  */
234 #define	MNTOPT_PCFS_HIDDEN	"hidden"
235 #define	MNTOPT_PCFS_NOHIDDEN	"nohidden"
236 #define	MNTOPT_PCFS_FOLDCASE	"foldcase"
237 #define	MNTOPT_PCFS_NOFOLDCASE	"nofoldcase"
238 #define	MNTOPT_PCFS_CLAMPTIME	"clamptime"
239 #define	MNTOPT_PCFS_NOCLAMPTIME	"noclamptime"
240 
241 /*
242  * Disk timeout value in sec.
243  * This is used to time out the in core FAT and to re-verify the disk.
244  * This should be less than the time it takes to change floppys
245  */
246 #define	PCFS_DISKTIMEOUT	2
247 
248 #define	VFSTOPCFS(VFSP)		((struct pcfs *)((VFSP)->vfs_data))
249 #define	PCFSTOVFS(FSP)		((FSP)->pcfs_vfs)
250 
251 /*
252  * special cluster numbers in FAT
253  */
254 #define	PCF_FREECLUSTER		0x00	/* cluster is available */
255 #define	PCF_ERRORCLUSTER	0x01	/* error occurred allocating cluster */
256 #define	PCF_12BCLUSTER		0xFF0	/* 12-bit version of reserved cluster */
257 #define	PCF_RESCLUSTER		0xFFF0	/* 16-bit version of reserved cluster */
258 #define	PCF_RESCLUSTER32	0xFFFFFF0 /* 32-bit version */
259 #define	PCF_BADCLUSTER		0xFFF7	/* bad cluster, do not use */
260 #define	PCF_BADCLUSTER32	0xFFFFFF7 /* 32-bit version */
261 #define	PCF_LASTCLUSTER		0xFFF8	/* >= means last cluster in file */
262 #define	PCF_LASTCLUSTER32	0xFFFFFF8 /* 32-bit version */
263 #define	PCF_LASTCLUSTERMARK	0xFFFF	/* value used to mark last cluster */
264 #define	PCF_LASTCLUSTERMARK32	0xFFFFFFF /* 32-bit version */
265 #define	PCF_FIRSTCLUSTER	2	/* first valid cluster number */
266 
267 /*
268  * file system constants
269  */
270 #define	PC_MAXFATSEC	256		/* maximum number of sectors in FAT */
271 
272 /*
273  * file system parameter macros
274  */
275 
276 #define	IS_FAT32(PCFS) \
277 	(((PCFS)->pcfs_flags & PCFS_FAT32) == PCFS_FAT32)
278 
279 #define	IS_FAT16(PCFS) \
280 	(((PCFS)->pcfs_flags & PCFS_FAT16) == PCFS_FAT16)
281 
282 #define	IS_FAT12(PCFS) \
283 	(((PCFS)->pcfs_flags & (PCFS_FAT16 | PCFS_FAT32)) == 0)
284 
285 #define	pc_clear_fatchanges(PCFS) \
286 	bzero((PCFS)->pcfs_fat_changemap, (PCFS)->pcfs_fat_changemapsize)
287 
288 #define	pc_blksize(PCFS, PCP, OFF)	/* file system block size */ \
289 	(((PCTOV(PCP)->v_flag & VROOT) && !IS_FAT32(PCFS)) ? \
290 	    ((OFF) >= \
291 	    ((PCFS)->pcfs_rdirsec & \
292 	    ~((PCFS)->pcfs_spcl - 1)) * ((PCFS)->pcfs_secsize)? \
293 	    ((PCFS)->pcfs_rdirsec & \
294 	    ((PCFS)->pcfs_spcl - 1)) * ((PCFS)->pcfs_secsize): \
295 	    (PCFS)->pcfs_clsize): \
296 	    (PCFS)->pcfs_clsize)
297 
298 #define	pc_blkoff(PCFS, OFF)		/* offset within block */ \
299 	((int)((OFF) & ((PCFS)->pcfs_clsize - 1)))
300 
301 #define	pc_lblkno(PCFS, OFF)		/* logical block (cluster) no */ \
302 	((daddr_t)((OFF) / (PCFS)->pcfs_clsize))
303 
304 #define	pc_dbtocl(PCFS, DB)		/* disk blks to clusters */ \
305 	((int)((DB) / (PCFS)->pcfs_spcl))
306 
307 #define	pc_cltodb(PCFS, CL)		/* clusters to disk blks */ \
308 	((daddr_t)((CL) * (PCFS)->pcfs_spcl))
309 
310 #define	pc_cldaddr(PCFS, CL)	/* DEV_BSIZE "sector" addr for cluster */ \
311 	(((daddr_t)((PCFS)->pcfs_datastart + \
312 	    ((CL) - PCF_FIRSTCLUSTER) * (PCFS)->pcfs_spcl)) << \
313 	    (PCFS)->pcfs_sdshift)
314 
315 #define	pc_daddrcl(PCFS, DADDR)		/* cluster for disk address */ \
316 	((int)(((((DADDR) >> (PCFS)->pcfs_sdshift) - (PCFS)->pcfs_datastart) / \
317 	(PCFS)->pcfs_spcl) + 2))
318 
319 #define	pc_dbdaddr(PCFS, DB)	/* sector to DEV_BSIZE "sector" addr */ \
320 	((DB) << (PCFS)->pcfs_sdshift)
321 
322 #define	pc_daddrdb(PCFS, DADDR)	/* DEV_BSIZE "sector" addr to sector addr */ \
323 	((DADDR) >> (PCFS)->pcfs_sdshift)
324 
325 #define	pc_validcl(PCFS, CL)		/* check that cluster no is legit */ \
326 	((int)(CL) >= PCF_FIRSTCLUSTER && \
327 	    (int)(CL) <= (PCFS)->pcfs_ncluster)
328 
329 /*
330  * external routines.
331  */
332 extern int pc_lockfs(struct pcfs *, int, int); /* lock fs and get fat */
333 extern void pc_unlockfs(struct pcfs *);	/* ulock the fs */
334 extern int pc_getfat(struct pcfs *);	/* get fat from disk */
335 extern void pc_invalfat(struct pcfs *);	/* invalidate incore fat */
336 extern int pc_syncfat(struct pcfs *);	/* sync fat to disk */
337 extern int pc_freeclusters(struct pcfs *);	/* num free clusters in fs */
338 extern pc_cluster32_t pc_alloccluster(struct pcfs *, int);
339 extern void pc_setcluster(struct pcfs *, pc_cluster32_t, pc_cluster32_t);
340 extern void pc_mark_fat_updated(struct pcfs *fsp, pc_cluster32_t cn);
341 extern int pc_fat_is_changed(struct pcfs *fsp, pc_cluster32_t bn);
342 
343 /*
344  * debugging
345  */
346 extern int pcfsdebuglevel;
347 #define	PC_DPRINTF0(level, A) \
348 	if (pcfsdebuglevel >= level) \
349 	    cmn_err(CE_CONT, (A))
350 #define	PC_DPRINTF1(level, A, B) \
351 	if (pcfsdebuglevel >= level) \
352 	    cmn_err(CE_CONT, (A), (B))
353 #define	PC_DPRINTF2(level, A, B, C) \
354 	if (pcfsdebuglevel >= level) \
355 	    cmn_err(CE_CONT, (A), (B), (C))
356 #define	PC_DPRINTF3(level, A, B, C, D) \
357 	if (pcfsdebuglevel >= level) \
358 	    cmn_err(CE_CONT, (A), (B), (C), (D))
359 #define	PC_DPRINTF4(level, A, B, C, D, E) \
360 	if (pcfsdebuglevel >= level) \
361 	    cmn_err(CE_CONT, (A), (B), (C), (D), (E))
362 
363 #ifdef	__cplusplus
364 }
365 #endif
366 
367 #endif	/* _SYS_FS_PC_FS_H */
368