xref: /original-bsd/sys/ufs/lfs/lfs_vfsops.c (revision e59fb703)
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  *	@(#)lfs_vfsops.c	7.70 (Berkeley) 12/31/91
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/inode.h>
27 #include <ufs/ufs/ufsmount.h>
28 #include <ufs/ufs/ufs_extern.h>
29 
30 #include <ufs/lfs/lfs.h>
31 #include <ufs/lfs/lfs_extern.h>
32 
33 int lfs_mountfs __P((struct vnode *, struct mount *, struct proc *));
34 
35 struct vfsops lfs_vfsops = {
36 	lfs_mount,
37 	ufs_start,
38 	lfs_unmount,
39 	lfs_root,
40 	ufs_quotactl,
41 	lfs_statfs,
42 	lfs_sync,
43 	lfs_fhtovp,
44 	lfs_vptofh,
45 	lfs_init,
46 };
47 
48 int
49 lfs_mountroot()
50 {
51 	panic("lfs_mountroot");		/* XXX -- implement */
52 }
53 
54 /*
55  * VFS Operations.
56  *
57  * mount system call
58  */
59 lfs_mount(mp, path, data, ndp, p)
60 	register struct mount *mp;
61 	char *path;
62 	caddr_t data;
63 	struct nameidata *ndp;
64 	struct proc *p;
65 {
66 	struct vnode *devvp;
67 	struct ufs_args args;
68 	struct ufsmount *ump;
69 	register struct lfs *fs;				/* LFS */
70 	u_int size;
71 	int error;
72 
73 	if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
74 		return (error);
75 
76 	/* Until LFS can do NFS right.		XXX */
77 	if (args.exflags & MNT_EXPORTED)
78 		return (EINVAL);
79 	/*
80 	 * Process export requests.
81 	 */
82 	if ((args.exflags & MNT_EXPORTED) || (mp->mnt_flag & MNT_EXPORTED)) {
83 		if (args.exflags & MNT_EXPORTED)
84 			mp->mnt_flag |= MNT_EXPORTED;
85 		else
86 			mp->mnt_flag &= ~MNT_EXPORTED;
87 		if (args.exflags & MNT_EXRDONLY)
88 			mp->mnt_flag |= MNT_EXRDONLY;
89 		else
90 			mp->mnt_flag &= ~MNT_EXRDONLY;
91 		mp->mnt_exroot = args.exroot;
92 	}
93 	/*
94 	 * If updating, check whether changing from read-only to
95 	 * read/write; if there is no device name, that's all we do.
96 	 */
97 	if (mp->mnt_flag & MNT_UPDATE) {
98 		ump = VFSTOUFS(mp);
99 #ifdef NOTLFS							/* LFS */
100 		fs = ump->um_fs;
101 		if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
102 			fs->fs_ronly = 0;
103 #else
104 		fs = ump->um_lfs;
105 		if (fs->lfs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
106 			fs->lfs_ronly = 0;
107 #endif
108 		if (args.fspec == 0)
109 			return (0);
110 	}
111 	/*
112 	 * Not an update, or updating the name: look up the name
113 	 * and verify that it refers to a sensible block device.
114 	 */
115 	ndp->ni_nameiop = LOOKUP | FOLLOW;
116 	ndp->ni_segflg = UIO_USERSPACE;
117 	ndp->ni_dirp = args.fspec;
118 	if (error = namei(ndp, p))
119 		return (error);
120 	devvp = ndp->ni_vp;
121 	if (devvp->v_type != VBLK) {
122 		vrele(devvp);
123 		return (ENOTBLK);
124 	}
125 	if (major(devvp->v_rdev) >= nblkdev) {
126 		vrele(devvp);
127 		return (ENXIO);
128 	}
129 	if ((mp->mnt_flag & MNT_UPDATE) == 0)
130 		error = lfs_mountfs(devvp, mp, p);		/* LFS */
131 	else {
132 		if (devvp != ump->um_devvp)
133 			error = EINVAL;	/* needs translation */
134 		else
135 			vrele(devvp);
136 	}
137 	if (error) {
138 		vrele(devvp);
139 		return (error);
140 	}
141 	ump = VFSTOUFS(mp);
142 	fs = ump->um_lfs;					/* LFS */
143 #ifdef NOTLFS							/* LFS */
144 	(void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
145 	bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
146 	bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
147 	    MNAMELEN);
148 	(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
149 	    &size);
150 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
151 	(void) ufs_statfs(mp, &mp->mnt_stat, p);
152 #else
153 	(void)copyinstr(path, fs->lfs_fsmnt, sizeof(fs->lfs_fsmnt) - 1, &size);
154 	bzero(fs->lfs_fsmnt + size, sizeof(fs->lfs_fsmnt) - size);
155 	bcopy((caddr_t)fs->lfs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
156 	    MNAMELEN);
157 	(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
158 	    &size);
159 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
160 	(void) lfs_statfs(mp, &mp->mnt_stat, p);
161 #endif
162 	return (0);
163 }
164 
165 /*
166  * Common code for mount and mountroot
167  * LFS specific
168  */
169 int
170 lfs_mountfs(devvp, mp, p)
171 	register struct vnode *devvp;
172 	struct mount *mp;
173 	struct proc *p;
174 {
175 	extern struct vnode *rootvp;
176 	register struct lfs *fs;
177 	register struct ufsmount *ump;
178 	struct inode *ip;
179 	struct vnode *vp;
180 	struct buf *bp;
181 	struct partinfo dpart;
182 	daddr_t seg_addr;
183 	dev_t dev;
184 	int error, i, ronly, size;
185 
186 	/*
187 	 * Disallow multiple mounts of the same device.
188 	 * Disallow mounting of a device that is currently in use
189 	 * (except for root, which might share swap device for miniroot).
190 	 * Flush out any old buffers remaining from a previous use.
191 	 */
192 	if (error = ufs_mountedon(devvp))
193 		return (error);
194 	if (vcount(devvp) > 1 && devvp != rootvp)
195 		return (EBUSY);
196 	vinvalbuf(devvp, 1);
197 
198 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
199 	if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p))
200 		return (error);
201 
202 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
203 		size = DEV_BSIZE;
204 	else {
205 		size = dpart.disklab->d_secsize;
206 #ifdef NEVER_USED
207 		dpart.part->p_fstype = FS_LFS;
208 		dpart.part->p_fsize = fs->lfs_fsize;	/* frag size */
209 		dpart.part->p_frag = fs->lfs_frag;	/* frags per block */
210 		dpart.part->p_cpg = fs->lfs_segshift;	/* segment shift */
211 #endif
212 	}
213 
214 	/* Don't free random space on error. */
215 	bp = NULL;
216 	ump = NULL;
217 
218 	/* Read in the superblock. */
219 	if (error = bread(devvp, LFS_LABELPAD / size, LFS_SBPAD, NOCRED, &bp))
220 		goto out;
221 	fs = bp->b_un.b_lfs;
222 
223 	/* Check the basics. */
224 	if (fs->lfs_magic != LFS_MAGIC || fs->lfs_bsize > MAXBSIZE ||
225 	    fs->lfs_bsize < sizeof(struct lfs)) {
226 		error = EINVAL;		/* XXX needs translation */
227 		goto out;
228 	}
229 #ifdef DEBUG
230 	lfs_dump_super(fs);
231 #endif
232 
233 	/* Allocate the mount structure, copy the superblock into it. */
234 	ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
235 	ump->um_lfs = malloc(sizeof(struct lfs), M_UFSMNT, M_WAITOK);
236 	bcopy(bp->b_un.b_addr, ump->um_lfs, sizeof(struct lfs));
237 	if (sizeof(struct lfs) < LFS_SBPAD)			/* XXX why? */
238 		bp->b_flags |= B_INVAL;
239 	brelse(bp);
240 	bp = NULL;
241 
242 	/* Set up the I/O information */
243 	fs->lfs_iocount = 0;
244 	/* XXX NOTUSED:	fs->lfs_seglist = NULL; */
245 
246 	/* Set the file system readonly/modify bits. */
247 	fs = ump->um_lfs;
248 	fs->lfs_ronly = ronly;
249 	if (ronly == 0)
250 		fs->lfs_fmod = 1;
251 
252 	/* Initialize the mount structure. */
253 	dev = devvp->v_rdev;
254 	mp->mnt_data = (qaddr_t)ump;
255 	mp->mnt_stat.f_fsid.val[0] = (long)dev;
256 	mp->mnt_stat.f_fsid.val[1] = MOUNT_LFS;
257 	mp->mnt_flag |= MNT_LOCAL;
258 	ump->um_mountp = mp;
259 	ump->um_dev = dev;
260 	ump->um_devvp = devvp;
261 	for (i = 0; i < MAXQUOTAS; i++)
262 		ump->um_quotas[i] = NULLVP;
263 
264 	/* Read the ifile disk inode and store it in a vnode. */
265 	if (error = bread(devvp, fs->lfs_idaddr, fs->lfs_bsize, NOCRED, &bp))
266 		goto out;
267 	if (error = lfs_vcreate(mp, LFS_IFILE_INUM, &vp))
268 		goto out;
269 	ip = VTOI(vp);
270 	VREF(ip->i_devvp);
271 
272 	/* The ifile inode is stored in the superblock. */
273 	fs->lfs_ivnode = vp;
274 
275 	/* Copy the on-disk inode into place. */
276 	ip->i_din = *lfs_ifind(fs, LFS_IFILE_INUM, bp->b_un.b_dino);
277 	brelse(bp);
278 
279 	/* Initialize the associated vnode */
280 	vp->v_type = IFTOVT(ip->i_mode);
281 
282 	devvp->v_specflags |= SI_MOUNTEDON;
283 	VREF(ip->i_devvp);
284 	return (0);
285 out:
286 	if (bp)
287 		brelse(bp);
288 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
289 	if (ump) {
290 		free(ump->um_lfs, M_UFSMNT);
291 		free(ump, M_UFSMNT);
292 		mp->mnt_data = (qaddr_t)0;
293 	}
294 	return (error);
295 }
296 
297 /*
298  * unmount system call
299  */
300 lfs_unmount(mp, mntflags, p)
301 	struct mount *mp;
302 	int mntflags;
303 	struct proc *p;
304 {
305 	extern int doforce;
306 	register struct ufsmount *ump;
307 	register struct lfs *fs;				/* LFS */
308 	int i, error, ronly, flags = 0;
309 	int ndirty;						/* LFS */
310 
311 #ifdef VERBOSE
312 	printf("lfs_unmount\n");
313 #endif
314 	if (mntflags & MNT_FORCE) {
315 		if (!doforce || mp == rootfs)
316 			return (EINVAL);
317 		flags |= FORCECLOSE;
318 	}
319 	if (error = lfs_segwrite(mp, 1))
320 		return(error);
321 
322 ndirty = lfs_umountdebug(mp);
323 printf("lfs_umountdebug: returned %d dirty\n", ndirty);
324 return(0);
325 	if (mntinvalbuf(mp))
326 		return (EBUSY);
327 	ump = VFSTOUFS(mp);
328 #ifdef QUOTA
329 	if (mp->mnt_flag & MNT_QUOTA) {
330 		if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags))
331 			return (error);
332 		for (i = 0; i < MAXQUOTAS; i++) {
333 			if (ump->um_quotas[i] == NULLVP)
334 				continue;
335 			quotaoff(p, mp, i);
336 		}
337 		/*
338 		 * Here we fall through to vflush again to ensure
339 		 * that we have gotten rid of all the system vnodes.
340 		 */
341 	}
342 #endif
343 	if (error = vflush(mp, NULLVP, flags))
344 		return (error);
345 #ifdef NOTLFS							/* LFS */
346 	fs = ump->um_fs;
347 	ronly = !fs->fs_ronly;
348 #else
349 	fs = ump->um_lfs;
350 	ronly = !fs->lfs_ronly;
351 #endif
352 	ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
353 	error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE,
354 		NOCRED, p);
355 	vrele(ump->um_devvp);
356 #ifdef NOTLFS							/* LFS */
357 	free((caddr_t)fs->fs_csp[0], M_UFSMNT);
358 #else
359 	iput(VTOI(fs->lfs_ivnode));
360 #endif
361 	free(fs, M_UFSMNT);
362 	free(ump, M_UFSMNT);
363 	mp->mnt_data = (qaddr_t)0;
364 	mp->mnt_flag &= ~MNT_LOCAL;
365 	return (error);
366 }
367 
368 /*
369  * Return root of a filesystem
370  */
371 int
372 lfs_root(mp, vpp)
373 	struct mount *mp;
374 	struct vnode **vpp;
375 {
376 	struct vnode *nvp;
377 	int error;
378 
379 #ifdef VERBOSE
380 	printf("lfs_root\n");
381 #endif
382 	if (error = lfs_vget(mp, (ino_t)ROOTINO, &nvp))
383 		return (error);
384 	*vpp = nvp;
385 	return (0);
386 }
387 
388 /*
389  * Get file system statistics.
390  */
391 lfs_statfs(mp, sbp, p)
392 	struct mount *mp;
393 	register struct statfs *sbp;
394 	struct proc *p;
395 {
396 	register struct lfs *fs;
397 	register struct ufsmount *ump;
398 
399 	ump = VFSTOUFS(mp);
400 	fs = ump->um_lfs;
401 	if (fs->lfs_magic != LFS_MAGIC)
402 		panic("lfs_statfs: magic");
403 	sbp->f_type = MOUNT_LFS;
404 	sbp->f_bsize = fs->lfs_bsize;
405 	sbp->f_iosize = fs->lfs_bsize;
406 	sbp->f_blocks = fs->lfs_dsize;
407 	sbp->f_bfree = fs->lfs_bfree;
408 	sbp->f_bavail = (fs->lfs_dsize * (100 - fs->lfs_minfree) / 100) -
409 		(fs->lfs_dsize - sbp->f_bfree);
410 	sbp->f_files = fs->lfs_nfiles;
411 	sbp->f_ffree = fs->lfs_bfree * INOPB(fs);
412 	if (sbp != &mp->mnt_stat) {
413 		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
414 			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
415 		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
416 			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
417 	}
418 	return (0);
419 }
420 
421 /*
422  * Go through the disk queues to initiate sandbagged IO;
423  * go through the inodes to write those that have been modified;
424  * initiate the writing of the super block if it has been modified.
425  *
426  * Note: we are always called with the filesystem marked `MPBUSY'.
427  */
428 lfs_sync(mp, waitfor)
429 	struct mount *mp;
430 	int waitfor;
431 {
432 	extern int crashandburn, syncprt;
433 	int error;
434 
435 #ifdef VERBOSE
436 	printf("lfs_sync\n");
437 #endif
438 
439 #ifdef DIAGNOSTIC
440 	if (crashandburn)
441 		return (0);
442 #endif
443 	if (syncprt)
444 		ufs_bufstats();
445 
446 	/* All syncs must be checkpoints until roll-forward is implemented. */
447 	error = lfs_segwrite(mp, 1);
448 #ifdef QUOTA
449 	qsync(mp);
450 #endif
451 	return (error);
452 }
453 
454 /*
455  * File handle to vnode
456  *
457  * Have to be really careful about stale file handles:
458  * - check that the inode number is valid
459  * - call lfs_vget() to get the locked inode
460  * - check for an unallocated inode (i_mode == 0)
461  * - check that the generation number matches
462  *
463  * XXX
464  * use ifile to see if inode is allocated instead of reading off disk
465  * what is the relationship between my generational number and the NFS
466  * generational number.
467  */
468 int
469 lfs_fhtovp(mp, fhp, vpp)
470 	register struct mount *mp;
471 	struct fid *fhp;
472 	struct vnode **vpp;
473 {
474 	register struct inode *ip;
475 	register struct ufid *ufhp;
476 	struct vnode *nvp;
477 	int error;
478 
479 	ufhp = (struct ufid *)fhp;
480 	if (ufhp->ufid_ino < ROOTINO)
481 		return (EINVAL);
482 	if (error = lfs_vget(mp, ufhp->ufid_ino, &nvp)) {
483 		*vpp = NULLVP;
484 		return (error);
485 	}
486 	ip = VTOI(nvp);
487 	if (ip->i_mode == 0) {
488 		ufs_iput(ip);
489 		*vpp = NULLVP;
490 		return (EINVAL);
491 	}
492 	if (ip->i_gen != ufhp->ufid_gen) {
493 		ufs_iput(ip);
494 		*vpp = NULLVP;
495 		return (EINVAL);
496 	}
497 	*vpp = nvp;
498 	return (0);
499 }
500 
501 /*
502  * Vnode pointer to File handle
503  */
504 /* ARGSUSED */
505 lfs_vptofh(vp, fhp)
506 	struct vnode *vp;
507 	struct fid *fhp;
508 {
509 	register struct inode *ip;
510 	register struct ufid *ufhp;
511 
512 	ip = VTOI(vp);
513 	ufhp = (struct ufid *)fhp;
514 	ufhp->ufid_len = sizeof(struct ufid);
515 	ufhp->ufid_ino = ip->i_number;
516 	ufhp->ufid_gen = ip->i_gen;
517 	return (0);
518 }
519