ffs_vfsops.c revision 1.4 1 /* $NetBSD: ffs_vfsops.c,v 1.4 1994/06/29 06:46:37 cgd Exp $ */
2
3 /*
4 * Copyright (c) 1989, 1991, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)ffs_vfsops.c 8.8 (Berkeley) 4/18/94
36 */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/namei.h>
41 #include <sys/proc.h>
42 #include <sys/kernel.h>
43 #include <sys/vnode.h>
44 #include <sys/socket.h>
45 #include <sys/mount.h>
46 #include <sys/buf.h>
47 #include <sys/mbuf.h>
48 #include <sys/file.h>
49 #include <sys/disklabel.h>
50 #include <sys/ioctl.h>
51 #include <sys/errno.h>
52 #include <sys/malloc.h>
53
54 #include <miscfs/specfs/specdev.h>
55
56 #include <ufs/ufs/quota.h>
57 #include <ufs/ufs/ufsmount.h>
58 #include <ufs/ufs/inode.h>
59 #include <ufs/ufs/ufs_extern.h>
60
61 #include <ufs/ffs/fs.h>
62 #include <ufs/ffs/ffs_extern.h>
63
64 int ffs_sbupdate __P((struct ufsmount *, int));
65
66 struct vfsops ufs_vfsops = {
67 MOUNT_UFS,
68 ffs_mount,
69 ufs_start,
70 ffs_unmount,
71 ufs_root,
72 ufs_quotactl,
73 ffs_statfs,
74 ffs_sync,
75 ffs_vget,
76 ffs_fhtovp,
77 ffs_vptofh,
78 ffs_init,
79 };
80
81 extern u_long nextgennumber;
82
83 /*
84 * Called by main() when ufs is going to be mounted as root.
85 *
86 * Name is updated by mount(8) after booting.
87 */
88 #define ROOTNAME "root_device"
89
90 ffs_mountroot()
91 {
92 extern struct vnode *rootvp;
93 register struct fs *fs;
94 register struct mount *mp;
95 struct proc *p = curproc; /* XXX */
96 struct ufsmount *ump;
97 u_int size;
98 int error;
99
100 /*
101 * Get vnodes for swapdev and rootdev.
102 */
103 if (bdevvp(swapdev, &swapdev_vp) || bdevvp(rootdev, &rootvp))
104 panic("ffs_mountroot: can't setup bdevvp's");
105
106 mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK);
107 bzero((char *)mp, (u_long)sizeof(struct mount));
108 mp->mnt_op = &ufs_vfsops;
109 mp->mnt_flag = MNT_RDONLY;
110 if (error = ffs_mountfs(rootvp, mp, p)) {
111 free(mp, M_MOUNT);
112 return (error);
113 }
114 if (error = vfs_lock(mp)) {
115 (void)ffs_unmount(mp, 0, p);
116 free(mp, M_MOUNT);
117 return (error);
118 }
119 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
120 mp->mnt_flag |= MNT_ROOTFS;
121 mp->mnt_vnodecovered = NULLVP;
122 ump = VFSTOUFS(mp);
123 fs = ump->um_fs;
124 bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt));
125 fs->fs_fsmnt[0] = '/';
126 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
127 MNAMELEN);
128 (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
129 &size);
130 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
131 (void)ffs_statfs(mp, &mp->mnt_stat, p);
132 vfs_unlock(mp);
133 inittodr(fs->fs_time);
134 return (0);
135 }
136
137 /*
138 * VFS Operations.
139 *
140 * mount system call
141 */
142 int
143 ffs_mount(mp, path, data, ndp, p)
144 register struct mount *mp;
145 char *path;
146 caddr_t data;
147 struct nameidata *ndp;
148 struct proc *p;
149 {
150 struct vnode *devvp;
151 struct ufs_args args;
152 struct ufsmount *ump;
153 register struct fs *fs;
154 u_int size;
155 int error, flags;
156
157 if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
158 return (error);
159 /*
160 * If updating, check whether changing from read-only to
161 * read/write; if there is no device name, that's all we do.
162 */
163 if (mp->mnt_flag & MNT_UPDATE) {
164 ump = VFSTOUFS(mp);
165 fs = ump->um_fs;
166 error = 0;
167 if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
168 flags = WRITECLOSE;
169 if (mp->mnt_flag & MNT_FORCE)
170 flags |= FORCECLOSE;
171 if (vfs_busy(mp))
172 return (EBUSY);
173 error = ffs_flushfiles(mp, flags, p);
174 vfs_unbusy(mp);
175 }
176 if (!error && (mp->mnt_flag & MNT_RELOAD))
177 error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p);
178 if (error)
179 return (error);
180 if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR))
181 fs->fs_ronly = 0;
182 if (args.fspec == 0) {
183 /*
184 * Process export requests.
185 */
186 return (vfs_export(mp, &ump->um_export, &args.export));
187 }
188 }
189 /*
190 * Not an update, or updating the name: look up the name
191 * and verify that it refers to a sensible block device.
192 */
193 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
194 if (error = namei(ndp))
195 return (error);
196 devvp = ndp->ni_vp;
197
198 if (devvp->v_type != VBLK) {
199 vrele(devvp);
200 return (ENOTBLK);
201 }
202 if (major(devvp->v_rdev) >= nblkdev) {
203 vrele(devvp);
204 return (ENXIO);
205 }
206 if ((mp->mnt_flag & MNT_UPDATE) == 0)
207 error = ffs_mountfs(devvp, mp, p);
208 else {
209 if (devvp != ump->um_devvp)
210 error = EINVAL; /* needs translation */
211 else
212 vrele(devvp);
213 }
214 if (error) {
215 vrele(devvp);
216 return (error);
217 }
218 ump = VFSTOUFS(mp);
219 fs = ump->um_fs;
220 (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
221 bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
222 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
223 MNAMELEN);
224 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
225 &size);
226 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
227 (void)ffs_statfs(mp, &mp->mnt_stat, p);
228 return (0);
229 }
230
231 /*
232 * Reload all incore data for a filesystem (used after running fsck on
233 * the root filesystem and finding things to fix). The filesystem must
234 * be mounted read-only.
235 *
236 * Things to do to update the mount:
237 * 1) invalidate all cached meta-data.
238 * 2) re-read superblock from disk.
239 * 3) re-read summary information from disk.
240 * 4) invalidate all inactive vnodes.
241 * 5) invalidate all cached file data.
242 * 6) re-read inode data for all active vnodes.
243 */
244 ffs_reload(mountp, cred, p)
245 register struct mount *mountp;
246 struct ucred *cred;
247 struct proc *p;
248 {
249 register struct vnode *vp, *nvp, *devvp;
250 struct inode *ip;
251 struct csum *space;
252 struct buf *bp;
253 struct fs *fs;
254 struct partinfo dpart;
255 int i, blks, size, error;
256
257 if ((mountp->mnt_flag & MNT_RDONLY) == 0)
258 return (EINVAL);
259 /*
260 * Step 1: invalidate all cached meta-data.
261 */
262 devvp = VFSTOUFS(mountp)->um_devvp;
263 if (vinvalbuf(devvp, 0, cred, p, 0, 0))
264 panic("ffs_reload: dirty1");
265 /*
266 * Step 2: re-read superblock from disk.
267 */
268 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
269 size = DEV_BSIZE;
270 else
271 size = dpart.disklab->d_secsize;
272 if (error = bread(devvp, (daddr_t)(SBOFF / size), SBSIZE, NOCRED, &bp))
273 return (error);
274 fs = (struct fs *)bp->b_data;
275 if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
276 fs->fs_bsize < sizeof(struct fs)) {
277 brelse(bp);
278 return (EIO); /* XXX needs translation */
279 }
280 fs = VFSTOUFS(mountp)->um_fs;
281 bcopy(&fs->fs_csp[0], &((struct fs *)bp->b_data)->fs_csp[0],
282 sizeof(fs->fs_csp));
283 bcopy(bp->b_data, fs, (u_int)fs->fs_sbsize);
284 if (fs->fs_sbsize < SBSIZE)
285 bp->b_flags |= B_INVAL;
286 brelse(bp);
287 mountp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
288 ffs_oldfscompat(fs);
289 /*
290 * Step 3: re-read summary information from disk.
291 */
292 blks = howmany(fs->fs_cssize, fs->fs_fsize);
293 space = fs->fs_csp[0];
294 for (i = 0; i < blks; i += fs->fs_frag) {
295 size = fs->fs_bsize;
296 if (i + fs->fs_frag > blks)
297 size = (blks - i) * fs->fs_fsize;
298 if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
299 NOCRED, &bp))
300 return (error);
301 bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size);
302 brelse(bp);
303 }
304 loop:
305 for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
306 nvp = vp->v_mntvnodes.le_next;
307 /*
308 * Step 4: invalidate all inactive vnodes.
309 */
310 if (vp->v_usecount == 0) {
311 vgone(vp);
312 continue;
313 }
314 /*
315 * Step 5: invalidate all cached file data.
316 */
317 if (vget(vp, 1))
318 goto loop;
319 if (vinvalbuf(vp, 0, cred, p, 0, 0))
320 panic("ffs_reload: dirty2");
321 /*
322 * Step 6: re-read inode data for all active vnodes.
323 */
324 ip = VTOI(vp);
325 if (error =
326 bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
327 (int)fs->fs_bsize, NOCRED, &bp)) {
328 vput(vp);
329 return (error);
330 }
331 ip->i_din = *((struct dinode *)bp->b_data +
332 ino_to_fsbo(fs, ip->i_number));
333 brelse(bp);
334 vput(vp);
335 if (vp->v_mount != mountp)
336 goto loop;
337 }
338 return (0);
339 }
340
341 /*
342 * Common code for mount and mountroot
343 */
344 int
345 ffs_mountfs(devvp, mp, p)
346 register struct vnode *devvp;
347 struct mount *mp;
348 struct proc *p;
349 {
350 register struct ufsmount *ump;
351 struct buf *bp;
352 register struct fs *fs;
353 dev_t dev = devvp->v_rdev;
354 struct partinfo dpart;
355 caddr_t base, space;
356 int blks;
357 int error, i, size;
358 int ronly;
359 extern struct vnode *rootvp;
360
361 /*
362 * Disallow multiple mounts of the same device.
363 * Disallow mounting of a device that is currently in use
364 * (except for root, which might share swap device for miniroot).
365 * Flush out any old buffers remaining from a previous use.
366 */
367 if (error = vfs_mountedon(devvp))
368 return (error);
369 if (vcount(devvp) > 1 && devvp != rootvp)
370 return (EBUSY);
371 if (error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0))
372 return (error);
373
374 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
375 if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p))
376 return (error);
377 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
378 size = DEV_BSIZE;
379 else
380 size = dpart.disklab->d_secsize;
381
382 bp = NULL;
383 ump = NULL;
384 if (error = bread(devvp, (daddr_t)(SBOFF / size), SBSIZE, NOCRED, &bp))
385 goto out;
386 fs = (struct fs *)bp->b_data;
387 if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
388 fs->fs_bsize < sizeof(struct fs)) {
389 error = EINVAL; /* XXX needs translation */
390 goto out;
391 }
392 /* XXX updating 4.2 FFS superblocks trashes rotational layout tables */
393 if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) {
394 error = EROFS; /* XXX what should be returned? */
395 goto out;
396 }
397 ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
398 bzero((caddr_t)ump, sizeof *ump);
399 ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT,
400 M_WAITOK);
401 bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
402 if (fs->fs_sbsize < SBSIZE)
403 bp->b_flags |= B_INVAL;
404 brelse(bp);
405 bp = NULL;
406 fs = ump->um_fs;
407 fs->fs_ronly = ronly;
408 if (ronly == 0)
409 fs->fs_fmod = 1;
410 blks = howmany(fs->fs_cssize, fs->fs_fsize);
411 base = space = malloc((u_long)fs->fs_cssize, M_UFSMNT,
412 M_WAITOK);
413 for (i = 0; i < blks; i += fs->fs_frag) {
414 size = fs->fs_bsize;
415 if (i + fs->fs_frag > blks)
416 size = (blks - i) * fs->fs_fsize;
417 error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
418 NOCRED, &bp);
419 if (error) {
420 free(base, M_UFSMNT);
421 goto out;
422 }
423 bcopy(bp->b_data, space, (u_int)size);
424 fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
425 space += size;
426 brelse(bp);
427 bp = NULL;
428 }
429 mp->mnt_data = (qaddr_t)ump;
430 mp->mnt_stat.f_fsid.val[0] = (long)dev;
431 mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_UFS);
432 mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
433 mp->mnt_flag |= MNT_LOCAL;
434 ump->um_mountp = mp;
435 ump->um_dev = dev;
436 ump->um_devvp = devvp;
437 ump->um_nindir = fs->fs_nindir;
438 ump->um_bptrtodb = fs->fs_fsbtodb;
439 ump->um_seqinc = fs->fs_frag;
440 for (i = 0; i < MAXQUOTAS; i++)
441 ump->um_quotas[i] = NULLVP;
442 devvp->v_specflags |= SI_MOUNTEDON;
443 ffs_oldfscompat(fs);
444 return (0);
445 out:
446 if (bp)
447 brelse(bp);
448 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
449 if (ump) {
450 free(ump->um_fs, M_UFSMNT);
451 free(ump, M_UFSMNT);
452 mp->mnt_data = (qaddr_t)0;
453 }
454 return (error);
455 }
456
457 /*
458 * Sanity checks for old file systems.
459 *
460 * XXX - goes away some day.
461 */
462 ffs_oldfscompat(fs)
463 struct fs *fs;
464 {
465 int i;
466
467 fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */
468 fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */
469 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
470 fs->fs_nrpos = 8; /* XXX */
471 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
472 quad_t sizepb = fs->fs_bsize; /* XXX */
473 /* XXX */
474 fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */
475 for (i = 0; i < NIADDR; i++) { /* XXX */
476 sizepb *= NINDIR(fs); /* XXX */
477 fs->fs_maxfilesize += sizepb; /* XXX */
478 } /* XXX */
479 fs->fs_qbmask = ~fs->fs_bmask; /* XXX */
480 fs->fs_qfmask = ~fs->fs_fmask; /* XXX */
481 } /* XXX */
482 return (0);
483 }
484
485 /*
486 * unmount system call
487 */
488 int
489 ffs_unmount(mp, mntflags, p)
490 struct mount *mp;
491 int mntflags;
492 struct proc *p;
493 {
494 register struct ufsmount *ump;
495 register struct fs *fs;
496 int error, flags, ronly;
497
498 flags = 0;
499 if (mntflags & MNT_FORCE) {
500 if (mp->mnt_flag & MNT_ROOTFS)
501 return (EINVAL);
502 flags |= FORCECLOSE;
503 }
504 if (error = ffs_flushfiles(mp, flags, p))
505 return (error);
506 ump = VFSTOUFS(mp);
507 fs = ump->um_fs;
508 ronly = !fs->fs_ronly;
509 ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
510 error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE,
511 NOCRED, p);
512 vrele(ump->um_devvp);
513 free(fs->fs_csp[0], M_UFSMNT);
514 free(fs, M_UFSMNT);
515 free(ump, M_UFSMNT);
516 mp->mnt_data = (qaddr_t)0;
517 mp->mnt_flag &= ~MNT_LOCAL;
518 return (error);
519 }
520
521 /*
522 * Flush out all the files in a filesystem.
523 */
524 ffs_flushfiles(mp, flags, p)
525 register struct mount *mp;
526 int flags;
527 struct proc *p;
528 {
529 extern int doforce;
530 register struct ufsmount *ump;
531 int i, error;
532
533 if (!doforce)
534 flags &= ~FORCECLOSE;
535 ump = VFSTOUFS(mp);
536 #ifdef QUOTA
537 if (mp->mnt_flag & MNT_QUOTA) {
538 if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags))
539 return (error);
540 for (i = 0; i < MAXQUOTAS; i++) {
541 if (ump->um_quotas[i] == NULLVP)
542 continue;
543 quotaoff(p, mp, i);
544 }
545 /*
546 * Here we fall through to vflush again to ensure
547 * that we have gotten rid of all the system vnodes.
548 */
549 }
550 #endif
551 error = vflush(mp, NULLVP, flags);
552 return (error);
553 }
554
555 /*
556 * Get file system statistics.
557 */
558 int
559 ffs_statfs(mp, sbp, p)
560 struct mount *mp;
561 register struct statfs *sbp;
562 struct proc *p;
563 {
564 register struct ufsmount *ump;
565 register struct fs *fs;
566
567 ump = VFSTOUFS(mp);
568 fs = ump->um_fs;
569 if (fs->fs_magic != FS_MAGIC)
570 panic("ffs_statfs");
571 #ifdef COMPAT_09
572 sbp->f_type = 1;
573 #else
574 sbp->f_type = 0;
575 #endif
576 sbp->f_bsize = fs->fs_fsize;
577 sbp->f_iosize = fs->fs_bsize;
578 sbp->f_blocks = fs->fs_dsize;
579 sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
580 fs->fs_cstotal.cs_nffree;
581 sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) -
582 (fs->fs_dsize - sbp->f_bfree);
583 sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO;
584 sbp->f_ffree = fs->fs_cstotal.cs_nifree;
585 if (sbp != &mp->mnt_stat) {
586 bcopy((caddr_t)mp->mnt_stat.f_mntonname,
587 (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
588 bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
589 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
590 }
591 strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN);
592 sbp->f_fstypename[MFSNAMELEN] = '\0';
593 return (0);
594 }
595
596 /*
597 * Go through the disk queues to initiate sandbagged IO;
598 * go through the inodes to write those that have been modified;
599 * initiate the writing of the super block if it has been modified.
600 *
601 * Note: we are always called with the filesystem marked `MPBUSY'.
602 */
603 int
604 ffs_sync(mp, waitfor, cred, p)
605 struct mount *mp;
606 int waitfor;
607 struct ucred *cred;
608 struct proc *p;
609 {
610 register struct vnode *vp;
611 register struct inode *ip;
612 register struct ufsmount *ump = VFSTOUFS(mp);
613 register struct fs *fs;
614 int error, allerror = 0;
615
616 fs = ump->um_fs;
617 /*
618 * Write back modified superblock.
619 * Consistency check that the superblock
620 * is still in the buffer cache.
621 */
622 if (fs->fs_fmod != 0) {
623 if (fs->fs_ronly != 0) { /* XXX */
624 printf("fs = %s\n", fs->fs_fsmnt);
625 panic("update: rofs mod");
626 }
627 fs->fs_fmod = 0;
628 fs->fs_time = time.tv_sec;
629 allerror = ffs_sbupdate(ump, waitfor);
630 }
631 /*
632 * Write back each (modified) inode.
633 */
634 loop:
635 for (vp = mp->mnt_vnodelist.lh_first;
636 vp != NULL;
637 vp = vp->v_mntvnodes.le_next) {
638 /*
639 * If the vnode that we are about to sync is no longer
640 * associated with this mount point, start over.
641 */
642 if (vp->v_mount != mp)
643 goto loop;
644 if (VOP_ISLOCKED(vp))
645 continue;
646 ip = VTOI(vp);
647 if ((ip->i_flag &
648 (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
649 vp->v_dirtyblkhd.lh_first == NULL)
650 continue;
651 if (vget(vp, 1))
652 goto loop;
653 if (error = VOP_FSYNC(vp, cred, waitfor, p))
654 allerror = error;
655 vput(vp);
656 }
657 /*
658 * Force stale file system control information to be flushed.
659 */
660 if (error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p))
661 allerror = error;
662 #ifdef QUOTA
663 qsync(mp);
664 #endif
665 return (allerror);
666 }
667
668 /*
669 * Look up a FFS dinode number to find its incore vnode, otherwise read it
670 * in from disk. If it is in core, wait for the lock bit to clear, then
671 * return the inode locked. Detection and handling of mount points must be
672 * done by the calling routine.
673 */
674 int
675 ffs_vget(mp, ino, vpp)
676 struct mount *mp;
677 ino_t ino;
678 struct vnode **vpp;
679 {
680 register struct fs *fs;
681 register struct inode *ip;
682 struct ufsmount *ump;
683 struct buf *bp;
684 struct vnode *vp;
685 dev_t dev;
686 int i, type, error;
687
688 ump = VFSTOUFS(mp);
689 dev = ump->um_dev;
690 if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
691 return (0);
692
693 /* Allocate a new vnode/inode. */
694 if (error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) {
695 *vpp = NULL;
696 return (error);
697 }
698 type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */
699 MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK);
700 bzero((caddr_t)ip, sizeof(struct inode));
701 vp->v_data = ip;
702 ip->i_vnode = vp;
703 ip->i_fs = fs = ump->um_fs;
704 ip->i_dev = dev;
705 ip->i_number = ino;
706 #ifdef QUOTA
707 for (i = 0; i < MAXQUOTAS; i++)
708 ip->i_dquot[i] = NODQUOT;
709 #endif
710 /*
711 * Put it onto its hash chain and lock it so that other requests for
712 * this inode will block if they arrive while we are sleeping waiting
713 * for old data structures to be purged or for the contents of the
714 * disk portion of this inode to be read.
715 */
716 ufs_ihashins(ip);
717
718 /* Read in the disk contents for the inode, copy into the inode. */
719 if (error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
720 (int)fs->fs_bsize, NOCRED, &bp)) {
721 /*
722 * The inode does not contain anything useful, so it would
723 * be misleading to leave it on its hash chain. With mode
724 * still zero, it will be unlinked and returned to the free
725 * list by vput().
726 */
727 vput(vp);
728 brelse(bp);
729 *vpp = NULL;
730 return (error);
731 }
732 ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino));
733 brelse(bp);
734
735 /*
736 * Initialize the vnode from the inode, check for aliases.
737 * Note that the underlying vnode may have changed.
738 */
739 if (error = ufs_vinit(mp, ffs_specop_p, FFS_FIFOOPS, &vp)) {
740 vput(vp);
741 *vpp = NULL;
742 return (error);
743 }
744 /*
745 * Finish inode initialization now that aliasing has been resolved.
746 */
747 ip->i_devvp = ump->um_devvp;
748 VREF(ip->i_devvp);
749 /*
750 * Set up a generation number for this inode if it does not
751 * already have one. This should only happen on old filesystems.
752 */
753 if (ip->i_gen == 0) {
754 if (++nextgennumber < (u_long)time.tv_sec)
755 nextgennumber = time.tv_sec;
756 ip->i_gen = nextgennumber;
757 if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
758 ip->i_flag |= IN_MODIFIED;
759 }
760 /*
761 * Ensure that uid and gid are correct. This is a temporary
762 * fix until fsck has been changed to do the update.
763 */
764 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
765 ip->i_uid = ip->i_din.di_ouid; /* XXX */
766 ip->i_gid = ip->i_din.di_ogid; /* XXX */
767 } /* XXX */
768
769 *vpp = vp;
770 return (0);
771 }
772
773 /*
774 * File handle to vnode
775 *
776 * Have to be really careful about stale file handles:
777 * - check that the inode number is valid
778 * - call ffs_vget() to get the locked inode
779 * - check for an unallocated inode (i_mode == 0)
780 * - check that the given client host has export rights and return
781 * those rights via. exflagsp and credanonp
782 */
783 int
784 ffs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
785 register struct mount *mp;
786 struct fid *fhp;
787 struct mbuf *nam;
788 struct vnode **vpp;
789 int *exflagsp;
790 struct ucred **credanonp;
791 {
792 register struct ufid *ufhp;
793 struct fs *fs;
794
795 ufhp = (struct ufid *)fhp;
796 fs = VFSTOUFS(mp)->um_fs;
797 if (ufhp->ufid_ino < ROOTINO ||
798 ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
799 return (ESTALE);
800 return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp));
801 }
802
803 /*
804 * Vnode pointer to File handle
805 */
806 /* ARGSUSED */
807 ffs_vptofh(vp, fhp)
808 struct vnode *vp;
809 struct fid *fhp;
810 {
811 register struct inode *ip;
812 register struct ufid *ufhp;
813
814 ip = VTOI(vp);
815 ufhp = (struct ufid *)fhp;
816 ufhp->ufid_len = sizeof(struct ufid);
817 ufhp->ufid_ino = ip->i_number;
818 ufhp->ufid_gen = ip->i_gen;
819 return (0);
820 }
821
822 /*
823 * Write a superblock and associated information back to disk.
824 */
825 int
826 ffs_sbupdate(mp, waitfor)
827 struct ufsmount *mp;
828 int waitfor;
829 {
830 register struct fs *fs = mp->um_fs;
831 register struct buf *bp;
832 int blks;
833 caddr_t space;
834 int i, size, error = 0;
835
836 bp = getblk(mp->um_devvp, SBOFF >> (fs->fs_fshift - fs->fs_fsbtodb),
837 (int)fs->fs_sbsize, 0, 0);
838 bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
839 /* Restore compatibility to old file systems. XXX */
840 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
841 ((struct fs *)bp->b_data)->fs_nrpos = -1; /* XXX */
842 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
843 long *lp, tmp; /* XXX */
844 /* XXX */
845 lp = (long *)&((struct fs *)bp->b_data)->fs_qbmask; /* XXX */
846 tmp = lp[4]; /* XXX */
847 for (i = 4; i > 0; i--) /* XXX */
848 lp[i] = lp[i-1]; /* XXX */
849 lp[0] = tmp; /* XXX */
850 } /* XXX */
851 if (waitfor == MNT_WAIT)
852 error = bwrite(bp);
853 else
854 bawrite(bp);
855 blks = howmany(fs->fs_cssize, fs->fs_fsize);
856 space = (caddr_t)fs->fs_csp[0];
857 for (i = 0; i < blks; i += fs->fs_frag) {
858 size = fs->fs_bsize;
859 if (i + fs->fs_frag > blks)
860 size = (blks - i) * fs->fs_fsize;
861 bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
862 size, 0, 0);
863 bcopy(space, bp->b_data, (u_int)size);
864 space += size;
865 if (waitfor == MNT_WAIT)
866 error = bwrite(bp);
867 else
868 bawrite(bp);
869 }
870 return (error);
871 }
872