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