lfs_vfsops.c revision 1.25 1 /* $NetBSD: lfs_vfsops.c,v 1.25 1999/02/26 23:44:49 wrstuden 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.20 (Berkeley) 6/10/95
36 */
37
38 #if defined(_KERNEL) && !defined(_LKM)
39 #include "opt_quota.h"
40 #endif
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/namei.h>
45 #include <sys/proc.h>
46 #include <sys/kernel.h>
47 #include <sys/vnode.h>
48 #include <sys/mount.h>
49 #include <sys/buf.h>
50 #include <sys/mbuf.h>
51 #include <sys/file.h>
52 #include <sys/disklabel.h>
53 #include <sys/ioctl.h>
54 #include <sys/errno.h>
55 #include <sys/malloc.h>
56 #include <sys/pool.h>
57 #include <sys/socket.h>
58
59 #include <miscfs/specfs/specdev.h>
60
61 #include <ufs/ufs/quota.h>
62 #include <ufs/ufs/inode.h>
63 #include <ufs/ufs/ufsmount.h>
64 #include <ufs/ufs/ufs_extern.h>
65
66 #include <ufs/lfs/lfs.h>
67 #include <ufs/lfs/lfs_extern.h>
68
69 int lfs_mountfs __P((struct vnode *, struct mount *, struct proc *));
70
71 extern struct vnodeopv_desc lfs_vnodeop_opv_desc;
72 extern struct vnodeopv_desc lfs_specop_opv_desc;
73 extern struct vnodeopv_desc lfs_fifoop_opv_desc;
74
75 struct vnodeopv_desc *lfs_vnodeopv_descs[] = {
76 &lfs_vnodeop_opv_desc,
77 &lfs_specop_opv_desc,
78 &lfs_fifoop_opv_desc,
79 NULL,
80 };
81
82 struct vfsops lfs_vfsops = {
83 MOUNT_LFS,
84 lfs_mount,
85 ufs_start,
86 lfs_unmount,
87 ufs_root,
88 ufs_quotactl,
89 lfs_statfs,
90 lfs_sync,
91 lfs_vget,
92 lfs_fhtovp,
93 lfs_vptofh,
94 lfs_init,
95 lfs_sysctl,
96 NULL,
97 ufs_check_export,
98 lfs_vnodeopv_descs,
99 };
100
101 struct pool lfs_inode_pool;
102
103 /*
104 * Initialize the filesystem, most work done by ufs_init.
105 */
106 void
107 lfs_init()
108 {
109 ufs_init();
110
111 /*
112 * XXX Same structure as FFS inodes? Should we share a common pool?
113 */
114 pool_init(&lfs_inode_pool, sizeof(struct inode), 0, 0, 0,
115 "lfsinopl", 0, pool_page_alloc_nointr, pool_page_free_nointr,
116 M_LFSNODE);
117 }
118
119 /*
120 * Called by main() when ufs is going to be mounted as root.
121 */
122 int
123 lfs_mountroot()
124 {
125 extern struct vnode *rootvp;
126 struct mount *mp;
127 struct proc *p = curproc; /* XXX */
128 int error;
129
130 /*
131 * Get vnodes for swapdev and rootdev.
132 */
133 if ((error = bdevvp(rootdev, &rootvp))) {
134 printf("lfs_mountroot: can't setup bdevvp's");
135 return (error);
136 }
137 if ((error = vfs_rootmountalloc(MOUNT_LFS, "root_device", &mp)))
138 return (error);
139 if ((error = lfs_mountfs(rootvp, mp, p))) {
140 mp->mnt_op->vfs_refcount--;
141 vfs_unbusy(mp);
142 free(mp, M_MOUNT);
143 return (error);
144 }
145 simple_lock(&mountlist_slock);
146 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
147 simple_unlock(&mountlist_slock);
148 (void)lfs_statfs(mp, &mp->mnt_stat, p);
149 vfs_unbusy(mp);
150 return (0);
151 }
152
153 /*
154 * VFS Operations.
155 *
156 * mount system call
157 */
158 int
159 lfs_mount(mp, path, data, ndp, p)
160 register struct mount *mp;
161 const char *path;
162 void *data;
163 struct nameidata *ndp;
164 struct proc *p;
165 {
166 struct vnode *devvp;
167 struct ufs_args args;
168 struct ufsmount *ump = NULL;
169 register struct lfs *fs = NULL; /* LFS */
170 size_t size;
171 int error;
172 mode_t accessmode;
173
174 error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args));
175 if (error)
176 return (error);
177
178 /* Until LFS can do NFS right. XXX */
179 if (args.export.ex_flags & MNT_EXPORTED)
180 return (EINVAL);
181
182 /*
183 * If updating, check whether changing from read-only to
184 * read/write; if there is no device name, that's all we do.
185 */
186 if (mp->mnt_flag & MNT_UPDATE) {
187 ump = VFSTOUFS(mp);
188 if (fs->lfs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) {
189 /*
190 * If upgrade to read-write by non-root, then verify
191 * that user has necessary permissions on the device.
192 */
193 if (p->p_ucred->cr_uid != 0) {
194 vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
195 error = VOP_ACCESS(ump->um_devvp, VREAD|VWRITE,
196 p->p_ucred, p);
197 VOP_UNLOCK(ump->um_devvp, 0);
198 if (error)
199 return (error);
200 }
201 fs->lfs_ronly = 0;
202 }
203 if (args.fspec == 0) {
204 /*
205 * Process export requests.
206 */
207 return (vfs_export(mp, &ump->um_export, &args.export));
208 }
209 }
210 /*
211 * Not an update, or updating the name: look up the name
212 * and verify that it refers to a sensible block device.
213 */
214 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
215 if ((error = namei(ndp)) != 0)
216 return (error);
217 devvp = ndp->ni_vp;
218 if (devvp->v_type != VBLK) {
219 vrele(devvp);
220 return (ENOTBLK);
221 }
222 if (major(devvp->v_rdev) >= nblkdev) {
223 vrele(devvp);
224 return (ENXIO);
225 }
226 /*
227 * If mount by non-root, then verify that user has necessary
228 * permissions on the device.
229 */
230 if (p->p_ucred->cr_uid != 0) {
231 accessmode = VREAD;
232 if ((mp->mnt_flag & MNT_RDONLY) == 0)
233 accessmode |= VWRITE;
234 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
235 error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p);
236 if (error) {
237 vput(devvp);
238 return (error);
239 }
240 VOP_UNLOCK(devvp, 0);
241 }
242 if ((mp->mnt_flag & MNT_UPDATE) == 0)
243 error = lfs_mountfs(devvp, mp, p); /* LFS */
244 else {
245 if (devvp != ump->um_devvp)
246 error = EINVAL; /* needs translation */
247 else
248 vrele(devvp);
249 }
250 if (error) {
251 vrele(devvp);
252 return (error);
253 }
254 ump = VFSTOUFS(mp);
255 fs = ump->um_lfs; /* LFS */
256 #ifdef NOTLFS /* LFS */
257 (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
258 bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
259 bcopy(fs->fs_fsmnt, mp->mnt_stat.f_mntonname, MNAMELEN);
260 #else
261 (void)copyinstr(path, fs->lfs_fsmnt, sizeof(fs->lfs_fsmnt) - 1, &size);
262 bzero(fs->lfs_fsmnt + size, sizeof(fs->lfs_fsmnt) - size);
263 bcopy(fs->lfs_fsmnt, mp->mnt_stat.f_mntonname, MNAMELEN);
264 #endif
265 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
266 &size);
267 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
268 return (0);
269 }
270
271 /*
272 * Common code for mount and mountroot
273 * LFS specific
274 */
275 int
276 lfs_mountfs(devvp, mp, p)
277 register struct vnode *devvp;
278 struct mount *mp;
279 struct proc *p;
280 {
281 extern struct vnode *rootvp;
282 struct dlfs *dfs;
283 register struct lfs *fs;
284 register struct ufsmount *ump;
285 struct vnode *vp;
286 struct buf *bp;
287 struct partinfo dpart;
288 dev_t dev;
289 int error, i, ronly, size;
290 struct ucred *cred;
291
292 cred = p ? p->p_ucred : NOCRED;
293 /*
294 * Disallow multiple mounts of the same device.
295 * Disallow mounting of a device that is currently in use
296 * (except for root, which might share swap device for miniroot).
297 * Flush out any old buffers remaining from a previous use.
298 */
299 if ((error = vfs_mountedon(devvp)) != 0)
300 return (error);
301 if (vcount(devvp) > 1 && devvp != rootvp)
302 return (EBUSY);
303 if ((error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)) != 0)
304 return (error);
305
306 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
307 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
308 if (error)
309 return (error);
310
311 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0)
312 size = DEV_BSIZE;
313 else {
314 size = dpart.disklab->d_secsize;
315 #ifdef NEVER_USED
316 dpart.part->p_fstype = FS_LFS;
317 dpart.part->p_fsize = fs->lfs_fsize; /* frag size */
318 dpart.part->p_frag = fs->lfs_frag; /* frags per block */
319 dpart.part->p_cpg = fs->lfs_segshift; /* segment shift */
320 #endif
321 }
322
323 /* Don't free random space on error. */
324 bp = NULL;
325 ump = NULL;
326
327 /* Read in the superblock. */
328 error = bread(devvp, LFS_LABELPAD / size, LFS_SBPAD, cred, &bp);
329 if (error)
330 goto out;
331
332 dfs = (struct dlfs *)bp->b_data;
333
334 /* Check the basics. */
335 if (dfs->dlfs_magic != LFS_MAGIC || dfs->dlfs_bsize > MAXBSIZE ||
336 dfs->dlfs_bsize < sizeof(struct dlfs)) {
337 error = EINVAL; /* XXX needs translation */
338 goto out;
339 }
340
341 /* Allocate the mount structure, copy the superblock into it. */
342 ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
343 fs = ump->um_lfs = malloc(sizeof(struct lfs), M_UFSMNT, M_WAITOK);
344 bcopy(bp->b_data, &(fs->lfs_dlfs), sizeof(struct dlfs));
345 if (sizeof(struct lfs) < LFS_SBPAD) /* XXX why? */
346 bp->b_flags |= B_INVAL;
347 brelse(bp);
348 bp = NULL;
349
350 /* Set up the I/O information */
351 fs->lfs_iocount = 0;
352
353 /* Set up the ifile and lock aflags */
354 fs->lfs_doifile = 0;
355 fs->lfs_writer = 0;
356 fs->lfs_dirops = 0;
357 fs->lfs_seglock = 0;
358
359 /* Set the file system readonly/modify bits. */
360 fs->lfs_ronly = ronly;
361 if (ronly == 0)
362 fs->lfs_fmod = 1;
363
364 /* Initialize the mount structure. */
365 dev = devvp->v_rdev;
366 mp->mnt_data = (qaddr_t)ump;
367 mp->mnt_stat.f_fsid.val[0] = (long)dev;
368 mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_LFS);
369 mp->mnt_maxsymlinklen = fs->lfs_maxsymlinklen;
370 mp->mnt_flag |= MNT_LOCAL;
371 ump->um_flags = 0;
372 ump->um_mountp = mp;
373 ump->um_dev = dev;
374 ump->um_devvp = devvp;
375 ump->um_bptrtodb = 0;
376 ump->um_seqinc = 1 << fs->lfs_fsbtodb;
377 ump->um_nindir = fs->lfs_nindir;
378 for (i = 0; i < MAXQUOTAS; i++)
379 ump->um_quotas[i] = NULLVP;
380 devvp->v_specflags |= SI_MOUNTEDON;
381
382 /*
383 * We use the ifile vnode for almost every operation. Instead of
384 * retrieving it from the hash table each time we retrieve it here,
385 * artificially increment the reference count and keep a pointer
386 * to it in the incore copy of the superblock.
387 */
388 if ((error = VFS_VGET(mp, LFS_IFILE_INUM, &vp)) != 0)
389 goto out;
390 fs->lfs_ivnode = vp;
391 VREF(vp);
392 vput(vp);
393
394 return (0);
395 out:
396 if (bp)
397 brelse(bp);
398 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
399 if (ump) {
400 free(ump->um_lfs, M_UFSMNT);
401 free(ump, M_UFSMNT);
402 mp->mnt_data = (qaddr_t)0;
403 }
404 return (error);
405 }
406
407 /*
408 * unmount system call
409 */
410 int
411 lfs_unmount(mp, mntflags, p)
412 struct mount *mp;
413 int mntflags;
414 struct proc *p;
415 {
416 register struct ufsmount *ump;
417 register struct lfs *fs;
418 int error, flags, ronly;
419
420 flags = 0;
421 if (mntflags & MNT_FORCE)
422 flags |= FORCECLOSE;
423
424 ump = VFSTOUFS(mp);
425 fs = ump->um_lfs;
426 #ifdef QUOTA
427 if (mp->mnt_flag & MNT_QUOTA) {
428 int i;
429 error = vflush(mp, fs->lfs_ivnode, SKIPSYSTEM|flags);
430 if (error)
431 return (error);
432 for (i = 0; i < MAXQUOTAS; i++) {
433 if (ump->um_quotas[i] == NULLVP)
434 continue;
435 quotaoff(p, mp, i);
436 }
437 /*
438 * Here we fall through to vflush again to ensure
439 * that we have gotten rid of all the system vnodes.
440 */
441 }
442 #endif
443 if ((error = vflush(mp, fs->lfs_ivnode, flags)) != 0)
444 return (error);
445 fs->lfs_clean = 1;
446 if ((error = VFS_SYNC(mp, 1, p->p_ucred, p)) != 0)
447 return (error);
448 if (fs->lfs_ivnode->v_dirtyblkhd.lh_first)
449 panic("lfs_unmount: still dirty blocks on ifile vnode\n");
450 vrele(fs->lfs_ivnode);
451 vgone(fs->lfs_ivnode);
452
453 ronly = !fs->lfs_ronly;
454 ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
455 error = VOP_CLOSE(ump->um_devvp,
456 ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
457 vrele(ump->um_devvp);
458 free(fs, M_UFSMNT);
459 free(ump, M_UFSMNT);
460 mp->mnt_data = (qaddr_t)0;
461 mp->mnt_flag &= ~MNT_LOCAL;
462 return (error);
463 }
464
465 /*
466 * Get file system statistics.
467 */
468 int
469 lfs_statfs(mp, sbp, p)
470 struct mount *mp;
471 register struct statfs *sbp;
472 struct proc *p;
473 {
474 register struct lfs *fs;
475 register struct ufsmount *ump;
476
477 ump = VFSTOUFS(mp);
478 fs = ump->um_lfs;
479 if (fs->lfs_magic != LFS_MAGIC)
480 panic("lfs_statfs: magic");
481 sbp->f_type = 0;
482 sbp->f_bsize = fs->lfs_bsize;
483 sbp->f_iosize = fs->lfs_bsize;
484 sbp->f_blocks = dbtofrags(fs, fs->lfs_dsize);
485 sbp->f_bfree = dbtofrags(fs, fs->lfs_bfree);
486 /*
487 * To compute the available space. Subtract the minimum free
488 * from the total number of blocks in the file system. Set avail
489 * to the smaller of this number and fs->lfs_bfree.
490 */
491 sbp->f_bavail = (long) ((u_int64_t) fs->lfs_dsize * (u_int64_t)
492 (100 - fs->lfs_minfree) / (u_int64_t) 100);
493 sbp->f_bavail =
494 sbp->f_bavail > fs->lfs_bfree ? fs->lfs_bfree : sbp->f_bavail;
495 sbp->f_bavail = dbtofrags(fs, sbp->f_bavail);
496 sbp->f_files = fs->lfs_nfiles;
497 sbp->f_ffree = sbp->f_bfree * INOPB(fs);
498 if (sbp != &mp->mnt_stat) {
499 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
500 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
501 }
502 strncpy(sbp->f_fstypename, mp->mnt_op->vfs_name, MFSNAMELEN);
503 return (0);
504 }
505
506 /*
507 * Go through the disk queues to initiate sandbagged IO;
508 * go through the inodes to write those that have been modified;
509 * initiate the writing of the super block if it has been modified.
510 *
511 * Note: we are always called with the filesystem marked `MPBUSY'.
512 */
513 int
514 lfs_sync(mp, waitfor, cred, p)
515 struct mount *mp;
516 int waitfor;
517 struct ucred *cred;
518 struct proc *p;
519 {
520 int error;
521
522 /* All syncs must be checkpoints until roll-forward is implemented. */
523 error = lfs_segwrite(mp, SEGM_CKP | (waitfor ? SEGM_SYNC : 0));
524 #ifdef QUOTA
525 qsync(mp);
526 #endif
527 return (error);
528 }
529
530 /*
531 * Look up an LFS dinode number to find its incore vnode. If not already
532 * in core, read it in from the specified device. Return the inode locked.
533 * Detection and handling of mount points must be done by the calling routine.
534 */
535 int
536 lfs_vget(mp, ino, vpp)
537 struct mount *mp;
538 ino_t ino;
539 struct vnode **vpp;
540 {
541 register struct lfs *fs;
542 register struct inode *ip;
543 struct buf *bp;
544 struct ifile *ifp;
545 struct vnode *vp;
546 struct ufsmount *ump;
547 ufs_daddr_t daddr;
548 dev_t dev;
549 int error;
550
551 ump = VFSTOUFS(mp);
552 dev = ump->um_dev;
553 if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
554 return (0);
555
556 /* Translate the inode number to a disk address. */
557 fs = ump->um_lfs;
558 if (ino == LFS_IFILE_INUM)
559 daddr = fs->lfs_idaddr;
560 else {
561 LFS_IENTRY(ifp, fs, ino, bp);
562 daddr = ifp->if_daddr;
563 brelse(bp);
564 if (daddr == LFS_UNUSED_DADDR)
565 return (ENOENT);
566 }
567
568 /* Allocate new vnode/inode. */
569 if ((error = lfs_vcreate(mp, ino, &vp)) != 0) {
570 *vpp = NULL;
571 return (error);
572 }
573
574 /*
575 * Put it onto its hash chain and lock it so that other requests for
576 * this inode will block if they arrive while we are sleeping waiting
577 * for old data structures to be purged or for the contents of the
578 * disk portion of this inode to be read.
579 */
580 ip = VTOI(vp);
581 ufs_ihashins(ip);
582
583 /*
584 * XXX
585 * This may not need to be here, logically it should go down with
586 * the i_devvp initialization.
587 * Ask Kirk.
588 */
589 ip->i_lfs = ump->um_lfs;
590
591 /* Read in the disk contents for the inode, copy into the inode. */
592 error = bread(ump->um_devvp, daddr, (int)fs->lfs_bsize, NOCRED, &bp);
593 if (error) {
594 /*
595 * The inode does not contain anything useful, so it would
596 * be misleading to leave it on its hash chain. With mode
597 * still zero, it will be unlinked and returned to the free
598 * list by vput().
599 */
600 vput(vp);
601 brelse(bp);
602 *vpp = NULL;
603 return (error);
604 }
605 ip->i_din.ffs_din = *lfs_ifind(fs, ino, (struct dinode *)bp->b_data);
606 brelse(bp);
607
608 /*
609 * Initialize the vnode from the inode, check for aliases. In all
610 * cases re-init ip, the underlying vnode/inode may have changed.
611 */
612 error = ufs_vinit(mp, lfs_specop_p, lfs_fifoop_p, &vp);
613 if (error) {
614 vput(vp);
615 *vpp = NULL;
616 return (error);
617 }
618 /*
619 * Finish inode initialization now that aliasing has been resolved.
620 */
621 ip->i_devvp = ump->um_devvp;
622 VREF(ip->i_devvp);
623 *vpp = vp;
624 return (0);
625 }
626
627 /*
628 * File handle to vnode
629 *
630 * Have to be really careful about stale file handles:
631 * - check that the inode number is valid
632 * - call lfs_vget() to get the locked inode
633 * - check for an unallocated inode (i_mode == 0)
634 *
635 * XXX
636 * use ifile to see if inode is allocated instead of reading off disk
637 * what is the relationship between my generational number and the NFS
638 * generational number.
639 */
640 int
641 lfs_fhtovp(mp, fhp, vpp)
642 register struct mount *mp;
643 struct fid *fhp;
644 struct vnode **vpp;
645 {
646 register struct ufid *ufhp;
647
648 ufhp = (struct ufid *)fhp;
649 if (ufhp->ufid_ino < ROOTINO)
650 return (ESTALE);
651 return (ufs_fhtovp(mp, ufhp, vpp));
652 }
653
654 /*
655 * Vnode pointer to File handle
656 */
657 /* ARGSUSED */
658 int
659 lfs_vptofh(vp, fhp)
660 struct vnode *vp;
661 struct fid *fhp;
662 {
663 register struct inode *ip;
664 register struct ufid *ufhp;
665
666 ip = VTOI(vp);
667 ufhp = (struct ufid *)fhp;
668 ufhp->ufid_len = sizeof(struct ufid);
669 ufhp->ufid_ino = ip->i_number;
670 ufhp->ufid_gen = ip->i_ffs_gen;
671 return (0);
672 }
673
674 int
675 lfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
676 int *name;
677 u_int namelen;
678 void *oldp;
679 size_t *oldlenp;
680 void *newp;
681 size_t newlen;
682 struct proc *p;
683 {
684 return (EOPNOTSUPP);
685 }
686