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