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