ffs_vfsops.c revision 1.9 1 /* $NetBSD: ffs_vfsops.c,v 1.9 1994/12/14 13:03:38 mycroft 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.14 (Berkeley) 11/28/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 mode_t accessmode;
157
158 if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
159 return (error);
160 /*
161 * If updating, check whether changing from read-only to
162 * read/write; if there is no device name, that's all we do.
163 */
164 if (mp->mnt_flag & MNT_UPDATE) {
165 ump = VFSTOUFS(mp);
166 fs = ump->um_fs;
167 error = 0;
168 if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
169 flags = WRITECLOSE;
170 if (mp->mnt_flag & MNT_FORCE)
171 flags |= FORCECLOSE;
172 if (vfs_busy(mp))
173 return (EBUSY);
174 error = ffs_flushfiles(mp, flags, p);
175 vfs_unbusy(mp);
176 }
177 if (!error && (mp->mnt_flag & MNT_RELOAD))
178 error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p);
179 if (error)
180 return (error);
181 if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) {
182 /*
183 * If upgrade to read-write by non-root, then verify
184 * that user has necessary permissions on the device.
185 */
186 if (p->p_ucred->cr_uid != 0) {
187 devvp = ump->um_devvp;
188 VOP_LOCK(devvp);
189 if (error = VOP_ACCESS(devvp, VREAD | VWRITE,
190 p->p_ucred, p)) {
191 VOP_UNLOCK(devvp);
192 return (error);
193 }
194 VOP_UNLOCK(devvp);
195 }
196 fs->fs_ronly = 0;
197 }
198 if (args.fspec == 0) {
199 /*
200 * Process export requests.
201 */
202 return (vfs_export(mp, &ump->um_export, &args.export));
203 }
204 }
205 /*
206 * Not an update, or updating the name: look up the name
207 * and verify that it refers to a sensible block device.
208 */
209 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
210 if (error = namei(ndp))
211 return (error);
212 devvp = ndp->ni_vp;
213
214 if (devvp->v_type != VBLK) {
215 vrele(devvp);
216 return (ENOTBLK);
217 }
218 if (major(devvp->v_rdev) >= nblkdev) {
219 vrele(devvp);
220 return (ENXIO);
221 }
222 /*
223 * If mount by non-root, then verify that user has necessary
224 * permissions on the device.
225 */
226 if (p->p_ucred->cr_uid != 0) {
227 accessmode = VREAD;
228 if ((mp->mnt_flag & MNT_RDONLY) == 0)
229 accessmode |= VWRITE;
230 VOP_LOCK(devvp);
231 if (error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p)) {
232 vput(devvp);
233 return (error);
234 }
235 VOP_UNLOCK(devvp);
236 }
237 if ((mp->mnt_flag & MNT_UPDATE) == 0)
238 error = ffs_mountfs(devvp, mp, p);
239 else {
240 if (devvp != ump->um_devvp)
241 error = EINVAL; /* needs translation */
242 else
243 vrele(devvp);
244 }
245 if (error) {
246 vrele(devvp);
247 return (error);
248 }
249 ump = VFSTOUFS(mp);
250 fs = ump->um_fs;
251 (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
252 bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
253 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
254 MNAMELEN);
255 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
256 &size);
257 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
258 (void)ffs_statfs(mp, &mp->mnt_stat, p);
259 return (0);
260 }
261
262 /*
263 * Reload all incore data for a filesystem (used after running fsck on
264 * the root filesystem and finding things to fix). The filesystem must
265 * be mounted read-only.
266 *
267 * Things to do to update the mount:
268 * 1) invalidate all cached meta-data.
269 * 2) re-read superblock from disk.
270 * 3) re-read summary information from disk.
271 * 4) invalidate all inactive vnodes.
272 * 5) invalidate all cached file data.
273 * 6) re-read inode data for all active vnodes.
274 */
275 ffs_reload(mountp, cred, p)
276 register struct mount *mountp;
277 struct ucred *cred;
278 struct proc *p;
279 {
280 register struct vnode *vp, *nvp, *devvp;
281 struct inode *ip;
282 struct csum *space;
283 struct buf *bp;
284 struct fs *fs;
285 struct partinfo dpart;
286 int i, blks, size, error;
287
288 if ((mountp->mnt_flag & MNT_RDONLY) == 0)
289 return (EINVAL);
290 /*
291 * Step 1: invalidate all cached meta-data.
292 */
293 devvp = VFSTOUFS(mountp)->um_devvp;
294 if (vinvalbuf(devvp, 0, cred, p, 0, 0))
295 panic("ffs_reload: dirty1");
296 /*
297 * Step 2: re-read superblock from disk.
298 */
299 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
300 size = DEV_BSIZE;
301 else
302 size = dpart.disklab->d_secsize;
303 if (error = bread(devvp, (daddr_t)(SBOFF / size), SBSIZE, NOCRED, &bp))
304 return (error);
305 fs = (struct fs *)bp->b_data;
306 if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
307 fs->fs_bsize < sizeof(struct fs)) {
308 brelse(bp);
309 return (EIO); /* XXX needs translation */
310 }
311 fs = VFSTOUFS(mountp)->um_fs;
312 bcopy(&fs->fs_csp[0], &((struct fs *)bp->b_data)->fs_csp[0],
313 sizeof(fs->fs_csp));
314 bcopy(bp->b_data, fs, (u_int)fs->fs_sbsize);
315 if (fs->fs_sbsize < SBSIZE)
316 bp->b_flags |= B_INVAL;
317 brelse(bp);
318 mountp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
319 ffs_oldfscompat(fs);
320 /*
321 * Step 3: re-read summary information from disk.
322 */
323 blks = howmany(fs->fs_cssize, fs->fs_fsize);
324 space = fs->fs_csp[0];
325 for (i = 0; i < blks; i += fs->fs_frag) {
326 size = fs->fs_bsize;
327 if (i + fs->fs_frag > blks)
328 size = (blks - i) * fs->fs_fsize;
329 if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
330 NOCRED, &bp))
331 return (error);
332 bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size);
333 brelse(bp);
334 }
335 loop:
336 for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
337 nvp = vp->v_mntvnodes.le_next;
338 /*
339 * Step 4: invalidate all inactive vnodes.
340 */
341 if (vp->v_usecount == 0) {
342 vgone(vp);
343 continue;
344 }
345 /*
346 * Step 5: invalidate all cached file data.
347 */
348 if (vget(vp, 1))
349 goto loop;
350 if (vinvalbuf(vp, 0, cred, p, 0, 0))
351 panic("ffs_reload: dirty2");
352 /*
353 * Step 6: re-read inode data for all active vnodes.
354 */
355 ip = VTOI(vp);
356 if (error =
357 bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
358 (int)fs->fs_bsize, NOCRED, &bp)) {
359 vput(vp);
360 return (error);
361 }
362 ip->i_din = *((struct dinode *)bp->b_data +
363 ino_to_fsbo(fs, ip->i_number));
364 brelse(bp);
365 vput(vp);
366 if (vp->v_mount != mountp)
367 goto loop;
368 }
369 return (0);
370 }
371
372 /*
373 * Common code for mount and mountroot
374 */
375 int
376 ffs_mountfs(devvp, mp, p)
377 register struct vnode *devvp;
378 struct mount *mp;
379 struct proc *p;
380 {
381 register struct ufsmount *ump;
382 struct buf *bp;
383 register struct fs *fs;
384 dev_t dev;
385 struct partinfo dpart;
386 caddr_t base, space;
387 int blks;
388 int error, i, size, ronly;
389 int32_t *lp;
390 struct ucred *cred;
391 extern struct vnode *rootvp;
392 u_int64_t maxfilesize; /* XXX */
393
394 dev = devvp->v_rdev;
395 cred = p ? p->p_ucred : NOCRED;
396 /*
397 * Disallow multiple mounts of the same device.
398 * Disallow mounting of a device that is currently in use
399 * (except for root, which might share swap device for miniroot).
400 * Flush out any old buffers remaining from a previous use.
401 */
402 if (error = vfs_mountedon(devvp))
403 return (error);
404 if (vcount(devvp) > 1 && devvp != rootvp)
405 return (EBUSY);
406 if (error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0))
407 return (error);
408
409 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
410 if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p))
411 return (error);
412 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0)
413 size = DEV_BSIZE;
414 else
415 size = dpart.disklab->d_secsize;
416
417 bp = NULL;
418 ump = NULL;
419 if (error = bread(devvp, (daddr_t)(SBOFF / size), SBSIZE, cred, &bp))
420 goto out;
421 fs = (struct fs *)bp->b_data;
422 if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
423 fs->fs_bsize < sizeof(struct fs)) {
424 error = EINVAL; /* XXX needs translation */
425 goto out;
426 }
427 /* XXX updating 4.2 FFS superblocks trashes rotational layout tables */
428 if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) {
429 error = EROFS; /* XXX what should be returned? */
430 goto out;
431 }
432 ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
433 bzero((caddr_t)ump, sizeof *ump);
434 ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT,
435 M_WAITOK);
436 bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize);
437 if (fs->fs_sbsize < SBSIZE)
438 bp->b_flags |= B_INVAL;
439 brelse(bp);
440 bp = NULL;
441 fs = ump->um_fs;
442 fs->fs_ronly = ronly;
443 if (ronly == 0)
444 fs->fs_fmod = 1;
445 size = fs->fs_cssize;
446 blks = howmany(size, fs->fs_fsize);
447 if (fs->fs_contigsumsize > 0)
448 size += fs->fs_ncg * sizeof(int32_t);
449 base = space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
450 for (i = 0; i < blks; i += fs->fs_frag) {
451 size = fs->fs_bsize;
452 if (i + fs->fs_frag > blks)
453 size = (blks - i) * fs->fs_fsize;
454 if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
455 cred, &bp)) {
456 free(base, M_UFSMNT);
457 goto out;
458 }
459 bcopy(bp->b_data, space, (u_int)size);
460 fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
461 space += size;
462 brelse(bp);
463 bp = NULL;
464 }
465 if (fs->fs_contigsumsize > 0) {
466 fs->fs_maxcluster = lp = (int32_t *)space;
467 for (i = 0; i < fs->fs_ncg; i++)
468 *lp++ = fs->fs_contigsumsize;
469 }
470 mp->mnt_data = (qaddr_t)ump;
471 mp->mnt_stat.f_fsid.val[0] = (long)dev;
472 mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_UFS);
473 mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
474 mp->mnt_flag |= MNT_LOCAL;
475 ump->um_mountp = mp;
476 ump->um_dev = dev;
477 ump->um_devvp = devvp;
478 ump->um_nindir = fs->fs_nindir;
479 ump->um_bptrtodb = fs->fs_fsbtodb;
480 ump->um_seqinc = fs->fs_frag;
481 for (i = 0; i < MAXQUOTAS; i++)
482 ump->um_quotas[i] = NULLVP;
483 devvp->v_specflags |= SI_MOUNTEDON;
484 ffs_oldfscompat(fs);
485 ump->um_savedmaxfilesize = fs->fs_maxfilesize; /* XXX */
486 maxfilesize = (u_int64_t)0x80000000 * fs->fs_bsize - 1; /* XXX */
487 if (fs->fs_maxfilesize > maxfilesize) /* XXX */
488 fs->fs_maxfilesize = maxfilesize; /* XXX */
489 return (0);
490 out:
491 if (bp)
492 brelse(bp);
493 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
494 if (ump) {
495 free(ump->um_fs, M_UFSMNT);
496 free(ump, M_UFSMNT);
497 mp->mnt_data = (qaddr_t)0;
498 }
499 return (error);
500 }
501
502 /*
503 * Sanity checks for old file systems.
504 *
505 * XXX - goes away some day.
506 */
507 ffs_oldfscompat(fs)
508 struct fs *fs;
509 {
510 int i;
511
512 fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */
513 fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */
514 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
515 fs->fs_nrpos = 8; /* XXX */
516 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
517 u_int64_t sizepb = fs->fs_bsize; /* XXX */
518 /* XXX */
519 fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */
520 for (i = 0; i < NIADDR; i++) { /* XXX */
521 sizepb *= NINDIR(fs); /* XXX */
522 fs->fs_maxfilesize += sizepb; /* XXX */
523 } /* XXX */
524 fs->fs_qbmask = ~fs->fs_bmask; /* XXX */
525 fs->fs_qfmask = ~fs->fs_fmask; /* XXX */
526 } /* XXX */
527 return (0);
528 }
529
530 /*
531 * unmount system call
532 */
533 int
534 ffs_unmount(mp, mntflags, p)
535 struct mount *mp;
536 int mntflags;
537 struct proc *p;
538 {
539 register struct ufsmount *ump;
540 register struct fs *fs;
541 int error, flags;
542
543 flags = 0;
544 if (mntflags & MNT_FORCE) {
545 if (mp->mnt_flag & MNT_ROOTFS)
546 return (EINVAL);
547 flags |= FORCECLOSE;
548 }
549 if (error = ffs_flushfiles(mp, flags, p))
550 return (error);
551 ump = VFSTOUFS(mp);
552 fs = ump->um_fs;
553 ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
554 error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE,
555 NOCRED, p);
556 vrele(ump->um_devvp);
557 free(fs->fs_csp[0], M_UFSMNT);
558 free(fs, M_UFSMNT);
559 free(ump, M_UFSMNT);
560 mp->mnt_data = (qaddr_t)0;
561 mp->mnt_flag &= ~MNT_LOCAL;
562 return (error);
563 }
564
565 /*
566 * Flush out all the files in a filesystem.
567 */
568 ffs_flushfiles(mp, flags, p)
569 register struct mount *mp;
570 int flags;
571 struct proc *p;
572 {
573 extern int doforce;
574 register struct ufsmount *ump;
575 int i, error;
576
577 if (!doforce)
578 flags &= ~FORCECLOSE;
579 ump = VFSTOUFS(mp);
580 #ifdef QUOTA
581 if (mp->mnt_flag & MNT_QUOTA) {
582 if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags))
583 return (error);
584 for (i = 0; i < MAXQUOTAS; i++) {
585 if (ump->um_quotas[i] == NULLVP)
586 continue;
587 quotaoff(p, mp, i);
588 }
589 /*
590 * Here we fall through to vflush again to ensure
591 * that we have gotten rid of all the system vnodes.
592 */
593 }
594 #endif
595 error = vflush(mp, NULLVP, flags);
596 return (error);
597 }
598
599 /*
600 * Get file system statistics.
601 */
602 int
603 ffs_statfs(mp, sbp, p)
604 struct mount *mp;
605 register struct statfs *sbp;
606 struct proc *p;
607 {
608 register struct ufsmount *ump;
609 register struct fs *fs;
610
611 ump = VFSTOUFS(mp);
612 fs = ump->um_fs;
613 if (fs->fs_magic != FS_MAGIC)
614 panic("ffs_statfs");
615 #ifdef COMPAT_09
616 sbp->f_type = 1;
617 #else
618 sbp->f_type = 0;
619 #endif
620 sbp->f_bsize = fs->fs_fsize;
621 sbp->f_iosize = fs->fs_bsize;
622 sbp->f_blocks = fs->fs_dsize;
623 sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
624 fs->fs_cstotal.cs_nffree;
625 sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) -
626 (fs->fs_dsize - sbp->f_bfree);
627 sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO;
628 sbp->f_ffree = fs->fs_cstotal.cs_nifree;
629 if (sbp != &mp->mnt_stat) {
630 bcopy((caddr_t)mp->mnt_stat.f_mntonname,
631 (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
632 bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
633 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
634 }
635 strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN);
636 sbp->f_fstypename[MFSNAMELEN] = '\0';
637 return (0);
638 }
639
640 /*
641 * Go through the disk queues to initiate sandbagged IO;
642 * go through the inodes to write those that have been modified;
643 * initiate the writing of the super block if it has been modified.
644 *
645 * Note: we are always called with the filesystem marked `MPBUSY'.
646 */
647 int
648 ffs_sync(mp, waitfor, cred, p)
649 struct mount *mp;
650 int waitfor;
651 struct ucred *cred;
652 struct proc *p;
653 {
654 register struct vnode *vp;
655 register struct inode *ip;
656 register struct ufsmount *ump = VFSTOUFS(mp);
657 register struct fs *fs;
658 int error, allerror = 0;
659
660 fs = ump->um_fs;
661 /*
662 * Write back modified superblock.
663 * Consistency check that the superblock
664 * is still in the buffer cache.
665 */
666 if (fs->fs_fmod != 0) {
667 if (fs->fs_ronly != 0) { /* XXX */
668 printf("fs = %s\n", fs->fs_fsmnt);
669 panic("update: rofs mod");
670 }
671 fs->fs_fmod = 0;
672 fs->fs_time = time.tv_sec;
673 allerror = ffs_sbupdate(ump, waitfor);
674 }
675 /*
676 * Write back each (modified) inode.
677 */
678 loop:
679 for (vp = mp->mnt_vnodelist.lh_first;
680 vp != NULL;
681 vp = vp->v_mntvnodes.le_next) {
682 /*
683 * If the vnode that we are about to sync is no longer
684 * associated with this mount point, start over.
685 */
686 if (vp->v_mount != mp)
687 goto loop;
688 if (VOP_ISLOCKED(vp))
689 continue;
690 ip = VTOI(vp);
691 if ((ip->i_flag &
692 (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
693 vp->v_dirtyblkhd.lh_first == NULL)
694 continue;
695 if (vget(vp, 1))
696 goto loop;
697 if (error = VOP_FSYNC(vp, cred, waitfor, p))
698 allerror = error;
699 vput(vp);
700 }
701 /*
702 * Force stale file system control information to be flushed.
703 */
704 if (error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p))
705 allerror = error;
706 #ifdef QUOTA
707 qsync(mp);
708 #endif
709 return (allerror);
710 }
711
712 /*
713 * Look up a FFS dinode number to find its incore vnode, otherwise read it
714 * in from disk. If it is in core, wait for the lock bit to clear, then
715 * return the inode locked. Detection and handling of mount points must be
716 * done by the calling routine.
717 */
718 int
719 ffs_vget(mp, ino, vpp)
720 struct mount *mp;
721 ino_t ino;
722 struct vnode **vpp;
723 {
724 register struct fs *fs;
725 register struct inode *ip;
726 struct ufsmount *ump;
727 struct buf *bp;
728 struct vnode *vp;
729 dev_t dev;
730 int i, type, error;
731
732 ump = VFSTOUFS(mp);
733 dev = ump->um_dev;
734 if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
735 return (0);
736
737 /* Allocate a new vnode/inode. */
738 if (error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) {
739 *vpp = NULL;
740 return (error);
741 }
742 type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */
743 MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK);
744 bzero((caddr_t)ip, sizeof(struct inode));
745 vp->v_data = ip;
746 ip->i_vnode = vp;
747 ip->i_fs = fs = ump->um_fs;
748 ip->i_dev = dev;
749 ip->i_number = ino;
750 #ifdef QUOTA
751 for (i = 0; i < MAXQUOTAS; i++)
752 ip->i_dquot[i] = NODQUOT;
753 #endif
754 /*
755 * Put it onto its hash chain and lock it so that other requests for
756 * this inode will block if they arrive while we are sleeping waiting
757 * for old data structures to be purged or for the contents of the
758 * disk portion of this inode to be read.
759 */
760 ufs_ihashins(ip);
761
762 /* Read in the disk contents for the inode, copy into the inode. */
763 if (error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
764 (int)fs->fs_bsize, NOCRED, &bp)) {
765 /*
766 * The inode does not contain anything useful, so it would
767 * be misleading to leave it on its hash chain. With mode
768 * still zero, it will be unlinked and returned to the free
769 * list by vput().
770 */
771 vput(vp);
772 brelse(bp);
773 *vpp = NULL;
774 return (error);
775 }
776 ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino));
777 brelse(bp);
778
779 /*
780 * Initialize the vnode from the inode, check for aliases.
781 * Note that the underlying vnode may have changed.
782 */
783 if (error = ufs_vinit(mp, ffs_specop_p, FFS_FIFOOPS, &vp)) {
784 vput(vp);
785 *vpp = NULL;
786 return (error);
787 }
788 /*
789 * Finish inode initialization now that aliasing has been resolved.
790 */
791 ip->i_devvp = ump->um_devvp;
792 VREF(ip->i_devvp);
793 /*
794 * Set up a generation number for this inode if it does not
795 * already have one. This should only happen on old filesystems.
796 */
797 if (ip->i_gen == 0) {
798 if (++nextgennumber < (u_long)time.tv_sec)
799 nextgennumber = time.tv_sec;
800 ip->i_gen = nextgennumber;
801 if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
802 ip->i_flag |= IN_MODIFIED;
803 }
804 /*
805 * Ensure that uid and gid are correct. This is a temporary
806 * fix until fsck has been changed to do the update.
807 */
808 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
809 ip->i_uid = ip->i_din.di_ouid; /* XXX */
810 ip->i_gid = ip->i_din.di_ogid; /* XXX */
811 } /* XXX */
812
813 *vpp = vp;
814 return (0);
815 }
816
817 /*
818 * File handle to vnode
819 *
820 * Have to be really careful about stale file handles:
821 * - check that the inode number is valid
822 * - call ffs_vget() to get the locked inode
823 * - check for an unallocated inode (i_mode == 0)
824 * - check that the given client host has export rights and return
825 * those rights via. exflagsp and credanonp
826 */
827 int
828 ffs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
829 register struct mount *mp;
830 struct fid *fhp;
831 struct mbuf *nam;
832 struct vnode **vpp;
833 int *exflagsp;
834 struct ucred **credanonp;
835 {
836 register struct ufid *ufhp;
837 struct fs *fs;
838
839 ufhp = (struct ufid *)fhp;
840 fs = VFSTOUFS(mp)->um_fs;
841 if (ufhp->ufid_ino < ROOTINO ||
842 ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
843 return (ESTALE);
844 return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp));
845 }
846
847 /*
848 * Vnode pointer to File handle
849 */
850 /* ARGSUSED */
851 ffs_vptofh(vp, fhp)
852 struct vnode *vp;
853 struct fid *fhp;
854 {
855 register struct inode *ip;
856 register struct ufid *ufhp;
857
858 ip = VTOI(vp);
859 ufhp = (struct ufid *)fhp;
860 ufhp->ufid_len = sizeof(struct ufid);
861 ufhp->ufid_ino = ip->i_number;
862 ufhp->ufid_gen = ip->i_gen;
863 return (0);
864 }
865
866 /*
867 * Write a superblock and associated information back to disk.
868 */
869 int
870 ffs_sbupdate(mp, waitfor)
871 struct ufsmount *mp;
872 int waitfor;
873 {
874 register struct fs *dfs, *fs = mp->um_fs;
875 register struct buf *bp;
876 int blks;
877 caddr_t space;
878 int i, size, error = 0;
879
880 bp = getblk(mp->um_devvp, SBOFF >> (fs->fs_fshift - fs->fs_fsbtodb),
881 (int)fs->fs_sbsize, 0, 0);
882 bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
883 /* Restore compatibility to old file systems. XXX */
884 dfs = (struct fs *)bp->b_data; /* XXX */
885 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
886 dfs->fs_nrpos = -1; /* XXX */
887 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
888 int32_t *lp, tmp; /* XXX */
889 /* XXX */
890 lp = (int32_t *)&dfs->fs_qbmask; /* XXX */
891 tmp = lp[4]; /* XXX */
892 for (i = 4; i > 0; i--) /* XXX */
893 lp[i] = lp[i-1]; /* XXX */
894 lp[0] = tmp; /* XXX */
895 } /* XXX */
896 dfs->fs_maxfilesize = mp->um_savedmaxfilesize; /* XXX */
897 if (waitfor == MNT_WAIT)
898 error = bwrite(bp);
899 else
900 bawrite(bp);
901 blks = howmany(fs->fs_cssize, fs->fs_fsize);
902 space = (caddr_t)fs->fs_csp[0];
903 for (i = 0; i < blks; i += fs->fs_frag) {
904 size = fs->fs_bsize;
905 if (i + fs->fs_frag > blks)
906 size = (blks - i) * fs->fs_fsize;
907 bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
908 size, 0, 0);
909 bcopy(space, bp->b_data, (u_int)size);
910 space += size;
911 if (waitfor == MNT_WAIT)
912 error = bwrite(bp);
913 else
914 bawrite(bp);
915 }
916 return (error);
917 }
918