lfs_vfsops.c revision 1.2 1 /* $NetBSD: lfs_vfsops.c,v 1.2 1994/06/29 06:47:06 cgd 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.7 (Berkeley) 4/16/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
106 if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
107 return (error);
108
109 /* Until LFS can do NFS right. XXX */
110 if (args.export.ex_flags & MNT_EXPORTED)
111 return (EINVAL);
112
113 /*
114 * If updating, check whether changing from read-only to
115 * read/write; if there is no device name, that's all we do.
116 */
117 if (mp->mnt_flag & MNT_UPDATE) {
118 ump = VFSTOUFS(mp);
119 #ifdef NOTLFS /* LFS */
120 fs = ump->um_fs;
121 if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
122 fs->fs_ronly = 0;
123 #else
124 fs = ump->um_lfs;
125 if (fs->lfs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
126 fs->lfs_ronly = 0;
127 #endif
128 if (args.fspec == 0) {
129 /*
130 * Process export requests.
131 */
132 return (vfs_export(mp, &ump->um_export, &args.export));
133 }
134 }
135 /*
136 * Not an update, or updating the name: look up the name
137 * and verify that it refers to a sensible block device.
138 */
139 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
140 if (error = namei(ndp))
141 return (error);
142 devvp = ndp->ni_vp;
143 if (devvp->v_type != VBLK) {
144 vrele(devvp);
145 return (ENOTBLK);
146 }
147 if (major(devvp->v_rdev) >= nblkdev) {
148 vrele(devvp);
149 return (ENXIO);
150 }
151 if ((mp->mnt_flag & MNT_UPDATE) == 0)
152 error = lfs_mountfs(devvp, mp, p); /* LFS */
153 else {
154 if (devvp != ump->um_devvp)
155 error = EINVAL; /* needs translation */
156 else
157 vrele(devvp);
158 }
159 if (error) {
160 vrele(devvp);
161 return (error);
162 }
163 ump = VFSTOUFS(mp);
164 fs = ump->um_lfs; /* LFS */
165 #ifdef NOTLFS /* LFS */
166 (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
167 bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
168 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
169 MNAMELEN);
170 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
171 &size);
172 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
173 (void) ufs_statfs(mp, &mp->mnt_stat, p);
174 #else
175 (void)copyinstr(path, fs->lfs_fsmnt, sizeof(fs->lfs_fsmnt) - 1, &size);
176 bzero(fs->lfs_fsmnt + size, sizeof(fs->lfs_fsmnt) - size);
177 bcopy((caddr_t)fs->lfs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
178 MNAMELEN);
179 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
180 &size);
181 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
182 (void) lfs_statfs(mp, &mp->mnt_stat, p);
183 #endif
184 return (0);
185 }
186
187 /*
188 * Common code for mount and mountroot
189 * LFS specific
190 */
191 int
192 lfs_mountfs(devvp, mp, p)
193 register struct vnode *devvp;
194 struct mount *mp;
195 struct proc *p;
196 {
197 extern struct vnode *rootvp;
198 register struct lfs *fs;
199 register struct ufsmount *ump;
200 struct vnode *vp;
201 struct buf *bp;
202 struct partinfo dpart;
203 dev_t dev;
204 int error, i, ronly, size;
205
206 /*
207 * Disallow multiple mounts of the same device.
208 * Disallow mounting of a device that is currently in use
209 * (except for root, which might share swap device for miniroot).
210 * Flush out any old buffers remaining from a previous use.
211 */
212 if (error = vfs_mountedon(devvp))
213 return (error);
214 if (vcount(devvp) > 1 && devvp != rootvp)
215 return (EBUSY);
216 if (error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0))
217 return (error);
218
219 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
220 if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p))
221 return (error);
222
223 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
224 size = DEV_BSIZE;
225 else {
226 size = dpart.disklab->d_secsize;
227 #ifdef NEVER_USED
228 dpart.part->p_fstype = FS_LFS;
229 dpart.part->p_fsize = fs->lfs_fsize; /* frag size */
230 dpart.part->p_frag = fs->lfs_frag; /* frags per block */
231 dpart.part->p_cpg = fs->lfs_segshift; /* segment shift */
232 #endif
233 }
234
235 /* Don't free random space on error. */
236 bp = NULL;
237 ump = NULL;
238
239 /* Read in the superblock. */
240 if (error = bread(devvp, LFS_LABELPAD / size, LFS_SBPAD, NOCRED, &bp))
241 goto out;
242 fs = (struct lfs *)bp->b_data;
243
244 /* Check the basics. */
245 if (fs->lfs_magic != LFS_MAGIC || fs->lfs_bsize > MAXBSIZE ||
246 fs->lfs_bsize < sizeof(struct lfs)) {
247 error = EINVAL; /* XXX needs translation */
248 goto out;
249 }
250
251 /* Allocate the mount structure, copy the superblock into it. */
252 ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
253 fs = ump->um_lfs = malloc(sizeof(struct lfs), M_UFSMNT, M_WAITOK);
254 bcopy(bp->b_data, fs, sizeof(struct lfs));
255 if (sizeof(struct lfs) < LFS_SBPAD) /* XXX why? */
256 bp->b_flags |= B_INVAL;
257 brelse(bp);
258 bp = NULL;
259
260 /* Set up the I/O information */
261 fs->lfs_iocount = 0;
262
263 /* Set up the ifile and lock aflags */
264 fs->lfs_doifile = 0;
265 fs->lfs_writer = 0;
266 fs->lfs_dirops = 0;
267 fs->lfs_seglock = 0;
268
269 /* Set the file system readonly/modify bits. */
270 fs->lfs_ronly = ronly;
271 if (ronly == 0)
272 fs->lfs_fmod = 1;
273
274 /* Initialize the mount structure. */
275 dev = devvp->v_rdev;
276 mp->mnt_data = (qaddr_t)ump;
277 mp->mnt_stat.f_fsid.val[0] = (long)dev;
278 mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_LFS);
279 mp->mnt_maxsymlinklen = fs->lfs_maxsymlinklen;
280 mp->mnt_flag |= MNT_LOCAL;
281 ump->um_mountp = mp;
282 ump->um_dev = dev;
283 ump->um_devvp = devvp;
284 ump->um_bptrtodb = 0;
285 ump->um_seqinc = 1 << fs->lfs_fsbtodb;
286 ump->um_nindir = fs->lfs_nindir;
287 for (i = 0; i < MAXQUOTAS; i++)
288 ump->um_quotas[i] = NULLVP;
289 devvp->v_specflags |= SI_MOUNTEDON;
290
291 /*
292 * We use the ifile vnode for almost every operation. Instead of
293 * retrieving it from the hash table each time we retrieve it here,
294 * artificially increment the reference count and keep a pointer
295 * to it in the incore copy of the superblock.
296 */
297 if (error = VFS_VGET(mp, LFS_IFILE_INUM, &vp))
298 goto out;
299 fs->lfs_ivnode = vp;
300 VREF(vp);
301 vput(vp);
302
303 return (0);
304 out:
305 if (bp)
306 brelse(bp);
307 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
308 if (ump) {
309 free(ump->um_lfs, M_UFSMNT);
310 free(ump, M_UFSMNT);
311 mp->mnt_data = (qaddr_t)0;
312 }
313 return (error);
314 }
315
316 /*
317 * unmount system call
318 */
319 lfs_unmount(mp, mntflags, p)
320 struct mount *mp;
321 int mntflags;
322 struct proc *p;
323 {
324 extern int doforce;
325 register struct ufsmount *ump;
326 register struct lfs *fs;
327 int i, error, flags, ronly;
328
329 flags = 0;
330 if (mntflags & MNT_FORCE) {
331 if (!doforce || (mp->mnt_flag & MNT_ROOTFS))
332 return (EINVAL);
333 flags |= FORCECLOSE;
334 }
335
336 ump = VFSTOUFS(mp);
337 fs = ump->um_lfs;
338 #ifdef QUOTA
339 if (mp->mnt_flag & MNT_QUOTA) {
340 if (error = vflush(mp, fs->lfs_ivnode, SKIPSYSTEM|flags))
341 return (error);
342 for (i = 0; i < MAXQUOTAS; i++) {
343 if (ump->um_quotas[i] == NULLVP)
344 continue;
345 quotaoff(p, mp, i);
346 }
347 /*
348 * Here we fall through to vflush again to ensure
349 * that we have gotten rid of all the system vnodes.
350 */
351 }
352 #endif
353 if (error = vflush(mp, fs->lfs_ivnode, flags))
354 return (error);
355 fs->lfs_clean = 1;
356 if (error = VFS_SYNC(mp, 1, p->p_ucred, p))
357 return (error);
358 if (fs->lfs_ivnode->v_dirtyblkhd.lh_first)
359 panic("lfs_unmount: still dirty blocks on ifile vnode\n");
360 vrele(fs->lfs_ivnode);
361 vgone(fs->lfs_ivnode);
362
363 ronly = !fs->lfs_ronly;
364 ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
365 error = VOP_CLOSE(ump->um_devvp,
366 ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
367 vrele(ump->um_devvp);
368 free(fs, M_UFSMNT);
369 free(ump, M_UFSMNT);
370 mp->mnt_data = (qaddr_t)0;
371 mp->mnt_flag &= ~MNT_LOCAL;
372 return (error);
373 }
374
375 /*
376 * Get file system statistics.
377 */
378 lfs_statfs(mp, sbp, p)
379 struct mount *mp;
380 register struct statfs *sbp;
381 struct proc *p;
382 {
383 register struct lfs *fs;
384 register struct ufsmount *ump;
385
386 ump = VFSTOUFS(mp);
387 fs = ump->um_lfs;
388 if (fs->lfs_magic != LFS_MAGIC)
389 panic("lfs_statfs: magic");
390 sbp->f_type = 0;
391 sbp->f_bsize = fs->lfs_bsize;
392 sbp->f_iosize = fs->lfs_bsize;
393 sbp->f_blocks = dbtofsb(fs,fs->lfs_dsize);
394 sbp->f_bfree = dbtofsb(fs, fs->lfs_bfree);
395 sbp->f_bavail = (fs->lfs_dsize * (100 - fs->lfs_minfree) / 100) -
396 (fs->lfs_dsize - fs->lfs_bfree);
397 sbp->f_bavail = dbtofsb(fs, sbp->f_bavail);
398 sbp->f_files = fs->lfs_nfiles;
399 sbp->f_ffree = sbp->f_bfree * INOPB(fs);
400 if (sbp != &mp->mnt_stat) {
401 bcopy((caddr_t)mp->mnt_stat.f_mntonname,
402 (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
403 bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
404 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
405 }
406 strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN);
407 sbp->f_fstypename[MFSNAMELEN] = '\0';
408 return (0);
409 }
410
411 /*
412 * Go through the disk queues to initiate sandbagged IO;
413 * go through the inodes to write those that have been modified;
414 * initiate the writing of the super block if it has been modified.
415 *
416 * Note: we are always called with the filesystem marked `MPBUSY'.
417 */
418 lfs_sync(mp, waitfor, cred, p)
419 struct mount *mp;
420 int waitfor;
421 struct ucred *cred;
422 struct proc *p;
423 {
424 int error;
425
426 /* All syncs must be checkpoints until roll-forward is implemented. */
427 error = lfs_segwrite(mp, SEGM_CKP | (waitfor ? SEGM_SYNC : 0));
428 #ifdef QUOTA
429 qsync(mp);
430 #endif
431 return (error);
432 }
433
434 /*
435 * Look up an LFS dinode number to find its incore vnode. If not already
436 * in core, read it in from the specified device. Return the inode locked.
437 * Detection and handling of mount points must be done by the calling routine.
438 */
439 int
440 lfs_vget(mp, ino, vpp)
441 struct mount *mp;
442 ino_t ino;
443 struct vnode **vpp;
444 {
445 register struct lfs *fs;
446 register struct inode *ip;
447 struct buf *bp;
448 struct ifile *ifp;
449 struct vnode *vp;
450 struct ufsmount *ump;
451 daddr_t daddr;
452 dev_t dev;
453 int error;
454
455 ump = VFSTOUFS(mp);
456 dev = ump->um_dev;
457 if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
458 return (0);
459
460 /* Translate the inode number to a disk address. */
461 fs = ump->um_lfs;
462 if (ino == LFS_IFILE_INUM)
463 daddr = fs->lfs_idaddr;
464 else {
465 LFS_IENTRY(ifp, fs, ino, bp);
466 daddr = ifp->if_daddr;
467 brelse(bp);
468 if (daddr == LFS_UNUSED_DADDR)
469 return (ENOENT);
470 }
471
472 /* Allocate new vnode/inode. */
473 if (error = lfs_vcreate(mp, ino, &vp)) {
474 *vpp = NULL;
475 return (error);
476 }
477
478 /*
479 * Put it onto its hash chain and lock it so that other requests for
480 * this inode will block if they arrive while we are sleeping waiting
481 * for old data structures to be purged or for the contents of the
482 * disk portion of this inode to be read.
483 */
484 ip = VTOI(vp);
485 ufs_ihashins(ip);
486
487 /*
488 * XXX
489 * This may not need to be here, logically it should go down with
490 * the i_devvp initialization.
491 * Ask Kirk.
492 */
493 ip->i_lfs = ump->um_lfs;
494
495 /* Read in the disk contents for the inode, copy into the inode. */
496 if (error =
497 bread(ump->um_devvp, daddr, (int)fs->lfs_bsize, NOCRED, &bp)) {
498 /*
499 * The inode does not contain anything useful, so it would
500 * be misleading to leave it on its hash chain. With mode
501 * still zero, it will be unlinked and returned to the free
502 * list by vput().
503 */
504 vput(vp);
505 brelse(bp);
506 *vpp = NULL;
507 return (error);
508 }
509 ip->i_din = *lfs_ifind(fs, ino, (struct dinode *)bp->b_data);
510 brelse(bp);
511
512 /*
513 * Initialize the vnode from the inode, check for aliases. In all
514 * cases re-init ip, the underlying vnode/inode may have changed.
515 */
516 if (error = ufs_vinit(mp, lfs_specop_p, LFS_FIFOOPS, &vp)) {
517 vput(vp);
518 *vpp = NULL;
519 return (error);
520 }
521 /*
522 * Finish inode initialization now that aliasing has been resolved.
523 */
524 ip->i_devvp = ump->um_devvp;
525 VREF(ip->i_devvp);
526 *vpp = vp;
527 return (0);
528 }
529
530 /*
531 * File handle to vnode
532 *
533 * Have to be really careful about stale file handles:
534 * - check that the inode number is valid
535 * - call lfs_vget() to get the locked inode
536 * - check for an unallocated inode (i_mode == 0)
537 * - check that the given client host has export rights and return
538 * those rights via. exflagsp and credanonp
539 *
540 * XXX
541 * use ifile to see if inode is allocated instead of reading off disk
542 * what is the relationship between my generational number and the NFS
543 * generational number.
544 */
545 int
546 lfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
547 register struct mount *mp;
548 struct fid *fhp;
549 struct mbuf *nam;
550 struct vnode **vpp;
551 int *exflagsp;
552 struct ucred **credanonp;
553 {
554 register struct ufid *ufhp;
555
556 ufhp = (struct ufid *)fhp;
557 if (ufhp->ufid_ino < ROOTINO)
558 return (ESTALE);
559 return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp));
560 }
561
562 /*
563 * Vnode pointer to File handle
564 */
565 /* ARGSUSED */
566 lfs_vptofh(vp, fhp)
567 struct vnode *vp;
568 struct fid *fhp;
569 {
570 register struct inode *ip;
571 register struct ufid *ufhp;
572
573 ip = VTOI(vp);
574 ufhp = (struct ufid *)fhp;
575 ufhp->ufid_len = sizeof(struct ufid);
576 ufhp->ufid_ino = ip->i_number;
577 ufhp->ufid_gen = ip->i_gen;
578 return (0);
579 }
580