Line data Source code
1 : /* $OpenBSD: msdosfs_vfsops.c,v 1.90 2018/05/27 06:02:15 visa Exp $ */
2 : /* $NetBSD: msdosfs_vfsops.c,v 1.48 1997/10/18 02:54:57 briggs Exp $ */
3 :
4 : /*-
5 : * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
6 : * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
7 : * All rights reserved.
8 : * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
9 : *
10 : * Redistribution and use in source and binary forms, with or without
11 : * modification, are permitted provided that the following conditions
12 : * are met:
13 : * 1. Redistributions of source code must retain the above copyright
14 : * notice, this list of conditions and the following disclaimer.
15 : * 2. Redistributions in binary form must reproduce the above copyright
16 : * notice, this list of conditions and the following disclaimer in the
17 : * documentation and/or other materials provided with the distribution.
18 : * 3. All advertising materials mentioning features or use of this software
19 : * must display the following acknowledgement:
20 : * This product includes software developed by TooLs GmbH.
21 : * 4. The name of TooLs GmbH may not be used to endorse or promote products
22 : * derived from this software without specific prior written permission.
23 : *
24 : * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
25 : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 : * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30 : * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 : */
35 : /*
36 : * Written by Paul Popelka (paulp@uts.amdahl.com)
37 : *
38 : * You can do anything you want with this software, just don't say you wrote
39 : * it, and don't remove this notice.
40 : *
41 : * This software is provided "as is".
42 : *
43 : * The author supplies this software to be publicly redistributed on the
44 : * understanding that the author is not responsible for the correct
45 : * functioning of this software in any circumstances and is not liable for
46 : * any damages caused by this software.
47 : *
48 : * October 1992
49 : */
50 :
51 : #include <sys/param.h>
52 : #include <sys/systm.h>
53 : #include <sys/namei.h>
54 : #include <sys/proc.h>
55 : #include <sys/kernel.h>
56 : #include <sys/vnode.h>
57 : #include <sys/lock.h>
58 : #include <sys/specdev.h> /* XXX */ /* defines v_rdev */
59 : #include <sys/mount.h>
60 : #include <sys/buf.h>
61 : #include <sys/fcntl.h>
62 : #include <sys/disklabel.h>
63 : #include <sys/ioctl.h>
64 : #include <sys/malloc.h>
65 : #include <sys/dirent.h>
66 : #include <sys/disk.h>
67 : #include <sys/dkio.h>
68 : #include <sys/stdint.h>
69 :
70 : #include <msdosfs/bpb.h>
71 : #include <msdosfs/bootsect.h>
72 : #include <msdosfs/direntry.h>
73 : #include <msdosfs/denode.h>
74 : #include <msdosfs/msdosfsmount.h>
75 : #include <msdosfs/fat.h>
76 :
77 : int msdosfs_mount(struct mount *, const char *, void *, struct nameidata *,
78 : struct proc *);
79 : int msdosfs_start(struct mount *, int, struct proc *);
80 : int msdosfs_unmount(struct mount *, int, struct proc *);
81 : int msdosfs_root(struct mount *, struct vnode **);
82 : int msdosfs_statfs(struct mount *, struct statfs *, struct proc *);
83 : int msdosfs_sync(struct mount *, int, int, struct ucred *, struct proc *);
84 : int msdosfs_fhtovp(struct mount *, struct fid *, struct vnode **);
85 : int msdosfs_vptofh(struct vnode *, struct fid *);
86 : int msdosfs_check_export(struct mount *mp, struct mbuf *nam,
87 : int *extflagsp, struct ucred **credanonp);
88 :
89 : int msdosfs_mountfs(struct vnode *, struct mount *, struct proc *,
90 : struct msdosfs_args *);
91 :
92 : int msdosfs_sync_vnode(struct vnode *, void *);
93 :
94 : /*
95 : * mp - path - addr in user space of mount point (ie /usr or whatever)
96 : * data - addr in user space of mount params including the name of the block
97 : * special file to treat as a filesystem.
98 : */
99 : int
100 0 : msdosfs_mount(struct mount *mp, const char *path, void *data,
101 : struct nameidata *ndp, struct proc *p)
102 : {
103 : struct vnode *devvp; /* vnode for blk device to mount */
104 0 : struct msdosfs_args *args = data; /* will hold data from mount request */
105 : /* msdosfs specific mount control block */
106 : struct msdosfsmount *pmp = NULL;
107 0 : char fname[MNAMELEN];
108 0 : char fspec[MNAMELEN];
109 : int error, flags;
110 :
111 : /*
112 : * If updating, check whether changing from read-only to
113 : * read/write; if there is no device name, that's all we do.
114 : */
115 0 : if (mp->mnt_flag & MNT_UPDATE) {
116 0 : pmp = VFSTOMSDOSFS(mp);
117 : error = 0;
118 0 : if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) &&
119 0 : (mp->mnt_flag & MNT_RDONLY)) {
120 0 : mp->mnt_flag &= ~MNT_RDONLY;
121 0 : VFS_SYNC(mp, MNT_WAIT, 0, p->p_ucred, p);
122 0 : mp->mnt_flag |= MNT_RDONLY;
123 :
124 : flags = WRITECLOSE;
125 0 : if (mp->mnt_flag & MNT_FORCE)
126 0 : flags |= FORCECLOSE;
127 0 : error = vflush(mp, NULLVP, flags);
128 0 : if (!error) {
129 0 : int force = 0;
130 :
131 0 : pmp->pm_flags |= MSDOSFSMNT_RONLY;
132 : /* may be not supported, ignore error */
133 0 : VOP_IOCTL(pmp->pm_devvp, DIOCCACHESYNC,
134 : &force, FWRITE, FSCRED, p);
135 0 : }
136 : }
137 0 : if (!error && (mp->mnt_flag & MNT_RELOAD))
138 : /* not yet implemented */
139 0 : error = EOPNOTSUPP;
140 0 : if (error)
141 0 : return (error);
142 0 : if ((pmp->pm_flags & MSDOSFSMNT_RONLY) &&
143 0 : (mp->mnt_flag & MNT_WANTRDWR))
144 0 : pmp->pm_flags &= ~MSDOSFSMNT_RONLY;
145 :
146 0 : if (args && args->fspec == NULL) {
147 : #ifdef __notyet__ /* doesn't work correctly with current mountd XXX */
148 : if (args->flags & MSDOSFSMNT_MNTOPT) {
149 : pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT;
150 : pmp->pm_flags |= args->flags & MSDOSFSMNT_MNTOPT;
151 : if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
152 : pmp->pm_flags |= MSDOSFSMNT_SHORTNAME;
153 : }
154 : #endif
155 : /*
156 : * Process export requests.
157 : */
158 0 : return (vfs_export(mp, &pmp->pm_export,
159 0 : &args->export_info));
160 : }
161 0 : if (args == NULL)
162 0 : return (0);
163 : }
164 :
165 : /*
166 : * Not an update, or updating the name: look up the name
167 : * and verify that it refers to a sensible block device.
168 : */
169 0 : error = copyinstr(args->fspec, fspec, sizeof(fspec), NULL);
170 0 : if (error)
171 : goto error;
172 :
173 0 : if (disk_map(fspec, fname, sizeof(fname), DM_OPENBLCK) == -1)
174 0 : bcopy(fspec, fname, sizeof(fname));
175 :
176 0 : NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fname, p);
177 0 : if ((error = namei(ndp)) != 0)
178 : goto error;
179 :
180 0 : devvp = ndp->ni_vp;
181 :
182 0 : if (devvp->v_type != VBLK) {
183 : error = ENOTBLK;
184 0 : goto error_devvp;
185 : }
186 0 : if (major(devvp->v_rdev) >= nblkdev) {
187 : error = ENXIO;
188 0 : goto error_devvp;
189 : }
190 :
191 0 : if ((mp->mnt_flag & MNT_UPDATE) == 0)
192 0 : error = msdosfs_mountfs(devvp, mp, p, args);
193 : else {
194 0 : if (devvp != pmp->pm_devvp)
195 0 : error = EINVAL; /* XXX needs translation */
196 : else
197 0 : vrele(devvp);
198 : }
199 0 : if (error)
200 : goto error_devvp;
201 :
202 0 : pmp = VFSTOMSDOSFS(mp);
203 0 : pmp->pm_gid = args->gid;
204 0 : pmp->pm_uid = args->uid;
205 0 : pmp->pm_mask = args->mask;
206 0 : pmp->pm_flags |= args->flags & MSDOSFSMNT_MNTOPT;
207 :
208 0 : if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
209 0 : pmp->pm_flags |= MSDOSFSMNT_SHORTNAME;
210 0 : else if (!(pmp->pm_flags &
211 : (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) {
212 0 : struct vnode *rvp;
213 :
214 : /*
215 : * Try to divine whether to support Win'95 long filenames
216 : */
217 0 : if (FAT32(pmp))
218 0 : pmp->pm_flags |= MSDOSFSMNT_LONGNAME;
219 : else {
220 0 : if ((error = msdosfs_root(mp, &rvp)) != 0) {
221 0 : msdosfs_unmount(mp, MNT_FORCE, p);
222 0 : goto error;
223 : }
224 0 : pmp->pm_flags |= findwin95(VTODE(rvp))
225 : ? MSDOSFSMNT_LONGNAME
226 : : MSDOSFSMNT_SHORTNAME;
227 0 : vput(rvp);
228 : }
229 0 : }
230 :
231 0 : if (pmp->pm_flags & MSDOSFSMNT_LONGNAME)
232 0 : mp->mnt_stat.f_namemax = WIN_MAXLEN;
233 : else
234 0 : mp->mnt_stat.f_namemax = 12;
235 :
236 0 : bzero(mp->mnt_stat.f_mntonname, MNAMELEN);
237 0 : strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN);
238 0 : bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
239 0 : strlcpy(mp->mnt_stat.f_mntfromname, fname, MNAMELEN);
240 0 : bzero(mp->mnt_stat.f_mntfromspec, MNAMELEN);
241 0 : strlcpy(mp->mnt_stat.f_mntfromspec, fspec, MNAMELEN);
242 0 : bcopy(args, &mp->mnt_stat.mount_info.msdosfs_args, sizeof(*args));
243 :
244 : #ifdef MSDOSFS_DEBUG
245 : printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp,
246 : pmp, pmp->pm_inusemap);
247 : #endif
248 :
249 0 : return (0);
250 :
251 : error_devvp:
252 0 : vrele(devvp);
253 :
254 : error:
255 0 : return (error);
256 0 : }
257 :
258 : int
259 0 : msdosfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p,
260 : struct msdosfs_args *argp)
261 : {
262 : struct msdosfsmount *pmp;
263 0 : struct buf *bp;
264 0 : dev_t dev = devvp->v_rdev;
265 : union bootsector *bsp;
266 : struct byte_bpb33 *b33;
267 : struct byte_bpb50 *b50;
268 : struct byte_bpb710 *b710;
269 : extern struct vnode *rootvp;
270 : u_int8_t SecPerClust;
271 : int ronly, error, bmapsiz;
272 : uint32_t fat_max_clusters;
273 :
274 : /*
275 : * Disallow multiple mounts of the same device.
276 : * Disallow mounting of a device that is currently in use
277 : * (except for root, which might share swap device for miniroot).
278 : * Flush out any old buffers remaining from a previous use.
279 : */
280 0 : if ((error = vfs_mountedon(devvp)) != 0)
281 0 : return (error);
282 0 : if (vcount(devvp) > 1 && devvp != rootvp)
283 0 : return (EBUSY);
284 0 : vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
285 0 : error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
286 0 : VOP_UNLOCK(devvp);
287 0 : if (error)
288 0 : return (error);
289 :
290 0 : ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
291 0 : error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
292 0 : if (error)
293 0 : return (error);
294 :
295 0 : bp = NULL; /* both used in error_exit */
296 : pmp = NULL;
297 :
298 : /*
299 : * Read the boot sector of the filesystem, and then check the
300 : * boot signature. If not a dos boot sector then error out.
301 : */
302 0 : if ((error = bread(devvp, 0, 4096, &bp)) != 0)
303 : goto error_exit;
304 0 : bsp = (union bootsector *)bp->b_data;
305 0 : b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
306 0 : b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
307 0 : b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB;
308 :
309 0 : pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK | M_ZERO);
310 0 : pmp->pm_mountp = mp;
311 :
312 : /*
313 : * Compute several useful quantities from the bpb in the
314 : * bootsector. Copy in the dos 5 variant of the bpb then fix up
315 : * the fields that are different between dos 5 and dos 3.3.
316 : */
317 0 : SecPerClust = b50->bpbSecPerClust;
318 0 : pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
319 0 : pmp->pm_ResSectors = getushort(b50->bpbResSectors);
320 0 : pmp->pm_FATs = b50->bpbFATs;
321 0 : pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
322 0 : pmp->pm_Sectors = getushort(b50->bpbSectors);
323 0 : pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
324 0 : pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
325 0 : pmp->pm_Heads = getushort(b50->bpbHeads);
326 0 : pmp->pm_Media = b50->bpbMedia;
327 :
328 : /* Determine the number of DEV_BSIZE blocks in a MSDOSFS sector */
329 0 : pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE;
330 :
331 0 : if (!pmp->pm_BytesPerSec || !SecPerClust) {
332 : error = EFTYPE;
333 0 : goto error_exit;
334 : }
335 :
336 0 : if (pmp->pm_Sectors == 0) {
337 0 : pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
338 0 : pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
339 0 : } else {
340 0 : pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
341 0 : pmp->pm_HugeSectors = pmp->pm_Sectors;
342 : }
343 :
344 0 : if (pmp->pm_RootDirEnts == 0) {
345 0 : if (pmp->pm_Sectors || pmp->pm_FATsecs ||
346 0 : getushort(b710->bpbFSVers)) {
347 : error = EINVAL;
348 0 : goto error_exit;
349 : }
350 0 : pmp->pm_fatmask = FAT32_MASK;
351 0 : pmp->pm_fatmult = 4;
352 0 : pmp->pm_fatdiv = 1;
353 0 : pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs);
354 0 : if (getushort(b710->bpbExtFlags) & FATMIRROR)
355 0 : pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM;
356 : else
357 0 : pmp->pm_flags |= MSDOSFS_FATMIRROR;
358 : } else
359 0 : pmp->pm_flags |= MSDOSFS_FATMIRROR;
360 :
361 : /*
362 : * More sanity checks:
363 : * MSDOSFS sectors per cluster: >0 && power of 2
364 : * MSDOSFS sector size: >= DEV_BSIZE && power of 2
365 : * HUGE sector count: >0
366 : * FAT sectors: >0
367 : */
368 0 : if ((SecPerClust == 0) || (SecPerClust & (SecPerClust - 1)) ||
369 0 : (pmp->pm_BytesPerSec < DEV_BSIZE) ||
370 0 : (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) ||
371 0 : (pmp->pm_HugeSectors == 0) || (pmp->pm_FATsecs == 0) ||
372 0 : (SecPerClust * pmp->pm_BlkPerSec > MAXBSIZE / DEV_BSIZE)) {
373 : error = EINVAL;
374 0 : goto error_exit;
375 : }
376 :
377 0 : pmp->pm_HugeSectors *= pmp->pm_BlkPerSec;
378 0 : pmp->pm_HiddenSects *= pmp->pm_BlkPerSec;
379 0 : pmp->pm_FATsecs *= pmp->pm_BlkPerSec;
380 0 : pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec;
381 0 : SecPerClust *= pmp->pm_BlkPerSec;
382 :
383 0 : if (FAT32(pmp)) {
384 0 : pmp->pm_rootdirblk = getulong(b710->bpbRootClust);
385 0 : pmp->pm_firstcluster = pmp->pm_fatblk
386 0 : + (pmp->pm_FATs * pmp->pm_FATsecs);
387 0 : pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec;
388 0 : } else {
389 0 : pmp->pm_rootdirblk = pmp->pm_fatblk +
390 0 : (pmp->pm_FATs * pmp->pm_FATsecs);
391 0 : pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)
392 0 : + DEV_BSIZE - 1) / DEV_BSIZE;
393 0 : pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
394 : }
395 :
396 0 : pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
397 0 : SecPerClust;
398 0 : pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
399 0 : pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE;
400 :
401 0 : if (pmp->pm_fatmask == 0) {
402 0 : if (pmp->pm_maxcluster
403 0 : <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
404 : /*
405 : * This will usually be a floppy disk. This size makes
406 : * sure that one fat entry will not be split across
407 : * multiple blocks.
408 : */
409 0 : pmp->pm_fatmask = FAT12_MASK;
410 0 : pmp->pm_fatmult = 3;
411 0 : pmp->pm_fatdiv = 2;
412 0 : } else {
413 0 : pmp->pm_fatmask = FAT16_MASK;
414 0 : pmp->pm_fatmult = 2;
415 0 : pmp->pm_fatdiv = 1;
416 : }
417 : }
418 0 : if (FAT12(pmp))
419 0 : pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
420 : else
421 0 : pmp->pm_fatblocksize = MAXBSIZE;
422 :
423 : /*
424 : * We now have the number of sectors in each FAT, so can work
425 : * out how many clusters can be represented in a FAT. Let's
426 : * make sure the file system doesn't claim to have more clusters
427 : * than this.
428 : *
429 : * We perform the calculation like we do to avoid integer overflow.
430 : *
431 : * This will give us a count of clusters. They are numbered
432 : * from 0, so the max cluster value is one less than the value
433 : * we end up with.
434 : */
435 0 : fat_max_clusters = pmp->pm_fatsize / pmp->pm_fatmult;
436 0 : fat_max_clusters *= pmp->pm_fatdiv;
437 0 : if (pmp->pm_maxcluster >= fat_max_clusters) {
438 : #ifndef SMALL_KERNEL
439 0 : printf("msdosfs: reducing max cluster to %d from %d "
440 0 : "due to FAT size\n", fat_max_clusters - 1,
441 : pmp->pm_maxcluster);
442 : #endif
443 0 : pmp->pm_maxcluster = fat_max_clusters - 1;
444 0 : }
445 :
446 0 : pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE;
447 0 : pmp->pm_bnshift = ffs(DEV_BSIZE) - 1;
448 :
449 : /*
450 : * Compute mask and shift value for isolating cluster relative byte
451 : * offsets and cluster numbers from a file offset.
452 : */
453 0 : pmp->pm_bpcluster = SecPerClust * DEV_BSIZE;
454 0 : pmp->pm_crbomask = pmp->pm_bpcluster - 1;
455 0 : pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;
456 :
457 : /*
458 : * Check for valid cluster size
459 : * must be a power of 2
460 : */
461 0 : if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
462 : error = EFTYPE;
463 0 : goto error_exit;
464 : }
465 :
466 : /*
467 : * Release the bootsector buffer.
468 : */
469 0 : brelse(bp);
470 0 : bp = NULL;
471 :
472 : /*
473 : * Check FSInfo
474 : */
475 0 : if (pmp->pm_fsinfo) {
476 : struct fsinfo *fp;
477 :
478 0 : if ((error = bread(devvp, pmp->pm_fsinfo, fsi_size(pmp),
479 0 : &bp)) != 0)
480 0 : goto error_exit;
481 0 : fp = (struct fsinfo *)bp->b_data;
482 0 : if (!bcmp(fp->fsisig1, "RRaA", 4)
483 0 : && !bcmp(fp->fsisig2, "rrAa", 4)
484 0 : && !bcmp(fp->fsisig3, "\0\0\125\252", 4)
485 0 : && !bcmp(fp->fsisig4, "\0\0\125\252", 4))
486 : /* Valid FSInfo. */
487 : ;
488 : else
489 0 : pmp->pm_fsinfo = 0;
490 : /* XXX make sure this tiny buf doesn't come back in fillinusemap! */
491 0 : SET(bp->b_flags, B_INVAL);
492 0 : brelse(bp);
493 0 : bp = NULL;
494 0 : }
495 :
496 : /*
497 : * Check and validate (or perhaps invalidate?) the fsinfo structure? XXX
498 : */
499 :
500 : /*
501 : * Allocate memory for the bitmap of allocated clusters, and then
502 : * fill it in.
503 : */
504 0 : bmapsiz = howmany(pmp->pm_maxcluster + 1, N_INUSEBITS);
505 0 : if (bmapsiz == 0 || SIZE_MAX / bmapsiz < sizeof(*pmp->pm_inusemap)) {
506 : /* detect multiplicative integer overflow */
507 : error = EINVAL;
508 0 : goto error_exit;
509 : }
510 0 : pmp->pm_inusemap = mallocarray(bmapsiz, sizeof(*pmp->pm_inusemap),
511 : M_MSDOSFSFAT, M_WAITOK | M_CANFAIL);
512 0 : if (pmp->pm_inusemap == NULL) {
513 : error = EINVAL;
514 0 : goto error_exit;
515 : }
516 :
517 : /*
518 : * fillinusemap() needs pm_devvp.
519 : */
520 0 : pmp->pm_dev = dev;
521 0 : pmp->pm_devvp = devvp;
522 :
523 : /*
524 : * Have the inuse map filled in.
525 : */
526 0 : if ((error = fillinusemap(pmp)) != 0)
527 : goto error_exit;
528 :
529 : /*
530 : * If they want fat updates to be synchronous then let them suffer
531 : * the performance degradation in exchange for the on disk copy of
532 : * the fat being correct just about all the time. I suppose this
533 : * would be a good thing to turn on if the kernel is still flakey.
534 : */
535 0 : if (mp->mnt_flag & MNT_SYNCHRONOUS)
536 0 : pmp->pm_flags |= MSDOSFSMNT_WAITONFAT;
537 :
538 : /*
539 : * Finish up.
540 : */
541 0 : if (ronly)
542 0 : pmp->pm_flags |= MSDOSFSMNT_RONLY;
543 : else
544 0 : pmp->pm_fmod = 1;
545 0 : mp->mnt_data = pmp;
546 0 : mp->mnt_stat.f_fsid.val[0] = (long)dev;
547 0 : mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
548 : #ifdef QUOTA
549 : /*
550 : * If we ever do quotas for DOS filesystems this would be a place
551 : * to fill in the info in the msdosfsmount structure. You dolt,
552 : * quotas on dos filesystems make no sense because files have no
553 : * owners on dos filesystems. of course there is some empty space
554 : * in the directory entry where we could put uid's and gid's.
555 : */
556 : #endif
557 0 : devvp->v_specmountpoint = mp;
558 :
559 0 : return (0);
560 :
561 : error_exit:
562 0 : if (devvp->v_specinfo)
563 0 : devvp->v_specmountpoint = NULL;
564 0 : if (bp)
565 0 : brelse(bp);
566 :
567 0 : vn_lock(devvp, LK_EXCLUSIVE|LK_RETRY);
568 0 : (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
569 0 : VOP_UNLOCK(devvp);
570 :
571 0 : if (pmp) {
572 0 : if (pmp->pm_inusemap)
573 0 : free(pmp->pm_inusemap, M_MSDOSFSFAT, 0);
574 0 : free(pmp, M_MSDOSFSMNT, 0);
575 0 : mp->mnt_data = NULL;
576 0 : }
577 0 : return (error);
578 0 : }
579 :
580 : int
581 0 : msdosfs_start(struct mount *mp, int flags, struct proc *p)
582 : {
583 :
584 0 : return (0);
585 : }
586 :
587 : /*
588 : * Unmount the filesystem described by mp.
589 : */
590 : int
591 0 : msdosfs_unmount(struct mount *mp, int mntflags,struct proc *p)
592 : {
593 : struct msdosfsmount *pmp;
594 : int error, flags;
595 : struct vnode *vp;
596 :
597 : flags = 0;
598 0 : if (mntflags & MNT_FORCE)
599 0 : flags |= FORCECLOSE;
600 0 : if ((error = vflush(mp, NULLVP, flags)) != 0)
601 0 : return (error);
602 0 : pmp = VFSTOMSDOSFS(mp);
603 0 : pmp->pm_devvp->v_specmountpoint = NULL;
604 0 : vp = pmp->pm_devvp;
605 : #ifdef MSDOSFS_DEBUG
606 : vprint("msdosfs_umount(): just before calling VOP_CLOSE()\n", vp);
607 : #endif
608 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
609 0 : (void)VOP_CLOSE(vp,
610 0 : pmp->pm_flags & MSDOSFSMNT_RONLY ? FREAD : FREAD|FWRITE, NOCRED, p);
611 0 : vput(vp);
612 0 : free(pmp->pm_inusemap, M_MSDOSFSFAT, 0);
613 0 : free(pmp, M_MSDOSFSMNT, 0);
614 0 : mp->mnt_data = NULL;
615 0 : mp->mnt_flag &= ~MNT_LOCAL;
616 0 : return (0);
617 0 : }
618 :
619 : int
620 0 : msdosfs_root(struct mount *mp, struct vnode **vpp)
621 : {
622 0 : struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
623 0 : struct denode *ndep;
624 : int error;
625 :
626 0 : if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep)) != 0)
627 0 : return (error);
628 :
629 : #ifdef MSDOSFS_DEBUG
630 : printf("msdosfs_root(); mp %p, pmp %p, ndep %p, vp %p\n",
631 : mp, pmp, ndep, DETOV(ndep));
632 : #endif
633 :
634 0 : *vpp = DETOV(ndep);
635 0 : return (0);
636 0 : }
637 :
638 : int
639 0 : msdosfs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
640 : {
641 : struct msdosfsmount *pmp;
642 :
643 0 : pmp = VFSTOMSDOSFS(mp);
644 0 : sbp->f_bsize = pmp->pm_bpcluster;
645 0 : sbp->f_iosize = pmp->pm_bpcluster;
646 0 : sbp->f_blocks = pmp->pm_nmbrofclusters;
647 0 : sbp->f_bfree = pmp->pm_freeclustercount;
648 0 : sbp->f_bavail = pmp->pm_freeclustercount;
649 0 : sbp->f_files = pmp->pm_RootDirEnts; /* XXX */
650 0 : sbp->f_ffree = sbp->f_favail = 0; /* what to put in here? */
651 0 : copy_statfs_info(sbp, mp);
652 :
653 0 : return (0);
654 : }
655 :
656 :
657 : struct msdosfs_sync_arg {
658 : struct proc *p;
659 : struct ucred *cred;
660 : int allerror;
661 : int waitfor;
662 : };
663 :
664 : int
665 0 : msdosfs_sync_vnode(struct vnode *vp, void *arg)
666 : {
667 0 : struct msdosfs_sync_arg *msa = arg;
668 : int error;
669 : struct denode *dep;
670 :
671 0 : dep = VTODE(vp);
672 0 : if (vp->v_type == VNON ||
673 0 : ((dep->de_flag & (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0
674 0 : && LIST_EMPTY(&vp->v_dirtyblkhd)) ||
675 0 : msa->waitfor == MNT_LAZY) {
676 0 : return (0);
677 : }
678 :
679 0 : if (vget(vp, LK_EXCLUSIVE | LK_NOWAIT))
680 0 : return (0);
681 :
682 0 : if ((error = VOP_FSYNC(vp, msa->cred, msa->waitfor, msa->p)) != 0)
683 0 : msa->allerror = error;
684 0 : VOP_UNLOCK(vp);
685 0 : vrele(vp);
686 :
687 0 : return (0);
688 0 : }
689 :
690 :
691 : int
692 0 : msdosfs_sync(struct mount *mp, int waitfor, int stall, struct ucred *cred,
693 : struct proc *p)
694 : {
695 0 : struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
696 0 : struct msdosfs_sync_arg msa;
697 : int error;
698 :
699 0 : msa.allerror = 0;
700 0 : msa.p = p;
701 0 : msa.cred = cred;
702 0 : msa.waitfor = waitfor;
703 :
704 : /*
705 : * If we ever switch to not updating all of the fats all the time,
706 : * this would be the place to update them from the first one.
707 : */
708 0 : if (pmp->pm_fmod != 0) {
709 0 : if (pmp->pm_flags & MSDOSFSMNT_RONLY)
710 0 : panic("msdosfs_sync: rofs mod");
711 : else {
712 : /* update fats here */
713 : }
714 : }
715 : /*
716 : * Write back each (modified) denode.
717 : */
718 0 : vfs_mount_foreach_vnode(mp, msdosfs_sync_vnode, &msa);
719 :
720 : /*
721 : * Force stale file system control information to be flushed.
722 : */
723 0 : if (waitfor != MNT_LAZY) {
724 0 : vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY);
725 0 : if ((error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p)) != 0)
726 0 : msa.allerror = error;
727 0 : VOP_UNLOCK(pmp->pm_devvp);
728 0 : }
729 :
730 0 : return (msa.allerror);
731 0 : }
732 :
733 : int
734 0 : msdosfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
735 : {
736 0 : struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
737 0 : struct defid *defhp = (struct defid *) fhp;
738 0 : struct denode *dep;
739 : int error;
740 :
741 0 : error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep);
742 0 : if (error) {
743 0 : *vpp = NULLVP;
744 0 : return (error);
745 : }
746 0 : *vpp = DETOV(dep);
747 0 : return (0);
748 0 : }
749 :
750 : int
751 0 : msdosfs_vptofh(struct vnode *vp, struct fid *fhp)
752 : {
753 : struct denode *dep;
754 : struct defid *defhp;
755 :
756 0 : dep = VTODE(vp);
757 0 : defhp = (struct defid *)fhp;
758 0 : defhp->defid_len = sizeof(struct defid);
759 0 : defhp->defid_dirclust = dep->de_dirclust;
760 0 : defhp->defid_dirofs = dep->de_diroffset;
761 : /* defhp->defid_gen = dep->de_gen; */
762 0 : return (0);
763 : }
764 :
765 : int
766 0 : msdosfs_check_export(struct mount *mp, struct mbuf *nam, int *exflagsp,
767 : struct ucred **credanonp)
768 : {
769 : struct netcred *np;
770 0 : struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
771 :
772 : /*
773 : * Get the export permission structure for this <mp, client> tuple.
774 : */
775 0 : np = vfs_export_lookup(mp, &pmp->pm_export, nam);
776 0 : if (np == NULL)
777 0 : return (EACCES);
778 :
779 0 : *exflagsp = np->netc_exflags;
780 0 : *credanonp = &np->netc_anon;
781 0 : return (0);
782 0 : }
783 :
784 : #define msdosfs_vget ((int (*)(struct mount *, ino_t, struct vnode **)) \
785 : eopnotsupp)
786 :
787 : #define msdosfs_quotactl ((int (*)(struct mount *, int, uid_t, caddr_t, \
788 : struct proc *))eopnotsupp)
789 :
790 : #define msdosfs_sysctl ((int (*)(int *, u_int, void *, size_t *, void *, \
791 : size_t, struct proc *))eopnotsupp)
792 :
793 : const struct vfsops msdosfs_vfsops = {
794 : msdosfs_mount,
795 : msdosfs_start,
796 : msdosfs_unmount,
797 : msdosfs_root,
798 : msdosfs_quotactl,
799 : msdosfs_statfs,
800 : msdosfs_sync,
801 : msdosfs_vget,
802 : msdosfs_fhtovp,
803 : msdosfs_vptofh,
804 : msdosfs_init,
805 : msdosfs_sysctl,
806 : msdosfs_check_export
807 : };
|