Annotation of src/sys/fs/msdosfs/msdosfs_vfsops.c, Revision 1.121
1.121 ! hannken 1: /* $NetBSD: msdosfs_vfsops.c,v 1.120 2017/02/17 08:27:20 hannken Exp $ */
1.1 jdolecek 2:
3: /*-
4: * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
5: * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
6: * All rights reserved.
7: * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by TooLs GmbH.
20: * 4. The name of TooLs GmbH may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26: * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33: */
34: /*
35: * Written by Paul Popelka (paulp@uts.amdahl.com)
36: *
37: * You can do anything you want with this software, just don't say you wrote
38: * it, and don't remove this notice.
39: *
40: * This software is provided "as is".
41: *
42: * The author supplies this software to be publicly redistributed on the
43: * understanding that the author is not responsible for the correct
44: * functioning of this software in any circumstances and is not liable for
45: * any damages caused by this software.
46: *
47: * October 1992
48: */
49:
50: #include <sys/cdefs.h>
1.121 ! hannken 51: __KERNEL_RCSID(0, "$NetBSD: msdosfs_vfsops.c,v 1.120 2017/02/17 08:27:20 hannken Exp $");
1.1 jdolecek 52:
53: #if defined(_KERNEL_OPT)
54: #include "opt_compat_netbsd.h"
55: #endif
56:
57: #include <sys/param.h>
58: #include <sys/systm.h>
1.12 atatat 59: #include <sys/sysctl.h>
1.1 jdolecek 60: #include <sys/namei.h>
61: #include <sys/proc.h>
62: #include <sys/kernel.h>
63: #include <sys/vnode.h>
1.60 dholland 64: #include <miscfs/genfs/genfs.h>
1.1 jdolecek 65: #include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */
66: #include <sys/mount.h>
67: #include <sys/buf.h>
68: #include <sys/file.h>
69: #include <sys/device.h>
70: #include <sys/disklabel.h>
1.42 christos 71: #include <sys/disk.h>
1.81 hannken 72: #include <sys/fstrans.h>
1.1 jdolecek 73: #include <sys/ioctl.h>
74: #include <sys/malloc.h>
75: #include <sys/dirent.h>
76: #include <sys/stat.h>
77: #include <sys/conf.h>
1.31 elad 78: #include <sys/kauth.h>
1.66 rumble 79: #include <sys/module.h>
1.1 jdolecek 80:
81: #include <fs/msdosfs/bpb.h>
82: #include <fs/msdosfs/bootsect.h>
83: #include <fs/msdosfs/direntry.h>
84: #include <fs/msdosfs/denode.h>
85: #include <fs/msdosfs/msdosfsmount.h>
86: #include <fs/msdosfs/fat.h>
87:
1.82 pooka 88: MODULE(MODULE_CLASS_VFS, msdos, NULL);
1.66 rumble 89:
1.42 christos 90: #ifdef MSDOSFS_DEBUG
1.115 maxv 91: #define DPRINTF(fmt, ...) uprintf("%s(): " fmt "\n", __func__, ##__VA_ARGS__)
1.42 christos 92: #else
1.115 maxv 93: #define DPRINTF(fmt, ...)
1.42 christos 94: #endif
95:
1.110 maxv 96: #define GEMDOSFS_BSIZE 512
97:
1.20 jdolecek 98: #define MSDOSFS_NAMEMAX(pmp) \
99: (pmp)->pm_flags & MSDOSFSMNT_LONGNAME ? WIN_MAXLEN : 12
100:
1.29 christos 101: int msdosfs_mountfs(struct vnode *, struct mount *, struct lwp *,
1.26 xtraeme 102: struct msdosfs_args *);
1.1 jdolecek 103:
1.26 xtraeme 104: static int update_mp(struct mount *, struct msdosfs_args *);
1.2 thorpej 105:
1.45 pooka 106: MALLOC_JUSTDEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOS FS mount structure");
1.100 jakllsch 107: MALLOC_JUSTDEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOS FS FAT table");
1.51 rumble 108: MALLOC_JUSTDEFINE(M_MSDOSFSTMP, "MSDOSFS temp", "MSDOS FS temp. structures");
1.1 jdolecek 109:
1.68 rumble 110: static struct sysctllog *msdosfs_sysctl_log;
111:
1.1 jdolecek 112: extern const struct vnodeopv_desc msdosfs_vnodeop_opv_desc;
113:
114: const struct vnodeopv_desc * const msdosfs_vnodeopv_descs[] = {
115: &msdosfs_vnodeop_opv_desc,
116: NULL,
117: };
118:
119: struct vfsops msdosfs_vfsops = {
1.106 hannken 120: .vfs_name = MOUNT_MSDOS,
121: .vfs_min_mount_data = sizeof (struct msdosfs_args),
122: .vfs_mount = msdosfs_mount,
123: .vfs_start = msdosfs_start,
124: .vfs_unmount = msdosfs_unmount,
125: .vfs_root = msdosfs_root,
126: .vfs_quotactl = (void *)eopnotsupp,
127: .vfs_statvfs = msdosfs_statvfs,
128: .vfs_sync = msdosfs_sync,
129: .vfs_vget = msdosfs_vget,
1.109 hannken 130: .vfs_loadvnode = msdosfs_loadvnode,
1.106 hannken 131: .vfs_fhtovp = msdosfs_fhtovp,
132: .vfs_vptofh = msdosfs_vptofh,
133: .vfs_init = msdosfs_init,
134: .vfs_reinit = msdosfs_reinit,
135: .vfs_done = msdosfs_done,
136: .vfs_mountroot = msdosfs_mountroot,
137: .vfs_snapshot = (void *)eopnotsupp,
138: .vfs_extattrctl = vfs_stdextattrctl,
139: .vfs_suspendctl = msdosfs_suspendctl,
140: .vfs_renamelock_enter = genfs_renamelock_enter,
141: .vfs_renamelock_exit = genfs_renamelock_exit,
142: .vfs_fsync = (void *)eopnotsupp,
143: .vfs_opv_descs = msdosfs_vnodeopv_descs
1.1 jdolecek 144: };
1.66 rumble 145:
146: static int
1.83 mlelstv 147: msdos_modcmd(modcmd_t cmd, void *arg)
1.66 rumble 148: {
1.68 rumble 149: int error;
1.66 rumble 150:
151: switch (cmd) {
152: case MODULE_CMD_INIT:
1.68 rumble 153: error = vfs_attach(&msdosfs_vfsops);
154: if (error != 0)
155: break;
156: sysctl_createv(&msdosfs_sysctl_log, 0, NULL, NULL,
157: CTLFLAG_PERMANENT,
158: CTLTYPE_NODE, "msdosfs",
159: SYSCTL_DESCR("MS-DOS file system"),
160: NULL, 0, NULL, 0,
161: CTL_VFS, 4, CTL_EOL);
162: /*
163: * XXX the "4" above could be dynamic, thereby eliminating one
164: * more instance of the "number to vfs" mapping problem, but
165: * "4" is the order as taken from sys/mount.h
166: */
167: break;
1.66 rumble 168: case MODULE_CMD_FINI:
1.68 rumble 169: error = vfs_detach(&msdosfs_vfsops);
170: if (error != 0)
171: break;
172: sysctl_teardown(&msdosfs_sysctl_log);
173: break;
1.66 rumble 174: default:
1.68 rumble 175: error = ENOTTY;
176: break;
1.66 rumble 177: }
1.68 rumble 178:
179: return (error);
1.66 rumble 180: }
1.1 jdolecek 181:
182: static int
1.72 dsl 183: update_mp(struct mount *mp, struct msdosfs_args *argp)
1.1 jdolecek 184: {
185: struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
186: int error;
187:
188: pmp->pm_gid = argp->gid;
189: pmp->pm_uid = argp->uid;
190: pmp->pm_mask = argp->mask & ALLPERMS;
1.8 jdolecek 191: pmp->pm_dirmask = argp->dirmask & ALLPERMS;
1.9 itojun 192: pmp->pm_gmtoff = argp->gmtoff;
1.1 jdolecek 193: pmp->pm_flags |= argp->flags & MSDOSFSMNT_MNTOPT;
194:
195: /*
1.71 abs 196: * GEMDOS knows nothing about win95 long filenames
1.1 jdolecek 197: */
198: if (pmp->pm_flags & MSDOSFSMNT_GEMDOSFS)
199: pmp->pm_flags |= MSDOSFSMNT_NOWIN95;
200:
201: if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
202: pmp->pm_flags |= MSDOSFSMNT_SHORTNAME;
203: else if (!(pmp->pm_flags &
204: (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) {
1.24 christos 205: struct vnode *rtvp;
1.1 jdolecek 206:
207: /*
208: * Try to divine whether to support Win'95 long filenames
209: */
210: if (FAT32(pmp))
211: pmp->pm_flags |= MSDOSFSMNT_LONGNAME;
212: else {
1.24 christos 213: if ((error = msdosfs_root(mp, &rtvp)) != 0)
1.1 jdolecek 214: return error;
1.24 christos 215: pmp->pm_flags |= findwin95(VTODE(rtvp))
1.1 jdolecek 216: ? MSDOSFSMNT_LONGNAME
217: : MSDOSFSMNT_SHORTNAME;
1.24 christos 218: vput(rtvp);
1.1 jdolecek 219: }
220: }
1.20 jdolecek 221:
222: mp->mnt_stat.f_namemax = MSDOSFS_NAMEMAX(pmp);
223:
1.1 jdolecek 224: return 0;
225: }
226:
227: int
1.73 cegger 228: msdosfs_mountroot(void)
1.1 jdolecek 229: {
230: struct mount *mp;
1.29 christos 231: struct lwp *l = curlwp; /* XXX */
1.1 jdolecek 232: int error;
233: struct msdosfs_args args;
234:
1.30 thorpej 235: if (device_class(root_device) != DV_DISK)
1.1 jdolecek 236: return (ENODEV);
237:
238: if ((error = vfs_rootmountalloc(MOUNT_MSDOS, "root_device", &mp))) {
239: vrele(rootvp);
240: return (error);
241: }
242:
1.8 jdolecek 243: args.flags = MSDOSFSMNT_VERSIONED;
1.1 jdolecek 244: args.uid = 0;
245: args.gid = 0;
246: args.mask = 0777;
1.8 jdolecek 247: args.version = MSDOSFSMNT_VERSION;
248: args.dirmask = 0777;
1.1 jdolecek 249:
1.29 christos 250: if ((error = msdosfs_mountfs(rootvp, mp, l, &args)) != 0) {
1.63 ad 251: vfs_unbusy(mp, false, NULL);
1.65 ad 252: vfs_destroy(mp);
1.1 jdolecek 253: return (error);
254: }
255:
1.6 thorpej 256: if ((error = update_mp(mp, &args)) != 0) {
1.54 pooka 257: (void)msdosfs_unmount(mp, 0);
1.63 ad 258: vfs_unbusy(mp, false, NULL);
1.65 ad 259: vfs_destroy(mp);
1.1 jdolecek 260: vrele(rootvp);
261: return (error);
262: }
263:
1.103 christos 264: mountlist_append(mp);
1.54 pooka 265: (void)msdosfs_statvfs(mp, &mp->mnt_stat);
1.63 ad 266: vfs_unbusy(mp, false, NULL);
1.1 jdolecek 267: return (0);
268: }
269:
270: /*
271: * mp - path - addr in user space of mount point (ie /usr or whatever)
272: * data - addr in user space of mount params including the name of the block
273: * special file to treat as a filesystem.
274: */
275: int
1.72 dsl 276: msdosfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
1.1 jdolecek 277: {
1.54 pooka 278: struct lwp *l = curlwp;
1.1 jdolecek 279: struct vnode *devvp; /* vnode for blk device to mount */
1.46 dsl 280: struct msdosfs_args *args = data; /* holds data from mount request */
1.1 jdolecek 281: /* msdosfs specific mount control block */
282: struct msdosfsmount *pmp = NULL;
283: int error, flags;
284: mode_t accessmode;
285:
1.107 maxv 286: if (args == NULL)
287: return EINVAL;
1.46 dsl 288: if (*data_len < sizeof *args)
289: return EINVAL;
290:
1.1 jdolecek 291: if (mp->mnt_flag & MNT_GETARGS) {
292: pmp = VFSTOMSDOSFS(mp);
293: if (pmp == NULL)
294: return EIO;
1.46 dsl 295: args->fspec = NULL;
296: args->uid = pmp->pm_uid;
297: args->gid = pmp->pm_gid;
298: args->mask = pmp->pm_mask;
299: args->flags = pmp->pm_flags;
300: args->version = MSDOSFSMNT_VERSION;
301: args->dirmask = pmp->pm_dirmask;
302: args->gmtoff = pmp->pm_gmtoff;
303: *data_len = sizeof *args;
304: return 0;
1.42 christos 305: }
1.8 jdolecek 306:
307: /*
308: * If not versioned (i.e. using old mount_msdos(8)), fill in
309: * the additional structure items with suitable defaults.
310: */
1.46 dsl 311: if ((args->flags & MSDOSFSMNT_VERSIONED) == 0) {
312: args->version = 1;
313: args->dirmask = args->mask;
1.8 jdolecek 314: }
315:
1.1 jdolecek 316: /*
1.15 jdolecek 317: * Reset GMT offset for pre-v3 mount structure args.
318: */
1.46 dsl 319: if (args->version < 3)
320: args->gmtoff = 0;
1.15 jdolecek 321:
322: /*
1.1 jdolecek 323: * If updating, check whether changing from read-only to
324: * read/write; if there is no device name, that's all we do.
325: */
326: if (mp->mnt_flag & MNT_UPDATE) {
327: pmp = VFSTOMSDOSFS(mp);
328: error = 0;
1.75 elad 329: if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) &&
330: (mp->mnt_flag & MNT_RDONLY)) {
1.1 jdolecek 331: flags = WRITECLOSE;
332: if (mp->mnt_flag & MNT_FORCE)
333: flags |= FORCECLOSE;
334: error = vflush(mp, NULLVP, flags);
335: }
336: if (!error && (mp->mnt_flag & MNT_RELOAD))
337: /* not yet implemented */
338: error = EOPNOTSUPP;
1.42 christos 339: if (error) {
1.115 maxv 340: DPRINTF("vflush %d", error);
1.1 jdolecek 341: return (error);
1.42 christos 342: }
1.75 elad 343: if ((pmp->pm_flags & MSDOSFSMNT_RONLY) &&
344: (mp->mnt_iflag & IMNT_WANTRDWR)) {
1.1 jdolecek 345: /*
346: * If upgrade to read-write by non-root, then verify
347: * that user has necessary permissions on the device.
1.74 elad 348: *
1.75 elad 349: * Permission to update a mount is checked higher, so
350: * here we presume updating the mount is okay (for
351: * example, as far as securelevel goes) which leaves us
352: * with the normal check.
1.1 jdolecek 353: */
1.74 elad 354: devvp = pmp->pm_devvp;
355: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
1.94 elad 356: error = kauth_authorize_system(l->l_cred,
357: KAUTH_SYSTEM_MOUNT, KAUTH_REQ_SYSTEM_MOUNT_DEVICE,
358: mp, devvp, KAUTH_ARG(VREAD | VWRITE));
1.86 hannken 359: VOP_UNLOCK(devvp);
1.115 maxv 360: DPRINTF("KAUTH_REQ_SYSTEM_MOUNT_DEVICE %d", error);
1.74 elad 361: if (error)
362: return (error);
363:
1.1 jdolecek 364: pmp->pm_flags &= ~MSDOSFSMNT_RONLY;
365: }
1.46 dsl 366: if (args->fspec == NULL) {
1.115 maxv 367: DPRINTF("missing fspec");
1.28 jmmv 368: return EINVAL;
1.42 christos 369: }
1.1 jdolecek 370: }
371: /*
372: * Not an update, or updating the name: look up the name
373: * and verify that it refers to a sensible block device.
374: */
1.76 dholland 375: error = namei_simple_user(args->fspec,
376: NSM_FOLLOW_NOEMULROOT, &devvp);
377: if (error != 0) {
1.115 maxv 378: DPRINTF("namei %d", error);
1.1 jdolecek 379: return (error);
1.42 christos 380: }
1.1 jdolecek 381:
382: if (devvp->v_type != VBLK) {
1.115 maxv 383: DPRINTF("not block");
1.1 jdolecek 384: vrele(devvp);
385: return (ENOTBLK);
386: }
387: if (bdevsw_lookup(devvp->v_rdev) == NULL) {
1.115 maxv 388: DPRINTF("no block switch");
1.1 jdolecek 389: vrele(devvp);
390: return (ENXIO);
391: }
392: /*
393: * If mount by non-root, then verify that user has necessary
394: * permissions on the device.
395: */
1.74 elad 396: accessmode = VREAD;
397: if ((mp->mnt_flag & MNT_RDONLY) == 0)
398: accessmode |= VWRITE;
399: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
1.94 elad 400: error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
401: KAUTH_REQ_SYSTEM_MOUNT_DEVICE, mp, devvp, KAUTH_ARG(accessmode));
1.86 hannken 402: VOP_UNLOCK(devvp);
1.74 elad 403: if (error) {
1.115 maxv 404: DPRINTF("KAUTH_REQ_SYSTEM_MOUNT_DEVICE %d", error);
1.74 elad 405: vrele(devvp);
406: return (error);
1.1 jdolecek 407: }
408: if ((mp->mnt_flag & MNT_UPDATE) == 0) {
1.24 christos 409: int xflags;
1.22 mycroft 410:
411: if (mp->mnt_flag & MNT_RDONLY)
1.24 christos 412: xflags = FREAD;
1.22 mycroft 413: else
1.24 christos 414: xflags = FREAD|FWRITE;
1.93 hannken 415: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
1.54 pooka 416: error = VOP_OPEN(devvp, xflags, FSCRED);
1.93 hannken 417: VOP_UNLOCK(devvp);
1.42 christos 418: if (error) {
1.115 maxv 419: DPRINTF("VOP_OPEN %d", error);
1.22 mycroft 420: goto fail;
1.42 christos 421: }
1.46 dsl 422: error = msdosfs_mountfs(devvp, mp, l, args);
1.22 mycroft 423: if (error) {
1.115 maxv 424: DPRINTF("msdosfs_mountfs %d", error);
1.22 mycroft 425: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
1.54 pooka 426: (void) VOP_CLOSE(devvp, xflags, NOCRED);
1.86 hannken 427: VOP_UNLOCK(devvp);
1.22 mycroft 428: goto fail;
429: }
1.1 jdolecek 430: #ifdef MSDOSFS_DEBUG /* only needed for the printf below */
431: pmp = VFSTOMSDOSFS(mp);
432: #endif
433: } else {
1.22 mycroft 434: vrele(devvp);
1.42 christos 435: if (devvp != pmp->pm_devvp) {
1.115 maxv 436: DPRINTF("devvp %p pmp %p", devvp, pmp->pm_devvp);
1.22 mycroft 437: return (EINVAL); /* needs translation */
1.42 christos 438: }
1.1 jdolecek 439: }
1.46 dsl 440: if ((error = update_mp(mp, args)) != 0) {
1.54 pooka 441: msdosfs_unmount(mp, MNT_FORCE);
1.115 maxv 442: DPRINTF("update_mp %d", error);
1.1 jdolecek 443: return error;
444: }
445:
446: #ifdef MSDOSFS_DEBUG
447: printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap);
448: #endif
1.46 dsl 449: return set_statvfs_info(path, UIO_USERSPACE, args->fspec, UIO_USERSPACE,
1.47 pooka 450: mp->mnt_op->vfs_name, mp, l);
1.22 mycroft 451:
452: fail:
453: vrele(devvp);
454: return (error);
1.1 jdolecek 455: }
456:
457: int
1.72 dsl 458: msdosfs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l, struct msdosfs_args *argp)
1.1 jdolecek 459: {
460: struct msdosfsmount *pmp;
461: struct buf *bp;
462: dev_t dev = devvp->v_rdev;
463: union bootsector *bsp;
464: struct byte_bpb33 *b33;
465: struct byte_bpb50 *b50;
466: struct byte_bpb710 *b710;
1.79 mlelstv 467: uint8_t SecPerClust;
1.110 maxv 468: int ronly, error, BlkPerSec;
1.79 mlelstv 469: uint64_t psize;
470: unsigned secsize;
1.1 jdolecek 471:
1.22 mycroft 472: /* Flush out any old buffers remaining from a previous use. */
1.33 ad 473: if ((error = vinvalbuf(devvp, V_SAVE, l->l_cred, l, 0, 0)) != 0)
1.1 jdolecek 474: return (error);
475:
476: ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
477:
478: bp = NULL; /* both used in error_exit */
479: pmp = NULL;
480:
1.81 hannken 481: error = fstrans_mount(mp);
482: if (error)
483: goto error_exit;
484:
1.79 mlelstv 485: error = getdisksize(devvp, &psize, &secsize);
1.96 tsutsui 486: if (error) {
1.84 pooka 487: if (argp->flags & MSDOSFSMNT_GEMDOSFS)
488: goto error_exit;
1.85 pooka 489:
490: /* ok, so it failed. we most likely don't need the info */
1.84 pooka 491: secsize = DEV_BSIZE;
492: psize = 0;
1.85 pooka 493: error = 0;
1.84 pooka 494: }
1.114 maxv 495: if (secsize < DEV_BSIZE) {
1.115 maxv 496: DPRINTF("Invalid block secsize (%d < DEV_BSIZE)", secsize);
1.114 maxv 497: error = EINVAL;
498: goto error_exit;
499: }
1.79 mlelstv 500:
1.1 jdolecek 501: if (argp->flags & MSDOSFSMNT_GEMDOSFS) {
1.110 maxv 502: if (secsize != GEMDOSFS_BSIZE) {
1.115 maxv 503: DPRINTF("Invalid block secsize %d for GEMDOS", secsize);
1.1 jdolecek 504: error = EINVAL;
505: goto error_exit;
506: }
1.110 maxv 507: }
1.1 jdolecek 508:
509: /*
510: * Read the boot sector of the filesystem, and then check the
511: * boot signature. If not a dos boot sector then error out.
512: */
1.116 christos 513: if (secsize < sizeof(*b50)) {
1.117 christos 514: DPRINTF("50 bootsec %u\n", secsize);
1.116 christos 515: error = EINVAL;
516: goto error_exit;
517: }
1.118 maxv 518: if ((error = bread(devvp, 0, secsize, 0, &bp)) != 0)
1.1 jdolecek 519: goto error_exit;
520: bsp = (union bootsector *)bp->b_data;
521: b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
522: b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
1.10 lukem 523: b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB;
1.1 jdolecek 524:
525: if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) {
526: if (bsp->bs50.bsBootSectSig0 != BOOTSIG0
527: || bsp->bs50.bsBootSectSig1 != BOOTSIG1) {
1.115 maxv 528: DPRINTF("bootsig0 %d bootsig1 %d",
1.42 christos 529: bsp->bs50.bsBootSectSig0,
1.115 maxv 530: bsp->bs50.bsBootSectSig1);
1.1 jdolecek 531: error = EINVAL;
532: goto error_exit;
533: }
534: }
535:
1.112 maxv 536: pmp = malloc(sizeof(*pmp), M_MSDOSFSMNT, M_WAITOK|M_ZERO);
1.1 jdolecek 537: pmp->pm_mountp = mp;
538:
539: /*
540: * Compute several useful quantities from the bpb in the
541: * bootsector. Copy in the dos 5 variant of the bpb then fix up
542: * the fields that are different between dos 5 and dos 3.3.
543: */
544: SecPerClust = b50->bpbSecPerClust;
545: pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
546: pmp->pm_ResSectors = getushort(b50->bpbResSectors);
547: pmp->pm_FATs = b50->bpbFATs;
548: pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
549: pmp->pm_Sectors = getushort(b50->bpbSectors);
550: pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
551: pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
552: pmp->pm_Heads = getushort(b50->bpbHeads);
553: pmp->pm_Media = b50->bpbMedia;
554:
555: if (pmp->pm_Sectors == 0) {
556: pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
557: pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
558: } else {
1.116 christos 559: if (secsize < sizeof(*b33)) {
1.117 christos 560: DPRINTF("33 bootsec %u\n", secsize);
1.116 christos 561: error = EINVAL;
562: goto error_exit;
563: }
1.1 jdolecek 564: pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
565: pmp->pm_HugeSectors = pmp->pm_Sectors;
566: }
567:
1.110 maxv 568: /*
569: * Sanity checks, from the FAT specification:
570: * - sectors per cluster: >= 1, power of 2
571: * - logical sector size: >= 1, power of 2
572: * - cluster size: <= max FS block size
573: * - number of sectors: >= 1
574: */
575: if ((SecPerClust == 0) || !powerof2(SecPerClust) ||
576: (pmp->pm_BytesPerSec == 0) || !powerof2(pmp->pm_BytesPerSec) ||
577: (SecPerClust * pmp->pm_BytesPerSec > MAXBSIZE) ||
578: (pmp->pm_HugeSectors == 0)) {
1.115 maxv 579: DPRINTF("consistency checks");
1.110 maxv 580: error = EINVAL;
581: goto error_exit;
582: }
583:
584: if (!(argp->flags & MSDOSFSMNT_GEMDOSFS) &&
585: (pmp->pm_SecPerTrack > 63)) {
1.115 maxv 586: DPRINTF("SecPerTrack %d", pmp->pm_SecPerTrack);
1.110 maxv 587: error = EINVAL;
588: goto error_exit;
589: }
590:
1.1 jdolecek 591: if (pmp->pm_RootDirEnts == 0) {
1.116 christos 592: if (secsize < sizeof(*b710)) {
1.117 christos 593: DPRINTF("710 bootsec %u\n", secsize);
1.116 christos 594: error = EINVAL;
595: goto error_exit;
596: }
1.112 maxv 597: unsigned short FSVers = getushort(b710->bpbFSVers);
598: unsigned short ExtFlags = getushort(b710->bpbExtFlags);
1.34 gdt 599: /*
600: * Some say that bsBootSectSig[23] must be zero, but
601: * Windows does not require this and some digital cameras
602: * do not set these to zero. Therefore, do not insist.
603: */
1.112 maxv 604: if (pmp->pm_Sectors || pmp->pm_FATsecs || FSVers) {
1.115 maxv 605: DPRINTF("Sectors %d FATsecs %lu FSVers %d",
606: pmp->pm_Sectors, pmp->pm_FATsecs, FSVers);
1.1 jdolecek 607: error = EINVAL;
608: goto error_exit;
609: }
610: pmp->pm_fatmask = FAT32_MASK;
611: pmp->pm_fatmult = 4;
612: pmp->pm_fatdiv = 1;
613: pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs);
614:
1.112 maxv 615: /* Mirroring is enabled if the FATMIRROR bit is not set. */
616: if ((ExtFlags & FATMIRROR) == 0)
1.1 jdolecek 617: pmp->pm_flags |= MSDOSFS_FATMIRROR;
618: else
1.112 maxv 619: pmp->pm_curfat = ExtFlags & FATNUM;
1.1 jdolecek 620: } else
621: pmp->pm_flags |= MSDOSFS_FATMIRROR;
622:
623: if (argp->flags & MSDOSFSMNT_GEMDOSFS) {
624: if (FAT32(pmp)) {
1.112 maxv 625: /* GEMDOS doesn't know FAT32. */
1.115 maxv 626: DPRINTF("FAT32 for GEMDOS");
1.1 jdolecek 627: error = EINVAL;
628: goto error_exit;
629: }
630:
631: /*
632: * Check a few values (could do some more):
1.110 maxv 633: * - logical sector size: >= block size
634: * - number of sectors: <= size of partition
1.1 jdolecek 635: */
1.110 maxv 636: if ((pmp->pm_BytesPerSec < GEMDOSFS_BSIZE) ||
637: (pmp->pm_HugeSectors *
638: (pmp->pm_BytesPerSec / GEMDOSFS_BSIZE) > psize)) {
1.115 maxv 639: DPRINTF("consistency checks for GEMDOS");
1.1 jdolecek 640: error = EINVAL;
641: goto error_exit;
642: }
643: /*
1.100 jakllsch 644: * XXX - Many parts of the msdosfs driver seem to assume that
1.1 jdolecek 645: * the number of bytes per logical sector (BytesPerSec) will
646: * always be the same as the number of bytes per disk block
647: * Let's pretend it is.
648: */
1.110 maxv 649: BlkPerSec = pmp->pm_BytesPerSec / GEMDOSFS_BSIZE;
650: pmp->pm_BytesPerSec = GEMDOSFS_BSIZE;
651: pmp->pm_HugeSectors *= BlkPerSec;
652: pmp->pm_HiddenSects *= BlkPerSec;
653: pmp->pm_ResSectors *= BlkPerSec;
654: pmp->pm_Sectors *= BlkPerSec;
655: pmp->pm_FATsecs *= BlkPerSec;
656: SecPerClust *= BlkPerSec;
1.1 jdolecek 657: }
1.58 pooka 658:
659: /* Check that fs has nonzero FAT size */
660: if (pmp->pm_FATsecs == 0) {
1.115 maxv 661: DPRINTF("FATsecs is 0");
1.58 pooka 662: error = EINVAL;
663: goto error_exit;
664: }
665:
1.1 jdolecek 666: pmp->pm_fatblk = pmp->pm_ResSectors;
667: if (FAT32(pmp)) {
1.116 christos 668: if (secsize < sizeof(*b710)) {
1.117 christos 669: DPRINTF("710 bootsec %u\n", secsize);
1.116 christos 670: error = EINVAL;
671: goto error_exit;
672: }
1.1 jdolecek 673: pmp->pm_rootdirblk = getulong(b710->bpbRootClust);
674: pmp->pm_firstcluster = pmp->pm_fatblk
675: + (pmp->pm_FATs * pmp->pm_FATsecs);
676: pmp->pm_fsinfo = getushort(b710->bpbFSInfo);
677: } else {
678: pmp->pm_rootdirblk = pmp->pm_fatblk +
679: (pmp->pm_FATs * pmp->pm_FATsecs);
680: pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)
681: + pmp->pm_BytesPerSec - 1)
682: / pmp->pm_BytesPerSec;/* in sectors */
683: pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
684: }
685:
686: pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
687: SecPerClust;
688: pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
689: pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec;
690:
691: if (argp->flags & MSDOSFSMNT_GEMDOSFS) {
1.78 mlelstv 692: if (pmp->pm_nmbrofclusters <= (0xff0 - 2)) {
1.1 jdolecek 693: pmp->pm_fatmask = FAT12_MASK;
694: pmp->pm_fatmult = 3;
695: pmp->pm_fatdiv = 2;
696: } else {
697: pmp->pm_fatmask = FAT16_MASK;
698: pmp->pm_fatmult = 2;
699: pmp->pm_fatdiv = 1;
700: }
701: } else if (pmp->pm_fatmask == 0) {
702: if (pmp->pm_maxcluster
703: <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
704: /*
705: * This will usually be a floppy disk. This size makes
1.100 jakllsch 706: * sure that one FAT entry will not be split across
1.1 jdolecek 707: * multiple blocks.
708: */
709: pmp->pm_fatmask = FAT12_MASK;
710: pmp->pm_fatmult = 3;
711: pmp->pm_fatdiv = 2;
712: } else {
713: pmp->pm_fatmask = FAT16_MASK;
714: pmp->pm_fatmult = 2;
715: pmp->pm_fatdiv = 1;
716: }
717: }
718: if (FAT12(pmp))
719: pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
720: else
721: pmp->pm_fatblocksize = MAXBSIZE;
722:
723: pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
724: pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1;
725:
726: /*
727: * Compute mask and shift value for isolating cluster relative byte
728: * offsets and cluster numbers from a file offset.
729: */
730: pmp->pm_bpcluster = SecPerClust * pmp->pm_BytesPerSec;
731: pmp->pm_crbomask = pmp->pm_bpcluster - 1;
732: pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;
733:
734: /*
735: * Check for valid cluster size
736: * must be a power of 2
737: */
738: if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
1.115 maxv 739: DPRINTF("bpcluster %lu cnshift %lu", pmp->pm_bpcluster,
740: pmp->pm_cnshift);
1.1 jdolecek 741: error = EINVAL;
742: goto error_exit;
743: }
744:
745: /*
1.101 jakllsch 746: * Cluster size must be within limit of MAXBSIZE.
747: * Many FAT filesystems will not have clusters larger than
748: * 32KiB due to limits in Windows versions before Vista.
749: */
750: if (pmp->pm_bpcluster > MAXBSIZE) {
1.115 maxv 751: DPRINTF("bpcluster %lu > MAXBSIZE %d",
752: pmp->pm_bpcluster, MAXBSIZE);
1.101 jakllsch 753: error = EINVAL;
754: goto error_exit;
755: }
756:
757: /*
1.1 jdolecek 758: * Release the bootsector buffer.
759: */
1.52 ad 760: brelse(bp, BC_AGE);
1.1 jdolecek 761: bp = NULL;
762:
763: /*
764: * Check FSInfo.
765: */
766: if (pmp->pm_fsinfo) {
767: struct fsinfo *fp;
1.113 christos 768: const int rdsz = roundup(sizeof(*fp), pmp->pm_BytesPerSec);
1.1 jdolecek 769:
1.40 scw 770: /*
771: * XXX If the fsinfo block is stored on media with
772: * 2KB or larger sectors, is the fsinfo structure
773: * padded at the end or in the middle?
774: */
775: if ((error = bread(devvp, de_bn2kb(pmp, pmp->pm_fsinfo),
1.118 maxv 776: rdsz, 0, &bp)) != 0)
1.1 jdolecek 777: goto error_exit;
778: fp = (struct fsinfo *)bp->b_data;
779: if (!memcmp(fp->fsisig1, "RRaA", 4)
780: && !memcmp(fp->fsisig2, "rrAa", 4)
781: && !memcmp(fp->fsisig3, "\0\0\125\252", 4)
782: && !memcmp(fp->fsisig4, "\0\0\125\252", 4))
783: pmp->pm_nxtfree = getulong(fp->fsinxtfree);
784: else
785: pmp->pm_fsinfo = 0;
1.52 ad 786: brelse(bp, 0);
1.1 jdolecek 787: bp = NULL;
788: }
789:
790: /*
791: * Check and validate (or perhaps invalidate?) the fsinfo structure?
792: * XXX
793: */
794: if (pmp->pm_fsinfo) {
1.99 jakllsch 795: if ((pmp->pm_nxtfree == 0xffffffffUL) ||
796: (pmp->pm_nxtfree > pmp->pm_maxcluster))
1.1 jdolecek 797: pmp->pm_fsinfo = 0;
798: }
799:
800: /*
801: * Allocate memory for the bitmap of allocated clusters, and then
802: * fill it in.
803: */
1.97 jakllsch 804: pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS)
1.1 jdolecek 805: / N_INUSEBITS)
806: * sizeof(*pmp->pm_inusemap),
807: M_MSDOSFSFAT, M_WAITOK);
808:
809: /*
810: * fillinusemap() needs pm_devvp.
811: */
812: pmp->pm_dev = dev;
813: pmp->pm_devvp = devvp;
814:
815: /*
816: * Have the inuse map filled in.
817: */
1.42 christos 818: if ((error = fillinusemap(pmp)) != 0) {
1.115 maxv 819: DPRINTF("fillinusemap %d", error);
1.1 jdolecek 820: goto error_exit;
1.42 christos 821: }
1.1 jdolecek 822:
823: /*
1.100 jakllsch 824: * If they want FAT updates to be synchronous then let them suffer
1.1 jdolecek 825: * the performance degradation in exchange for the on disk copy of
1.100 jakllsch 826: * the FAT being correct just about all the time. I suppose this
1.1 jdolecek 827: * would be a good thing to turn on if the kernel is still flakey.
828: */
829: if (mp->mnt_flag & MNT_SYNCHRONOUS)
830: pmp->pm_flags |= MSDOSFSMNT_WAITONFAT;
831:
832: /*
833: * Finish up.
834: */
835: if (ronly)
836: pmp->pm_flags |= MSDOSFSMNT_RONLY;
837: else
838: pmp->pm_fmod = 1;
839: mp->mnt_data = pmp;
1.20 jdolecek 840: mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev;
841: mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_MSDOS);
842: mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
843: mp->mnt_stat.f_namemax = MSDOSFS_NAMEMAX(pmp);
1.1 jdolecek 844: mp->mnt_flag |= MNT_LOCAL;
845: mp->mnt_dev_bshift = pmp->pm_bnshift;
846: mp->mnt_fs_bshift = pmp->pm_cnshift;
847:
848: /*
849: * If we ever do quotas for DOS filesystems this would be a place
850: * to fill in the info in the msdosfsmount structure. You dolt,
851: * quotas on dos filesystems make no sense because files have no
852: * owners on dos filesystems. of course there is some empty space
853: * in the directory entry where we could put uid's and gid's.
854: */
1.69 pooka 855:
1.102 hannken 856: spec_node_setmountedfs(devvp, mp);
1.1 jdolecek 857:
858: return (0);
859:
1.80 pooka 860: error_exit:
1.81 hannken 861: fstrans_unmount(mp);
1.1 jdolecek 862: if (bp)
1.52 ad 863: brelse(bp, BC_AGE);
1.1 jdolecek 864: if (pmp) {
865: if (pmp->pm_inusemap)
866: free(pmp->pm_inusemap, M_MSDOSFSFAT);
867: free(pmp, M_MSDOSFSMNT);
868: mp->mnt_data = NULL;
869: }
870: return (error);
871: }
872:
873: int
1.54 pooka 874: msdosfs_start(struct mount *mp, int flags)
1.1 jdolecek 875: {
876:
877: return (0);
878: }
879:
880: /*
881: * Unmount the filesystem described by mp.
882: */
883: int
1.72 dsl 884: msdosfs_unmount(struct mount *mp, int mntflags)
1.1 jdolecek 885: {
886: struct msdosfsmount *pmp;
887: int error, flags;
888:
889: flags = 0;
890: if (mntflags & MNT_FORCE)
891: flags |= FORCECLOSE;
892: if ((error = vflush(mp, NULLVP, flags)) != 0)
893: return (error);
894: pmp = VFSTOMSDOSFS(mp);
895: if (pmp->pm_devvp->v_type != VBAD)
1.102 hannken 896: spec_node_setmountedfs(pmp->pm_devvp, NULL);
1.1 jdolecek 897: #ifdef MSDOSFS_DEBUG
898: {
899: struct vnode *vp = pmp->pm_devvp;
900:
901: printf("msdosfs_umount(): just before calling VOP_CLOSE()\n");
1.64 ad 902: printf("flag %08x, usecount %d, writecount %d, holdcnt %d\n",
1.53 ad 903: vp->v_vflag | vp->v_iflag | vp->v_uflag, vp->v_usecount,
904: vp->v_writecount, vp->v_holdcnt);
1.25 jmmv 905: printf("mount %p, op %p\n",
906: vp->v_mount, vp->v_op);
1.1 jdolecek 907: printf("cleanblkhd %p, dirtyblkhd %p, numoutput %d, type %d\n",
908: vp->v_cleanblkhd.lh_first,
909: vp->v_dirtyblkhd.lh_first,
910: vp->v_numoutput, vp->v_type);
911: printf("union %p, tag %d, data[0] %08x, data[1] %08x\n",
912: vp->v_socket, vp->v_tag,
913: ((u_int *)vp->v_data)[0],
914: ((u_int *)vp->v_data)[1]);
915: }
916: #endif
917: vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY);
1.80 pooka 918: (void) VOP_CLOSE(pmp->pm_devvp,
1.54 pooka 919: pmp->pm_flags & MSDOSFSMNT_RONLY ? FREAD : FREAD|FWRITE, NOCRED);
1.1 jdolecek 920: vput(pmp->pm_devvp);
1.90 hannken 921: msdosfs_fh_destroy(pmp);
1.1 jdolecek 922: free(pmp->pm_inusemap, M_MSDOSFSFAT);
923: free(pmp, M_MSDOSFSMNT);
924: mp->mnt_data = NULL;
925: mp->mnt_flag &= ~MNT_LOCAL;
1.81 hannken 926: fstrans_unmount(mp);
1.80 pooka 927: return (0);
1.1 jdolecek 928: }
929:
930: int
1.72 dsl 931: msdosfs_root(struct mount *mp, struct vnode **vpp)
1.1 jdolecek 932: {
933: struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
934: int error;
935:
936: #ifdef MSDOSFS_DEBUG
937: printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp);
938: #endif
1.109 hannken 939: if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, vpp)) != 0)
940: return error;
941: error = vn_lock(*vpp, LK_EXCLUSIVE);
942: if (error) {
943: vrele(*vpp);
944: *vpp = NULL;
945: return error;
946: }
947: return 0;
1.1 jdolecek 948: }
949:
950: int
1.54 pooka 951: msdosfs_statvfs(struct mount *mp, struct statvfs *sbp)
1.1 jdolecek 952: {
953: struct msdosfsmount *pmp;
954:
955: pmp = VFSTOMSDOSFS(mp);
956: sbp->f_bsize = pmp->pm_bpcluster;
1.14 christos 957: sbp->f_frsize = sbp->f_bsize;
1.1 jdolecek 958: sbp->f_iosize = pmp->pm_bpcluster;
959: sbp->f_blocks = pmp->pm_nmbrofclusters;
960: sbp->f_bfree = pmp->pm_freeclustercount;
961: sbp->f_bavail = pmp->pm_freeclustercount;
1.14 christos 962: sbp->f_bresvd = 0;
1.1 jdolecek 963: sbp->f_files = pmp->pm_RootDirEnts; /* XXX */
964: sbp->f_ffree = 0; /* what to put in here? */
1.14 christos 965: sbp->f_favail = 0; /* what to put in here? */
966: sbp->f_fresvd = 0;
967: copy_statvfs_info(sbp, mp);
1.1 jdolecek 968: return (0);
969: }
970:
1.108 christos 971: struct msdosfs_sync_ctx {
972: int waitfor;
973: };
974:
975: static bool
976: msdosfs_sync_selector(void *cl, struct vnode *vp)
977: {
978: struct msdosfs_sync_ctx *c = cl;
979: struct denode *dep;
980:
981: dep = VTODE(vp);
982: if (c->waitfor == MNT_LAZY || vp->v_type == VNON ||
983: dep == NULL || (((dep->de_flag &
984: (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0) &&
985: (LIST_EMPTY(&vp->v_dirtyblkhd) &&
986: UVM_OBJ_IS_CLEAN(&vp->v_uobj))))
987: return false;
988: return true;
989: }
990:
1.1 jdolecek 991: int
1.72 dsl 992: msdosfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred)
1.1 jdolecek 993: {
1.105 hannken 994: struct vnode *vp;
995: struct vnode_iterator *marker;
1.1 jdolecek 996: struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
1.89 hannken 997: int error, allerror = 0;
1.108 christos 998: struct msdosfs_sync_ctx ctx;
1.1 jdolecek 999:
1000: /*
1.100 jakllsch 1001: * If we ever switch to not updating all of the FATs all the time,
1.1 jdolecek 1002: * this would be the place to update them from the first one.
1003: */
1004: if (pmp->pm_fmod != 0) {
1005: if (pmp->pm_flags & MSDOSFSMNT_RONLY)
1006: panic("msdosfs_sync: rofs mod");
1007: else {
1.100 jakllsch 1008: /* update FATs here */
1.1 jdolecek 1009: }
1010: }
1.81 hannken 1011: fstrans_start(mp, FSTRANS_SHARED);
1.1 jdolecek 1012: /*
1013: * Write back each (modified) denode.
1014: */
1.105 hannken 1015: vfs_vnode_iterator_init(mp, &marker);
1.108 christos 1016: ctx.waitfor = waitfor;
1017: while ((vp = vfs_vnode_iterator_next(marker, msdosfs_sync_selector,
1018: &ctx)))
1019: {
1.105 hannken 1020: error = vn_lock(vp, LK_EXCLUSIVE);
1021: if (error) {
1022: vrele(vp);
1.56 ad 1023: continue;
1.105 hannken 1024: }
1.1 jdolecek 1025: if ((error = VOP_FSYNC(vp, cred,
1.54 pooka 1026: waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0)) != 0)
1.1 jdolecek 1027: allerror = error;
1.89 hannken 1028: vput(vp);
1.1 jdolecek 1029: }
1.105 hannken 1030: vfs_vnode_iterator_destroy(marker);
1.56 ad 1031:
1.1 jdolecek 1032: /*
1033: * Force stale file system control information to be flushed.
1034: */
1.120 hannken 1035: vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY);
1.1 jdolecek 1036: if ((error = VOP_FSYNC(pmp->pm_devvp, cred,
1.54 pooka 1037: waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0)) != 0)
1.1 jdolecek 1038: allerror = error;
1.120 hannken 1039: VOP_UNLOCK(pmp->pm_devvp);
1.81 hannken 1040: fstrans_done(mp);
1.1 jdolecek 1041: return (allerror);
1042: }
1043:
1044: int
1.72 dsl 1045: msdosfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
1.1 jdolecek 1046: {
1047: struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
1.32 martin 1048: struct defid defh;
1.90 hannken 1049: uint32_t gen;
1.1 jdolecek 1050: int error;
1051:
1.42 christos 1052: if (fhp->fid_len != sizeof(struct defid)) {
1.115 maxv 1053: DPRINTF("fid_len %d %zd", fhp->fid_len, sizeof(struct defid));
1.32 martin 1054: return EINVAL;
1.42 christos 1055: }
1.32 martin 1056: memcpy(&defh, fhp, sizeof(defh));
1.90 hannken 1057: error = msdosfs_fh_lookup(pmp, defh.defid_dirclust, defh.defid_dirofs,
1058: &gen);
1059: if (error == 0 && gen != defh.defid_gen)
1060: error = ESTALE;
1061: if (error) {
1062: *vpp = NULLVP;
1063: return error;
1064: }
1.109 hannken 1065: error = deget(pmp, defh.defid_dirclust, defh.defid_dirofs, vpp);
1.1 jdolecek 1066: if (error) {
1.115 maxv 1067: DPRINTF("deget %d", error);
1.1 jdolecek 1068: *vpp = NULLVP;
1.109 hannken 1069: return error;
1070: }
1071: error = vn_lock(*vpp, LK_EXCLUSIVE);
1072: if (error) {
1073: vrele(*vpp);
1074: *vpp = NULLVP;
1075: return error;
1.1 jdolecek 1076: }
1.109 hannken 1077: return 0;
1.1 jdolecek 1078: }
1079:
1080: int
1.72 dsl 1081: msdosfs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
1.1 jdolecek 1082: {
1.90 hannken 1083: struct msdosfsmount *pmp = VFSTOMSDOSFS(vp->v_mount);
1.1 jdolecek 1084: struct denode *dep;
1.32 martin 1085: struct defid defh;
1.90 hannken 1086: int error;
1.1 jdolecek 1087:
1.32 martin 1088: if (*fh_size < sizeof(struct defid)) {
1089: *fh_size = sizeof(struct defid);
1090: return E2BIG;
1091: }
1092: *fh_size = sizeof(struct defid);
1.1 jdolecek 1093: dep = VTODE(vp);
1.32 martin 1094: memset(&defh, 0, sizeof(defh));
1095: defh.defid_len = sizeof(struct defid);
1096: defh.defid_dirclust = dep->de_dirclust;
1097: defh.defid_dirofs = dep->de_diroffset;
1.90 hannken 1098: error = msdosfs_fh_enter(pmp, dep->de_dirclust, dep->de_diroffset,
1099: &defh.defid_gen);
1100: if (error == 0)
1101: memcpy(fhp, &defh, sizeof(defh));
1102: return error;
1.1 jdolecek 1103: }
1104:
1105: int
1.39 christos 1106: msdosfs_vget(struct mount *mp, ino_t ino,
1107: struct vnode **vpp)
1.1 jdolecek 1108: {
1109:
1110: return (EOPNOTSUPP);
1111: }
1.81 hannken 1112:
1113: int
1114: msdosfs_suspendctl(struct mount *mp, int cmd)
1115: {
1116: int error;
1117: struct lwp *l = curlwp;
1118:
1119: switch (cmd) {
1120: case SUSPEND_SUSPEND:
1121: if ((error = fstrans_setstate(mp, FSTRANS_SUSPENDING)) != 0)
1122: return error;
1.121 ! hannken 1123: if ((error = fstrans_setstate(mp, FSTRANS_SUSPENDED)) != 0) {
1.81 hannken 1124: (void) fstrans_setstate(mp, FSTRANS_NORMAL);
1125: return error;
1126: }
1127: return 0;
1128:
1129: case SUSPEND_RESUME:
1130: return fstrans_setstate(mp, FSTRANS_NORMAL);
1131:
1132: default:
1133: return EINVAL;
1134: }
1135: }
CVSweb <webmaster@jp.NetBSD.org>