1 /* $OpenBSD: msdosfs_vfsops.c,v 1.98 2024/10/18 05:52:32 miod 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
msdosfs_mount(struct mount * mp,const char * path,void * data,struct nameidata * ndp,struct proc * p)100 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 struct msdosfs_args *args = data; /* will hold data from mount request */
105 /* msdosfs specific mount control block */
106 struct msdosfsmount *pmp = NULL;
107 char fname[MNAMELEN];
108 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 if (mp->mnt_flag & MNT_UPDATE) {
116 pmp = VFSTOMSDOSFS(mp);
117 error = 0;
118 if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) &&
119 (mp->mnt_flag & MNT_RDONLY)) {
120 mp->mnt_flag &= ~MNT_RDONLY;
121 VFS_SYNC(mp, MNT_WAIT, 0, p->p_ucred, p);
122 mp->mnt_flag |= MNT_RDONLY;
123
124 flags = WRITECLOSE;
125 if (mp->mnt_flag & MNT_FORCE)
126 flags |= FORCECLOSE;
127 error = vflush(mp, NULLVP, flags);
128 if (!error) {
129 int force = 0;
130
131 pmp->pm_flags |= MSDOSFSMNT_RONLY;
132 /* may be not supported, ignore error */
133 VOP_IOCTL(pmp->pm_devvp, DIOCCACHESYNC,
134 &force, FWRITE, FSCRED, p);
135 }
136 }
137 if (!error && (mp->mnt_flag & MNT_RELOAD))
138 /* not yet implemented */
139 error = EOPNOTSUPP;
140 if (error)
141 return (error);
142 if ((pmp->pm_flags & MSDOSFSMNT_RONLY) &&
143 (mp->mnt_flag & MNT_WANTRDWR))
144 pmp->pm_flags &= ~MSDOSFSMNT_RONLY;
145
146 if (args && args->fspec == NULL) {
147 /*
148 * Process export requests.
149 */
150 return (vfs_export(mp, &pmp->pm_export,
151 &args->export_info));
152 }
153 if (args == NULL)
154 return (0);
155 }
156
157 /*
158 * Not an update, or updating the name: look up the name
159 * and verify that it refers to a sensible block device.
160 */
161 error = copyinstr(args->fspec, fspec, sizeof(fspec), NULL);
162 if (error)
163 goto error;
164
165 if (disk_map(fspec, fname, sizeof(fname), DM_OPENBLCK) == -1)
166 bcopy(fspec, fname, sizeof(fname));
167
168 NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fname, p);
169 if ((error = namei(ndp)) != 0)
170 goto error;
171
172 devvp = ndp->ni_vp;
173
174 if (devvp->v_type != VBLK) {
175 error = ENOTBLK;
176 goto error_devvp;
177 }
178 if (major(devvp->v_rdev) >= nblkdev) {
179 error = ENXIO;
180 goto error_devvp;
181 }
182
183 if ((mp->mnt_flag & MNT_UPDATE) == 0)
184 error = msdosfs_mountfs(devvp, mp, p, args);
185 else {
186 if (devvp != pmp->pm_devvp)
187 error = EINVAL; /* XXX needs translation */
188 else
189 vrele(devvp);
190 }
191 if (error)
192 goto error_devvp;
193
194 pmp = VFSTOMSDOSFS(mp);
195 pmp->pm_gid = args->gid;
196 pmp->pm_uid = args->uid;
197 pmp->pm_mask = args->mask;
198 pmp->pm_flags |= args->flags & MSDOSFSMNT_MNTOPT;
199
200 if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
201 pmp->pm_flags |= MSDOSFSMNT_SHORTNAME;
202 else if (!(pmp->pm_flags &
203 (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME)))
204 pmp->pm_flags |= MSDOSFSMNT_LONGNAME;
205
206 if (pmp->pm_flags & MSDOSFSMNT_LONGNAME)
207 mp->mnt_stat.f_namemax = WIN_MAXLEN;
208 else
209 mp->mnt_stat.f_namemax = 12;
210
211 bzero(mp->mnt_stat.f_mntonname, MNAMELEN);
212 strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN);
213 bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
214 strlcpy(mp->mnt_stat.f_mntfromname, fname, MNAMELEN);
215 bzero(mp->mnt_stat.f_mntfromspec, MNAMELEN);
216 strlcpy(mp->mnt_stat.f_mntfromspec, fspec, MNAMELEN);
217 bcopy(args, &mp->mnt_stat.mount_info.msdosfs_args, sizeof(*args));
218
219 #ifdef MSDOSFS_DEBUG
220 printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp,
221 pmp, pmp->pm_inusemap);
222 #endif
223
224 return (0);
225
226 error_devvp:
227 vrele(devvp);
228
229 error:
230 return (error);
231 }
232
233 int
msdosfs_mountfs(struct vnode * devvp,struct mount * mp,struct proc * p,struct msdosfs_args * argp)234 msdosfs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p,
235 struct msdosfs_args *argp)
236 {
237 struct msdosfsmount *pmp;
238 struct buf *bp;
239 dev_t dev = devvp->v_rdev;
240 union bootsector *bsp;
241 struct byte_bpb33 *b33;
242 struct byte_bpb50 *b50;
243 struct byte_bpb710 *b710;
244 extern struct vnode *rootvp;
245 u_int8_t SecPerClust;
246 int ronly, error, bmapsiz;
247 uint32_t fat_max_clusters;
248
249 /*
250 * Disallow multiple mounts of the same device.
251 * Disallow mounting of a device that is currently in use
252 * (except for root, which might share swap device for miniroot).
253 * Flush out any old buffers remaining from a previous use.
254 */
255 if ((error = vfs_mountedon(devvp)) != 0)
256 return (error);
257 if (vcount(devvp) > 1 && devvp != rootvp)
258 return (EBUSY);
259 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
260 error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, INFSLP);
261 VOP_UNLOCK(devvp);
262 if (error)
263 return (error);
264
265 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
266 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
267 if (error)
268 return (error);
269
270 bp = NULL; /* both used in error_exit */
271 pmp = NULL;
272
273 /*
274 * Read the boot sector of the filesystem, and then check the
275 * boot signature. If not a dos boot sector then error out.
276 */
277 if ((error = bread(devvp, 0, 4096, &bp)) != 0)
278 goto error_exit;
279 bsp = (union bootsector *)bp->b_data;
280 b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
281 b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
282 b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB;
283
284 pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK | M_ZERO);
285 pmp->pm_mountp = mp;
286
287 /*
288 * Compute several useful quantities from the bpb in the
289 * bootsector. Copy in the dos 5 variant of the bpb then fix up
290 * the fields that are different between dos 5 and dos 3.3.
291 */
292 SecPerClust = b50->bpbSecPerClust;
293 pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
294 pmp->pm_ResSectors = getushort(b50->bpbResSectors);
295 pmp->pm_FATs = b50->bpbFATs;
296 pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
297 pmp->pm_Sectors = getushort(b50->bpbSectors);
298 pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
299 pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
300 pmp->pm_Heads = getushort(b50->bpbHeads);
301 pmp->pm_Media = b50->bpbMedia;
302
303 /* Determine the number of DEV_BSIZE blocks in a MSDOSFS sector */
304 pmp->pm_BlkPerSec = pmp->pm_BytesPerSec / DEV_BSIZE;
305
306 if (!pmp->pm_BytesPerSec || !SecPerClust) {
307 error = EINVAL;
308 goto error_exit;
309 }
310
311 if (pmp->pm_Sectors == 0) {
312 pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
313 pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
314 } else {
315 pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
316 pmp->pm_HugeSectors = pmp->pm_Sectors;
317 }
318
319 if (pmp->pm_RootDirEnts == 0) {
320 if (pmp->pm_Sectors || pmp->pm_FATsecs ||
321 getushort(b710->bpbFSVers)) {
322 error = EINVAL;
323 goto error_exit;
324 }
325 pmp->pm_fatmask = FAT32_MASK;
326 pmp->pm_fatmult = 4;
327 pmp->pm_fatdiv = 1;
328 pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs);
329 if (getushort(b710->bpbExtFlags) & FATMIRROR)
330 pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM;
331 else
332 pmp->pm_flags |= MSDOSFS_FATMIRROR;
333 } else
334 pmp->pm_flags |= MSDOSFS_FATMIRROR;
335
336 /*
337 * More sanity checks:
338 * MSDOSFS sectors per cluster: >0 && power of 2
339 * MSDOSFS sector size: >= DEV_BSIZE && power of 2
340 * HUGE sector count: >0
341 * FAT sectors: >0
342 */
343 if ((SecPerClust == 0) || (SecPerClust & (SecPerClust - 1)) ||
344 (pmp->pm_BytesPerSec < DEV_BSIZE) ||
345 (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) ||
346 (pmp->pm_HugeSectors == 0) || (pmp->pm_FATsecs == 0) ||
347 (SecPerClust * pmp->pm_BlkPerSec > MAXBSIZE / DEV_BSIZE)) {
348 error = EINVAL;
349 goto error_exit;
350 }
351
352 pmp->pm_HugeSectors *= pmp->pm_BlkPerSec;
353 pmp->pm_HiddenSects *= pmp->pm_BlkPerSec;
354 pmp->pm_FATsecs *= pmp->pm_BlkPerSec;
355 pmp->pm_fatblk = pmp->pm_ResSectors * pmp->pm_BlkPerSec;
356 SecPerClust *= pmp->pm_BlkPerSec;
357
358 if (FAT32(pmp)) {
359 pmp->pm_rootdirblk = getulong(b710->bpbRootClust);
360 pmp->pm_firstcluster = pmp->pm_fatblk
361 + (pmp->pm_FATs * pmp->pm_FATsecs);
362 pmp->pm_fsinfo = getushort(b710->bpbFSInfo) * pmp->pm_BlkPerSec;
363 } else {
364 pmp->pm_rootdirblk = pmp->pm_fatblk +
365 (pmp->pm_FATs * pmp->pm_FATsecs);
366 pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)
367 + DEV_BSIZE - 1) / DEV_BSIZE;
368 pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
369 }
370
371 pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
372 SecPerClust;
373 pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
374 pmp->pm_fatsize = pmp->pm_FATsecs * DEV_BSIZE;
375
376 if (pmp->pm_fatmask == 0) {
377 if (pmp->pm_maxcluster
378 <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
379 /*
380 * This will usually be a floppy disk. This size makes
381 * sure that one fat entry will not be split across
382 * multiple blocks.
383 */
384 pmp->pm_fatmask = FAT12_MASK;
385 pmp->pm_fatmult = 3;
386 pmp->pm_fatdiv = 2;
387 } else {
388 pmp->pm_fatmask = FAT16_MASK;
389 pmp->pm_fatmult = 2;
390 pmp->pm_fatdiv = 1;
391 }
392 }
393 if (FAT12(pmp))
394 pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
395 else
396 pmp->pm_fatblocksize = MAXBSIZE;
397
398 /*
399 * We now have the number of sectors in each FAT, so can work
400 * out how many clusters can be represented in a FAT. Let's
401 * make sure the file system doesn't claim to have more clusters
402 * than this.
403 *
404 * We perform the calculation like we do to avoid integer overflow.
405 *
406 * This will give us a count of clusters. They are numbered
407 * from 0, so the max cluster value is one less than the value
408 * we end up with.
409 */
410 fat_max_clusters = pmp->pm_fatsize / pmp->pm_fatmult;
411 fat_max_clusters *= pmp->pm_fatdiv;
412 if (pmp->pm_maxcluster >= fat_max_clusters) {
413 #ifndef SMALL_KERNEL
414 printf("msdosfs: reducing max cluster to %d from %d "
415 "due to FAT size\n", fat_max_clusters - 1,
416 pmp->pm_maxcluster);
417 #endif
418 pmp->pm_maxcluster = fat_max_clusters - 1;
419 }
420
421 pmp->pm_fatblocksec = pmp->pm_fatblocksize / DEV_BSIZE;
422 pmp->pm_bnshift = ffs(DEV_BSIZE) - 1;
423
424 /*
425 * Compute mask and shift value for isolating cluster relative byte
426 * offsets and cluster numbers from a file offset.
427 */
428 pmp->pm_bpcluster = SecPerClust * DEV_BSIZE;
429 pmp->pm_crbomask = pmp->pm_bpcluster - 1;
430 pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;
431
432 /*
433 * Check for valid cluster size
434 * must be a power of 2
435 */
436 if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
437 error = EINVAL;
438 goto error_exit;
439 }
440
441 /*
442 * Release the bootsector buffer.
443 */
444 brelse(bp);
445 bp = NULL;
446
447 /*
448 * Check FSInfo
449 */
450 if (pmp->pm_fsinfo) {
451 struct fsinfo *fp;
452
453 if ((error = bread(devvp, pmp->pm_fsinfo, fsi_size(pmp),
454 &bp)) != 0)
455 goto error_exit;
456 fp = (struct fsinfo *)bp->b_data;
457 if (!bcmp(fp->fsisig1, "RRaA", 4)
458 && !bcmp(fp->fsisig2, "rrAa", 4)
459 && !bcmp(fp->fsisig3, "\0\0\125\252", 4)
460 && !bcmp(fp->fsisig4, "\0\0\125\252", 4))
461 /* Valid FSInfo. */
462 ;
463 else
464 pmp->pm_fsinfo = 0;
465 /* XXX make sure this tiny buf doesn't come back in fillinusemap! */
466 SET(bp->b_flags, B_INVAL);
467 brelse(bp);
468 bp = NULL;
469 }
470
471 /*
472 * Check and validate (or perhaps invalidate?) the fsinfo structure? XXX
473 */
474
475 /*
476 * Allocate memory for the bitmap of allocated clusters, and then
477 * fill it in.
478 */
479 bmapsiz = howmany(pmp->pm_maxcluster + 1, N_INUSEBITS);
480 if (bmapsiz == 0 || SIZE_MAX / bmapsiz < sizeof(*pmp->pm_inusemap)) {
481 /* detect multiplicative integer overflow */
482 error = EINVAL;
483 goto error_exit;
484 }
485 pmp->pm_inusemap = mallocarray(bmapsiz, sizeof(*pmp->pm_inusemap),
486 M_MSDOSFSFAT, M_WAITOK | M_CANFAIL);
487 if (pmp->pm_inusemap == NULL) {
488 error = EINVAL;
489 goto error_exit;
490 }
491
492 /*
493 * fillinusemap() needs pm_devvp.
494 */
495 pmp->pm_dev = dev;
496 pmp->pm_devvp = devvp;
497
498 /*
499 * Have the inuse map filled in.
500 */
501 if ((error = fillinusemap(pmp)) != 0)
502 goto error_exit;
503
504 /*
505 * If they want fat updates to be synchronous then let them suffer
506 * the performance degradation in exchange for the on disk copy of
507 * the fat being correct just about all the time. I suppose this
508 * would be a good thing to turn on if the kernel is still flakey.
509 */
510 if (mp->mnt_flag & MNT_SYNCHRONOUS)
511 pmp->pm_flags |= MSDOSFSMNT_WAITONFAT;
512
513 /*
514 * Finish up.
515 */
516 if (ronly)
517 pmp->pm_flags |= MSDOSFSMNT_RONLY;
518 else
519 pmp->pm_fmod = 1;
520 mp->mnt_data = pmp;
521 mp->mnt_stat.f_fsid.val[0] = (long)dev;
522 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
523 #ifdef QUOTA
524 /*
525 * If we ever do quotas for DOS filesystems this would be a place
526 * to fill in the info in the msdosfsmount structure. You dolt,
527 * quotas on dos filesystems make no sense because files have no
528 * owners on dos filesystems. of course there is some empty space
529 * in the directory entry where we could put uid's and gid's.
530 */
531 #endif
532 devvp->v_specmountpoint = mp;
533
534 return (0);
535
536 error_exit:
537 if (devvp->v_specinfo)
538 devvp->v_specmountpoint = NULL;
539 if (bp)
540 brelse(bp);
541
542 vn_lock(devvp, LK_EXCLUSIVE|LK_RETRY);
543 (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
544 VOP_UNLOCK(devvp);
545
546 if (pmp) {
547 if (pmp->pm_inusemap)
548 free(pmp->pm_inusemap, M_MSDOSFSFAT, 0);
549 free(pmp, M_MSDOSFSMNT, 0);
550 mp->mnt_data = NULL;
551 }
552 return (error);
553 }
554
555 int
msdosfs_start(struct mount * mp,int flags,struct proc * p)556 msdosfs_start(struct mount *mp, int flags, struct proc *p)
557 {
558
559 return (0);
560 }
561
562 /*
563 * Unmount the filesystem described by mp.
564 */
565 int
msdosfs_unmount(struct mount * mp,int mntflags,struct proc * p)566 msdosfs_unmount(struct mount *mp, int mntflags,struct proc *p)
567 {
568 struct msdosfsmount *pmp;
569 int error, flags;
570 struct vnode *vp;
571
572 flags = 0;
573 if (mntflags & MNT_FORCE)
574 flags |= FORCECLOSE;
575 if ((error = vflush(mp, NULLVP, flags)) != 0)
576 return (error);
577 pmp = VFSTOMSDOSFS(mp);
578 pmp->pm_devvp->v_specmountpoint = NULL;
579 vp = pmp->pm_devvp;
580 #if defined(MSDOSFS_DEBUG) && (defined(DEBUG) || defined(DIAGNOSTIC))
581 vprint("msdosfs_umount(): just before calling VOP_CLOSE()\n", vp);
582 #endif
583 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
584 (void)VOP_CLOSE(vp,
585 pmp->pm_flags & MSDOSFSMNT_RONLY ? FREAD : FREAD|FWRITE, NOCRED, p);
586 vput(vp);
587 free(pmp->pm_inusemap, M_MSDOSFSFAT, 0);
588 free(pmp, M_MSDOSFSMNT, 0);
589 mp->mnt_data = NULL;
590 mp->mnt_flag &= ~MNT_LOCAL;
591 return (0);
592 }
593
594 int
msdosfs_root(struct mount * mp,struct vnode ** vpp)595 msdosfs_root(struct mount *mp, struct vnode **vpp)
596 {
597 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
598 struct denode *ndep;
599 int error;
600
601 if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep)) != 0)
602 return (error);
603
604 #ifdef MSDOSFS_DEBUG
605 printf("msdosfs_root(); mp %p, pmp %p, ndep %p, vp %p\n",
606 mp, pmp, ndep, DETOV(ndep));
607 #endif
608
609 *vpp = DETOV(ndep);
610 return (0);
611 }
612
613 int
msdosfs_statfs(struct mount * mp,struct statfs * sbp,struct proc * p)614 msdosfs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
615 {
616 struct msdosfsmount *pmp;
617
618 pmp = VFSTOMSDOSFS(mp);
619 sbp->f_bsize = pmp->pm_bpcluster;
620 sbp->f_iosize = pmp->pm_bpcluster;
621 sbp->f_blocks = pmp->pm_nmbrofclusters;
622 sbp->f_bfree = pmp->pm_freeclustercount;
623 sbp->f_bavail = pmp->pm_freeclustercount;
624 sbp->f_files = pmp->pm_RootDirEnts; /* XXX */
625 sbp->f_ffree = sbp->f_favail = 0; /* what to put in here? */
626 copy_statfs_info(sbp, mp);
627
628 return (0);
629 }
630
631
632 struct msdosfs_sync_arg {
633 struct proc *p;
634 struct ucred *cred;
635 int allerror;
636 int waitfor;
637 };
638
639 int
msdosfs_sync_vnode(struct vnode * vp,void * arg)640 msdosfs_sync_vnode(struct vnode *vp, void *arg)
641 {
642 struct msdosfs_sync_arg *msa = arg;
643 struct denode *dep;
644 int error;
645 int s, skip = 0;
646
647 dep = VTODE(vp);
648 s = splbio();
649 if (vp->v_type == VNON ||
650 ((dep->de_flag & (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0
651 && LIST_EMPTY(&vp->v_dirtyblkhd)) ||
652 msa->waitfor == MNT_LAZY) {
653 skip = 1;
654 }
655 splx(s);
656
657 if (skip)
658 return (0);
659
660 if (vget(vp, LK_EXCLUSIVE | LK_NOWAIT))
661 return (0);
662
663 if ((error = VOP_FSYNC(vp, msa->cred, msa->waitfor, msa->p)) != 0)
664 msa->allerror = error;
665 VOP_UNLOCK(vp);
666 vrele(vp);
667
668 return (0);
669 }
670
671
672 int
msdosfs_sync(struct mount * mp,int waitfor,int stall,struct ucred * cred,struct proc * p)673 msdosfs_sync(struct mount *mp, int waitfor, int stall, struct ucred *cred,
674 struct proc *p)
675 {
676 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
677 struct msdosfs_sync_arg msa;
678 int error;
679
680 msa.allerror = 0;
681 msa.p = p;
682 msa.cred = cred;
683 msa.waitfor = waitfor;
684
685 /*
686 * If we ever switch to not updating all of the fats all the time,
687 * this would be the place to update them from the first one.
688 */
689 if (pmp->pm_fmod != 0) {
690 if (pmp->pm_flags & MSDOSFSMNT_RONLY)
691 panic("msdosfs_sync: rofs mod");
692 else {
693 /* update fats here */
694 }
695 }
696 /*
697 * Write back each (modified) denode.
698 */
699 vfs_mount_foreach_vnode(mp, msdosfs_sync_vnode, &msa);
700
701 /*
702 * Force stale file system control information to be flushed.
703 */
704 if (waitfor != MNT_LAZY) {
705 vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY);
706 if ((error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p)) != 0)
707 msa.allerror = error;
708 VOP_UNLOCK(pmp->pm_devvp);
709 }
710
711 return (msa.allerror);
712 }
713
714 int
msdosfs_fhtovp(struct mount * mp,struct fid * fhp,struct vnode ** vpp)715 msdosfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
716 {
717 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
718 struct defid *defhp = (struct defid *) fhp;
719 struct denode *dep;
720 int error;
721
722 error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep);
723 if (error) {
724 *vpp = NULLVP;
725 return (error);
726 }
727 *vpp = DETOV(dep);
728 return (0);
729 }
730
731 int
msdosfs_vptofh(struct vnode * vp,struct fid * fhp)732 msdosfs_vptofh(struct vnode *vp, struct fid *fhp)
733 {
734 struct denode *dep;
735 struct defid *defhp;
736
737 dep = VTODE(vp);
738 defhp = (struct defid *)fhp;
739 defhp->defid_len = sizeof(struct defid);
740 defhp->defid_dirclust = dep->de_dirclust;
741 defhp->defid_dirofs = dep->de_diroffset;
742 /* defhp->defid_gen = dep->de_gen; */
743 return (0);
744 }
745
746 int
msdosfs_check_export(struct mount * mp,struct mbuf * nam,int * exflagsp,struct ucred ** credanonp)747 msdosfs_check_export(struct mount *mp, struct mbuf *nam, int *exflagsp,
748 struct ucred **credanonp)
749 {
750 struct netcred *np;
751 struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
752
753 /*
754 * Get the export permission structure for this <mp, client> tuple.
755 */
756 np = vfs_export_lookup(mp, &pmp->pm_export, nam);
757 if (np == NULL)
758 return (EACCES);
759
760 *exflagsp = np->netc_exflags;
761 *credanonp = &np->netc_anon;
762 return (0);
763 }
764
765 const struct vfsops msdosfs_vfsops = {
766 .vfs_mount = msdosfs_mount,
767 .vfs_start = msdosfs_start,
768 .vfs_unmount = msdosfs_unmount,
769 .vfs_root = msdosfs_root,
770 .vfs_quotactl = (void *)eopnotsupp,
771 .vfs_statfs = msdosfs_statfs,
772 .vfs_sync = msdosfs_sync,
773 .vfs_vget = (void *)eopnotsupp,
774 .vfs_fhtovp = msdosfs_fhtovp,
775 .vfs_vptofh = msdosfs_vptofh,
776 .vfs_init = msdosfs_init,
777 .vfs_sysctl = (void *)eopnotsupp,
778 .vfs_checkexp = msdosfs_check_export,
779 };
780