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