put in key words
[unix-history] / usr / src / sys / ufs / ffs / ffs_vfsops.c
CommitLineData
da7c5cc6 1/*
190244fb 2 * Copyright (c) 1989, 1991 The Regents of the University of California.
7188ac27 3 * All rights reserved.
da7c5cc6 4 *
b702c21d 5 * %sccs.include.redist.c%
7188ac27 6 *
03f3a6e4 7 * @(#)ffs_vfsops.c 7.72 (Berkeley) %G%
da7c5cc6 8 */
71e4e98b 9
ab9f4fb0
KB
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>
03f3a6e4 19#include <sys/mbuf.h>
ab9f4fb0
KB
20#include <sys/file.h>
21#include <sys/disklabel.h>
22#include <sys/ioctl.h>
23#include <sys/errno.h>
24#include <sys/malloc.h>
03f3a6e4 25#include <sys/socket.h>
609e7cfa
MK
26#include "ioctl.h"
27#include "disklabel.h"
28#include "stat.h"
71e4e98b 29
ab9f4fb0
KB
30#include <ufs/ufs/quota.h>
31#include <ufs/ufs/ufsmount.h>
32#include <ufs/ufs/inode.h>
33#include <ufs/ufs/ufs_extern.h>
34
35#include <ufs/ffs/fs.h>
36#include <ufs/ffs/ffs_extern.h>
37
06445aba 38int ffs_sbupdate __P((struct ufsmount *, int));
c6f5111d 39
7188ac27 40struct vfsops ufs_vfsops = {
ab9f4fb0 41 ffs_mount,
5bf9d21f 42 ufs_start,
ab9f4fb0 43 ffs_unmount,
a9013e03 44 ffs_root,
8dc876c1 45 ufs_quotactl,
ab9f4fb0
KB
46 ffs_statfs,
47 ffs_sync,
067ae075 48 ffs_vget,
a9013e03
KM
49 ffs_fhtovp,
50 ffs_vptofh,
ab9f4fb0 51 ffs_init,
7188ac27
KM
52};
53
067ae075
KM
54extern u_long nextgennumber;
55
7188ac27 56/*
4ac55ebc 57 * Called by main() when ufs is going to be mounted as root.
7188ac27 58 *
d48157d5 59 * Name is updated by mount(8) after booting.
7188ac27 60 */
8a4911ca 61#define ROOTNAME "root_device"
7188ac27 62
ab9f4fb0 63ffs_mountroot()
71e4e98b 64{
7188ac27 65 extern struct vnode *rootvp;
ab9f4fb0
KB
66 register struct fs *fs;
67 register struct mount *mp;
0eb6f54a 68 struct proc *p = curproc; /* XXX */
7188ac27 69 struct ufsmount *ump;
7188ac27
KM
70 u_int size;
71 int error;
71e4e98b 72
4ac55ebc 73 mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK);
ea301039 74 bzero((char *)mp, (u_long)sizeof(struct mount));
82161bc8
KM
75 mp->mnt_op = &ufs_vfsops;
76 mp->mnt_flag = MNT_RDONLY;
ab9f4fb0
KB
77 if (error = ffs_mountfs(rootvp, mp, p)) {
78 free(mp, M_MOUNT);
7188ac27 79 return (error);
71e4e98b 80 }
d48157d5 81 if (error = vfs_lock(mp)) {
ab9f4fb0
KB
82 (void)ffs_unmount(mp, 0, p);
83 free(mp, M_MOUNT);
7188ac27 84 return (error);
6d07f4cd 85 }
d48157d5 86 rootfs = mp;
82161bc8
KM
87 mp->mnt_next = mp;
88 mp->mnt_prev = mp;
89 mp->mnt_vnodecovered = NULLVP;
7188ac27
KM
90 ump = VFSTOUFS(mp);
91 fs = ump->um_fs;
d45de50d 92 bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt));
7188ac27 93 fs->fs_fsmnt[0] = '/';
82161bc8
KM
94 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
95 MNAMELEN);
96 (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
97 &size);
98 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
ab9f4fb0 99 (void)ffs_statfs(mp, &mp->mnt_stat, p);
7188ac27
KM
100 vfs_unlock(mp);
101 inittodr(fs->fs_time);
102 return (0);
103}
104
105/*
106 * VFS Operations.
107 *
108 * mount system call
109 */
06445aba 110int
ab9f4fb0 111ffs_mount(mp, path, data, ndp, p)
d45de50d 112 register struct mount *mp;
7188ac27
KM
113 char *path;
114 caddr_t data;
115 struct nameidata *ndp;
0eb6f54a 116 struct proc *p;
7188ac27
KM
117{
118 struct vnode *devvp;
119 struct ufs_args args;
120 struct ufsmount *ump;
121 register struct fs *fs;
122 u_int size;
123 int error;
124
125 if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)))
126 return (error);
190244fb
MK
127 /*
128 * If updating, check whether changing from read-only to
129 * read/write; if there is no device name, that's all we do.
130 */
131 if (mp->mnt_flag & MNT_UPDATE) {
d48157d5
KM
132 ump = VFSTOUFS(mp);
133 fs = ump->um_fs;
82161bc8 134 if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
d48157d5 135 fs->fs_ronly = 0;
c906fba1
KM
136 if (args.fspec == 0) {
137 /*
138 * Process export requests.
139 */
140 if (args.exflags & MNT_EXPORTED) {
cb09ceb4 141 if (error = ufs_hang_addrlist(mp, &args))
c906fba1
KM
142 return (error);
143 mp->mnt_flag |= MNT_EXPORTED;
144 }
145 if (args.exflags & MNT_DELEXPORT) {
cb09ceb4 146 ufs_free_addrlist(ump);
c906fba1
KM
147 mp->mnt_flag &=
148 ~(MNT_EXPORTED | MNT_DEFEXPORTED);
149 }
3b931949 150 return (0);
c906fba1 151 }
190244fb
MK
152 }
153 /*
154 * Not an update, or updating the name: look up the name
155 * and verify that it refers to a sensible block device.
156 */
995e59df
KM
157 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
158 if (error = namei(ndp))
190244fb
MK
159 return (error);
160 devvp = ndp->ni_vp;
ab9f4fb0 161
190244fb
MK
162 if (devvp->v_type != VBLK) {
163 vrele(devvp);
164 return (ENOTBLK);
165 }
166 if (major(devvp->v_rdev) >= nblkdev) {
167 vrele(devvp);
168 return (ENXIO);
169 }
170 if ((mp->mnt_flag & MNT_UPDATE) == 0)
ab9f4fb0 171 error = ffs_mountfs(devvp, mp, p);
190244fb 172 else {
d48157d5
KM
173 if (devvp != ump->um_devvp)
174 error = EINVAL; /* needs translation */
2a7dbb09
KM
175 else
176 vrele(devvp);
d48157d5 177 }
7188ac27
KM
178 if (error) {
179 vrele(devvp);
180 return (error);
27d00e76 181 }
7188ac27
KM
182 ump = VFSTOUFS(mp);
183 fs = ump->um_fs;
184 (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
185 bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
82161bc8
KM
186 bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
187 MNAMELEN);
188 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
189 &size);
190 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
ab9f4fb0 191 (void)ffs_statfs(mp, &mp->mnt_stat, p);
7188ac27 192 return (0);
71e4e98b
SL
193}
194
7188ac27
KM
195/*
196 * Common code for mount and mountroot
197 */
ab9f4fb0
KB
198int
199ffs_mountfs(devvp, mp, p)
1182ae61 200 register struct vnode *devvp;
7188ac27 201 struct mount *mp;
0eb6f54a 202 struct proc *p;
71e4e98b 203{
6b50a7c5
KM
204 register struct ufsmount *ump;
205 struct buf *bp;
71e4e98b 206 register struct fs *fs;
7188ac27 207 dev_t dev = devvp->v_rdev;
ec67a3ce
MK
208 struct partinfo dpart;
209 int havepart = 0, blks;
27d00e76 210 caddr_t base, space;
7188ac27
KM
211 int havepart = 0, blks;
212 int error, i, size;
6b50a7c5 213 int ronly;
1c26e003 214 extern struct vnode *rootvp;
71e4e98b 215
0eb6f54a 216 if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p))
7188ac27 217 return (error);
0eb6f54a 218 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
609e7cfa 219 size = DEV_BSIZE;
0eb6f54a 220 else {
ec67a3ce
MK
221 havepart = 1;
222 size = dpart.disklab->d_secsize;
7188ac27 223 }
6b50a7c5
KM
224
225 bp = NULL;
226 ump = NULL;
8dc876c1 227 if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp))
71e4e98b 228 goto out;
e018935f 229 fs = bp->b_un.b_fs;
8dc876c1 230 error = EINVAL; /* XXX needs translation */
1c281610
MK
231 goto out;
232 }
ab9f4fb0 233 ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
7bff53ea 234 bzero((caddr_t)ump, sizeof *ump);
b1ca3fbf 235 ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT,
5adcb337 236 M_WAITOK);
7188ac27 237 bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs,
71e4e98b 238 (u_int)fs->fs_sbsize);
5d96a9ad
KM
239 if (fs->fs_sbsize < SBSIZE)
240 bp->b_flags |= B_INVAL;
e018935f
MK
241 brelse(bp);
242 bp = NULL;
7188ac27
KM
243 fs = ump->um_fs;
244 fs->fs_ronly = ronly;
71e4e98b
SL
245 if (ronly == 0)
246 fs->fs_fmod = 1;
609e7cfa
MK
247 if (havepart) {
248 dpart.part->p_fstype = FS_BSDFFS;
249 dpart.part->p_fsize = fs->fs_fsize;
250 dpart.part->p_frag = fs->fs_frag;
42ff4c2e 251 dpart.part->p_cpg = fs->fs_cpg;
609e7cfa 252 }
ec67a3ce
MK
253#ifdef SECSIZE
254 /*
255 * If we have a disk label, force per-partition
256 * filesystem information to be correct
257 * and set correct current fsbtodb shift.
258 */
259#endif SECSIZE
260 if (havepart) {
261 dpart.part->p_fstype = FS_BSDFFS;
262 dpart.part->p_fsize = fs->fs_fsize;
263 dpart.part->p_frag = fs->fs_frag;
264#ifdef SECSIZE
265#ifdef tahoe
266 /*
267 * Save the original fsbtodb shift to restore on updates.
268 * (Console doesn't understand fsbtodb changes.)
269 */
270 fs->fs_sparecon[0] = fs->fs_fsbtodb;
271#endif
272 i = fs->fs_fsize / size;
273 for (fs->fs_fsbtodb = 0; i > 1; i >>= 1)
274 fs->fs_fsbtodb++;
275#endif SECSIZE
276 fs->fs_dbsize = size;
277 }
71e4e98b 278 blks = howmany(fs->fs_cssize, fs->fs_fsize);
b1ca3fbf 279 base = space = malloc((u_long)fs->fs_cssize, M_UFSMNT,
5adcb337 280 M_WAITOK);
71e4e98b
SL
281 for (i = 0; i < blks; i += fs->fs_frag) {
282 size = fs->fs_bsize;
283 if (i + fs->fs_frag > blks)
284 size = (blks - i) * fs->fs_fsize;
ec67a3ce
MK
285#ifdef SECSIZE
286 tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size,
287 fs->fs_dbsize);
288#else SECSIZE
a937f856
KM
289 error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size,
290 NOCRED, &bp);
7188ac27 291 if (error) {
b1ca3fbf 292 free(base, M_UFSMNT);
71e4e98b
SL
293 goto out;
294 }
e018935f 295 bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size);
60f9c9e3 296 fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
71e4e98b 297 space += size;
e018935f
MK
298 brelse(bp);
299 bp = NULL;
71e4e98b 300 }
82161bc8
KM
301 mp->mnt_data = (qaddr_t)ump;
302 mp->mnt_stat.f_fsid.val[0] = (long)dev;
303 mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS;
ea301039 304 mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen;
82161bc8 305 mp->mnt_flag |= MNT_LOCAL;
7188ac27
KM
306 ump->um_mountp = mp;
307 ump->um_dev = dev;
308 ump->um_devvp = devvp;
8dc876c1
KM
309 for (i = 0; i < MAXQUOTAS; i++)
310 ump->um_quotas[i] = NULLVP;
0f93ba7b 311 devvp->v_specflags |= SI_MOUNTEDON;
7188ac27 312
94354803
KM
313 /* Sanity checks for old file systems. XXX */
314 fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */
315 fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */
2af59000
KM
316 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
317 fs->fs_nrpos = 8; /* XXX */
4605fb61
KM
318 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
319 quad_t sizepb = fs->fs_bsize; /* XXX */
320 /* XXX */
321 fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */
322 for (i = 0; i < NIADDR; i++) { /* XXX */
323 sizepb *= NINDIR(fs); /* XXX */
324 fs->fs_maxfilesize += sizepb; /* XXX */
325 } /* XXX */
326 fs->fs_qbmask = ~fs->fs_bmask; /* XXX */
327 fs->fs_qfmask = ~fs->fs_fmask; /* XXX */
328 } /* XXX */
609e7cfa 329
7188ac27 330 return (0);
71e4e98b 331out:
c86c9b6e
KM
332 if (bp)
333 brelse(bp);
3a328e36 334 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
8dc876c1 335 if (ump) {
b1ca3fbf 336 free(ump->um_fs, M_UFSMNT);
ab9f4fb0 337 free(ump, M_UFSMNT);
82161bc8 338 mp->mnt_data = (qaddr_t)0;
27d00e76 339 }
7188ac27 340 return (error);
71e4e98b
SL
341}
342
7188ac27
KM
343/*
344 * unmount system call
345 */
ab9f4fb0
KB
346int
347ffs_unmount(mp, mntflags, p)
7188ac27 348 struct mount *mp;
8dc876c1 349 int mntflags;
0eb6f54a 350 struct proc *p;
71e4e98b 351{
ab9f4fb0 352 extern int doforce;
7188ac27 353 register struct ufsmount *ump;
71e4e98b 354 register struct fs *fs;
6b50a7c5 355 int i, error, flags, ronly;
71e4e98b 356
6b50a7c5 357 flags = 0;
87be6db2 358 if (mntflags & MNT_FORCE) {
d85a9d1b 359 if (!doforce || mp == rootfs)
87be6db2 360 return (EINVAL);
8dc876c1 361 flags |= FORCECLOSE;
87be6db2 362 }
7188ac27 363 ump = VFSTOUFS(mp);
ec67a3ce 364 return (error);
71e4e98b 365#ifdef QUOTA
82161bc8 366 if (mp->mnt_flag & MNT_QUOTA) {
8dc876c1 367 if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags))
6d943995 368 return (error);
8dc876c1
KM
369 for (i = 0; i < MAXQUOTAS; i++) {
370 if (ump->um_quotas[i] == NULLVP)
371 continue;
70a360ba 372 quotaoff(p, mp, i);
8dc876c1 373 }
6d943995 374 /*
8dc876c1
KM
375 * Here we fall through to vflush again to ensure
376 * that we have gotten rid of all the system vnodes.
6d943995 377 */
8dc876c1 378 }
71e4e98b 379#endif
8dc876c1 380 if (error = vflush(mp, NULLVP, flags))
6d943995 381 return (error);
7188ac27
KM
382 fs = ump->um_fs;
383 ronly = !fs->fs_ronly;
7188ac27
KM
384 * Get file system statistics.
385 */
ab9f4fb0
KB
386int
387ffs_statfs(mp, sbp, p)
7188ac27
KM
388 struct mount *mp;
389 register struct statfs *sbp;
0eb6f54a 390 struct proc *p;
7188ac27
KM
391{
392 register struct ufsmount *ump;
393 register struct fs *fs;
394
395 ump = VFSTOUFS(mp);
396 fs = ump->um_fs;
397 if (fs->fs_magic != FS_MAGIC)
ab9f4fb0 398 panic("ffs_statfs");
7188ac27 399 sbp->f_type = MOUNT_UFS;
06445aba
KM
400 sbp->f_bsize = fs->fs_fsize;
401 sbp->f_iosize = fs->fs_bsize;
7188ac27
KM
402 sbp->f_blocks = fs->fs_dsize;
403 sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag +
404 fs->fs_cstotal.cs_nffree;
405 sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) -
406 (fs->fs_dsize - sbp->f_bfree);
5c41c19e 407 sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO;
7188ac27 408 sbp->f_ffree = fs->fs_cstotal.cs_nifree;
82161bc8
KM
409 if (sbp != &mp->mnt_stat) {
410 bcopy((caddr_t)mp->mnt_stat.f_mntonname,
d45de50d 411 (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
82161bc8 412 bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
d45de50d
KM
413 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
414 }
7188ac27
KM
415 return (0);
416}
417
7188ac27
KM
418/*
419 * Go through the disk queues to initiate sandbagged IO;
420 * go through the inodes to write those that have been modified;
421 * initiate the writing of the super block if it has been modified.
8dc876c1
KM
422 *
423 * Note: we are always called with the filesystem marked `MPBUSY'.
7188ac27 424 */
ab9f4fb0 425int
6b50a7c5 426ffs_sync(mp, waitfor, cred, p)
71e4e98b 427 struct mount *mp;
7188ac27 428 int waitfor;
6b50a7c5
KM
429 struct ucred *cred;
430 struct proc *p;
71e4e98b 431{
ab9f4fb0 432 extern int syncprt;
31593ba7 433 register struct vnode *vp;
7188ac27
KM
434 register struct inode *ip;
435 register struct ufsmount *ump = VFSTOUFS(mp);
436 register struct fs *fs;
812b91f3 437 int error, allerror = 0;
7188ac27
KM
438
439 if (syncprt)
ab9f4fb0 440 ufs_bufstats();
7188ac27 441 fs = ump->um_fs;
7188ac27
KM
442 /*
443 * Write back modified superblock.
444 * Consistency check that the superblock
445 * is still in the buffer cache.
446 */
447 if (fs->fs_fmod != 0) {
448 if (fs->fs_ronly != 0) { /* XXX */
449 printf("fs = %s\n", fs->fs_fsmnt);
450 panic("update: rofs mod");
451 }
452 fs->fs_fmod = 0;
453 fs->fs_time = time.tv_sec;
ab9f4fb0 454 allerror = ffs_sbupdate(ump, waitfor);
7188ac27
KM
455 }
456 /*
457 * Write back each (modified) inode.
458 */
25b5cf58 459loop:
a242f429
KM
460 for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
461 /*
462 * If the vnode that we are about to sync is no longer
463 * associated with this mount point, start over.
464 */
465 if (vp->v_mount != mp)
466 goto loop;
d85a9d1b
KM
467 if (VOP_ISLOCKED(vp))
468 continue;
31593ba7 469 ip = VTOI(vp);
25b5cf58
KM
470 if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 &&
471 vp->v_dirtyblkhd == NULL)
7188ac27 472 continue;
25b5cf58
KM
473 if (vget(vp))
474 goto loop;
6b50a7c5 475 if (error = VOP_FSYNC(vp, cred, waitfor, p))
812b91f3
KM
476 allerror = error;
477 vput(vp);
7188ac27 478 }
7188ac27 479 /*
5d96a9ad 480 * Force stale file system control information to be flushed.
7188ac27 481 */
6b50a7c5
KM
482 if (error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p))
483 allerror = error;
8dc876c1
KM
484#ifdef QUOTA
485 qsync(mp);
486#endif
812b91f3 487 return (allerror);
7188ac27
KM
488}
489
067ae075
KM
490/*
491 * Look up a FFS dinode number to find its incore vnode.
492 * If it is not in core, read it in from the specified device.
493 * If it is in core, wait for the lock bit to clear, then
494 * return the inode locked. Detection and handling of mount
495 * points must be done by the calling routine.
496 */
497int
498ffs_vget(mp, ino, vpp)
499 struct mount *mp;
500 ino_t ino;
501 struct vnode **vpp;
502{
503 register struct fs *fs;
504 register struct inode *ip;
505 struct ufsmount *ump;
506 struct buf *bp;
507 struct dinode *dp;
508 struct vnode *vp;
509 union ihead *ih;
510 dev_t dev;
511 int i, type, error;
512
513 ump = VFSTOUFS(mp);
514 dev = ump->um_dev;
515 if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
516 return (0);
517
518 /* Allocate a new vnode/inode. */
519 if (error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) {
520 *vpp = NULL;
521 return (error);
522 }
523 type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */
524 MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK);
525 vp->v_data = ip;
526 ip->i_vnode = vp;
527 ip->i_flag = 0;
528 ip->i_devvp = 0;
529 ip->i_mode = 0;
530 ip->i_diroff = 0;
531 ip->i_lockf = 0;
532 ip->i_fs = fs = ump->um_fs;
533 ip->i_dev = dev;
534 ip->i_number = ino;
535#ifdef QUOTA
536 for (i = 0; i < MAXQUOTAS; i++)
537 ip->i_dquot[i] = NODQUOT;
538#endif
539 /*
540 * Put it onto its hash chain and lock it so that other requests for
541 * this inode will block if they arrive while we are sleeping waiting
542 * for old data structures to be purged or for the contents of the
543 * disk portion of this inode to be read.
544 */
545 ufs_ihashins(ip);
546
547 /* Read in the disk contents for the inode, copy into the inode. */
548 if (error = bread(ump->um_devvp, fsbtodb(fs, itod(fs, ino)),
549 (int)fs->fs_bsize, NOCRED, &bp)) {
550 /*
551 * The inode does not contain anything useful, so it would
552 * be misleading to leave it on its hash chain. It will be
553 * returned to the free list by ufs_iput().
554 */
555 remque(ip);
556 ip->i_forw = ip;
557 ip->i_back = ip;
558
559 /* Unlock and discard unneeded inode. */
560 ufs_iput(ip);
561 brelse(bp);
562 *vpp = NULL;
563 return (error);
564 }
565 dp = bp->b_un.b_dino;
566 dp += itoo(fs, ino);
567 ip->i_din = *dp;
568 brelse(bp);
569
570 /*
571 * Initialize the vnode from the inode, check for aliases.
572 * Note that the underlying vnode may have changed.
573 */
574 if (error = ufs_vinit(mp, ffs_specop_p, FFS_FIFOOPS, &vp)) {
575 ufs_iput(ip);
576 *vpp = NULL;
577 return (error);
578 }
579 /*
580 * Finish inode initialization now that aliasing has been resolved.
581 */
582 ip->i_devvp = ump->um_devvp;
583 VREF(ip->i_devvp);
584 /*
585 * Set up a generation number for this inode if it does not
586 * already have one. This should only happen on old filesystems.
587 */
588 if (ip->i_gen == 0) {
589 if (++nextgennumber < (u_long)time.tv_sec)
590 nextgennumber = time.tv_sec;
591 ip->i_gen = nextgennumber;
592 if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
593 ip->i_flag |= IMOD;
594 }
595 /*
596 * Ensure that uid and gid are correct. This is a temporary
597 * fix until fsck has been changed to do the update.
598 */
599 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */
600 ip->i_uid = ip->i_din.di_ouid; /* XXX */
601 ip->i_gid = ip->i_din.di_ogid; /* XXX */
602 } /* XXX */
603
604 *vpp = vp;
605 return (0);
606}
607
a9013e03
KM
608/*
609 * File handle to vnode
610 *
611 * Have to be really careful about stale file handles:
612 * - check that the inode number is valid
613 * - call ffs_vget() to get the locked inode
614 * - check for an unallocated inode (i_mode == 0)
03f3a6e4
KM
615 * - check that the given client host has export rights and return
616 * those rights via. exflagsp and credanonp
a9013e03
KM
617 */
618int
03f3a6e4 619ffs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
a9013e03
KM
620 register struct mount *mp;
621 struct fid *fhp;
03f3a6e4 622 struct mbuf *nam;
a9013e03 623 struct vnode **vpp;
03f3a6e4
KM
624 int *exflagsp;
625 struct ucred **credanonp;
a9013e03
KM
626{
627 register struct inode *ip;
628 register struct ufid *ufhp;
03f3a6e4
KM
629 register struct netaddrhash *np;
630 register struct ufsmount *ump = VFSTOUFS(mp);
a9013e03
KM
631 struct fs *fs;
632 struct vnode *nvp;
03f3a6e4 633 struct sockaddr *saddr;
a9013e03
KM
634 int error;
635
636 ufhp = (struct ufid *)fhp;
03f3a6e4 637 fs = ump->um_fs;
a9013e03
KM
638 if (ufhp->ufid_ino < ROOTINO ||
639 ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg)
03f3a6e4
KM
640 return (ESTALE);
641 /*
642 * Get the export permission structure for this <mp, client> tuple.
643 */
644 if ((mp->mnt_flag & MNT_EXPORTED) == 0)
645 return (EACCES);
646 if (nam == NULL) {
647 np = (struct netaddrhash *)0;
648 } else {
649 /*
650 * First search for a network match.
651 */
652 np = ump->um_netaddr[NETMASK_HASH];
653 while (np) {
654 if (netaddr_match(np->neth_family, &np->neth_haddr,
655 &np->neth_hmask, nam))
656 break;
657 np = np->neth_next;
658 }
659
660 /*
661 * If not found, try for an address match.
662 */
663 if (np == (struct netaddrhash *)0) {
664 saddr = mtod(nam, struct sockaddr *);
665 np = ump->um_netaddr[NETADDRHASH(saddr)];
666 while (np) {
667 if (netaddr_match(np->neth_family,
668 &np->neth_haddr, (struct netaddrhash *)0,
669 nam))
670 break;
671 np = np->neth_next;
672 }
673 }
674 }
675 if (np == (struct netaddrhash *)0) {
676 /*
677 * If no address match, use the default if it exists.
678 */
679 if ((mp->mnt_flag & MNT_DEFEXPORTED) == 0)
680 return (EACCES);
681 np = &ump->um_defexported;
682 }
067ae075 683 if (error = VFS_VGET(mp, ufhp->ufid_ino, &nvp)) {
a9013e03
KM
684 *vpp = NULLVP;
685 return (error);
686 }
687 ip = VTOI(nvp);
6b50a7c5 688 if (ip->i_mode == 0 || ip->i_gen != ufhp->ufid_gen) {
a9013e03
KM
689 ufs_iput(ip);
690 *vpp = NULLVP;
03f3a6e4 691 return (ESTALE);
a9013e03 692 }
a9013e03 693 *vpp = nvp;
03f3a6e4
KM
694 *exflagsp = np->neth_exflags;
695 *credanonp = &np->neth_anon;
a9013e03
KM
696 return (0);
697}
698
699/*
700 * Vnode pointer to File handle
701 */
702/* ARGSUSED */
703ffs_vptofh(vp, fhp)
704 struct vnode *vp;
705 struct fid *fhp;
706{
707 register struct inode *ip;
708 register struct ufid *ufhp;
709
710 ip = VTOI(vp);
711 ufhp = (struct ufid *)fhp;
712 ufhp->ufid_len = sizeof(struct ufid);
713 ufhp->ufid_ino = ip->i_number;
714 ufhp->ufid_gen = ip->i_gen;
715 return (0);
716}
717
7188ac27
KM
718/*
719 * Write a superblock and associated information back to disk.
720 */
06445aba 721int
ab9f4fb0 722ffs_sbupdate(mp, waitfor)
7188ac27
KM
723 struct ufsmount *mp;
724 int waitfor;
725{
726 register struct fs *fs = mp->um_fs;
71e4e98b
SL
727 register struct buf *bp;
728 int blks;
729 caddr_t space;
7188ac27 730 int i, size, error = 0;
71e4e98b 731
ec67a3ce
MK
732#ifdef SECSIZE
733 bp = getblk(mp->m_dev, (daddr_t)fsbtodb(fs, SBOFF / fs->fs_fsize),
734 (int)fs->fs_sbsize, fs->fs_dbsize);
735#else SECSIZE
7188ac27 736 bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize);
ec67a3ce 737#endif SECSIZE
71e4e98b 738 bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
2af59000
KM
739 /* Restore compatibility to old file systems. XXX */
740 if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */
741 bp->b_un.b_fs->fs_nrpos = -1; /* XXX */
ec67a3ce
MK
742#ifdef SECSIZE
743#ifdef tahoe
744 /* restore standard fsbtodb shift */
745 bp->b_un.b_fs->fs_fsbtodb = fs->fs_sparecon[0];
746 bp->b_un.b_fs->fs_sparecon[0] = 0;
747#endif
748#endif SECSIZE
7188ac27
KM
749 if (waitfor == MNT_WAIT)
750 error = bwrite(bp);
751 else
752 bawrite(bp);
71e4e98b
SL
753 blks = howmany(fs->fs_cssize, fs->fs_fsize);
754 space = (caddr_t)fs->fs_csp[0];
755 for (i = 0; i < blks; i += fs->fs_frag) {
756 size = fs->fs_bsize;
757 if (i + fs->fs_frag > blks)
758 size = (blks - i) * fs->fs_fsize;
ec67a3ce
MK
759#ifdef SECSIZE
760 bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size,
761 fs->fs_dbsize);
762#else SECSIZE
7188ac27 763 bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size);
ec67a3ce 764#endif SECSIZE
71e4e98b
SL
765 bcopy(space, bp->b_un.b_addr, (u_int)size);
766 space += size;
7188ac27
KM
767 if (waitfor == MNT_WAIT)
768 error = bwrite(bp);
769 else
770 bawrite(bp);
71e4e98b 771 }
7188ac27 772 return (error);
71e4e98b 773}