xref: /netbsd-src/sys/ufs/lfs/lfs_vfsops.c (revision ae9172d6cd9432a6a1a56760d86b32c57a66c39c)
1 /*	$NetBSD: lfs_vfsops.c,v 1.4 1994/12/15 19:51:06 mycroft Exp $	*/
2 
3 /*
4  * Copyright (c) 1989, 1991, 1993, 1994
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  *	@(#)lfs_vfsops.c	8.10 (Berkeley) 11/21/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/mount.h>
45 #include <sys/buf.h>
46 #include <sys/mbuf.h>
47 #include <sys/file.h>
48 #include <sys/disklabel.h>
49 #include <sys/ioctl.h>
50 #include <sys/errno.h>
51 #include <sys/malloc.h>
52 #include <sys/socket.h>
53 
54 #include <miscfs/specfs/specdev.h>
55 
56 #include <ufs/ufs/quota.h>
57 #include <ufs/ufs/inode.h>
58 #include <ufs/ufs/ufsmount.h>
59 #include <ufs/ufs/ufs_extern.h>
60 
61 #include <ufs/lfs/lfs.h>
62 #include <ufs/lfs/lfs_extern.h>
63 
64 int lfs_mountfs __P((struct vnode *, struct mount *, struct proc *));
65 
66 struct vfsops lfs_vfsops = {
67 	MOUNT_LFS,
68 	lfs_mount,
69 	ufs_start,
70 	lfs_unmount,
71 	ufs_root,
72 	ufs_quotactl,
73 	lfs_statfs,
74 	lfs_sync,
75 	lfs_vget,
76 	lfs_fhtovp,
77 	lfs_vptofh,
78 	lfs_init,
79 };
80 
81 int
82 lfs_mountroot()
83 {
84 	panic("lfs_mountroot");		/* XXX -- implement */
85 }
86 
87 /*
88  * VFS Operations.
89  *
90  * mount system call
91  */
92 lfs_mount(mp, path, data, ndp, p)
93 	register struct mount *mp;
94 	char *path;
95 	caddr_t data;
96 	struct nameidata *ndp;
97 	struct proc *p;
98 {
99 	struct vnode *devvp;
100 	struct ufs_args args;
101 	struct ufsmount *ump;
102 	register struct lfs *fs;				/* LFS */
103 	u_int size;
104 	int error;
105 	mode_t accessmode;
106 
107 	if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
108 		return (error);
109 
110 	/* Until LFS can do NFS right.		XXX */
111 	if (args.export.ex_flags & MNT_EXPORTED)
112 		return (EINVAL);
113 
114 	/*
115 	 * If updating, check whether changing from read-only to
116 	 * read/write; if there is no device name, that's all we do.
117 	 */
118 	if (mp->mnt_flag & MNT_UPDATE) {
119 		ump = VFSTOUFS(mp);
120 		if (fs->lfs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) {
121 			/*
122 			 * If upgrade to read-write by non-root, then verify
123 			 * that user has necessary permissions on the device.
124 			 */
125 			if (p->p_ucred->cr_uid != 0) {
126 				VOP_LOCK(ump->um_devvp);
127 				if (error = VOP_ACCESS(ump->um_devvp,
128 				    VREAD | VWRITE, p->p_ucred, p)) {
129 					VOP_UNLOCK(ump->um_devvp);
130 					return (error);
131 				}
132 				VOP_UNLOCK(ump->um_devvp);
133 			}
134 			fs->lfs_ronly = 0;
135 		}
136 		if (args.fspec == 0) {
137 			/*
138 			 * Process export requests.
139 			 */
140 			return (vfs_export(mp, &ump->um_export, &args.export));
141 		}
142 	}
143 	/*
144 	 * Not an update, or updating the name: look up the name
145 	 * and verify that it refers to a sensible block device.
146 	 */
147 	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
148 	if (error = namei(ndp))
149 		return (error);
150 	devvp = ndp->ni_vp;
151 	if (devvp->v_type != VBLK) {
152 		vrele(devvp);
153 		return (ENOTBLK);
154 	}
155 	if (major(devvp->v_rdev) >= nblkdev) {
156 		vrele(devvp);
157 		return (ENXIO);
158 	}
159 	/*
160 	 * If mount by non-root, then verify that user has necessary
161 	 * permissions on the device.
162 	 */
163 	if (p->p_ucred->cr_uid != 0) {
164 		accessmode = VREAD;
165 		if ((mp->mnt_flag & MNT_RDONLY) == 0)
166 			accessmode |= VWRITE;
167 		VOP_LOCK(devvp);
168 		if (error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p)) {
169 			vput(devvp);
170 			return (error);
171 		}
172 		VOP_UNLOCK(devvp);
173 	}
174 	if ((mp->mnt_flag & MNT_UPDATE) == 0)
175 		error = lfs_mountfs(devvp, mp, p);		/* LFS */
176 	else {
177 		if (devvp != ump->um_devvp)
178 			error = EINVAL;	/* needs translation */
179 		else
180 			vrele(devvp);
181 	}
182 	if (error) {
183 		vrele(devvp);
184 		return (error);
185 	}
186 	ump = VFSTOUFS(mp);
187 	fs = ump->um_lfs;					/* LFS */
188 #ifdef NOTLFS							/* LFS */
189 	(void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
190 	bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
191 	bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
192 	    MNAMELEN);
193 #else
194 	(void)copyinstr(path, fs->lfs_fsmnt, sizeof(fs->lfs_fsmnt) - 1, &size);
195 	bzero(fs->lfs_fsmnt + size, sizeof(fs->lfs_fsmnt) - size);
196 	bcopy((caddr_t)fs->lfs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
197 	    MNAMELEN);
198 #endif
199 	(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
200 	    &size);
201 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
202 	return (0);
203 }
204 
205 /*
206  * Common code for mount and mountroot
207  * LFS specific
208  */
209 int
210 lfs_mountfs(devvp, mp, p)
211 	register struct vnode *devvp;
212 	struct mount *mp;
213 	struct proc *p;
214 {
215 	extern struct vnode *rootvp;
216 	register struct lfs *fs;
217 	register struct ufsmount *ump;
218 	struct vnode *vp;
219 	struct buf *bp;
220 	struct partinfo dpart;
221 	dev_t dev;
222 	int error, i, ronly, size;
223 	struct ucred *cred;
224 
225 	cred = p ? p->p_ucred : NOCRED;
226 	/*
227 	 * Disallow multiple mounts of the same device.
228 	 * Disallow mounting of a device that is currently in use
229 	 * (except for root, which might share swap device for miniroot).
230 	 * Flush out any old buffers remaining from a previous use.
231 	 */
232 	if (error = vfs_mountedon(devvp))
233 		return (error);
234 	if (vcount(devvp) > 1 && devvp != rootvp)
235 		return (EBUSY);
236 	if (error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0))
237 		return (error);
238 
239 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
240 	if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p))
241 		return (error);
242 
243 	if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0)
244 		size = DEV_BSIZE;
245 	else {
246 		size = dpart.disklab->d_secsize;
247 #ifdef NEVER_USED
248 		dpart.part->p_fstype = FS_LFS;
249 		dpart.part->p_fsize = fs->lfs_fsize;	/* frag size */
250 		dpart.part->p_frag = fs->lfs_frag;	/* frags per block */
251 		dpart.part->p_cpg = fs->lfs_segshift;	/* segment shift */
252 #endif
253 	}
254 
255 	/* Don't free random space on error. */
256 	bp = NULL;
257 	ump = NULL;
258 
259 	/* Read in the superblock. */
260 	if (error = bread(devvp, LFS_LABELPAD / size, LFS_SBPAD, cred, &bp))
261 		goto out;
262 	fs = (struct lfs *)bp->b_data;
263 
264 	/* Check the basics. */
265 	if (fs->lfs_magic != LFS_MAGIC || fs->lfs_bsize > MAXBSIZE ||
266 	    fs->lfs_bsize < sizeof(struct lfs)) {
267 		error = EINVAL;		/* XXX needs translation */
268 		goto out;
269 	}
270 
271 	/* Allocate the mount structure, copy the superblock into it. */
272 	ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
273 	fs = ump->um_lfs = malloc(sizeof(struct lfs), M_UFSMNT, M_WAITOK);
274 	bcopy(bp->b_data, fs, sizeof(struct lfs));
275 	if (sizeof(struct lfs) < LFS_SBPAD)			/* XXX why? */
276 		bp->b_flags |= B_INVAL;
277 	brelse(bp);
278 	bp = NULL;
279 
280 	/* Set up the I/O information */
281 	fs->lfs_iocount = 0;
282 
283 	/* Set up the ifile and lock aflags */
284 	fs->lfs_doifile = 0;
285 	fs->lfs_writer = 0;
286 	fs->lfs_dirops = 0;
287 	fs->lfs_seglock = 0;
288 
289 	/* Set the file system readonly/modify bits. */
290 	fs->lfs_ronly = ronly;
291 	if (ronly == 0)
292 		fs->lfs_fmod = 1;
293 
294 	/* Initialize the mount structure. */
295 	dev = devvp->v_rdev;
296 	mp->mnt_data = (qaddr_t)ump;
297 	mp->mnt_stat.f_fsid.val[0] = (long)dev;
298 	mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_LFS);
299 	mp->mnt_maxsymlinklen = fs->lfs_maxsymlinklen;
300 	mp->mnt_flag |= MNT_LOCAL;
301 	ump->um_mountp = mp;
302 	ump->um_dev = dev;
303 	ump->um_devvp = devvp;
304 	ump->um_bptrtodb = 0;
305 	ump->um_seqinc = 1 << fs->lfs_fsbtodb;
306 	ump->um_nindir = fs->lfs_nindir;
307 	for (i = 0; i < MAXQUOTAS; i++)
308 		ump->um_quotas[i] = NULLVP;
309 	devvp->v_specflags |= SI_MOUNTEDON;
310 
311 	/*
312 	 * We use the ifile vnode for almost every operation.  Instead of
313 	 * retrieving it from the hash table each time we retrieve it here,
314 	 * artificially increment the reference count and keep a pointer
315 	 * to it in the incore copy of the superblock.
316 	 */
317 	if (error = VFS_VGET(mp, LFS_IFILE_INUM, &vp))
318 		goto out;
319 	fs->lfs_ivnode = vp;
320 	VREF(vp);
321 	vput(vp);
322 
323 	return (0);
324 out:
325 	if (bp)
326 		brelse(bp);
327 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
328 	if (ump) {
329 		free(ump->um_lfs, M_UFSMNT);
330 		free(ump, M_UFSMNT);
331 		mp->mnt_data = (qaddr_t)0;
332 	}
333 	return (error);
334 }
335 
336 /*
337  * unmount system call
338  */
339 lfs_unmount(mp, mntflags, p)
340 	struct mount *mp;
341 	int mntflags;
342 	struct proc *p;
343 {
344 	extern int doforce;
345 	register struct ufsmount *ump;
346 	register struct lfs *fs;
347 	int i, error, flags, ronly;
348 
349 	flags = 0;
350 	if (mntflags & MNT_FORCE) {
351 		if (!doforce || (mp->mnt_flag & MNT_ROOTFS))
352 			return (EINVAL);
353 		flags |= FORCECLOSE;
354 	}
355 
356 	ump = VFSTOUFS(mp);
357 	fs = ump->um_lfs;
358 #ifdef QUOTA
359 	if (mp->mnt_flag & MNT_QUOTA) {
360 		if (error = vflush(mp, fs->lfs_ivnode, SKIPSYSTEM|flags))
361 			return (error);
362 		for (i = 0; i < MAXQUOTAS; i++) {
363 			if (ump->um_quotas[i] == NULLVP)
364 				continue;
365 			quotaoff(p, mp, i);
366 		}
367 		/*
368 		 * Here we fall through to vflush again to ensure
369 		 * that we have gotten rid of all the system vnodes.
370 		 */
371 	}
372 #endif
373 	if (error = vflush(mp, fs->lfs_ivnode, flags))
374 		return (error);
375 	fs->lfs_clean = 1;
376 	if (error = VFS_SYNC(mp, 1, p->p_ucred, p))
377 		return (error);
378 	if (fs->lfs_ivnode->v_dirtyblkhd.lh_first)
379 		panic("lfs_unmount: still dirty blocks on ifile vnode\n");
380 	vrele(fs->lfs_ivnode);
381 	vgone(fs->lfs_ivnode);
382 
383 	ronly = !fs->lfs_ronly;
384 	ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
385 	error = VOP_CLOSE(ump->um_devvp,
386 	    ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
387 	vrele(ump->um_devvp);
388 	free(fs, M_UFSMNT);
389 	free(ump, M_UFSMNT);
390 	mp->mnt_data = (qaddr_t)0;
391 	mp->mnt_flag &= ~MNT_LOCAL;
392 	return (error);
393 }
394 
395 /*
396  * Get file system statistics.
397  */
398 lfs_statfs(mp, sbp, p)
399 	struct mount *mp;
400 	register struct statfs *sbp;
401 	struct proc *p;
402 {
403 	register struct lfs *fs;
404 	register struct ufsmount *ump;
405 
406 	ump = VFSTOUFS(mp);
407 	fs = ump->um_lfs;
408 	if (fs->lfs_magic != LFS_MAGIC)
409 		panic("lfs_statfs: magic");
410 	sbp->f_type = 0;
411 	sbp->f_bsize = fs->lfs_bsize;
412 	sbp->f_iosize = fs->lfs_bsize;
413 	sbp->f_blocks = dbtofsb(fs,fs->lfs_dsize);
414 	sbp->f_bfree = dbtofsb(fs, fs->lfs_bfree);
415 	sbp->f_bavail = (fs->lfs_dsize * (100 - fs->lfs_minfree) / 100) -
416 		(fs->lfs_dsize - fs->lfs_bfree);
417 	sbp->f_bavail = dbtofsb(fs, sbp->f_bavail);
418 	sbp->f_files = fs->lfs_nfiles;
419 	sbp->f_ffree = sbp->f_bfree * INOPB(fs);
420 	if (sbp != &mp->mnt_stat) {
421 		bcopy((caddr_t)mp->mnt_stat.f_mntonname,
422 			(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
423 		bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
424 			(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
425 	}
426 	strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN);
427 	sbp->f_fstypename[MFSNAMELEN] = '\0';
428 	return (0);
429 }
430 
431 /*
432  * Go through the disk queues to initiate sandbagged IO;
433  * go through the inodes to write those that have been modified;
434  * initiate the writing of the super block if it has been modified.
435  *
436  * Note: we are always called with the filesystem marked `MPBUSY'.
437  */
438 lfs_sync(mp, waitfor, cred, p)
439 	struct mount *mp;
440 	int waitfor;
441 	struct ucred *cred;
442 	struct proc *p;
443 {
444 	int error;
445 
446 	/* All syncs must be checkpoints until roll-forward is implemented. */
447 	error = lfs_segwrite(mp, SEGM_CKP | (waitfor ? SEGM_SYNC : 0));
448 #ifdef QUOTA
449 	qsync(mp);
450 #endif
451 	return (error);
452 }
453 
454 /*
455  * Look up an LFS dinode number to find its incore vnode.  If not already
456  * in core, read it in from the specified device.  Return the inode locked.
457  * Detection and handling of mount points must be done by the calling routine.
458  */
459 int
460 lfs_vget(mp, ino, vpp)
461 	struct mount *mp;
462 	ino_t ino;
463 	struct vnode **vpp;
464 {
465 	register struct lfs *fs;
466 	register struct inode *ip;
467 	struct buf *bp;
468 	struct ifile *ifp;
469 	struct vnode *vp;
470 	struct ufsmount *ump;
471 	daddr_t daddr;
472 	dev_t dev;
473 	int error;
474 
475 	ump = VFSTOUFS(mp);
476 	dev = ump->um_dev;
477 	if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
478 		return (0);
479 
480 	/* Translate the inode number to a disk address. */
481 	fs = ump->um_lfs;
482 	if (ino == LFS_IFILE_INUM)
483 		daddr = fs->lfs_idaddr;
484 	else {
485 		LFS_IENTRY(ifp, fs, ino, bp);
486 		daddr = ifp->if_daddr;
487 		brelse(bp);
488 		if (daddr == LFS_UNUSED_DADDR)
489 			return (ENOENT);
490 	}
491 
492 	/* Allocate new vnode/inode. */
493 	if (error = lfs_vcreate(mp, ino, &vp)) {
494 		*vpp = NULL;
495 		return (error);
496 	}
497 
498 	/*
499 	 * Put it onto its hash chain and lock it so that other requests for
500 	 * this inode will block if they arrive while we are sleeping waiting
501 	 * for old data structures to be purged or for the contents of the
502 	 * disk portion of this inode to be read.
503 	 */
504 	ip = VTOI(vp);
505 	ufs_ihashins(ip);
506 
507 	/*
508 	 * XXX
509 	 * This may not need to be here, logically it should go down with
510 	 * the i_devvp initialization.
511 	 * Ask Kirk.
512 	 */
513 	ip->i_lfs = ump->um_lfs;
514 
515 	/* Read in the disk contents for the inode, copy into the inode. */
516 	if (error =
517 	    bread(ump->um_devvp, daddr, (int)fs->lfs_bsize, NOCRED, &bp)) {
518 		/*
519 		 * The inode does not contain anything useful, so it would
520 		 * be misleading to leave it on its hash chain. With mode
521 		 * still zero, it will be unlinked and returned to the free
522 		 * list by vput().
523 		 */
524 		vput(vp);
525 		brelse(bp);
526 		*vpp = NULL;
527 		return (error);
528 	}
529 	ip->i_din = *lfs_ifind(fs, ino, (struct dinode *)bp->b_data);
530 	brelse(bp);
531 
532 	/*
533 	 * Initialize the vnode from the inode, check for aliases.  In all
534 	 * cases re-init ip, the underlying vnode/inode may have changed.
535 	 */
536 	if (error = ufs_vinit(mp, lfs_specop_p, LFS_FIFOOPS, &vp)) {
537 		vput(vp);
538 		*vpp = NULL;
539 		return (error);
540 	}
541 	/*
542 	 * Finish inode initialization now that aliasing has been resolved.
543 	 */
544 	ip->i_devvp = ump->um_devvp;
545 	VREF(ip->i_devvp);
546 	*vpp = vp;
547 	return (0);
548 }
549 
550 /*
551  * File handle to vnode
552  *
553  * Have to be really careful about stale file handles:
554  * - check that the inode number is valid
555  * - call lfs_vget() to get the locked inode
556  * - check for an unallocated inode (i_mode == 0)
557  * - check that the given client host has export rights and return
558  *   those rights via. exflagsp and credanonp
559  *
560  * XXX
561  * use ifile to see if inode is allocated instead of reading off disk
562  * what is the relationship between my generational number and the NFS
563  * generational number.
564  */
565 int
566 lfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
567 	register struct mount *mp;
568 	struct fid *fhp;
569 	struct mbuf *nam;
570 	struct vnode **vpp;
571 	int *exflagsp;
572 	struct ucred **credanonp;
573 {
574 	register struct ufid *ufhp;
575 
576 	ufhp = (struct ufid *)fhp;
577 	if (ufhp->ufid_ino < ROOTINO)
578 		return (ESTALE);
579 	return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp));
580 }
581 
582 /*
583  * Vnode pointer to File handle
584  */
585 /* ARGSUSED */
586 lfs_vptofh(vp, fhp)
587 	struct vnode *vp;
588 	struct fid *fhp;
589 {
590 	register struct inode *ip;
591 	register struct ufid *ufhp;
592 
593 	ip = VTOI(vp);
594 	ufhp = (struct ufid *)fhp;
595 	ufhp->ufid_len = sizeof(struct ufid);
596 	ufhp->ufid_ino = ip->i_number;
597 	ufhp->ufid_gen = ip->i_gen;
598 	return (0);
599 }
600