Annotation of src/sys/ufs/ffs/ffs_vfsops.c, Revision 1.104
1.104 ! scw 1: /* $NetBSD: ffs_vfsops.c,v 1.103 2002/09/28 20:11:08 dbj Exp $ */
1.4 cgd 2:
1.1 mycroft 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: *
1.33 fvdl 35: * @(#)ffs_vfsops.c 8.31 (Berkeley) 5/20/95
1.1 mycroft 36: */
1.88 lukem 37:
38: #include <sys/cdefs.h>
1.104 ! scw 39: __KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.103 2002/09/28 20:11:08 dbj Exp $");
1.36 scottr 40:
1.81 mrg 41: #if defined(_KERNEL_OPT)
1.45 thorpej 42: #include "opt_ffs.h"
1.36 scottr 43: #include "opt_quota.h"
1.41 jonathan 44: #include "opt_compat_netbsd.h"
1.66 matt 45: #include "opt_softdep.h"
1.37 scottr 46: #endif
1.1 mycroft 47:
48: #include <sys/param.h>
49: #include <sys/systm.h>
50: #include <sys/namei.h>
51: #include <sys/proc.h>
52: #include <sys/kernel.h>
53: #include <sys/vnode.h>
54: #include <sys/socket.h>
55: #include <sys/mount.h>
56: #include <sys/buf.h>
1.23 thorpej 57: #include <sys/device.h>
1.1 mycroft 58: #include <sys/mbuf.h>
59: #include <sys/file.h>
60: #include <sys/disklabel.h>
61: #include <sys/ioctl.h>
62: #include <sys/errno.h>
63: #include <sys/malloc.h>
1.43 thorpej 64: #include <sys/pool.h>
1.29 fvdl 65: #include <sys/lock.h>
1.33 fvdl 66: #include <sys/sysctl.h>
1.101 gehenna 67: #include <sys/conf.h>
1.1 mycroft 68:
69: #include <miscfs/specfs/specdev.h>
70:
71: #include <ufs/ufs/quota.h>
72: #include <ufs/ufs/ufsmount.h>
73: #include <ufs/ufs/inode.h>
1.25 bouyer 74: #include <ufs/ufs/dir.h>
1.1 mycroft 75: #include <ufs/ufs/ufs_extern.h>
1.34 bouyer 76: #include <ufs/ufs/ufs_bswap.h>
1.1 mycroft 77:
78: #include <ufs/ffs/fs.h>
79: #include <ufs/ffs/ffs_extern.h>
80:
1.59 jdolecek 81: /* how many times ffs_init() was called */
82: int ffs_initcount = 0;
83:
1.29 fvdl 84: extern struct lock ufs_hashlock;
85:
1.32 thorpej 86: extern struct vnodeopv_desc ffs_vnodeop_opv_desc;
87: extern struct vnodeopv_desc ffs_specop_opv_desc;
88: extern struct vnodeopv_desc ffs_fifoop_opv_desc;
89:
1.79 jdolecek 90: const struct vnodeopv_desc * const ffs_vnodeopv_descs[] = {
1.32 thorpej 91: &ffs_vnodeop_opv_desc,
92: &ffs_specop_opv_desc,
93: &ffs_fifoop_opv_desc,
94: NULL,
95: };
96:
1.17 mycroft 97: struct vfsops ffs_vfsops = {
98: MOUNT_FFS,
1.1 mycroft 99: ffs_mount,
100: ufs_start,
101: ffs_unmount,
102: ufs_root,
103: ufs_quotactl,
104: ffs_statfs,
105: ffs_sync,
106: ffs_vget,
107: ffs_fhtovp,
108: ffs_vptofh,
109: ffs_init,
1.86 chs 110: ffs_reinit,
1.59 jdolecek 111: ffs_done,
1.33 fvdl 112: ffs_sysctl,
1.23 thorpej 113: ffs_mountroot,
1.48 wrstuden 114: ufs_check_export,
1.32 thorpej 115: ffs_vnodeopv_descs,
1.1 mycroft 116: };
117:
1.87 chs 118: struct genfs_ops ffs_genfsops = {
119: ffs_gop_size,
120: ffs_gop_alloc,
121: genfs_gop_write,
122: };
123:
1.43 thorpej 124: struct pool ffs_inode_pool;
125:
1.1 mycroft 126: /*
1.33 fvdl 127: * Called by main() when ffs is going to be mounted as root.
1.1 mycroft 128: */
129:
1.19 christos 130: int
1.1 mycroft 131: ffs_mountroot()
132: {
1.33 fvdl 133: struct fs *fs;
134: struct mount *mp;
1.1 mycroft 135: struct proc *p = curproc; /* XXX */
136: struct ufsmount *ump;
137: int error;
1.23 thorpej 138:
139: if (root_device->dv_class != DV_DISK)
140: return (ENODEV);
141:
1.1 mycroft 142: /*
1.26 mrg 143: * Get vnodes for rootdev.
1.1 mycroft 144: */
1.26 mrg 145: if (bdevvp(rootdev, &rootvp))
1.1 mycroft 146: panic("ffs_mountroot: can't setup bdevvp's");
147:
1.51 wrstuden 148: if ((error = vfs_rootmountalloc(MOUNT_FFS, "root_device", &mp))) {
149: vrele(rootvp);
1.33 fvdl 150: return (error);
1.51 wrstuden 151: }
1.19 christos 152: if ((error = ffs_mountfs(rootvp, mp, p)) != 0) {
1.33 fvdl 153: mp->mnt_op->vfs_refcount--;
154: vfs_unbusy(mp);
1.1 mycroft 155: free(mp, M_MOUNT);
1.51 wrstuden 156: vrele(rootvp);
1.1 mycroft 157: return (error);
158: }
1.33 fvdl 159: simple_lock(&mountlist_slock);
1.11 mycroft 160: CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
1.33 fvdl 161: simple_unlock(&mountlist_slock);
1.1 mycroft 162: ump = VFSTOUFS(mp);
163: fs = ump->um_fs;
1.42 perry 164: memset(fs->fs_fsmnt, 0, sizeof(fs->fs_fsmnt));
1.33 fvdl 165: (void)copystr(mp->mnt_stat.f_mntonname, fs->fs_fsmnt, MNAMELEN - 1, 0);
1.1 mycroft 166: (void)ffs_statfs(mp, &mp->mnt_stat, p);
1.33 fvdl 167: vfs_unbusy(mp);
1.1 mycroft 168: inittodr(fs->fs_time);
169: return (0);
170: }
171:
172: /*
173: * VFS Operations.
174: *
175: * mount system call
176: */
177: int
178: ffs_mount(mp, path, data, ndp, p)
1.61 augustss 179: struct mount *mp;
1.22 cgd 180: const char *path;
181: void *data;
1.1 mycroft 182: struct nameidata *ndp;
183: struct proc *p;
184: {
1.104 ! scw 185: struct vnode *devvp = NULL;
1.1 mycroft 186: struct ufs_args args;
1.19 christos 187: struct ufsmount *ump = NULL;
1.61 augustss 188: struct fs *fs;
1.14 mycroft 189: size_t size;
1.95 christos 190: int error, flags, update;
1.9 mycroft 191: mode_t accessmode;
1.1 mycroft 192:
1.102 christos 193: if (mp->mnt_flag & MNT_GETARGS) {
194: ump = VFSTOUFS(mp);
195: if (ump == NULL)
196: return EIO;
197: args.fspec = NULL;
198: vfs_showexport(mp, &args.export, &ump->um_export);
199: return copyout(&args, data, sizeof(args));
200: }
1.19 christos 201: error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args));
202: if (error)
1.1 mycroft 203: return (error);
1.66 matt 204:
205: #if !defined(SOFTDEP)
1.67 perseant 206: mp->mnt_flag &= ~MNT_SOFTDEP;
1.66 matt 207: #endif
208:
1.95 christos 209: update = mp->mnt_flag & MNT_UPDATE;
210:
211: /* Check arguments */
212: if (update) {
213: /* Use the extant mount */
214: ump = VFSTOUFS(mp);
215: devvp = ump->um_devvp;
1.97 enami 216: if (args.fspec == NULL)
217: vref(devvp);
1.95 christos 218: } else {
219: /* New mounts must have a filename for the device */
220: if (args.fspec == NULL)
1.96 christos 221: return (EINVAL);
1.95 christos 222: }
223:
1.97 enami 224: if (args.fspec != NULL) {
1.95 christos 225: /*
226: * Look up the name and verify that it's sane.
227: */
228: NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
229: if ((error = namei(ndp)) != 0)
230: return (error);
231: devvp = ndp->ni_vp;
232:
233: if (!update) {
234: /*
235: * Be sure this is a valid block device
236: */
237: if (devvp->v_type != VBLK)
238: error = ENOTBLK;
1.101 gehenna 239: else if (bdevsw_lookup(devvp->v_rdev) == NULL)
1.95 christos 240: error = ENXIO;
241: } else {
242: /*
243: * Be sure we're still naming the same device
244: * used for our initial mount
245: */
246: if (devvp != ump->um_devvp)
247: error = EINVAL;
248: }
249: }
250:
1.1 mycroft 251: /*
1.95 christos 252: * If mount by non-root, then verify that user has necessary
253: * permissions on the device.
1.1 mycroft 254: */
1.95 christos 255: if (error == 0 && p->p_ucred->cr_uid != 0) {
256: accessmode = VREAD;
1.96 christos 257: if (update ?
258: (mp->mnt_flag & MNT_WANTRDWR) != 0 :
259: (mp->mnt_flag & MNT_RDONLY) == 0)
1.95 christos 260: accessmode |= VWRITE;
261: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
262: error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p);
263: VOP_UNLOCK(devvp, 0);
264: }
265:
266: if (error) {
267: vrele(devvp);
268: return (error);
269: }
270:
271: if (!update) {
272: error = ffs_mountfs(devvp, mp, p);
273: if (error) {
274: vrele(devvp);
275: return (error);
276: }
277:
1.1 mycroft 278: ump = VFSTOUFS(mp);
279: fs = ump->um_fs;
1.95 christos 280: if ((mp->mnt_flag & (MNT_SOFTDEP | MNT_ASYNC)) ==
281: (MNT_SOFTDEP | MNT_ASYNC)) {
282: printf("%s fs uses soft updates, "
1.96 christos 283: "ignoring async mode\n",
284: fs->fs_fsmnt);
1.95 christos 285: mp->mnt_flag &= ~MNT_ASYNC;
286: }
287: } else {
288: /*
1.96 christos 289: * Update the mount.
290: */
291:
292: /*
293: * The initial mount got a reference on this
294: * device, so drop the one obtained via
295: * namei(), above.
1.95 christos 296: */
1.96 christos 297: vrele(devvp);
298:
1.95 christos 299: fs = ump->um_fs;
1.1 mycroft 300: if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
1.95 christos 301: /*
302: * Changing from r/w to r/o
303: */
1.1 mycroft 304: flags = WRITECLOSE;
305: if (mp->mnt_flag & MNT_FORCE)
306: flags |= FORCECLOSE;
1.55 fvdl 307: if (mp->mnt_flag & MNT_SOFTDEP)
308: error = softdep_flushfiles(mp, flags, p);
309: else
310: error = ffs_flushfiles(mp, flags, p);
1.89 fvdl 311: if (fs->fs_pendingblocks != 0 ||
312: fs->fs_pendinginodes != 0) {
313: printf("%s: update error: blocks %d files %d\n",
314: fs->fs_fsmnt, fs->fs_pendingblocks,
315: fs->fs_pendinginodes);
316: fs->fs_pendingblocks = 0;
317: fs->fs_pendinginodes = 0;
318: }
1.15 mycroft 319: if (error == 0 &&
320: ffs_cgupdate(ump, MNT_WAIT) == 0 &&
321: fs->fs_clean & FS_WASCLEAN) {
1.65 fvdl 322: if (mp->mnt_flag & MNT_SOFTDEP)
323: fs->fs_flags &= ~FS_DOSOFTDEP;
1.15 mycroft 324: fs->fs_clean = FS_ISCLEAN;
325: (void) ffs_sbupdate(ump, MNT_WAIT);
326: }
327: if (error)
328: return (error);
329: fs->fs_ronly = 1;
1.78 mycroft 330: fs->fs_fmod = 0;
1.1 mycroft 331: }
1.65 fvdl 332:
333: /*
334: * Flush soft dependencies if disabling it via an update
335: * mount. This may leave some items to be processed,
336: * so don't do this yet XXX.
337: */
338: if ((fs->fs_flags & FS_DOSOFTDEP) &&
339: !(mp->mnt_flag & MNT_SOFTDEP) && fs->fs_ronly == 0) {
340: #ifdef notyet
341: flags = WRITECLOSE;
342: if (mp->mnt_flag & MNT_FORCE)
343: flags |= FORCECLOSE;
344: error = softdep_flushfiles(mp, flags, p);
345: if (error == 0 && ffs_cgupdate(ump, MNT_WAIT) == 0)
346: fs->fs_flags &= ~FS_DOSOFTDEP;
347: (void) ffs_sbupdate(ump, MNT_WAIT);
1.66 matt 348: #elif defined(SOFTDEP)
1.65 fvdl 349: mp->mnt_flag |= MNT_SOFTDEP;
350: #endif
351: }
352:
353: /*
354: * When upgrading to a softdep mount, we must first flush
355: * all vnodes. (not done yet -- see above)
356: */
357: if (!(fs->fs_flags & FS_DOSOFTDEP) &&
358: (mp->mnt_flag & MNT_SOFTDEP) && fs->fs_ronly == 0) {
359: #ifdef notyet
360: flags = WRITECLOSE;
361: if (mp->mnt_flag & MNT_FORCE)
362: flags |= FORCECLOSE;
363: error = ffs_flushfiles(mp, flags, p);
364: #else
365: mp->mnt_flag &= ~MNT_SOFTDEP;
366: #endif
367: }
368:
1.15 mycroft 369: if (mp->mnt_flag & MNT_RELOAD) {
1.96 christos 370: error = ffs_reload(mp, p->p_ucred, p);
1.15 mycroft 371: if (error)
372: return (error);
373: }
1.95 christos 374:
1.9 mycroft 375: if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) {
376: /*
1.95 christos 377: * Changing from read-only to read/write
1.9 mycroft 378: */
1.1 mycroft 379: fs->fs_ronly = 0;
1.15 mycroft 380: fs->fs_clean <<= 1;
381: fs->fs_fmod = 1;
1.55 fvdl 382: if ((fs->fs_flags & FS_DOSOFTDEP)) {
383: error = softdep_mount(devvp, mp, fs,
384: p->p_ucred);
385: if (error)
386: return (error);
1.65 fvdl 387: }
1.9 mycroft 388: }
1.1 mycroft 389: if (args.fspec == 0) {
390: /*
391: * Process export requests.
392: */
393: return (vfs_export(mp, &ump->um_export, &args.export));
394: }
1.55 fvdl 395: if ((mp->mnt_flag & (MNT_SOFTDEP | MNT_ASYNC)) ==
396: (MNT_SOFTDEP | MNT_ASYNC)) {
397: printf("%s fs uses soft updates, ignoring async mode\n",
398: fs->fs_fsmnt);
399: mp->mnt_flag &= ~MNT_ASYNC;
400: }
1.1 mycroft 401: }
402:
403: (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
1.42 perry 404: memset(fs->fs_fsmnt + size, 0, sizeof(fs->fs_fsmnt) - size);
405: memcpy(mp->mnt_stat.f_mntonname, fs->fs_fsmnt, MNAMELEN);
1.1 mycroft 406: (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
407: &size);
1.42 perry 408: memset(mp->mnt_stat.f_mntfromname + size, 0, MNAMELEN - size);
1.65 fvdl 409: if (mp->mnt_flag & MNT_SOFTDEP)
410: fs->fs_flags |= FS_DOSOFTDEP;
1.74 fvdl 411: else
412: fs->fs_flags &= ~FS_DOSOFTDEP;
1.15 mycroft 413: if (fs->fs_fmod != 0) { /* XXX */
414: fs->fs_fmod = 0;
415: if (fs->fs_clean & FS_WASCLEAN)
416: fs->fs_time = time.tv_sec;
1.89 fvdl 417: else {
1.82 lukem 418: printf("%s: file system not clean (fs_clean=%x); please fsck(8)\n",
1.34 bouyer 419: mp->mnt_stat.f_mntfromname, fs->fs_clean);
1.89 fvdl 420: printf("%s: lost blocks %d files %d\n",
421: mp->mnt_stat.f_mntfromname, fs->fs_pendingblocks,
422: fs->fs_pendinginodes);
423: }
1.15 mycroft 424: (void) ffs_cgupdate(ump, MNT_WAIT);
425: }
1.1 mycroft 426: return (0);
427: }
428:
429: /*
430: * Reload all incore data for a filesystem (used after running fsck on
431: * the root filesystem and finding things to fix). The filesystem must
432: * be mounted read-only.
433: *
434: * Things to do to update the mount:
435: * 1) invalidate all cached meta-data.
436: * 2) re-read superblock from disk.
437: * 3) re-read summary information from disk.
438: * 4) invalidate all inactive vnodes.
439: * 5) invalidate all cached file data.
440: * 6) re-read inode data for all active vnodes.
441: */
1.19 christos 442: int
1.1 mycroft 443: ffs_reload(mountp, cred, p)
1.61 augustss 444: struct mount *mountp;
1.1 mycroft 445: struct ucred *cred;
446: struct proc *p;
447: {
1.61 augustss 448: struct vnode *vp, *nvp, *devvp;
1.1 mycroft 449: struct inode *ip;
1.84 lukem 450: void *space;
1.1 mycroft 451: struct buf *bp;
1.18 cgd 452: struct fs *fs, *newfs;
1.1 mycroft 453: struct partinfo dpart;
454: int i, blks, size, error;
1.18 cgd 455: int32_t *lp;
1.44 thorpej 456: caddr_t cp;
1.1 mycroft 457:
458: if ((mountp->mnt_flag & MNT_RDONLY) == 0)
459: return (EINVAL);
460: /*
461: * Step 1: invalidate all cached meta-data.
462: */
463: devvp = VFSTOUFS(mountp)->um_devvp;
1.55 fvdl 464: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
465: error = vinvalbuf(devvp, 0, cred, p, 0, 0);
466: VOP_UNLOCK(devvp, 0);
467: if (error)
1.1 mycroft 468: panic("ffs_reload: dirty1");
469: /*
470: * Step 2: re-read superblock from disk.
471: */
472: if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
473: size = DEV_BSIZE;
474: else
475: size = dpart.disklab->d_secsize;
1.33 fvdl 476: error = bread(devvp, (ufs_daddr_t)(SBOFF / size), SBSIZE, NOCRED, &bp);
1.47 bouyer 477: if (error) {
478: brelse(bp);
1.1 mycroft 479: return (error);
1.47 bouyer 480: }
1.34 bouyer 481: fs = VFSTOUFS(mountp)->um_fs;
482: newfs = malloc(fs->fs_sbsize, M_UFSMNT, M_WAITOK);
1.42 perry 483: memcpy(newfs, bp->b_data, fs->fs_sbsize);
1.34 bouyer 484: #ifdef FFS_EI
1.55 fvdl 485: if (VFSTOUFS(mountp)->um_flags & UFS_NEEDSWAP) {
1.83 lukem 486: ffs_sb_swap((struct fs*)bp->b_data, newfs);
1.55 fvdl 487: fs->fs_flags |= FS_SWAPPED;
488: }
1.34 bouyer 489: #endif
1.18 cgd 490: if (newfs->fs_magic != FS_MAGIC || newfs->fs_bsize > MAXBSIZE ||
491: newfs->fs_bsize < sizeof(struct fs)) {
1.1 mycroft 492: brelse(bp);
1.34 bouyer 493: free(newfs, M_UFSMNT);
1.1 mycroft 494: return (EIO); /* XXX needs translation */
495: }
1.18 cgd 496: /*
497: * Copy pointer fields back into superblock before copying in XXX
498: * new superblock. These should really be in the ufsmount. XXX
499: * Note that important parameters (eg fs_ncg) are unchanged.
500: */
1.84 lukem 501: newfs->fs_csp = fs->fs_csp;
1.18 cgd 502: newfs->fs_maxcluster = fs->fs_maxcluster;
1.85 lukem 503: newfs->fs_contigdirs = fs->fs_contigdirs;
1.76 mycroft 504: newfs->fs_ronly = fs->fs_ronly;
1.42 perry 505: memcpy(fs, newfs, (u_int)fs->fs_sbsize);
1.1 mycroft 506: if (fs->fs_sbsize < SBSIZE)
507: bp->b_flags |= B_INVAL;
508: brelse(bp);
1.34 bouyer 509: free(newfs, M_UFSMNT);
1.103 dbj 510:
511: /* Recheck for apple UFS filesystem */
512: VFSTOUFS(mountp)->um_flags &= ~UFS_ISAPPLEUFS;
513: /* First check to see if this is tagged as an Apple UFS filesystem
514: * in the disklabel
515: */
516: if ((VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) == 0) &&
517: (dpart.part->p_fstype == FS_APPLEUFS)) {
518: VFSTOUFS(mountp)->um_flags |= UFS_ISAPPLEUFS;
519: }
520: #ifdef APPLE_UFS
521: else {
522: /* Manually look for an apple ufs label, and if a valid one
523: * is found, then treat it like an Apple UFS filesystem anyway
524: */
525: error = bread(devvp, (ufs_daddr_t)(APPLEUFS_LABEL_OFFSET / size),
526: APPLEUFS_LABEL_SIZE, cred, &bp);
527: if (error) {
528: brelse(bp);
529: return (error);
530: }
531: error = ffs_appleufs_validate(fs->fs_fsmnt,
532: (struct appleufslabel *)bp->b_data,NULL);
533: if (error == 0) {
534: VFSTOUFS(mountp)->um_flags |= UFS_ISAPPLEUFS;
535: }
536: brelse(bp);
537: bp = NULL;
538: }
539: #else
540: if (VFSTOUFS(mountp)->um_flags & UFS_ISAPPLEUFS)
541: return (EIO);
542: #endif
543:
1.3 mycroft 544: mountp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
1.103 dbj 545: if (UFS_MPISAPPLEUFS(mountp)) {
546: /* see comment about NeXT below */
547: mountp->mnt_maxsymlinklen = APPLEUFS_MAXSYMLINKLEN;
548: }
1.1 mycroft 549: ffs_oldfscompat(fs);
1.85 lukem 550: /* An old fsck may have zeroed these fields, so recheck them. */
551: if (fs->fs_avgfilesize <= 0)
552: fs->fs_avgfilesize = AVFILESIZ;
553: if (fs->fs_avgfpdir <= 0)
554: fs->fs_avgfpdir = AFPDIR;
1.89 fvdl 555: if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
556: fs->fs_pendingblocks = 0;
557: fs->fs_pendinginodes = 0;
558: }
1.85 lukem 559:
1.55 fvdl 560: ffs_statfs(mountp, &mountp->mnt_stat, p);
1.1 mycroft 561: /*
562: * Step 3: re-read summary information from disk.
563: */
564: blks = howmany(fs->fs_cssize, fs->fs_fsize);
1.84 lukem 565: space = fs->fs_csp;
1.1 mycroft 566: for (i = 0; i < blks; i += fs->fs_frag) {
567: size = fs->fs_bsize;
568: if (i + fs->fs_frag > blks)
569: size = (blks - i) * fs->fs_fsize;
1.19 christos 570: error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
571: NOCRED, &bp);
1.47 bouyer 572: if (error) {
573: brelse(bp);
1.1 mycroft 574: return (error);
1.47 bouyer 575: }
1.34 bouyer 576: #ifdef FFS_EI
1.55 fvdl 577: if (UFS_FSNEEDSWAP(fs))
1.84 lukem 578: ffs_csum_swap((struct csum *)bp->b_data,
579: (struct csum *)space, size);
1.34 bouyer 580: else
581: #endif
1.84 lukem 582: memcpy(space, bp->b_data, (size_t)size);
583: space = (char *)space + size;
1.1 mycroft 584: brelse(bp);
585: }
1.55 fvdl 586: if ((fs->fs_flags & FS_DOSOFTDEP))
587: softdep_mount(devvp, mountp, fs, cred);
1.18 cgd 588: /*
589: * We no longer know anything about clusters per cylinder group.
590: */
591: if (fs->fs_contigsumsize > 0) {
592: lp = fs->fs_maxcluster;
593: for (i = 0; i < fs->fs_ncg; i++)
594: *lp++ = fs->fs_contigsumsize;
595: }
596:
1.1 mycroft 597: loop:
1.33 fvdl 598: simple_lock(&mntvnode_slock);
1.1 mycroft 599: for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
1.33 fvdl 600: if (vp->v_mount != mountp) {
601: simple_unlock(&mntvnode_slock);
602: goto loop;
603: }
1.1 mycroft 604: nvp = vp->v_mntvnodes.le_next;
605: /*
606: * Step 4: invalidate all inactive vnodes.
607: */
1.33 fvdl 608: if (vrecycle(vp, &mntvnode_slock, p))
609: goto loop;
1.1 mycroft 610: /*
611: * Step 5: invalidate all cached file data.
612: */
1.33 fvdl 613: simple_lock(&vp->v_interlock);
614: simple_unlock(&mntvnode_slock);
615: if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
1.1 mycroft 616: goto loop;
617: if (vinvalbuf(vp, 0, cred, p, 0, 0))
618: panic("ffs_reload: dirty2");
619: /*
620: * Step 6: re-read inode data for all active vnodes.
621: */
622: ip = VTOI(vp);
1.19 christos 623: error = bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
624: (int)fs->fs_bsize, NOCRED, &bp);
625: if (error) {
1.47 bouyer 626: brelse(bp);
1.1 mycroft 627: vput(vp);
628: return (error);
629: }
1.44 thorpej 630: cp = (caddr_t)bp->b_data +
631: (ino_to_fsbo(fs, ip->i_number) * DINODE_SIZE);
1.34 bouyer 632: #ifdef FFS_EI
1.55 fvdl 633: if (UFS_FSNEEDSWAP(fs))
1.44 thorpej 634: ffs_dinode_swap((struct dinode *)cp,
635: &ip->i_din.ffs_din);
1.34 bouyer 636: else
637: #endif
1.44 thorpej 638: memcpy(&ip->i_din.ffs_din, cp, DINODE_SIZE);
1.55 fvdl 639: ip->i_ffs_effnlink = ip->i_ffs_nlink;
1.1 mycroft 640: brelse(bp);
641: vput(vp);
1.33 fvdl 642: simple_lock(&mntvnode_slock);
1.1 mycroft 643: }
1.33 fvdl 644: simple_unlock(&mntvnode_slock);
1.1 mycroft 645: return (0);
646: }
647:
648: /*
649: * Common code for mount and mountroot
650: */
651: int
652: ffs_mountfs(devvp, mp, p)
1.61 augustss 653: struct vnode *devvp;
1.1 mycroft 654: struct mount *mp;
655: struct proc *p;
656: {
1.34 bouyer 657: struct ufsmount *ump;
1.1 mycroft 658: struct buf *bp;
1.34 bouyer 659: struct fs *fs;
1.9 mycroft 660: dev_t dev;
1.1 mycroft 661: struct partinfo dpart;
1.84 lukem 662: void *space;
1.1 mycroft 663: int blks;
1.52 drochner 664: int error, i, size, ronly;
665: #ifdef FFS_EI
666: int needswap;
667: #endif
1.9 mycroft 668: int32_t *lp;
669: struct ucred *cred;
670: u_int64_t maxfilesize; /* XXX */
1.34 bouyer 671: u_int32_t sbsize;
1.1 mycroft 672:
1.9 mycroft 673: dev = devvp->v_rdev;
674: cred = p ? p->p_ucred : NOCRED;
1.1 mycroft 675: /*
676: * Disallow multiple mounts of the same device.
677: * Disallow mounting of a device that is currently in use
678: * (except for root, which might share swap device for miniroot).
679: * Flush out any old buffers remaining from a previous use.
680: */
1.19 christos 681: if ((error = vfs_mountedon(devvp)) != 0)
1.1 mycroft 682: return (error);
683: if (vcount(devvp) > 1 && devvp != rootvp)
684: return (EBUSY);
1.55 fvdl 685: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
686: error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0);
687: VOP_UNLOCK(devvp, 0);
688: if (error)
1.1 mycroft 689: return (error);
690:
691: ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
1.19 christos 692: error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
693: if (error)
1.1 mycroft 694: return (error);
1.9 mycroft 695: if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0)
1.1 mycroft 696: size = DEV_BSIZE;
697: else
698: size = dpart.disklab->d_secsize;
699:
700: bp = NULL;
701: ump = NULL;
1.33 fvdl 702: error = bread(devvp, (ufs_daddr_t)(SBOFF / size), SBSIZE, cred, &bp);
1.19 christos 703: if (error)
1.1 mycroft 704: goto out;
1.34 bouyer 705:
706: fs = (struct fs*)bp->b_data;
707: if (fs->fs_magic == FS_MAGIC) {
708: sbsize = fs->fs_sbsize;
709: #ifdef FFS_EI
1.52 drochner 710: needswap = 0;
1.34 bouyer 711: } else if (fs->fs_magic == bswap32(FS_MAGIC)) {
1.52 drochner 712: sbsize = bswap32(fs->fs_sbsize);
1.34 bouyer 713: needswap = 1;
714: #endif
715: } else {
716: error = EINVAL;
717: goto out;
1.46 bouyer 718: }
1.49 bouyer 719: if (sbsize > MAXBSIZE || sbsize < sizeof(struct fs)) {
1.46 bouyer 720: error = EINVAL;
721: goto out;
1.34 bouyer 722: }
723:
724: fs = malloc((u_long)sbsize, M_UFSMNT, M_WAITOK);
1.42 perry 725: memcpy(fs, bp->b_data, sbsize);
1.34 bouyer 726: #ifdef FFS_EI
1.55 fvdl 727: if (needswap) {
1.83 lukem 728: ffs_sb_swap((struct fs*)bp->b_data, fs);
1.55 fvdl 729: fs->fs_flags |= FS_SWAPPED;
730: }
1.34 bouyer 731: #endif
1.56 drochner 732: ffs_oldfscompat(fs);
733:
1.49 bouyer 734: if (fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
735: error = EINVAL;
736: goto out;
737: }
1.46 bouyer 738: /* make sure cylinder group summary area is a reasonable size. */
739: if (fs->fs_cgsize == 0 || fs->fs_cpg == 0 ||
740: fs->fs_ncg > fs->fs_ncyl / fs->fs_cpg + 1 ||
741: fs->fs_cssize >
742: fragroundup(fs, fs->fs_ncg * sizeof(struct csum))) {
1.1 mycroft 743: error = EINVAL; /* XXX needs translation */
1.34 bouyer 744: goto out2;
1.1 mycroft 745: }
1.89 fvdl 746: if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
747: fs->fs_pendingblocks = 0;
748: fs->fs_pendinginodes = 0;
749: }
1.1 mycroft 750: /* XXX updating 4.2 FFS superblocks trashes rotational layout tables */
751: if (fs->fs_postblformat == FS_42POSTBLFMT && !ronly) {
752: error = EROFS; /* XXX what should be returned? */
1.34 bouyer 753: goto out2;
1.1 mycroft 754: }
1.56 drochner 755:
1.1 mycroft 756: ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
1.42 perry 757: memset((caddr_t)ump, 0, sizeof *ump);
1.34 bouyer 758: ump->um_fs = fs;
1.1 mycroft 759: if (fs->fs_sbsize < SBSIZE)
760: bp->b_flags |= B_INVAL;
761: brelse(bp);
762: bp = NULL;
1.94 chs 763:
1.103 dbj 764: /* First check to see if this is tagged as an Apple UFS filesystem
765: * in the disklabel
766: */
767: if ((VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) == 0) &&
768: (dpart.part->p_fstype == FS_APPLEUFS)) {
769: ump->um_flags |= UFS_ISAPPLEUFS;
770: }
771: #ifdef APPLE_UFS
772: else {
773: /* Manually look for an apple ufs label, and if a valid one
774: * is found, then treat it like an Apple UFS filesystem anyway
775: */
776: error = bread(devvp, (ufs_daddr_t)(APPLEUFS_LABEL_OFFSET / size),
777: APPLEUFS_LABEL_SIZE, cred, &bp);
778: if (error)
779: goto out;
780: error = ffs_appleufs_validate(fs->fs_fsmnt,
781: (struct appleufslabel *)bp->b_data,NULL);
782: if (error == 0) {
783: ump->um_flags |= UFS_ISAPPLEUFS;
784: }
785: brelse(bp);
786: bp = NULL;
787: }
788: #else
789: if (ump->um_flags & UFS_ISAPPLEUFS) {
790: error = EINVAL;
791: goto out;
792: }
793: #endif
794:
1.94 chs 795: /*
1.99 chs 796: * verify that we can access the last block in the fs
797: * if we're mounting read/write.
1.94 chs 798: */
799:
1.99 chs 800: if (!ronly) {
801: error = bread(devvp, fsbtodb(fs, fs->fs_size - 1), fs->fs_fsize,
802: cred, &bp);
803: if (bp->b_bcount != fs->fs_fsize)
804: error = EINVAL;
805: bp->b_flags |= B_INVAL;
806: if (error)
807: goto out;
808: brelse(bp);
809: bp = NULL;
810: }
1.94 chs 811:
1.1 mycroft 812: fs->fs_ronly = ronly;
1.15 mycroft 813: if (ronly == 0) {
814: fs->fs_clean <<= 1;
1.1 mycroft 815: fs->fs_fmod = 1;
1.15 mycroft 816: }
1.9 mycroft 817: size = fs->fs_cssize;
818: blks = howmany(size, fs->fs_fsize);
819: if (fs->fs_contigsumsize > 0)
820: size += fs->fs_ncg * sizeof(int32_t);
1.85 lukem 821: size += fs->fs_ncg * sizeof(*fs->fs_contigdirs);
1.84 lukem 822: space = malloc((u_long)size, M_UFSMNT, M_WAITOK);
823: fs->fs_csp = space;
1.1 mycroft 824: for (i = 0; i < blks; i += fs->fs_frag) {
825: size = fs->fs_bsize;
826: if (i + fs->fs_frag > blks)
827: size = (blks - i) * fs->fs_fsize;
1.19 christos 828: error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
829: cred, &bp);
830: if (error) {
1.84 lukem 831: free(fs->fs_csp, M_UFSMNT);
1.34 bouyer 832: goto out2;
1.1 mycroft 833: }
1.34 bouyer 834: #ifdef FFS_EI
835: if (needswap)
1.84 lukem 836: ffs_csum_swap((struct csum *)bp->b_data,
837: (struct csum *)space, size);
1.34 bouyer 838: else
839: #endif
1.42 perry 840: memcpy(space, bp->b_data, (u_int)size);
1.34 bouyer 841:
1.84 lukem 842: space = (char *)space + size;
1.1 mycroft 843: brelse(bp);
844: bp = NULL;
845: }
1.9 mycroft 846: if (fs->fs_contigsumsize > 0) {
1.85 lukem 847: fs->fs_maxcluster = lp = space;
1.9 mycroft 848: for (i = 0; i < fs->fs_ncg; i++)
849: *lp++ = fs->fs_contigsumsize;
1.85 lukem 850: space = lp;
1.9 mycroft 851: }
1.85 lukem 852: size = fs->fs_ncg * sizeof(*fs->fs_contigdirs);
853: fs->fs_contigdirs = space;
854: space = (char *)space + size;
855: memset(fs->fs_contigdirs, 0, size);
856: /* Compatibility for old filesystems - XXX */
857: if (fs->fs_avgfilesize <= 0)
858: fs->fs_avgfilesize = AVFILESIZ;
859: if (fs->fs_avgfpdir <= 0)
860: fs->fs_avgfpdir = AFPDIR;
1.100 soren 861: mp->mnt_data = ump;
1.1 mycroft 862: mp->mnt_stat.f_fsid.val[0] = (long)dev;
1.17 mycroft 863: mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_FFS);
1.1 mycroft 864: mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
1.103 dbj 865: if (UFS_MPISAPPLEUFS(mp)) {
866: /* NeXT used to keep short symlinks in the inode even
867: * when using FS_42INODEFMT. In that case fs->fs_maxsymlinklen
868: * is probably -1, but we still need to be able to identify
869: * short symlinks.
870: */
871: mp->mnt_maxsymlinklen = APPLEUFS_MAXSYMLINKLEN;
872: }
1.73 chs 873: mp->mnt_fs_bshift = fs->fs_bshift;
874: mp->mnt_dev_bshift = DEV_BSHIFT; /* XXX */
1.1 mycroft 875: mp->mnt_flag |= MNT_LOCAL;
1.34 bouyer 876: #ifdef FFS_EI
877: if (needswap)
878: ump->um_flags |= UFS_NEEDSWAP;
879: #endif
1.1 mycroft 880: ump->um_mountp = mp;
881: ump->um_dev = dev;
882: ump->um_devvp = devvp;
883: ump->um_nindir = fs->fs_nindir;
1.73 chs 884: ump->um_lognindir = ffs(fs->fs_nindir) - 1;
1.1 mycroft 885: ump->um_bptrtodb = fs->fs_fsbtodb;
886: ump->um_seqinc = fs->fs_frag;
887: for (i = 0; i < MAXQUOTAS; i++)
888: ump->um_quotas[i] = NULLVP;
1.55 fvdl 889: devvp->v_specmountpoint = mp;
1.9 mycroft 890: ump->um_savedmaxfilesize = fs->fs_maxfilesize; /* XXX */
891: maxfilesize = (u_int64_t)0x80000000 * fs->fs_bsize - 1; /* XXX */
892: if (fs->fs_maxfilesize > maxfilesize) /* XXX */
893: fs->fs_maxfilesize = maxfilesize; /* XXX */
1.55 fvdl 894: if (ronly == 0 && (fs->fs_flags & FS_DOSOFTDEP)) {
895: error = softdep_mount(devvp, mp, fs, cred);
896: if (error) {
1.84 lukem 897: free(fs->fs_csp, M_UFSMNT);
1.55 fvdl 898: goto out;
899: }
900: }
1.1 mycroft 901: return (0);
1.34 bouyer 902: out2:
903: free(fs, M_UFSMNT);
1.1 mycroft 904: out:
1.55 fvdl 905: devvp->v_specmountpoint = NULL;
1.1 mycroft 906: if (bp)
907: brelse(bp);
1.53 wrstuden 908: vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
1.9 mycroft 909: (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
1.53 wrstuden 910: VOP_UNLOCK(devvp, 0);
1.1 mycroft 911: if (ump) {
912: free(ump, M_UFSMNT);
1.100 soren 913: mp->mnt_data = NULL;
1.1 mycroft 914: }
915: return (error);
916: }
917:
918: /*
919: * Sanity checks for old file systems.
920: *
921: * XXX - goes away some day.
922: */
1.19 christos 923: int
1.1 mycroft 924: ffs_oldfscompat(fs)
925: struct fs *fs;
926: {
927: int i;
928:
929: fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */
930: fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */
931: if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
932: fs->fs_nrpos = 8; /* XXX */
933: if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
1.5 mycroft 934: u_int64_t sizepb = fs->fs_bsize; /* XXX */
1.1 mycroft 935: /* XXX */
936: fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */
937: for (i = 0; i < NIADDR; i++) { /* XXX */
938: sizepb *= NINDIR(fs); /* XXX */
939: fs->fs_maxfilesize += sizepb; /* XXX */
940: } /* XXX */
941: fs->fs_qbmask = ~fs->fs_bmask; /* XXX */
942: fs->fs_qfmask = ~fs->fs_fmask; /* XXX */
943: } /* XXX */
944: return (0);
945: }
946:
947: /*
948: * unmount system call
949: */
950: int
951: ffs_unmount(mp, mntflags, p)
952: struct mount *mp;
953: int mntflags;
954: struct proc *p;
955: {
1.61 augustss 956: struct ufsmount *ump;
957: struct fs *fs;
1.91 fvdl 958: int error, flags, penderr;
1.1 mycroft 959:
1.91 fvdl 960: penderr = 0;
1.1 mycroft 961: flags = 0;
1.11 mycroft 962: if (mntflags & MNT_FORCE)
1.1 mycroft 963: flags |= FORCECLOSE;
1.55 fvdl 964: if (mp->mnt_flag & MNT_SOFTDEP) {
965: if ((error = softdep_flushfiles(mp, flags, p)) != 0)
966: return (error);
967: } else {
968: if ((error = ffs_flushfiles(mp, flags, p)) != 0)
969: return (error);
970: }
1.1 mycroft 971: ump = VFSTOUFS(mp);
972: fs = ump->um_fs;
1.89 fvdl 973: if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
974: printf("%s: unmount pending error: blocks %d files %d\n",
975: fs->fs_fsmnt, fs->fs_pendingblocks, fs->fs_pendinginodes);
976: fs->fs_pendingblocks = 0;
977: fs->fs_pendinginodes = 0;
1.91 fvdl 978: penderr = 1;
1.89 fvdl 979: }
1.15 mycroft 980: if (fs->fs_ronly == 0 &&
981: ffs_cgupdate(ump, MNT_WAIT) == 0 &&
982: fs->fs_clean & FS_WASCLEAN) {
1.91 fvdl 983: /*
984: * XXXX don't mark fs clean in the case of softdep
985: * pending block errors, until they are fixed.
986: */
987: if (penderr == 0) {
988: if (mp->mnt_flag & MNT_SOFTDEP)
989: fs->fs_flags &= ~FS_DOSOFTDEP;
990: fs->fs_clean = FS_ISCLEAN;
991: }
1.15 mycroft 992: (void) ffs_sbupdate(ump, MNT_WAIT);
993: }
1.54 enami 994: if (ump->um_devvp->v_type != VBAD)
1.55 fvdl 995: ump->um_devvp->v_specmountpoint = NULL;
1.53 wrstuden 996: vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
1.9 mycroft 997: error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE,
1.1 mycroft 998: NOCRED, p);
1.53 wrstuden 999: vput(ump->um_devvp);
1.84 lukem 1000: free(fs->fs_csp, M_UFSMNT);
1.1 mycroft 1001: free(fs, M_UFSMNT);
1002: free(ump, M_UFSMNT);
1.100 soren 1003: mp->mnt_data = NULL;
1.1 mycroft 1004: mp->mnt_flag &= ~MNT_LOCAL;
1005: return (error);
1006: }
1007:
1008: /*
1009: * Flush out all the files in a filesystem.
1010: */
1.19 christos 1011: int
1.1 mycroft 1012: ffs_flushfiles(mp, flags, p)
1.61 augustss 1013: struct mount *mp;
1.1 mycroft 1014: int flags;
1015: struct proc *p;
1016: {
1017: extern int doforce;
1.61 augustss 1018: struct ufsmount *ump;
1.19 christos 1019: int error;
1.1 mycroft 1020:
1021: if (!doforce)
1022: flags &= ~FORCECLOSE;
1023: ump = VFSTOUFS(mp);
1024: #ifdef QUOTA
1025: if (mp->mnt_flag & MNT_QUOTA) {
1.19 christos 1026: int i;
1027: if ((error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) != 0)
1.1 mycroft 1028: return (error);
1029: for (i = 0; i < MAXQUOTAS; i++) {
1030: if (ump->um_quotas[i] == NULLVP)
1031: continue;
1032: quotaoff(p, mp, i);
1033: }
1034: /*
1035: * Here we fall through to vflush again to ensure
1036: * that we have gotten rid of all the system vnodes.
1037: */
1038: }
1039: #endif
1.55 fvdl 1040: /*
1041: * Flush all the files.
1042: */
1.1 mycroft 1043: error = vflush(mp, NULLVP, flags);
1.55 fvdl 1044: if (error)
1045: return (error);
1046: /*
1047: * Flush filesystem metadata.
1048: */
1049: vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
1.71 fvdl 1050: error = VOP_FSYNC(ump->um_devvp, p->p_ucred, FSYNC_WAIT, 0, 0, p);
1.55 fvdl 1051: VOP_UNLOCK(ump->um_devvp, 0);
1.1 mycroft 1052: return (error);
1053: }
1054:
1055: /*
1056: * Get file system statistics.
1057: */
1058: int
1059: ffs_statfs(mp, sbp, p)
1060: struct mount *mp;
1.61 augustss 1061: struct statfs *sbp;
1.1 mycroft 1062: struct proc *p;
1063: {
1.61 augustss 1064: struct ufsmount *ump;
1065: struct fs *fs;
1.1 mycroft 1066:
1067: ump = VFSTOUFS(mp);
1068: fs = ump->um_fs;
1069: if (fs->fs_magic != FS_MAGIC)
1070: panic("ffs_statfs");
1071: #ifdef COMPAT_09
1072: sbp->f_type = 1;
1073: #else
1074: sbp->f_type = 0;
1075: #endif
1076: sbp->f_bsize = fs->fs_fsize;
1077: sbp->f_iosize = fs->fs_bsize;
1078: sbp->f_blocks = fs->fs_dsize;
1.98 mycroft 1079: sbp->f_bfree = blkstofrags(fs, fs->fs_cstotal.cs_nbfree) +
1.89 fvdl 1080: fs->fs_cstotal.cs_nffree + dbtofsb(fs, fs->fs_pendingblocks);
1.31 mjacob 1081: sbp->f_bavail = (long) (((u_int64_t) fs->fs_dsize * (u_int64_t)
1.38 kleink 1082: (100 - fs->fs_minfree) / (u_int64_t) 100) -
1.92 pooka 1083: (u_int64_t) (fs->fs_dsize - sbp->f_bfree));
1.1 mycroft 1084: sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO;
1.89 fvdl 1085: sbp->f_ffree = fs->fs_cstotal.cs_nifree + fs->fs_pendinginodes;
1.1 mycroft 1086: if (sbp != &mp->mnt_stat) {
1.42 perry 1087: memcpy(sbp->f_mntonname, mp->mnt_stat.f_mntonname, MNAMELEN);
1088: memcpy(sbp->f_mntfromname, mp->mnt_stat.f_mntfromname, MNAMELEN);
1.1 mycroft 1089: }
1.12 mycroft 1090: strncpy(sbp->f_fstypename, mp->mnt_op->vfs_name, MFSNAMELEN);
1.1 mycroft 1091: return (0);
1092: }
1093:
1094: /*
1095: * Go through the disk queues to initiate sandbagged IO;
1096: * go through the inodes to write those that have been modified;
1097: * initiate the writing of the super block if it has been modified.
1098: *
1099: * Note: we are always called with the filesystem marked `MPBUSY'.
1100: */
1101: int
1102: ffs_sync(mp, waitfor, cred, p)
1103: struct mount *mp;
1104: int waitfor;
1105: struct ucred *cred;
1106: struct proc *p;
1107: {
1.33 fvdl 1108: struct vnode *vp, *nvp;
1109: struct inode *ip;
1110: struct ufsmount *ump = VFSTOUFS(mp);
1111: struct fs *fs;
1.1 mycroft 1112: int error, allerror = 0;
1113:
1114: fs = ump->um_fs;
1.33 fvdl 1115: if (fs->fs_fmod != 0 && fs->fs_ronly != 0) { /* XXX */
1116: printf("fs = %s\n", fs->fs_fsmnt);
1117: panic("update: rofs mod");
1.1 mycroft 1118: }
1119: /*
1120: * Write back each (modified) inode.
1121: */
1.33 fvdl 1122: simple_lock(&mntvnode_slock);
1.1 mycroft 1123: loop:
1.64 mycroft 1124: for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp != NULL; vp = nvp) {
1.1 mycroft 1125: /*
1126: * If the vnode that we are about to sync is no longer
1127: * associated with this mount point, start over.
1128: */
1129: if (vp->v_mount != mp)
1130: goto loop;
1.33 fvdl 1131: simple_lock(&vp->v_interlock);
1.64 mycroft 1132: nvp = LIST_NEXT(vp, v_mntvnodes);
1.1 mycroft 1133: ip = VTOI(vp);
1.57 fvdl 1134: if (vp->v_type == VNON ||
1135: ((ip->i_flag &
1.63 mycroft 1136: (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFIED | IN_ACCESSED)) == 0 &&
1.75 chs 1137: LIST_EMPTY(&vp->v_dirtyblkhd) &&
1.87 chs 1138: vp->v_uobj.uo_npages == 0))
1.57 fvdl 1139: {
1.33 fvdl 1140: simple_unlock(&vp->v_interlock);
1141: continue;
1142: }
1143: simple_unlock(&mntvnode_slock);
1144: error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK);
1145: if (error) {
1146: simple_lock(&mntvnode_slock);
1147: if (error == ENOENT)
1148: goto loop;
1.1 mycroft 1149: continue;
1.33 fvdl 1150: }
1.35 kleink 1151: if ((error = VOP_FSYNC(vp, cred,
1.71 fvdl 1152: waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0, p)) != 0)
1.1 mycroft 1153: allerror = error;
1154: vput(vp);
1.33 fvdl 1155: simple_lock(&mntvnode_slock);
1.1 mycroft 1156: }
1.33 fvdl 1157: simple_unlock(&mntvnode_slock);
1.1 mycroft 1158: /*
1159: * Force stale file system control information to be flushed.
1160: */
1.55 fvdl 1161: if (waitfor != MNT_LAZY) {
1162: if (ump->um_mountp->mnt_flag & MNT_SOFTDEP)
1163: waitfor = MNT_NOWAIT;
1164: vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
1165: if ((error = VOP_FSYNC(ump->um_devvp, cred,
1.71 fvdl 1166: waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0, p)) != 0)
1.55 fvdl 1167: allerror = error;
1168: VOP_UNLOCK(ump->um_devvp, 0);
1169: }
1.1 mycroft 1170: #ifdef QUOTA
1171: qsync(mp);
1172: #endif
1.33 fvdl 1173: /*
1174: * Write back modified superblock.
1175: */
1176: if (fs->fs_fmod != 0) {
1177: fs->fs_fmod = 0;
1178: fs->fs_time = time.tv_sec;
1.64 mycroft 1179: if ((error = ffs_cgupdate(ump, waitfor)))
1180: allerror = error;
1.33 fvdl 1181: }
1.1 mycroft 1182: return (allerror);
1183: }
1184:
1185: /*
1186: * Look up a FFS dinode number to find its incore vnode, otherwise read it
1187: * in from disk. If it is in core, wait for the lock bit to clear, then
1188: * return the inode locked. Detection and handling of mount points must be
1189: * done by the calling routine.
1190: */
1191: int
1192: ffs_vget(mp, ino, vpp)
1193: struct mount *mp;
1194: ino_t ino;
1195: struct vnode **vpp;
1196: {
1.33 fvdl 1197: struct fs *fs;
1198: struct inode *ip;
1.1 mycroft 1199: struct ufsmount *ump;
1200: struct buf *bp;
1201: struct vnode *vp;
1202: dev_t dev;
1.43 thorpej 1203: int error;
1.44 thorpej 1204: caddr_t cp;
1.1 mycroft 1205:
1206: ump = VFSTOUFS(mp);
1207: dev = ump->um_dev;
1.68 fvdl 1208:
1209: if ((*vpp = ufs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL)
1210: return (0);
1.1 mycroft 1211:
1212: /* Allocate a new vnode/inode. */
1.19 christos 1213: if ((error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) != 0) {
1.1 mycroft 1214: *vpp = NULL;
1215: return (error);
1216: }
1.68 fvdl 1217:
1218: /*
1219: * If someone beat us to it while sleeping in getnewvnode(),
1220: * push back the freshly allocated vnode we don't need, and return.
1221: */
1.87 chs 1222:
1.68 fvdl 1223: do {
1224: if ((*vpp = ufs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) {
1.69 fvdl 1225: ungetnewvnode(vp);
1.68 fvdl 1226: return (0);
1227: }
1228: } while (lockmgr(&ufs_hashlock, LK_EXCLUSIVE|LK_SLEEPFAIL, 0));
1229:
1.43 thorpej 1230: /*
1231: * XXX MFS ends up here, too, to allocate an inode. Should we
1232: * XXX create another pool for MFS inodes?
1233: */
1.87 chs 1234:
1.43 thorpej 1235: ip = pool_get(&ffs_inode_pool, PR_WAITOK);
1.87 chs 1236: memset(ip, 0, sizeof(struct inode));
1.1 mycroft 1237: vp->v_data = ip;
1238: ip->i_vnode = vp;
1239: ip->i_fs = fs = ump->um_fs;
1240: ip->i_dev = dev;
1241: ip->i_number = ino;
1.77 chs 1242: LIST_INIT(&ip->i_pcbufhd);
1.1 mycroft 1243: #ifdef QUOTA
1.19 christos 1244: {
1245: int i;
1246:
1247: for (i = 0; i < MAXQUOTAS; i++)
1248: ip->i_dquot[i] = NODQUOT;
1249: }
1.1 mycroft 1250: #endif
1.86 chs 1251:
1.1 mycroft 1252: /*
1253: * Put it onto its hash chain and lock it so that other requests for
1254: * this inode will block if they arrive while we are sleeping waiting
1255: * for old data structures to be purged or for the contents of the
1256: * disk portion of this inode to be read.
1257: */
1.87 chs 1258:
1.1 mycroft 1259: ufs_ihashins(ip);
1.33 fvdl 1260: lockmgr(&ufs_hashlock, LK_RELEASE, 0);
1.1 mycroft 1261:
1262: /* Read in the disk contents for the inode, copy into the inode. */
1.19 christos 1263: error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
1264: (int)fs->fs_bsize, NOCRED, &bp);
1265: if (error) {
1.87 chs 1266:
1.1 mycroft 1267: /*
1268: * The inode does not contain anything useful, so it would
1269: * be misleading to leave it on its hash chain. With mode
1270: * still zero, it will be unlinked and returned to the free
1271: * list by vput().
1272: */
1.87 chs 1273:
1.1 mycroft 1274: vput(vp);
1275: brelse(bp);
1276: *vpp = NULL;
1277: return (error);
1278: }
1.44 thorpej 1279: cp = (caddr_t)bp->b_data + (ino_to_fsbo(fs, ino) * DINODE_SIZE);
1.34 bouyer 1280: #ifdef FFS_EI
1.55 fvdl 1281: if (UFS_FSNEEDSWAP(fs))
1.44 thorpej 1282: ffs_dinode_swap((struct dinode *)cp, &ip->i_din.ffs_din);
1.34 bouyer 1283: else
1284: #endif
1.44 thorpej 1285: memcpy(&ip->i_din.ffs_din, cp, DINODE_SIZE);
1.55 fvdl 1286: if (DOINGSOFTDEP(vp))
1287: softdep_load_inodeblock(ip);
1288: else
1289: ip->i_ffs_effnlink = ip->i_ffs_nlink;
1.1 mycroft 1290: brelse(bp);
1291:
1292: /*
1293: * Initialize the vnode from the inode, check for aliases.
1294: * Note that the underlying vnode may have changed.
1295: */
1.87 chs 1296:
1297: ufs_vinit(mp, ffs_specop_p, ffs_fifoop_p, &vp);
1298:
1.1 mycroft 1299: /*
1300: * Finish inode initialization now that aliasing has been resolved.
1301: */
1.87 chs 1302:
1303: genfs_node_init(vp, &ffs_genfsops);
1.1 mycroft 1304: ip->i_devvp = ump->um_devvp;
1305: VREF(ip->i_devvp);
1.87 chs 1306:
1.1 mycroft 1307: /*
1308: * Ensure that uid and gid are correct. This is a temporary
1309: * fix until fsck has been changed to do the update.
1310: */
1.87 chs 1311:
1.38 kleink 1312: if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
1313: ip->i_ffs_uid = ip->i_din.ffs_din.di_ouid; /* XXX */
1314: ip->i_ffs_gid = ip->i_din.ffs_din.di_ogid; /* XXX */
1315: } /* XXX */
1.73 chs 1316: uvm_vnp_setsize(vp, ip->i_ffs_size);
1.1 mycroft 1317: *vpp = vp;
1318: return (0);
1319: }
1320:
1321: /*
1322: * File handle to vnode
1323: *
1324: * Have to be really careful about stale file handles:
1325: * - check that the inode number is valid
1326: * - call ffs_vget() to get the locked inode
1327: * - check for an unallocated inode (i_mode == 0)
1328: * - check that the given client host has export rights and return
1329: * those rights via. exflagsp and credanonp
1330: */
1331: int
1.48 wrstuden 1332: ffs_fhtovp(mp, fhp, vpp)
1.61 augustss 1333: struct mount *mp;
1.1 mycroft 1334: struct fid *fhp;
1335: struct vnode **vpp;
1336: {
1.61 augustss 1337: struct ufid *ufhp;
1.1 mycroft 1338: struct fs *fs;
1339:
1340: ufhp = (struct ufid *)fhp;
1341: fs = VFSTOUFS(mp)->um_fs;
1342: if (ufhp->ufid_ino < ROOTINO ||
1343: ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
1344: return (ESTALE);
1.48 wrstuden 1345: return (ufs_fhtovp(mp, ufhp, vpp));
1.1 mycroft 1346: }
1347:
1348: /*
1349: * Vnode pointer to File handle
1350: */
1351: /* ARGSUSED */
1.19 christos 1352: int
1.1 mycroft 1353: ffs_vptofh(vp, fhp)
1354: struct vnode *vp;
1355: struct fid *fhp;
1356: {
1.61 augustss 1357: struct inode *ip;
1358: struct ufid *ufhp;
1.1 mycroft 1359:
1360: ip = VTOI(vp);
1361: ufhp = (struct ufid *)fhp;
1362: ufhp->ufid_len = sizeof(struct ufid);
1363: ufhp->ufid_ino = ip->i_number;
1.25 bouyer 1364: ufhp->ufid_gen = ip->i_ffs_gen;
1.1 mycroft 1365: return (0);
1.33 fvdl 1366: }
1367:
1368: void
1369: ffs_init()
1370: {
1.59 jdolecek 1371: if (ffs_initcount++ > 0)
1372: return;
1373:
1.55 fvdl 1374: softdep_initialize();
1.33 fvdl 1375: ufs_init();
1.43 thorpej 1376:
1377: pool_init(&ffs_inode_pool, sizeof(struct inode), 0, 0, 0, "ffsinopl",
1.93 thorpej 1378: &pool_allocator_nointr);
1.86 chs 1379: }
1380:
1381: void
1382: ffs_reinit()
1383: {
1384: softdep_reinitialize();
1385: ufs_reinit();
1.59 jdolecek 1386: }
1387:
1388: void
1389: ffs_done()
1390: {
1391: if (--ffs_initcount > 0)
1392: return;
1393:
1394: /* XXX softdep cleanup ? */
1395: ufs_done();
1396: pool_destroy(&ffs_inode_pool);
1.33 fvdl 1397: }
1398:
1399: int
1400: ffs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
1401: int *name;
1402: u_int namelen;
1403: void *oldp;
1404: size_t *oldlenp;
1405: void *newp;
1406: size_t newlen;
1407: struct proc *p;
1408: {
1.87 chs 1409: extern int doasyncfree;
1.62 jdolecek 1410: extern int ffs_log_changeopt;
1.33 fvdl 1411:
1412: /* all sysctl names at this level are terminal */
1413: if (namelen != 1)
1414: return (ENOTDIR); /* overloaded */
1415:
1416: switch (name[0]) {
1417: case FFS_ASYNCFREE:
1418: return (sysctl_int(oldp, oldlenp, newp, newlen, &doasyncfree));
1.62 jdolecek 1419: case FFS_LOG_CHANGEOPT:
1420: return (sysctl_int(oldp, oldlenp, newp, newlen,
1421: &ffs_log_changeopt));
1.33 fvdl 1422: default:
1423: return (EOPNOTSUPP);
1424: }
1425: /* NOTREACHED */
1.1 mycroft 1426: }
1427:
1428: /*
1429: * Write a superblock and associated information back to disk.
1430: */
1431: int
1432: ffs_sbupdate(mp, waitfor)
1433: struct ufsmount *mp;
1434: int waitfor;
1435: {
1.61 augustss 1436: struct fs *fs = mp->um_fs;
1437: struct buf *bp;
1.15 mycroft 1438: int i, error = 0;
1.34 bouyer 1439: int32_t saved_nrpos = fs->fs_nrpos;
1440: int64_t saved_qbmask = fs->fs_qbmask;
1441: int64_t saved_qfmask = fs->fs_qfmask;
1442: u_int64_t saved_maxfilesize = fs->fs_maxfilesize;
1.55 fvdl 1443: u_int8_t saveflag;
1.1 mycroft 1444:
1445: /* Restore compatibility to old file systems. XXX */
1446: if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
1.34 bouyer 1447: fs->fs_nrpos = -1; /* XXX */
1.1 mycroft 1448: if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
1.5 mycroft 1449: int32_t *lp, tmp; /* XXX */
1.1 mycroft 1450: /* XXX */
1.38 kleink 1451: lp = (int32_t *)&fs->fs_qbmask; /* XXX nuke qfmask too */
1.1 mycroft 1452: tmp = lp[4]; /* XXX */
1453: for (i = 4; i > 0; i--) /* XXX */
1454: lp[i] = lp[i-1]; /* XXX */
1455: lp[0] = tmp; /* XXX */
1456: } /* XXX */
1.34 bouyer 1457: fs->fs_maxfilesize = mp->um_savedmaxfilesize; /* XXX */
1458:
1459: bp = getblk(mp->um_devvp, SBOFF >> (fs->fs_fshift - fs->fs_fsbtodb),
1460: (int)fs->fs_sbsize, 0, 0);
1.55 fvdl 1461: saveflag = fs->fs_flags & FS_INTERNAL;
1462: fs->fs_flags &= ~FS_INTERNAL;
1.42 perry 1463: memcpy(bp->b_data, fs, fs->fs_sbsize);
1.34 bouyer 1464: #ifdef FFS_EI
1465: if (mp->um_flags & UFS_NEEDSWAP)
1.83 lukem 1466: ffs_sb_swap(fs, (struct fs*)bp->b_data);
1.34 bouyer 1467: #endif
1468:
1.55 fvdl 1469: fs->fs_flags |= saveflag;
1.34 bouyer 1470: fs->fs_nrpos = saved_nrpos; /* XXX */
1471: fs->fs_qbmask = saved_qbmask; /* XXX */
1472: fs->fs_qfmask = saved_qfmask; /* XXX */
1473: fs->fs_maxfilesize = saved_maxfilesize; /* XXX */
1474:
1.1 mycroft 1475: if (waitfor == MNT_WAIT)
1476: error = bwrite(bp);
1477: else
1478: bawrite(bp);
1.15 mycroft 1479: return (error);
1480: }
1481:
1482: int
1483: ffs_cgupdate(mp, waitfor)
1484: struct ufsmount *mp;
1485: int waitfor;
1486: {
1.61 augustss 1487: struct fs *fs = mp->um_fs;
1488: struct buf *bp;
1.15 mycroft 1489: int blks;
1.84 lukem 1490: void *space;
1.15 mycroft 1491: int i, size, error = 0, allerror = 0;
1492:
1493: allerror = ffs_sbupdate(mp, waitfor);
1.1 mycroft 1494: blks = howmany(fs->fs_cssize, fs->fs_fsize);
1.84 lukem 1495: space = fs->fs_csp;
1.1 mycroft 1496: for (i = 0; i < blks; i += fs->fs_frag) {
1497: size = fs->fs_bsize;
1498: if (i + fs->fs_frag > blks)
1499: size = (blks - i) * fs->fs_fsize;
1500: bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i),
1501: size, 0, 0);
1.34 bouyer 1502: #ifdef FFS_EI
1503: if (mp->um_flags & UFS_NEEDSWAP)
1504: ffs_csum_swap((struct csum*)space,
1.38 kleink 1505: (struct csum*)bp->b_data, size);
1.34 bouyer 1506: else
1507: #endif
1.42 perry 1508: memcpy(bp->b_data, space, (u_int)size);
1.84 lukem 1509: space = (char *)space + size;
1.1 mycroft 1510: if (waitfor == MNT_WAIT)
1511: error = bwrite(bp);
1512: else
1513: bawrite(bp);
1514: }
1.15 mycroft 1515: if (!allerror && error)
1516: allerror = error;
1517: return (allerror);
1.1 mycroft 1518: }
CVSweb <webmaster@jp.NetBSD.org>