xref: /csrg-svn/sys/ufs/ffs/ffs_vfsops.c (revision 52177)
1 /*
2  * Copyright (c) 1989, 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)ffs_vfsops.c	7.61 (Berkeley) 01/13/92
8  */
9 
10 #include <sys/param.h>
11 #include <sys/systm.h>
12 #include <sys/namei.h>
13 #include <sys/proc.h>
14 #include <sys/kernel.h>
15 #include <sys/vnode.h>
16 #include <sys/specdev.h>
17 #include <sys/mount.h>
18 #include <sys/buf.h>
19 #include <sys/file.h>
20 #include <sys/disklabel.h>
21 #include <sys/ioctl.h>
22 #include <sys/errno.h>
23 #include <sys/malloc.h>
24 
25 #include <ufs/ufs/quota.h>
26 #include <ufs/ufs/ufsmount.h>
27 #include <ufs/ufs/inode.h>
28 #include <ufs/ufs/ufs_extern.h>
29 
30 #include <ufs/ffs/fs.h>
31 #include <ufs/ffs/ffs_extern.h>
32 
33 int ffs_sbupdate __P((struct ufsmount *, int));
34 
35 struct vfsops ufs_vfsops = {
36 	ffs_mount,
37 	ufs_start,
38 	ffs_unmount,
39 	ffs_root,
40 	ufs_quotactl,
41 	ffs_statfs,
42 	ffs_sync,
43 	ffs_fhtovp,
44 	ffs_vptofh,
45 	ffs_init,
46 };
47 
48 /*
49  * Called by vfs_mountroot when ufs is going to be mounted as root.
50  *
51  * Name is updated by mount(8) after booting.
52  */
53 #define ROOTNAME	"root_device"
54 
55 ffs_mountroot()
56 {
57 	extern struct vnode *rootvp;
58 	register struct fs *fs;
59 	register struct mount *mp;
60 	struct proc *p = curproc;	/* XXX */
61 	struct ufsmount *ump;
62 	u_int size;
63 	int error;
64 
65 	mp = malloc((u_long)sizeof(struct mount),
66 		M_MOUNT, M_WAITOK);
67 	mp->mnt_op = &ufs_vfsops;
68 	mp->mnt_flag = MNT_RDONLY;
69 	mp->mnt_mounth = NULLVP;
70 	if (error = ffs_mountfs(rootvp, mp, p)) {
71 		free(mp, M_MOUNT);
72 		return (error);
73 	}
74 	if (error = vfs_lock(mp)) {
75 		(void)ffs_unmount(mp, 0, p);
76 		free(mp, M_MOUNT);
77 		return (error);
78 	}
79 	rootfs = mp;
80 	mp->mnt_next = mp;
81 	mp->mnt_prev = mp;
82 	mp->mnt_vnodecovered = NULLVP;
83 	ump = VFSTOUFS(mp);
84 	fs = ump->um_fs;
85 	bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt));
86 	fs->fs_fsmnt[0] = '/';
87 	bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
88 	    MNAMELEN);
89 	(void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
90 	    &size);
91 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
92 	(void)ffs_statfs(mp, &mp->mnt_stat, p);
93 	vfs_unlock(mp);
94 	inittodr(fs->fs_time);
95 	return (0);
96 }
97 
98 /*
99  * VFS Operations.
100  *
101  * mount system call
102  */
103 int
104 ffs_mount(mp, path, data, ndp, p)
105 	register struct mount *mp;
106 	char *path;
107 	caddr_t data;
108 	struct nameidata *ndp;
109 	struct proc *p;
110 {
111 	struct vnode *devvp;
112 	struct ufs_args args;
113 	struct ufsmount *ump;
114 	register struct fs *fs;
115 	u_int size;
116 	int error;
117 
118 	if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
119 		return (error);
120 	/*
121 	 * If updating, check whether changing from read-only to
122 	 * read/write; if there is no device name, that's all we do.
123 	 */
124 	if (mp->mnt_flag & MNT_UPDATE) {
125 		ump = VFSTOUFS(mp);
126 		fs = ump->um_fs;
127 		if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
128 			fs->fs_ronly = 0;
129 		if (args.fspec == 0) {
130 			/*
131 			 * Process export requests.
132 			 */
133 			if (args.exflags & MNT_EXPORTED) {
134 				if (error = hang_addrlist(mp, &args))
135 					return (error);
136 				mp->mnt_flag |= MNT_EXPORTED;
137 			}
138 			if (args.exflags & MNT_DELEXPORT) {
139 				free_addrlist(ump);
140 				mp->mnt_flag &=
141 				    ~(MNT_EXPORTED | MNT_DEFEXPORTED);
142 			}
143 			return (0);
144 		}
145 	}
146 	/*
147 	 * Not an update, or updating the name: look up the name
148 	 * and verify that it refers to a sensible block device.
149 	 */
150 	ndp->ni_nameiop = LOOKUP | FOLLOW;
151 	ndp->ni_segflg = UIO_USERSPACE;
152 	ndp->ni_dirp = args.fspec;
153 	if (error = namei(ndp, p))
154 		return (error);
155 	devvp = ndp->ni_vp;
156 
157 	if (devvp->v_type != VBLK) {
158 		vrele(devvp);
159 		return (ENOTBLK);
160 	}
161 	if (major(devvp->v_rdev) >= nblkdev) {
162 		vrele(devvp);
163 		return (ENXIO);
164 	}
165 	if ((mp->mnt_flag & MNT_UPDATE) == 0)
166 		error = ffs_mountfs(devvp, mp, p);
167 	else {
168 		if (devvp != ump->um_devvp)
169 			error = EINVAL;	/* needs translation */
170 		else
171 			vrele(devvp);
172 	}
173 	if (error) {
174 		vrele(devvp);
175 		return (error);
176 	}
177 	ump = VFSTOUFS(mp);
178 	fs = ump->um_fs;
179 	(void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
180 	bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
181 	bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
182 	    MNAMELEN);
183 	(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
184 	    &size);
185 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
186 	(void)ffs_statfs(mp, &mp->mnt_stat, p);
187 	return (0);
188 }
189 
190 /*
191  * Common code for mount and mountroot
192  */
193 int
194 ffs_mountfs(devvp, mp, p)
195 	register struct vnode *devvp;
196 	struct mount *mp;
197 	struct proc *p;
198 {
199 	register struct ufsmount *ump = (struct ufsmount *)0;
200 	struct buf *bp = NULL;
201 	register struct fs *fs;
202 	dev_t dev = devvp->v_rdev;
203 	struct partinfo dpart;
204 	caddr_t base, space;
205 	int havepart = 0, blks;
206 	int error, i, size;
207 	int needclose = 0;
208 	int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
209 	extern struct vnode *rootvp;
210 
211 	/*
212 	 * Disallow multiple mounts of the same device.
213 	 * Disallow mounting of a device that is currently in use
214 	 * (except for root, which might share swap device for miniroot).
215 	 * Flush out any old buffers remaining from a previous use.
216 	 */
217 	if (error = ufs_mountedon(devvp))
218 		return (error);
219 	if (vcount(devvp) > 1 && devvp != rootvp)
220 		return (EBUSY);
221 	vinvalbuf(devvp, 1);
222 	if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p))
223 		return (error);
224 	needclose = 1;
225 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
226 		size = DEV_BSIZE;
227 	else {
228 		havepart = 1;
229 		size = dpart.disklab->d_secsize;
230 	}
231 	if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp))
232 		goto out;
233 	fs = bp->b_un.b_fs;
234 	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
235 	    fs->fs_bsize < sizeof(struct fs)) {
236 		error = EINVAL;		/* XXX needs translation */
237 		goto out;
238 	}
239 	ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
240 	ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT,
241 	    M_WAITOK);
242 	bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs,
243 	   (u_int)fs->fs_sbsize);
244 	if (fs->fs_sbsize < SBSIZE)
245 		bp->b_flags |= B_INVAL;
246 	brelse(bp);
247 	bp = NULL;
248 	fs = ump->um_fs;
249 	fs->fs_ronly = ronly;
250 	if (ronly == 0)
251 		fs->fs_fmod = 1;
252 	if (havepart) {
253 		dpart.part->p_fstype = FS_BSDFFS;
254 		dpart.part->p_fsize = fs->fs_fsize;
255 		dpart.part->p_frag = fs->fs_frag;
256 		dpart.part->p_cpg = fs->fs_cpg;
257 	}
258 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
259 	base = space = malloc((u_long)fs->fs_cssize, M_UFSMNT,
260 	    M_WAITOK);
261 	for (i = 0; i < blks; i += fs->fs_frag) {
262 		size = fs->fs_bsize;
263 		if (i + fs->fs_frag > blks)
264 			size = (blks - i) * fs->fs_fsize;
265 		error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
266 			NOCRED, &bp);
267 		if (error) {
268 			free(base, M_UFSMNT);
269 			goto out;
270 		}
271 		bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size);
272 		fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
273 		space += size;
274 		brelse(bp);
275 		bp = NULL;
276 	}
277 	mp->mnt_data = (qaddr_t)ump;
278 	mp->mnt_stat.f_fsid.val[0] = (long)dev;
279 	mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS;
280 	mp->mnt_flag |= MNT_LOCAL;
281 	ump->um_mountp = mp;
282 	ump->um_dev = dev;
283 	ump->um_devvp = devvp;
284 	for (i = 0; i < MAXQUOTAS; i++)
285 		ump->um_quotas[i] = NULLVP;
286 	devvp->v_specflags |= SI_MOUNTEDON;
287 
288 	/* Sanity checks for old file systems.			   XXX */
289 	fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect);	/* XXX */
290 	fs->fs_interleave = MAX(fs->fs_interleave, 1);		/* XXX */
291 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
292 		fs->fs_nrpos = 8;				/* XXX */
293 	return (0);
294 out:
295 	if (bp)
296 		brelse(bp);
297 	if (needclose)
298 		(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
299 	if (ump) {
300 		free(ump->um_fs, M_UFSMNT);
301 		free(ump, M_UFSMNT);
302 		mp->mnt_data = (qaddr_t)0;
303 	}
304 	return (error);
305 }
306 
307 /*
308  * unmount system call
309  */
310 int
311 ffs_unmount(mp, mntflags, p)
312 	struct mount *mp;
313 	int mntflags;
314 	struct proc *p;
315 {
316 	extern int doforce;
317 	register struct ufsmount *ump;
318 	register struct fs *fs;
319 	int i, error, ronly, flags = 0;
320 
321 	if (mntflags & MNT_FORCE) {
322 		if (!doforce || mp == rootfs)
323 			return (EINVAL);
324 		flags |= FORCECLOSE;
325 	}
326 	mntflushbuf(mp, 0);
327 	if (mntinvalbuf(mp))
328 		return (EBUSY);
329 	ump = VFSTOUFS(mp);
330 #ifdef QUOTA
331 	if (mp->mnt_flag & MNT_QUOTA) {
332 		if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags))
333 			return (error);
334 		for (i = 0; i < MAXQUOTAS; i++) {
335 			if (ump->um_quotas[i] == NULLVP)
336 				continue;
337 			quotaoff(p, mp, i);
338 		}
339 		/*
340 		 * Here we fall through to vflush again to ensure
341 		 * that we have gotten rid of all the system vnodes.
342 		 */
343 	}
344 #endif
345 	if (error = vflush(mp, NULLVP, flags))
346 		return (error);
347 	fs = ump->um_fs;
348 	ronly = !fs->fs_ronly;
349 	ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
350 	error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE,
351 		NOCRED, p);
352 	vrele(ump->um_devvp);
353 	free(fs->fs_csp[0], M_UFSMNT);
354 	free(fs, M_UFSMNT);
355 	free(ump, M_UFSMNT);
356 	mp->mnt_data = (qaddr_t)0;
357 	mp->mnt_flag &= ~MNT_LOCAL;
358 	return (error);
359 }
360 
361 /*
362  * Return root of a filesystem
363  */
364 int
365 ffs_root(mp, vpp)
366 	struct mount *mp;
367 	struct vnode **vpp;
368 {
369 	struct vnode *nvp;
370 	int error;
371 
372 	if (error = ffs_vget(mp, (ino_t)ROOTINO, &nvp))
373 		return (error);
374 	*vpp = nvp;
375 	return (0);
376 }
377 
378 /*
379  * Get file system statistics.
380  */
381 int
382 ffs_statfs(mp, sbp, p)
383 	struct mount *mp;
384 	register struct statfs *sbp;
385 	struct proc *p;
386 {
387 	register struct ufsmount *ump;
388 	register struct fs *fs;
389 
390 	ump = VFSTOUFS(mp);
391 	fs = ump->um_fs;
392 	if (fs->fs_magic != FS_MAGIC)
393 		panic("ffs_statfs");
394 	sbp->f_type = MOUNT_UFS;
395 	sbp->f_bsize = fs->fs_fsize;
396 	sbp->f_iosize = fs->fs_bsize;
397 	sbp->f_blocks = fs->fs_dsize;
398 	sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
399 		fs->fs_cstotal.cs_nffree;
400 	sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) -
401 		(fs->fs_dsize - sbp->f_bfree);
402 	sbp->f_files =  fs->fs_ncg * fs->fs_ipg - ROOTINO;
403 	sbp->f_ffree = fs->fs_cstotal.cs_nifree;
404 	if (sbp != &mp->mnt_stat) {
405 		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
406 			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
407 		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
408 			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
409 	}
410 	return (0);
411 }
412 
413 /*
414  * Go through the disk queues to initiate sandbagged IO;
415  * go through the inodes to write those that have been modified;
416  * initiate the writing of the super block if it has been modified.
417  *
418  * Note: we are always called with the filesystem marked `MPBUSY'.
419  */
420 int
421 ffs_sync(mp, waitfor)
422 	struct mount *mp;
423 	int waitfor;
424 {
425 	extern int syncprt;
426 	register struct vnode *vp;
427 	register struct inode *ip;
428 	register struct ufsmount *ump = VFSTOUFS(mp);
429 	register struct fs *fs;
430 	int error, allerror = 0;
431 
432 	if (syncprt)
433 		ufs_bufstats();
434 	fs = ump->um_fs;
435 	/*
436 	 * Write back modified superblock.
437 	 * Consistency check that the superblock
438 	 * is still in the buffer cache.
439 	 */
440 	if (fs->fs_fmod != 0) {
441 		if (fs->fs_ronly != 0) {		/* XXX */
442 			printf("fs = %s\n", fs->fs_fsmnt);
443 			panic("update: rofs mod");
444 		}
445 		fs->fs_fmod = 0;
446 		fs->fs_time = time.tv_sec;
447 		allerror = ffs_sbupdate(ump, waitfor);
448 	}
449 	/*
450 	 * Write back each (modified) inode.
451 	 */
452 loop:
453 	for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
454 		/*
455 		 * If the vnode that we are about to sync is no longer
456 		 * associated with this mount point, start over.
457 		 */
458 		if (vp->v_mount != mp)
459 			goto loop;
460 		if (VOP_ISLOCKED(vp))
461 			continue;
462 		ip = VTOI(vp);
463 		if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 &&
464 		    vp->v_dirtyblkhd == NULL)
465 			continue;
466 		if (vget(vp))
467 			goto loop;
468 		if (vp->v_dirtyblkhd)
469 			vflushbuf(vp, 0);
470 		if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) &&
471 		    (error = ffs_update(vp, &time, &time, 0)))
472 			allerror = error;
473 		vput(vp);
474 	}
475 	/*
476 	 * Force stale file system control information to be flushed.
477 	 */
478 	vflushbuf(ump->um_devvp, waitfor == MNT_WAIT ? B_SYNC : 0);
479 #ifdef QUOTA
480 	qsync(mp);
481 #endif
482 	return (allerror);
483 }
484 
485 /*
486  * File handle to vnode
487  *
488  * Have to be really careful about stale file handles:
489  * - check that the inode number is valid
490  * - call ffs_vget() to get the locked inode
491  * - check for an unallocated inode (i_mode == 0)
492  * - check that the generation number matches unless setgen true
493  */
494 int
495 ffs_fhtovp(mp, fhp, setgen, vpp)
496 	register struct mount *mp;
497 	struct fid *fhp;
498 	int setgen;
499 	struct vnode **vpp;
500 {
501 	register struct inode *ip;
502 	register struct ufid *ufhp;
503 	struct fs *fs;
504 	struct vnode *nvp;
505 	int error;
506 
507 	ufhp = (struct ufid *)fhp;
508 	fs = VFSTOUFS(mp)->um_fs;
509 	if (ufhp->ufid_ino < ROOTINO ||
510 	    ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
511 		return (EINVAL);
512 	if (error = ffs_vget(mp, ufhp->ufid_ino, &nvp)) {
513 		*vpp = NULLVP;
514 		return (error);
515 	}
516 	ip = VTOI(nvp);
517 	if (ip->i_mode == 0) {
518 		ufs_iput(ip);
519 		*vpp = NULLVP;
520 		return (EINVAL);
521 	}
522 	if (ip->i_gen != ufhp->ufid_gen) {
523 		if (setgen)
524 			ufhp->ufid_gen = ip->i_gen;
525 		else {
526 			ufs_iput(ip);
527 			*vpp = NULLVP;
528 			return (EINVAL);
529 		}
530 	}
531 	*vpp = nvp;
532 	return (0);
533 }
534 
535 /*
536  * Vnode pointer to File handle
537  */
538 /* ARGSUSED */
539 ffs_vptofh(vp, fhp)
540 	struct vnode *vp;
541 	struct fid *fhp;
542 {
543 	register struct inode *ip;
544 	register struct ufid *ufhp;
545 
546 	ip = VTOI(vp);
547 	ufhp = (struct ufid *)fhp;
548 	ufhp->ufid_len = sizeof(struct ufid);
549 	ufhp->ufid_ino = ip->i_number;
550 	ufhp->ufid_gen = ip->i_gen;
551 	return (0);
552 }
553 
554 /*
555  * Write a superblock and associated information back to disk.
556  */
557 int
558 ffs_sbupdate(mp, waitfor)
559 	struct ufsmount *mp;
560 	int waitfor;
561 {
562 	register struct fs *fs = mp->um_fs;
563 	register struct buf *bp;
564 	int blks;
565 	caddr_t space;
566 	int i, size, error = 0;
567 
568 	bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize);
569 	bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
570 	/* Restore compatibility to old file systems.		   XXX */
571 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
572 		bp->b_un.b_fs->fs_nrpos = -1;			/* XXX */
573 	if (waitfor == MNT_WAIT)
574 		error = bwrite(bp);
575 	else
576 		bawrite(bp);
577 	blks = howmany(fs->fs_cssize, fs->fs_fsize);
578 	space = (caddr_t)fs->fs_csp[0];
579 	for (i = 0; i < blks; i += fs->fs_frag) {
580 		size = fs->fs_bsize;
581 		if (i + fs->fs_frag > blks)
582 			size = (blks - i) * fs->fs_fsize;
583 		bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size);
584 		bcopy(space, bp->b_un.b_addr, (u_int)size);
585 		space += size;
586 		if (waitfor == MNT_WAIT)
587 			error = bwrite(bp);
588 		else
589 			bawrite(bp);
590 	}
591 	return (error);
592 }
593