|
|
1.1 root 1: /*
2: * Written by Paul Popelka ([email protected])
3: *
4: * You can do anything you want with this software,
5: * just don't say you wrote it,
6: * and don't remove this notice.
7: *
8: * This software is provided "as is".
9: *
10: * The author supplies this software to be publicly
11: * redistributed on the understanding that the author
12: * is not responsible for the correct functioning of
13: * this software in any circumstances and is not liable
14: * for any damages caused by this software.
15: *
16: * October 1992
17: *
18: * April 6, 1993:
19: * Changed MOUNT_PCFS to MOUNT_MSDOS, this whole package should be renamed
20: * to msdosfs, but I did not have the time to do it. Some one please do
21: * this and resubmit it to the patchkit!
22: * Rodney W. Grimes
23: *
24: * pcfs_vfsops.c,v 1.4.2.1 1993/08/05 02:37:21 cgd Exp
25: */
26:
27: #include "param.h"
28: #include "systm.h"
29: #include "namei.h"
30: #include "proc.h"
31: #include "kernel.h"
32: #include "vnode.h"
33: #include "specdev.h" /* defines v_rdev */
34: #include "mount.h"
35: #include "buf.h"
36: #include "file.h"
37: #include "malloc.h"
38:
39: #include "bpb.h"
40: #include "bootsect.h"
41: #include "direntry.h"
42: #include "denode.h"
43: #include "pcfsmount.h"
44: #include "fat.h"
45:
46: int pcfsdoforce = 0; /* 1 = force unmount */
47:
48: /*
49: * mp -
50: * path - addr in user space of mount point (ie /usr or whatever)
51: * data - addr in user space of mount params including the
52: * name of the block special file to treat as a filesystem.
53: * ndp -
54: * p -
55: */
56: int
57: pcfs_mount(mp, path, data, ndp, p)
58: struct mount *mp;
59: char *path;
60: caddr_t data;
61: struct nameidata *ndp;
62: struct proc *p;
63: {
64: struct vnode *devvp; /* vnode for blk device to mount */
65: struct pcfs_args args; /* will hold data from mount request */
66: struct pcfsmount *pmp; /* pcfs specific mount control block */
67: int error;
68: u_int size;
69:
70: /*
71: * Copy in the args for the mount request.
72: */
73: if (error = copyin(data, (caddr_t)&args, sizeof(struct pcfs_args)))
74: return error;
75:
76: /*
77: * Check to see if they want it to be an exportable
78: * filesystem via nfs. And, if they do, should it
79: * be read only, and what uid is root to be mapped
80: * to.
81: */
82: if ((args.exflags & MNT_EXPORTED) || (mp->mnt_flag & MNT_EXPORTED)) {
83: if (args.exflags & MNT_EXPORTED)
84: mp->mnt_flag |= MNT_EXPORTED;
85: else
86: mp->mnt_flag &= ~MNT_EXPORTED;
87: if (args.exflags & MNT_EXRDONLY)
88: mp->mnt_flag |= MNT_EXRDONLY;
89: else
90: mp->mnt_flag &= ~MNT_EXRDONLY;
91: mp->mnt_exroot = args.exroot;
92: }
93:
94: /*
95: * If they just want to update then be sure we can
96: * do what is asked. Can't change a filesystem from
97: * read/write to read only. Why?
98: * And if they've supplied a new device file name then we
99: * continue, otherwise return.
100: */
101: if (mp->mnt_flag & MNT_UPDATE) {
102: pmp = (struct pcfsmount *)mp->mnt_data;
103: if (pmp->pm_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
104: pmp->pm_ronly = 0;
105: if (args.fspec == 0)
106: return 0;
107: }
108:
109: /*
110: * Now, lookup the name of the block device this
111: * mount or name update request is to apply to.
112: */
113: ndp->ni_nameiop = LOOKUP | FOLLOW;
114: ndp->ni_segflg = UIO_USERSPACE;
115: ndp->ni_dirp = args.fspec;
116: if (error = namei(ndp, p))
117: return error;
118:
119: /*
120: * Be sure they've given us a block device to treat
121: * as a filesystem. And, that its major number is
122: * within the bdevsw table.
123: */
124: devvp = ndp->ni_vp;
125: if (devvp->v_type != VBLK) {
126: vrele(devvp); /* namei() acquires this? */
127: return ENOTBLK;
128: }
129: if (major(devvp->v_rdev) >= nblkdev) {
130: vrele(devvp);
131: return ENXIO;
132: }
133:
134: /*
135: * If this is an update, then make sure the vnode
136: * for the block special device is the same as the
137: * one our filesystem is in.
138: */
139: if (mp->mnt_flag & MNT_UPDATE) {
140: if (devvp != pmp->pm_devvp)
141: error = EINVAL;
142: else
143: vrele(devvp);
144: } else {
145:
146: /*
147: * Well, it's not an update, it's a real mount request.
148: * Time to get dirty.
149: */
150: error = mountpcfs(devvp, mp, p);
151: }
152: if (error) {
153: vrele(devvp);
154: return error;
155: }
156:
157: /*
158: * Copy in the name of the directory the filesystem
159: * is to be mounted on.
160: * Then copy in the name of the block special file
161: * representing the filesystem being mounted.
162: * And we clear the remainder of the character strings
163: * to be tidy.
164: * Then, we try to fill in the filesystem stats structure
165: * as best we can with whatever applies from a dos file
166: * system.
167: */
168: pmp = (struct pcfsmount *)mp->mnt_data;
169: copyinstr(path, (caddr_t)mp->mnt_stat.f_mntonname,
170: sizeof(mp->mnt_stat.f_mntonname)-1, &size);
171: bzero(mp->mnt_stat.f_mntonname + size,
172: sizeof(mp->mnt_stat.f_mntonname) - size);
173: copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN-1, &size);
174: bzero(mp->mnt_stat.f_mntfromname + size,
175: MNAMELEN - size);
176: (void)pcfs_statfs(mp, &mp->mnt_stat, p);
177: #if defined(PCFSDEBUG)
178: printf("pcfs_mount(): mp %x, pmp %x, inusemap %x\n", mp, pmp, pmp->pm_inusemap);
179: #endif /* defined(PCFSDEBUG) */
180: return 0;
181: }
182:
183: int
184: mountpcfs(devvp, mp, p)
185: struct vnode *devvp;
186: struct mount *mp;
187: struct proc *p;
188: {
189: int i;
190: u_long bpc;
191: int bit;
192: int error = 0;
193: int needclose;
194: int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
195: dev_t dev = devvp->v_rdev;
196: union bootsector *bsp;
197: struct pcfsmount *pmp = NULL;
198: struct buf *bp0 = NULL;
199: struct byte_bpb33 *b33;
200: struct byte_bpb50 *b50;
201:
202: /*
203: * Multiple mounts of the same block special file
204: * aren't allowed. Make sure no one else has the
205: * special file open. And flush any old buffers
206: * from this filesystem. Presumably this prevents
207: * us from running into buffers that are the wrong
208: * blocksize.
209: * NOTE: mountedon() is a part of the ufs filesystem.
210: * If the ufs filesystem is not gen'ed into the system
211: * we will get an unresolved reference.
212: */
213: if (error = mountedon(devvp))
214: return error;
215: if (vcount(devvp) > 1)
216: return EBUSY;
217: vinvalbuf(devvp, 1);
218:
219: /*
220: * Now open the block special file.
221: */
222: if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p))
223: return error;
224: needclose = 1;
225:
226: /*
227: * Read the boot sector of the filesystem, and then
228: * check the boot signature. If not a dos boot sector
229: * then error out. We could also add some checking on
230: * the bsOemName field. So far I've seen the following
231: * values:
232: * "IBM 3.3"
233: * "MSDOS3.3"
234: * "MSDOS5.0"
235: */
236: if (error = bread(devvp, 0, 512, NOCRED, &bp0))
237: goto error_exit;
238: bp0->b_flags |= B_AGE;
239: bsp = (union bootsector *)bp0->b_un.b_addr;
240: b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
241: b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
242: if (bsp->bs50.bsBootSectSig != BOOTSIG) {
243: error = EINVAL;
244: goto error_exit;
245: }
246:
247: pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK);
248: pmp->pm_inusemap = NULL;
249: pmp->pm_mountp = mp;
250:
251: /*
252: * Compute several useful quantities from the bpb in
253: * the bootsector. Copy in the dos 5 variant of the
254: * bpb then fix up the fields that are different between
255: * dos 5 and dos 3.3.
256: */
257: pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
258: pmp->pm_SectPerClust = b50->bpbSecPerClust;
259: pmp->pm_ResSectors = getushort(b50->bpbResSectors);
260: pmp->pm_FATs = b50->bpbFATs;
261: pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
262: pmp->pm_Sectors = getushort(b50->bpbSectors);
263: pmp->pm_Media = b50->bpbMedia;
264: pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
265: pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
266: pmp->pm_Heads = getushort(b50->bpbHeads);
267: if (pmp->pm_Sectors == 0) {
268: pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
269: pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
270: } else {
271: pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
272: pmp->pm_HugeSectors = pmp->pm_Sectors;
273: }
274: pmp->pm_fatblk = pmp->pm_ResSectors;
275: pmp->pm_rootdirblk = pmp->pm_fatblk +
276: (pmp->pm_FATs * pmp->pm_FATsecs);
277: pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry))
278: /
279: pmp->pm_BytesPerSec; /* in sectors */
280: pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
281: pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
282: pmp->pm_SectPerClust;
283: pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
284: pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec;
285: if (FAT12(pmp))
286: /* This will usually be a floppy disk.
287: * This size makes sure that one fat entry will not be split
288: * across multiple blocks. */
289: pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
290: else
291: /* This will usually be a hard disk.
292: * Reading or writing one block should be quite fast. */
293: pmp->pm_fatblocksize = MAXBSIZE;
294: pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
295:
296: if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0)
297: printf("mountpcfs(): root directory is not a multiple of the clustersize in length\n");
298:
299: /*
300: * Compute mask and shift value for isolating cluster relative
301: * byte offsets and cluster numbers from a file offset.
302: */
303: bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec;
304: if (!bpc || (bpc & (bpc - 1))) {
305: error = EINVAL;
306: goto error_exit;
307: }
308: pmp->pm_bpcluster = bpc;
309: pmp->pm_depclust = bpc/sizeof(struct direntry);
310: pmp->pm_crbomask = bpc - 1;
311: pmp->pm_cnshift = ffs(bpc) - 1;
312:
313: pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */
314: pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */
315:
316: /*
317: * Release the bootsector buffer.
318: */
319: brelse(bp0);
320: bp0 = NULL;
321:
322: /*
323: * Allocate memory for the bitmap of allocated clusters,
324: * and then fill it in.
325: */
326: pmp->pm_inusemap = malloc((pmp->pm_maxcluster / 8) + 1,
327: M_MSDOSFSFAT, M_WAITOK);
328:
329: /*
330: * fillinusemap() needs pm_devvp.
331: */
332: pmp->pm_dev = dev;
333: pmp->pm_devvp = devvp;
334:
335: /*
336: * Have the inuse map filled in.
337: */
338: error = fillinusemap(pmp);
339: if (error)
340: goto error_exit;
341:
342: /*
343: * If they want fat updates to be synchronous then let
344: * them suffer the performance degradation in exchange
345: * for the on disk copy of the fat being correct just
346: * about all the time. I suppose this would be a good
347: * thing to turn on if the kernel is still flakey.
348: */
349: pmp->pm_waitonfat = mp->mnt_flag & MNT_SYNCHRONOUS;
350:
351: /*
352: * Finish up.
353: */
354: pmp->pm_ronly = ronly;
355: if (ronly == 0)
356: pmp->pm_fmod = 1;
357: mp->mnt_data = (qaddr_t)pmp;
358: mp->mnt_stat.f_fsid.val[0] = (long)dev;
359: mp->mnt_stat.f_fsid.val[1] = MOUNT_MSDOS;
360: mp->mnt_flag |= MNT_LOCAL;
361: #if defined(QUOTA)
362: /*
363: * If we ever do quotas for DOS filesystems this would
364: * be a place to fill in the info in the pcfsmount
365: * structure.
366: * You dolt, quotas on dos filesystems make no sense
367: * because files have no owners on dos filesystems.
368: * of course there is some empty space in the directory
369: * entry where we could put uid's and gid's.
370: */
371: #endif /* defined(QUOTA) */
372: devvp->v_specflags |= SI_MOUNTEDON;
373:
374: return 0;
375:
376: error_exit:;
377: if (bp0)
378: brelse(bp0);
379: if (needclose)
380: (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE,
381: NOCRED, p);
382: if (pmp) {
383: if (pmp->pm_inusemap)
384: free((caddr_t)pmp->pm_inusemap, M_MSDOSFSFAT);
385: free((caddr_t)pmp, M_MSDOSFSMNT);
386: mp->mnt_data = (qaddr_t)0;
387: }
388: return error;
389: }
390:
391: int
392: pcfs_start(mp, flags, p)
393: struct mount *mp;
394: int flags;
395: struct proc *p;
396: {
397: return 0;
398: }
399:
400: /*
401: * Unmount the filesystem described by mp.
402: */
403: int
404: pcfs_unmount(mp, mntflags, p)
405: struct mount *mp;
406: int mntflags;
407: struct proc *p;
408: {
409: int flags = 0;
410: int error;
411: struct pcfsmount *pmp = (struct pcfsmount *)mp->mnt_data;
412: struct vnode *vp = pmp->pm_devvp;
413:
414: if (mntflags & MNT_FORCE) {
415: if (!pcfsdoforce)
416: return EINVAL;
417: flags |= FORCECLOSE;
418: }
419: mntflushbuf(mp, 0);
420: if (mntinvalbuf(mp))
421: return EBUSY;
422: #if defined(QUOTA)
423: #endif /* defined(QUOTA) */
424: if (error = vflush(mp, NULLVP, flags))
425: return error;
426: pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON;
427: #if defined(PCFSDEBUG)
428: printf("pcfs_umount(): just before calling VOP_CLOSE()\n");
429: printf("flag %08x, usecount %d, writecount %d, holdcnt %d\n",
430: vp->v_flag, vp->v_usecount, vp->v_writecount, vp->v_holdcnt);
431: printf("lastr %d, id %d, mount %08x, op %08x\n",
432: vp->v_lastr, vp->v_id, vp->v_mount, vp->v_op);
433: printf("freef %08x, freeb %08x, mountf %08x, mountb %08x\n",
434: vp->v_freef, vp->v_freeb, vp->v_mountf, vp->v_mountb);
435: printf("cleanblkhd %08x, dirtyblkhd %08x, numoutput %d, type %d\n",
436: vp->v_cleanblkhd, vp->v_dirtyblkhd, vp->v_numoutput, vp->v_type);
437: printf("union %08x, tag %d, data[0] %08x, data[1] %08x\n",
438: vp->v_socket, vp->v_tag, vp->v_data[0], vp->v_data[1]);
439: #endif /* defined(PCFSDEBUG) */
440: error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD|FWRITE,
441: NOCRED, p);
442: vrele(pmp->pm_devvp);
443: free((caddr_t)pmp->pm_inusemap, M_MSDOSFSFAT);
444: free((caddr_t)pmp, M_MSDOSFSMNT);
445: mp->mnt_data = (qaddr_t)0;
446: mp->mnt_flag &= ~MNT_LOCAL;
447: return error;
448: }
449:
450: int
451: pcfs_root(mp, vpp)
452: struct mount *mp;
453: struct vnode **vpp;
454: {
455: struct denode *ndep;
456: struct pcfsmount *pmp = (struct pcfsmount *)(mp->mnt_data);
457: int error;
458:
459: error = deget(pmp, PCFSROOT, PCFSROOT_OFS, NULL, &ndep);
460: #if defined(PCFSDEBUG)
461: printf("pcfs_root(); mp %08x, pmp %08x, ndep %08x, vp %08x\n",
462: mp, pmp, ndep, DETOV(ndep));
463: #endif /* defined(PCFSDEBUG) */
464: if (error == 0)
465: *vpp = DETOV(ndep);
466: return error;
467: }
468:
469: int
470: pcfs_quotactl(mp, cmds, uid, arg, p)
471: struct mount *mp;
472: int cmds;
473: uid_t uid;
474: caddr_t arg;
475: struct proc *p;
476: {
477: #if defined(QUOTA)
478: #else
479: return EOPNOTSUPP;
480: #endif /* defined(QUOTA) */
481: }
482:
483: int
484: pcfs_statfs(mp, sbp, p)
485: struct mount *mp;
486: struct statfs *sbp;
487: struct proc *p;
488: {
489: struct pcfsmount *pmp = (struct pcfsmount *)mp->mnt_data;
490:
491: /*
492: * Fill in the stat block.
493: */
494: sbp->f_type = MOUNT_MSDOS;
495: sbp->f_fsize = pmp->pm_bpcluster;
496: sbp->f_bsize = pmp->pm_bpcluster;
497: sbp->f_blocks = pmp->pm_nmbrofclusters;
498: sbp->f_bfree = pmp->pm_freeclustercount;
499: sbp->f_bavail = pmp->pm_freeclustercount;
500: sbp->f_files = pmp->pm_RootDirEnts;
501: sbp->f_ffree = 0; /* what to put in here? */
502:
503: /*
504: * Copy the mounted on and mounted from names into
505: * the passed in stat block, if it is not the one
506: * in the mount structure.
507: */
508: if (sbp != &mp->mnt_stat) {
509: bcopy((caddr_t)mp->mnt_stat.f_mntonname,
510: (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
511: bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
512: (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
513: }
514: return 0;
515: }
516:
517: int
518: pcfs_sync(mp, waitfor)
519: struct mount *mp;
520: int waitfor;
521: {
522: struct vnode *vp;
523: struct denode *dep;
524: struct pcfsmount *pmp;
525: int error;
526: int allerror = 0;
527:
528: pmp = (struct pcfsmount *)mp->mnt_data;
529:
530: /*
531: * If we ever switch to not updating all of the fats
532: * all the time, this would be the place to update them
533: * from the first one.
534: */
535: if (pmp->pm_fmod) {
536: if (pmp->pm_ronly) {
537: printf("pcfs_sync(): writing to readonly filesystem\n");
538: return EINVAL;
539: } else {
540: /* update fats here */
541: }
542: }
543:
544: /*
545: * Go thru in memory denodes and write them out along
546: * with unwritten file blocks.
547: */
548: loop:
549: for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
550: if (vp->v_mount != mp) /* not ours anymore */
551: goto loop;
552: if (VOP_ISLOCKED(vp)) /* file is busy */
553: continue;
554: dep = VTODE(vp);
555: if ((dep->de_flag & DEUPD) == 0 && vp->v_dirtyblkhd == NULL)
556: continue;
557: if (vget(vp)) /* not there anymore? */
558: goto loop;
559: if (vp->v_dirtyblkhd) /* flush dirty file blocks */
560: vflushbuf(vp, 0);
561: if ((dep->de_flag & DEUPD) &&
562: (error = deupdat(dep, &time, 0)))
563: allerror = error;
564: vput(vp); /* done with this one */
565: }
566:
567: /*
568: * Flush filesystem control info.
569: */
570: vflushbuf(pmp->pm_devvp, waitfor == MNT_WAIT ? B_SYNC : 0);
571: return allerror;
572: }
573:
574: int
575: pcfs_fhtovp (mp, fhp, vpp)
576: struct mount *mp;
577: struct fid *fhp;
578: struct vnode **vpp;
579: {
580: struct pcfsmount *pmp = (struct pcfsmount *)mp->mnt_data;
581: struct defid *defhp = (struct defid *)fhp;
582: struct denode *dep;
583: int error;
584:
585: error = deget (pmp, defhp->defid_dirclust, defhp->defid_dirofs,
586: NULL, &dep);
587: if (error)
588: return (error);
589: *vpp = DETOV (dep);
590: return (0);
591: }
592:
593:
594: int
595: pcfs_vptofh (vp, fhp)
596: struct vnode *vp;
597: struct fid *fhp;
598: {
599: struct denode *dep = VTODE(vp);
600: struct defid *defhp = (struct defid *)fhp;
601:
602: defhp->defid_len = sizeof(struct defid);
603: defhp->defid_dirclust = dep->de_dirclust;
604: defhp->defid_dirofs = dep->de_diroffset;
605: /* defhp->defid_gen = ip->i_gen; */
606: return (0);
607: }
608:
609: struct vfsops pcfs_vfsops = {
610: pcfs_mount,
611: pcfs_start,
612: pcfs_unmount,
613: pcfs_root,
614: pcfs_quotactl,
615: pcfs_statfs,
616: pcfs_sync,
617: pcfs_fhtovp,
618: pcfs_vptofh,
619: pcfs_init
620: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.