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