xref: /illumos-gate/usr/src/uts/common/sys/fs/pc_fs.h (revision 0173c38a73f34277e0c97a19fedfd25d81ba8380)
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 };
191 
192 /*
193  * flags
194  */
195 #define	PCFS_FATMOD	0x01		/* FAT has been modified */
196 #define	PCFS_LOCKED	0x02		/* fs is locked */
197 #define	PCFS_WANTED	0x04		/* locked fs is wanted */
198 #define	PCFS_FAT16	0x400		/* 16 bit FAT */
199 #define	PCFS_NOCHK	0x800		/* don't resync fat on error */
200 #define	PCFS_BOOTPART	0x1000		/* boot partition type */
201 #define	PCFS_HIDDEN	0x2000		/* show hidden files */
202 #define	PCFS_PCMCIA_NO_CIS 0x4000	/* PCMCIA psuedo floppy */
203 #define	PCFS_FOLDCASE	0x8000		/* fold all names from media to */
204 					/* lowercase */
205 #define	PCFS_FAT32	0x10000		/* 32 bit FAT */
206 #define	PCFS_IRRECOV	0x20000		/* FS was messed with during write */
207 
208 /* for compatibility */
209 struct old_pcfs_args {
210 	int	secondswest;	/* seconds west of Greenwich */
211 	int	dsttime;    	/* type of dst correction */
212 };
213 
214 struct pcfs_args {
215 	int	secondswest;	/* seconds west of Greenwich */
216 	int	dsttime;    	/* type of dst correction */
217 	int	flags;
218 };
219 
220 /*
221  * flags for the pcfs_args 'flags' field.
222  *
223  * Note that these two macros are obsolete - do not use them.
224  */
225 #define	PCFS_MNT_HIDDEN		0x01	/* show hidden files */
226 #define	PCFS_MNT_FOLDCASE	0x02	/* fold all names from media to */
227 					/* lowercase */
228 
229 /*
230  * pcfs mount options.
231  */
232 #define	MNTOPT_PCFS_HIDDEN	"hidden"
233 #define	MNTOPT_PCFS_NOHIDDEN	"nohidden"
234 #define	MNTOPT_PCFS_FOLDCASE	"foldcase"
235 #define	MNTOPT_PCFS_NOFOLDCASE	"nofoldcase"
236 
237 /*
238  * Disk timeout value in sec.
239  * This is used to time out the in core FAT and to re-verify the disk.
240  * This should be less than the time it takes to change floppys
241  */
242 #define	PCFS_DISKTIMEOUT	2
243 
244 #define	VFSTOPCFS(VFSP)		((struct pcfs *)((VFSP)->vfs_data))
245 #define	PCFSTOVFS(FSP)		((FSP)->pcfs_vfs)
246 
247 /*
248  * special cluster numbers in FAT
249  */
250 #define	PCF_FREECLUSTER		0x00	/* cluster is available */
251 #define	PCF_ERRORCLUSTER	0x01	/* error occurred allocating cluster */
252 #define	PCF_12BCLUSTER		0xFF0	/* 12-bit version of reserved cluster */
253 #define	PCF_RESCLUSTER		0xFFF0	/* 16-bit version of reserved cluster */
254 #define	PCF_RESCLUSTER32	0xFFFFFF0 /* 32-bit version */
255 #define	PCF_BADCLUSTER		0xFFF7	/* bad cluster, do not use */
256 #define	PCF_BADCLUSTER32	0xFFFFFF7 /* 32-bit version */
257 #define	PCF_LASTCLUSTER		0xFFF8	/* >= means last cluster in file */
258 #define	PCF_LASTCLUSTER32	0xFFFFFF8 /* 32-bit version */
259 #define	PCF_LASTCLUSTERMARK	0xFFFF	/* value used to mark last cluster */
260 #define	PCF_LASTCLUSTERMARK32	0xFFFFFFF /* 32-bit version */
261 #define	PCF_FIRSTCLUSTER	2	/* first valid cluster number */
262 
263 /*
264  * file system constants
265  */
266 #define	PC_MAXFATSEC	256		/* maximum number of sectors in FAT */
267 
268 /*
269  * file system parameter macros
270  */
271 
272 #define	IS_FAT32(PCFS) \
273 	(((PCFS)->pcfs_flags & PCFS_FAT32) == PCFS_FAT32)
274 
275 #define	IS_FAT16(PCFS) \
276 	(((PCFS)->pcfs_flags & PCFS_FAT16) == PCFS_FAT16)
277 
278 #define	IS_FAT12(PCFS) \
279 	(((PCFS)->pcfs_flags & (PCFS_FAT16 | PCFS_FAT32)) == 0)
280 
281 #define	pc_clear_fatchanges(PCFS) \
282 	bzero((PCFS)->pcfs_fat_changemap, (PCFS)->pcfs_fat_changemapsize)
283 
284 #define	pc_blksize(PCFS, PCP, OFF)	/* file system block size */ \
285 	(((PCTOV(PCP)->v_flag & VROOT) && !IS_FAT32(PCFS)) ? \
286 	    ((OFF) >= \
287 	    ((PCFS)->pcfs_rdirsec & \
288 	    ~((PCFS)->pcfs_spcl - 1)) * ((PCFS)->pcfs_secsize)? \
289 	    ((PCFS)->pcfs_rdirsec & \
290 	    ((PCFS)->pcfs_spcl - 1)) * ((PCFS)->pcfs_secsize): \
291 	    (PCFS)->pcfs_clsize): \
292 	    (PCFS)->pcfs_clsize)
293 
294 #define	pc_blkoff(PCFS, OFF)		/* offset within block */ \
295 	((int)((OFF) & ((PCFS)->pcfs_clsize - 1)))
296 
297 #define	pc_lblkno(PCFS, OFF)		/* logical block (cluster) no */ \
298 	((daddr_t)((OFF) / (PCFS)->pcfs_clsize))
299 
300 #define	pc_dbtocl(PCFS, DB)		/* disk blks to clusters */ \
301 	((int)((DB) / (PCFS)->pcfs_spcl))
302 
303 #define	pc_cltodb(PCFS, CL)		/* clusters to disk blks */ \
304 	((daddr_t)((CL) * (PCFS)->pcfs_spcl))
305 
306 #define	pc_cldaddr(PCFS, CL)	/* DEV_BSIZE "sector" addr for cluster */ \
307 	(((daddr_t)((PCFS)->pcfs_datastart + \
308 	    ((CL) - PCF_FIRSTCLUSTER) * (PCFS)->pcfs_spcl)) << \
309 	    (PCFS)->pcfs_sdshift)
310 
311 #define	pc_daddrcl(PCFS, DADDR)		/* cluster for disk address */ \
312 	((int)(((((DADDR) >> (PCFS)->pcfs_sdshift) - (PCFS)->pcfs_datastart) / \
313 	(PCFS)->pcfs_spcl) + 2))
314 
315 #define	pc_dbdaddr(PCFS, DB)	/* sector to DEV_BSIZE "sector" addr */ \
316 	((DB) << (PCFS)->pcfs_sdshift)
317 
318 #define	pc_daddrdb(PCFS, DADDR)	/* DEV_BSIZE "sector" addr to sector addr */ \
319 	((DADDR) >> (PCFS)->pcfs_sdshift)
320 
321 #define	pc_validcl(PCFS, CL)		/* check that cluster no is legit */ \
322 	((int)(CL) >= PCF_FIRSTCLUSTER && \
323 	    (int)(CL) <= (PCFS)->pcfs_ncluster)
324 
325 /*
326  * external routines.
327  */
328 extern int pc_lockfs(struct pcfs *, int, int); /* lock fs and get fat */
329 extern void pc_unlockfs(struct pcfs *);	/* ulock the fs */
330 extern int pc_getfat(struct pcfs *);	/* get fat from disk */
331 extern void pc_invalfat(struct pcfs *);	/* invalidate incore fat */
332 extern int pc_syncfat(struct pcfs *);	/* sync fat to disk */
333 extern int pc_freeclusters(struct pcfs *);	/* num free clusters in fs */
334 extern pc_cluster32_t pc_alloccluster(struct pcfs *, int);
335 extern void pc_setcluster(struct pcfs *, pc_cluster32_t, pc_cluster32_t);
336 extern void pc_mark_fat_updated(struct pcfs *fsp, pc_cluster32_t cn);
337 extern int pc_fat_is_changed(struct pcfs *fsp, pc_cluster32_t bn);
338 
339 /*
340  * debugging
341  */
342 extern int pcfsdebuglevel;
343 #define	PC_DPRINTF0(level, A) \
344 	if (pcfsdebuglevel >= level) \
345 	    cmn_err(CE_CONT, (A))
346 #define	PC_DPRINTF1(level, A, B) \
347 	if (pcfsdebuglevel >= level) \
348 	    cmn_err(CE_CONT, (A), (B))
349 #define	PC_DPRINTF2(level, A, B, C) \
350 	if (pcfsdebuglevel >= level) \
351 	    cmn_err(CE_CONT, (A), (B), (C))
352 #define	PC_DPRINTF3(level, A, B, C, D) \
353 	if (pcfsdebuglevel >= level) \
354 	    cmn_err(CE_CONT, (A), (B), (C), (D))
355 #define	PC_DPRINTF4(level, A, B, C, D, E) \
356 	if (pcfsdebuglevel >= level) \
357 	    cmn_err(CE_CONT, (A), (B), (C), (D), (E))
358 
359 #ifdef	__cplusplus
360 }
361 #endif
362 
363 #endif	/* _SYS_FS_PC_FS_H */
364