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