ext2fs_vfsops.c revision 1.4 1 /* $NetBSD: ext2fs_vfsops.c,v 1.4 1997/10/09 15:42:53 bouyer Exp $ */
2
3 /*
4 * Copyright (c) 1997 Manuel Bouyer.
5 * Copyright (c) 1989, 1991, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)ffs_vfsops.c 8.14 (Berkeley) 11/28/94
37 * Modified for ext2fs by Manuel Bouyer.
38 */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/namei.h>
43 #include <sys/proc.h>
44 #include <sys/kernel.h>
45 #include <sys/vnode.h>
46 #include <sys/socket.h>
47 #include <sys/mount.h>
48 #include <sys/buf.h>
49 #include <sys/device.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/lock.h>
57
58 #include <miscfs/specfs/specdev.h>
59
60 #include <ufs/ufs/quota.h>
61 #include <ufs/ufs/ufsmount.h>
62 #include <ufs/ufs/inode.h>
63 #include <ufs/ufs/dir.h>
64 #include <ufs/ufs/ufs_extern.h>
65
66 #include <ufs/ext2fs/ext2fs.h>
67 #include <ufs/ext2fs/ext2fs_extern.h>
68
69 extern struct lock ufs_hashlock;
70
71 int ext2fs_sbupdate __P((struct ufsmount *, int));
72 int ext2fs_check_export __P((struct mount *, struct ufid *, struct mbuf *,
73 struct vnode **, int *, struct ucred **));
74
75 struct vfsops ext2fs_vfsops = {
76 MOUNT_EXT2FS,
77 ext2fs_mount,
78 ufs_start,
79 ext2fs_unmount,
80 ufs_root,
81 ufs_quotactl,
82 ext2fs_statfs,
83 ext2fs_sync,
84 ext2fs_vget,
85 ext2fs_fhtovp,
86 ext2fs_vptofh,
87 ext2fs_init,
88 ext2fs_mountroot,
89 };
90
91 extern u_long ext2gennumber;
92
93 /*
94 * This is the generic part of fhtovp called after the underlying
95 * filesystem has validated the file handle.
96 *
97 * Verify that a host should have access to a filesystem, and if so
98 * return a vnode for the presented file handle.
99 */
100 int
101 ext2fs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp)
102 register struct mount *mp;
103 struct ufid *ufhp;
104 struct mbuf *nam;
105 struct vnode **vpp;
106 int *exflagsp;
107 struct ucred **credanonp;
108 {
109 register struct inode *ip;
110 register struct netcred *np;
111 register struct ufsmount *ump = VFSTOUFS(mp);
112 struct vnode *nvp;
113 int error;
114
115 /*
116 * Get the export permission structure for this <mp, client> tuple.
117 */
118 np = vfs_export_lookup(mp, &ump->um_export, nam);
119 if (np == NULL)
120 return (EACCES);
121
122 if ((error = VFS_VGET(mp, ufhp->ufid_ino, &nvp)) != 0) {
123 *vpp = NULLVP;
124 return (error);
125 }
126 ip = VTOI(nvp);
127 if (ip->i_e2fs_mode == 0 || ip->i_e2fs_dtime != 0 ||
128 ip->i_e2fs_gen != ufhp->ufid_gen) {
129 vput(nvp);
130 *vpp = NULLVP;
131 return (ESTALE);
132 }
133 *vpp = nvp;
134 *exflagsp = np->netc_exflags;
135 *credanonp = &np->netc_anon;
136 return (0);
137 }
138
139
140 /*
141 * Called by main() when ext2fs is going to be mounted as root.
142 *
143 * Name is updated by mount(8) after booting.
144 */
145 #define ROOTNAME "root_device"
146
147 int
148 ext2fs_mountroot()
149 {
150 extern struct vnode *rootvp;
151 register struct m_ext2fs *fs;
152 register struct mount *mp;
153 struct proc *p = curproc; /* XXX */
154 struct ufsmount *ump;
155 size_t size;
156 int error;
157
158 if (root_device->dv_class != DV_DISK)
159 return (ENODEV);
160
161 /*
162 * Get vnodes for rootdev.
163 */
164 if (bdevvp(rootdev, &rootvp))
165 panic("ext2fs_mountroot: can't setup bdevvp's");
166
167 mp = malloc(sizeof(struct mount), M_MOUNT, M_WAITOK);
168 bzero((char *)mp, sizeof(struct mount));
169 mp->mnt_op = &ext2fs_vfsops;
170 mp->mnt_flag = MNT_RDONLY;
171 if ((error = ext2fs_mountfs(rootvp, mp, p)) != 0) {
172 free(mp, M_MOUNT);
173 return (error);
174 }
175 if ((error = vfs_lock(mp)) != 0) {
176 (void)ext2fs_unmount(mp, 0, p);
177 free(mp, M_MOUNT);
178 return (error);
179 }
180 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
181 mp->mnt_vnodecovered = NULLVP;
182 ump = VFSTOUFS(mp);
183 fs = ump->um_e2fs;
184 bzero(fs->e2fs_fsmnt, sizeof(fs->e2fs_fsmnt));
185 fs->e2fs_fsmnt[0] = '/';
186 bcopy(fs->e2fs_fsmnt, mp->mnt_stat.f_mntonname, MNAMELEN);
187 (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
188 &size);
189 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
190 (void)ext2fs_statfs(mp, &mp->mnt_stat, p);
191 vfs_unlock(mp);
192 inittodr(fs->e2fs.e2fs_wtime);
193 return (0);
194 }
195
196 /*
197 * VFS Operations.
198 *
199 * mount system call
200 */
201 int
202 ext2fs_mount(mp, path, data, ndp, p)
203 register struct mount *mp;
204 const char *path;
205 void * data;
206 struct nameidata *ndp;
207 struct proc *p;
208 {
209 struct vnode *devvp;
210 struct ufs_args args;
211 struct ufsmount *ump = NULL;
212 register struct m_ext2fs *fs;
213 size_t size;
214 int error, flags;
215 mode_t accessmode;
216
217 error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args));
218 if (error)
219 return (error);
220 /*
221 * If updating, check whether changing from read-only to
222 * read/write; if there is no device name, that's all we do.
223 */
224 if (mp->mnt_flag & MNT_UPDATE) {
225 ump = VFSTOUFS(mp);
226 fs = ump->um_e2fs;
227 if (fs->e2fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
228 flags = WRITECLOSE;
229 if (mp->mnt_flag & MNT_FORCE)
230 flags |= FORCECLOSE;
231 if (vfs_busy(mp))
232 return (EBUSY);
233 error = ext2fs_flushfiles(mp, flags, p);
234 if (error == 0 &&
235 ext2fs_cgupdate(ump, MNT_WAIT) == 0 &&
236 (fs->e2fs.e2fs_state & E2FS_ERRORS) == 0) {
237 fs->e2fs.e2fs_state = E2FS_ISCLEAN;
238 (void) ext2fs_sbupdate(ump, MNT_WAIT);
239 }
240 vfs_unbusy(mp);
241 if (error)
242 return (error);
243 fs->e2fs_ronly = 1;
244 }
245 if (mp->mnt_flag & MNT_RELOAD) {
246 error = ext2fs_reload(mp, ndp->ni_cnd.cn_cred, p);
247 if (error)
248 return (error);
249 }
250 if (fs->e2fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) {
251 /*
252 * If upgrade to read-write by non-root, then verify
253 * that user has necessary permissions on the device.
254 */
255 if (p->p_ucred->cr_uid != 0) {
256 devvp = ump->um_devvp;
257 VOP_LOCK(devvp);
258 error = VOP_ACCESS(devvp, VREAD | VWRITE,
259 p->p_ucred, p);
260 if (error) {
261 VOP_UNLOCK(devvp);
262 return (error);
263 }
264 VOP_UNLOCK(devvp);
265 }
266 fs->e2fs_ronly = 0;
267 if (fs->e2fs.e2fs_state == E2FS_ISCLEAN)
268 fs->e2fs.e2fs_state = 0;
269 else
270 fs->e2fs.e2fs_state = E2FS_ERRORS;
271 fs->e2fs_fmod = 1;
272 }
273 if (args.fspec == 0) {
274 /*
275 * Process export requests.
276 */
277 return (vfs_export(mp, &ump->um_export, &args.export));
278 }
279 }
280 /*
281 * Not an update, or updating the name: look up the name
282 * and verify that it refers to a sensible block device.
283 */
284 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
285 if ((error = namei(ndp)) != 0)
286 return (error);
287 devvp = ndp->ni_vp;
288
289 if (devvp->v_type != VBLK) {
290 vrele(devvp);
291 return (ENOTBLK);
292 }
293 if (major(devvp->v_rdev) >= nblkdev) {
294 vrele(devvp);
295 return (ENXIO);
296 }
297 /*
298 * If mount by non-root, then verify that user has necessary
299 * permissions on the device.
300 */
301 if (p->p_ucred->cr_uid != 0) {
302 accessmode = VREAD;
303 if ((mp->mnt_flag & MNT_RDONLY) == 0)
304 accessmode |= VWRITE;
305 VOP_LOCK(devvp);
306 error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p);
307 if (error) {
308 vput(devvp);
309 return (error);
310 }
311 VOP_UNLOCK(devvp);
312 }
313 if ((mp->mnt_flag & MNT_UPDATE) == 0)
314 error = ext2fs_mountfs(devvp, mp, p);
315 else {
316 if (devvp != ump->um_devvp)
317 error = EINVAL; /* needs translation */
318 else
319 vrele(devvp);
320 }
321 if (error) {
322 vrele(devvp);
323 return (error);
324 }
325 ump = VFSTOUFS(mp);
326 fs = ump->um_e2fs;
327 (void) copyinstr(path, fs->e2fs_fsmnt, sizeof(fs->e2fs_fsmnt) - 1, &size);
328 bzero(fs->e2fs_fsmnt + size, sizeof(fs->e2fs_fsmnt) - size);
329 bcopy(fs->e2fs_fsmnt, mp->mnt_stat.f_mntonname, MNAMELEN);
330 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
331 &size);
332 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
333 if (fs->e2fs_fmod != 0) { /* XXX */
334 fs->e2fs_fmod = 0;
335 if (fs->e2fs.e2fs_state == 0)
336 fs->e2fs.e2fs_wtime = time.tv_sec;
337 else
338 printf("%s: file system not clean; please fsck(8)\n",
339 mp->mnt_stat.f_mntfromname);
340 (void) ext2fs_cgupdate(ump, MNT_WAIT);
341 }
342 return (0);
343 }
344
345 /*
346 * Reload all incore data for a filesystem (used after running fsck on
347 * the root filesystem and finding things to fix). The filesystem must
348 * be mounted read-only.
349 *
350 * Things to do to update the mount:
351 * 1) invalidate all cached meta-data.
352 * 2) re-read superblock from disk.
353 * 3) re-read summary information from disk.
354 * 4) invalidate all inactive vnodes.
355 * 5) invalidate all cached file data.
356 * 6) re-read inode data for all active vnodes.
357 */
358 int
359 ext2fs_reload(mountp, cred, p)
360 register struct mount *mountp;
361 struct ucred *cred;
362 struct proc *p;
363 {
364 register struct vnode *vp, *nvp, *devvp;
365 struct inode *ip;
366 struct buf *bp;
367 struct m_ext2fs *fs;
368 struct ext2fs *newfs;
369 struct partinfo dpart;
370 int i, size, error;
371
372 if ((mountp->mnt_flag & MNT_RDONLY) == 0)
373 return (EINVAL);
374 /*
375 * Step 1: invalidate all cached meta-data.
376 */
377 devvp = VFSTOUFS(mountp)->um_devvp;
378 if (vinvalbuf(devvp, 0, cred, p, 0, 0))
379 panic("ext2fs_reload: dirty1");
380 /*
381 * Step 2: re-read superblock from disk.
382 */
383 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
384 size = DEV_BSIZE;
385 else
386 size = dpart.disklab->d_secsize;
387 error = bread(devvp, (daddr_t)(SBOFF / size), SBSIZE, NOCRED, &bp);
388 if (error)
389 return (error);
390 newfs = (struct ext2fs *)bp->b_data;
391 if (fs2h16(newfs->e2fs_magic) != E2FS_MAGIC ||
392 fs2h32(newfs->e2fs_rev) != E2FS_REV) {
393 #ifdef DIAGNOSTIC
394 printf("Wrong magic number: %x (expected %x for ext2 fs)",
395 fs2h16(newfs->e2fs_magic), E2FS_MAGIC);
396 printf("or wrong revision number: %x (expected %x for ext2 fs)",
397 fs2h32(newfs->e2fs_rev), E2FS_REV);
398 #endif
399 brelse(bp);
400 return (EIO); /* XXX needs translation */
401 }
402 if (fs2h32(newfs->e2fs_log_bsize) > 2) { /* block size = 1024|2048|4096 */
403 #ifdef DIAGNOSTIC
404 printf("wrong block size: %d (expected <=2 for ext2 fs)\n",
405 fs2h32(newfs->e2fs_log_bsize));
406 #endif
407 brelse(bp);
408 return (EIO); /* XXX needs translation */
409 }
410
411
412 fs = VFSTOUFS(mountp)->um_e2fs;
413 /*
414 * copy in new superblock, and compute in-memory values
415 */
416 e2fs_sbload(newfs, &fs->e2fs);
417 fs->e2fs_ncg = howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock,
418 fs->e2fs.e2fs_bpg);
419 /* XXX assume hw bsize = 512 */
420 fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1;
421 fs->e2fs_bsize = 1024 << fs->e2fs.e2fs_log_bsize;
422 fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize;
423 fs->e2fs_qbmask = fs->e2fs_bsize - 1;
424 fs->e2fs_bmask = ~fs->e2fs_qbmask;
425 fs->e2fs_ngdb = howmany(fs->e2fs_ncg,
426 fs->e2fs_bsize / sizeof(struct ext2_gd));
427 fs->e2fs_ipb = fs->e2fs_bsize / sizeof(struct ext2fs_dinode);
428 fs->e2fs_itpg = fs->e2fs.e2fs_ipg/fs->e2fs_ipb;
429
430 /*
431 * Step 3: re-read summary information from disk.
432 */
433
434 for (i=0; i < fs->e2fs_ngdb; i++) {
435 error = bread(devvp , fsbtodb(fs, ((fs->e2fs_bsize>1024)?0:1)+i+1),
436 fs->e2fs_bsize, NOCRED, &bp);
437 if (error)
438 return (error);
439 e2fs_cgload((struct ext2_gd*)bp->b_data,
440 &fs->e2fs_gd[i* fs->e2fs_bsize / sizeof(struct ext2_gd)],
441 fs->e2fs_bsize);
442 brelse(bp);
443 }
444
445 loop:
446 for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
447 nvp = vp->v_mntvnodes.le_next;
448 /*
449 * Step 4: invalidate all inactive vnodes.
450 */
451 if (vp->v_usecount == 0) {
452 vgone(vp);
453 continue;
454 }
455 /*
456 * Step 5: invalidate all cached file data.
457 */
458 if (vget(vp, 1))
459 goto loop;
460 if (vinvalbuf(vp, 0, cred, p, 0, 0))
461 panic("ext2fs_reload: dirty2");
462 /*
463 * Step 6: re-read inode data for all active vnodes.
464 */
465 ip = VTOI(vp);
466 error = bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
467 (int)fs->e2fs_bsize, NOCRED, &bp);
468 if (error) {
469 vput(vp);
470 return (error);
471 }
472 e2fs_iload((struct ext2fs_dinode *)bp->b_data +
473 ino_to_fsbo(fs, ip->i_number),
474 &ip->i_din.e2fs_din);
475 brelse(bp);
476 vput(vp);
477 if (vp->v_mount != mountp)
478 goto loop;
479 }
480 return (0);
481 }
482
483 /*
484 * Common code for mount and mountroot
485 */
486 int
487 ext2fs_mountfs(devvp, mp, p)
488 register struct vnode *devvp;
489 struct mount *mp;
490 struct proc *p;
491 {
492 register struct ufsmount *ump;
493 struct buf *bp;
494 register struct ext2fs *fs;
495 register struct m_ext2fs *m_fs;
496 dev_t dev;
497 struct partinfo dpart;
498 int error, i, size, ronly;
499 struct ucred *cred;
500 extern struct vnode *rootvp;
501
502 dev = devvp->v_rdev;
503 cred = p ? p->p_ucred : NOCRED;
504 /*
505 * Disallow multiple mounts of the same device.
506 * Disallow mounting of a device that is currently in use
507 * (except for root, which might share swap device for miniroot).
508 * Flush out any old buffers remaining from a previous use.
509 */
510 if ((error = vfs_mountedon(devvp)) != 0)
511 return (error);
512 if (vcount(devvp) > 1 && devvp != rootvp)
513 return (EBUSY);
514 if ((error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)) != 0)
515 return (error);
516
517 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
518 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
519 if (error)
520 return (error);
521 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0)
522 size = DEV_BSIZE;
523 else
524 size = dpart.disklab->d_secsize;
525
526 bp = NULL;
527 ump = NULL;
528
529 #ifdef DEBUG_EXT2
530 printf("sb size: %d ino size %d\n", sizeof(struct ext2fs),
531 sizeof(struct ext2fs_dinode));
532 #endif
533 error = bread(devvp, (SBOFF / DEV_BSIZE), SBSIZE, cred, &bp);
534 if (error)
535 goto out;
536 fs = (struct ext2fs *)bp->b_data;
537 if (fs2h16(fs->e2fs_magic) != E2FS_MAGIC ||
538 fs2h32(fs->e2fs_rev) != E2FS_REV) {
539 #ifdef DIAGNOSTIC
540 printf("Wrong magic number: %x (expected %x for ext2 fs)",
541 fs2h16(fs->e2fs_magic), E2FS_MAGIC);
542 printf(" or wrong revision number: %x (expected %x for ext2 fs)\n",
543 fs2h32(fs->e2fs_rev), E2FS_REV);
544 #endif
545 error = EINVAL; /* XXX needs translation */
546 goto out;
547 }
548
549 if (fs2h32(fs->e2fs_log_bsize) > 2) { /* block size = 1024|2048|4096 */
550 #ifdef DIAGNOSTIC
551 printf("wrong block size: %d (expected <2 for ext2 fs)\n",
552 fs2h32(fs->e2fs_log_bsize));
553 #endif
554 error = EINVAL; /* XXX needs translation */
555 goto out;
556 }
557
558 ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
559 bzero((caddr_t)ump, sizeof *ump);
560 ump->um_e2fs = malloc(sizeof(struct m_ext2fs), M_UFSMNT, M_WAITOK);
561 e2fs_sbload((struct ext2fs*)bp->b_data, &ump->um_e2fs->e2fs);
562 brelse(bp);
563 bp = NULL;
564 m_fs = ump->um_e2fs;
565 m_fs->e2fs_ronly = ronly;
566 if (ronly == 0) {
567 if (m_fs->e2fs.e2fs_state == E2FS_ISCLEAN)
568 m_fs->e2fs.e2fs_state = 0;
569 else
570 m_fs->e2fs.e2fs_state = E2FS_ERRORS;
571 m_fs->e2fs_fmod = 1;
572 }
573
574 /* compute dynamic sb infos */
575 m_fs->e2fs_ncg =
576 howmany(m_fs->e2fs.e2fs_bcount - m_fs->e2fs.e2fs_first_dblock,
577 m_fs->e2fs.e2fs_bpg);
578 /* XXX assume hw bsize = 512 */
579 m_fs->e2fs_fsbtodb = m_fs->e2fs.e2fs_log_bsize + 1;
580 m_fs->e2fs_bsize = 1024 << m_fs->e2fs.e2fs_log_bsize;
581 m_fs->e2fs_bshift = LOG_MINBSIZE + m_fs->e2fs.e2fs_log_bsize;
582 m_fs->e2fs_qbmask = m_fs->e2fs_bsize - 1;
583 m_fs->e2fs_bmask = ~m_fs->e2fs_qbmask;
584 m_fs->e2fs_ngdb = howmany(m_fs->e2fs_ncg,
585 m_fs->e2fs_bsize / sizeof(struct ext2_gd));
586 m_fs->e2fs_ipb = m_fs->e2fs_bsize / sizeof(struct ext2fs_dinode);
587 m_fs->e2fs_itpg = m_fs->e2fs.e2fs_ipg/m_fs->e2fs_ipb;
588
589 m_fs->e2fs_gd = malloc(m_fs->e2fs_ngdb * m_fs->e2fs_bsize,
590 M_UFSMNT, M_WAITOK);
591 for (i=0; i < m_fs->e2fs_ngdb; i++) {
592 error = bread(devvp , fsbtodb(m_fs, ((m_fs->e2fs_bsize>1024)?0:1)+i+1),
593 m_fs->e2fs_bsize, NOCRED, &bp);
594 if (error) {
595 free(m_fs->e2fs_gd, M_UFSMNT);
596 goto out;
597 }
598 e2fs_cgload((struct ext2_gd*)bp->b_data,
599 &m_fs->e2fs_gd[i* m_fs->e2fs_bsize / sizeof(struct ext2_gd)],
600 m_fs->e2fs_bsize);
601 brelse(bp);
602 bp = NULL;
603 }
604
605 mp->mnt_data = (qaddr_t)ump;
606 mp->mnt_stat.f_fsid.val[0] = (long)dev;
607 mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_EXT2FS);
608 mp->mnt_maxsymlinklen = EXT2_MAXSYMLINKLEN;
609 mp->mnt_flag |= MNT_LOCAL;
610 ump->um_mountp = mp;
611 ump->um_dev = dev;
612 ump->um_devvp = devvp;
613 ump->um_nindir = NINDIR(m_fs);
614 ump->um_bptrtodb = m_fs->e2fs_fsbtodb;
615 ump->um_seqinc = 1; /* no frags */
616 devvp->v_specflags |= SI_MOUNTEDON;
617 return (0);
618 out:
619 if (bp)
620 brelse(bp);
621 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
622 if (ump) {
623 free(ump->um_e2fs, M_UFSMNT);
624 free(ump, M_UFSMNT);
625 mp->mnt_data = (qaddr_t)0;
626 }
627 return (error);
628 }
629
630 /*
631 * unmount system call
632 */
633 int
634 ext2fs_unmount(mp, mntflags, p)
635 struct mount *mp;
636 int mntflags;
637 struct proc *p;
638 {
639 register struct ufsmount *ump;
640 register struct m_ext2fs *fs;
641 int error, flags;
642
643 flags = 0;
644 if (mntflags & MNT_FORCE)
645 flags |= FORCECLOSE;
646 if ((error = ext2fs_flushfiles(mp, flags, p)) != 0)
647 return (error);
648 ump = VFSTOUFS(mp);
649 fs = ump->um_e2fs;
650 if (fs->e2fs_ronly == 0 &&
651 ext2fs_cgupdate(ump, MNT_WAIT) == 0 &&
652 (fs->e2fs.e2fs_state & E2FS_ERRORS) == 0) {
653 fs->e2fs.e2fs_state = E2FS_ISCLEAN;
654 (void) ext2fs_sbupdate(ump, MNT_WAIT);
655 }
656 ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
657 error = VOP_CLOSE(ump->um_devvp, fs->e2fs_ronly ? FREAD : FREAD|FWRITE,
658 NOCRED, p);
659 vrele(ump->um_devvp);
660 free(fs->e2fs_gd, M_UFSMNT);
661 free(fs, M_UFSMNT);
662 free(ump, M_UFSMNT);
663 mp->mnt_data = (qaddr_t)0;
664 mp->mnt_flag &= ~MNT_LOCAL;
665 return (error);
666 }
667
668 /*
669 * Flush out all the files in a filesystem.
670 */
671 int
672 ext2fs_flushfiles(mp, flags, p)
673 register struct mount *mp;
674 int flags;
675 struct proc *p;
676 {
677 extern int doforce;
678 register struct ufsmount *ump;
679 int error;
680
681 if (!doforce)
682 flags &= ~FORCECLOSE;
683 ump = VFSTOUFS(mp);
684 error = vflush(mp, NULLVP, flags);
685 return (error);
686 }
687
688 /*
689 * Get file system statistics.
690 */
691 int
692 ext2fs_statfs(mp, sbp, p)
693 struct mount *mp;
694 register struct statfs *sbp;
695 struct proc *p;
696 {
697 register struct ufsmount *ump;
698 register struct m_ext2fs *fs;
699 u_int32_t overhead, overhead_per_group;
700
701 ump = VFSTOUFS(mp);
702 fs = ump->um_e2fs;
703 if (fs->e2fs.e2fs_magic != E2FS_MAGIC)
704 panic("ext2fs_statfs");
705 #ifdef COMPAT_09
706 sbp->f_type = 1;
707 #else
708 sbp->f_type = 0;
709 #endif
710
711 /*
712 * Compute the overhead (FS structures)
713 */
714 overhead_per_group = 1 /* super block */ +
715 fs->e2fs_ngdb +
716 1 /* block bitmap */ +
717 1 /* inode bitmap */ +
718 fs->e2fs_itpg;
719 overhead = fs->e2fs.e2fs_first_dblock +
720 fs->e2fs_ncg * overhead_per_group;
721
722
723 sbp->f_bsize = fs->e2fs_bsize;
724 sbp->f_iosize = fs->e2fs_bsize;
725 sbp->f_blocks = fs->e2fs.e2fs_bcount - overhead;
726 sbp->f_bfree = fs->e2fs.e2fs_fbcount;
727 sbp->f_bavail = sbp->f_bfree - fs->e2fs.e2fs_rbcount;
728 sbp->f_files = fs->e2fs.e2fs_icount;
729 sbp->f_ffree = fs->e2fs.e2fs_ficount;
730 if (sbp != &mp->mnt_stat) {
731 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
732 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
733 }
734 strncpy(sbp->f_fstypename, mp->mnt_op->vfs_name, MFSNAMELEN);
735 return (0);
736 }
737
738 /*
739 * Go through the disk queues to initiate sandbagged IO;
740 * go through the inodes to write those that have been modified;
741 * initiate the writing of the super block if it has been modified.
742 *
743 * Note: we are always called with the filesystem marked `MPBUSY'.
744 */
745 int
746 ext2fs_sync(mp, waitfor, cred, p)
747 struct mount *mp;
748 int waitfor;
749 struct ucred *cred;
750 struct proc *p;
751 {
752 register struct vnode *vp;
753 register struct inode *ip;
754 register struct ufsmount *ump = VFSTOUFS(mp);
755 register struct m_ext2fs *fs;
756 int error, allerror = 0;
757
758 fs = ump->um_e2fs;
759 /*
760 * Write back modified superblock.
761 * Consistency check that the superblock
762 * is still in the buffer cache.
763 */
764 if (fs->e2fs_fmod != 0) {
765 if (fs->e2fs_ronly != 0) { /* XXX */
766 printf("fs = %s\n", fs->e2fs_fsmnt);
767 panic("update: rofs mod");
768 }
769 fs->e2fs_fmod = 0;
770 fs->e2fs.e2fs_wtime = time.tv_sec;
771 allerror = ext2fs_cgupdate(ump, waitfor);
772 }
773 /*
774 * Write back each (modified) inode.
775 */
776 loop:
777 for (vp = mp->mnt_vnodelist.lh_first;
778 vp != NULL;
779 vp = vp->v_mntvnodes.le_next) {
780 /*
781 * If the vnode that we are about to sync is no longer
782 * associated with this mount point, start over.
783 */
784 if (vp->v_mount != mp)
785 goto loop;
786 if (VOP_ISLOCKED(vp))
787 continue;
788 ip = VTOI(vp);
789 if ((ip->i_flag &
790 (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
791 vp->v_dirtyblkhd.lh_first == NULL)
792 continue;
793 if (vget(vp, 1))
794 goto loop;
795 if ((error = VOP_FSYNC(vp, cred, waitfor, p)) != 0)
796 allerror = error;
797 vput(vp);
798 }
799 /*
800 * Force stale file system control information to be flushed.
801 */
802 if ((error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) != 0)
803 allerror = error;
804 return (allerror);
805 }
806
807 /*
808 * Look up a EXT2FS dinode number to find its incore vnode, otherwise read it
809 * in from disk. If it is in core, wait for the lock bit to clear, then
810 * return the inode locked. Detection and handling of mount points must be
811 * done by the calling routine.
812 */
813 int
814 ext2fs_vget(mp, ino, vpp)
815 struct mount *mp;
816 ino_t ino;
817 struct vnode **vpp;
818 {
819 register struct m_ext2fs *fs;
820 register struct inode *ip;
821 struct ufsmount *ump;
822 struct buf *bp;
823 struct vnode *vp;
824 dev_t dev;
825 int error;
826
827 ump = VFSTOUFS(mp);
828 dev = ump->um_dev;
829 do {
830 if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
831 return (0);
832 } while (lockmgr(&ufs_hashlock, LK_EXCLUSIVE|LK_SLEEPFAIL, 0, curproc));
833
834 /* Allocate a new vnode/inode. */
835 if ((error = getnewvnode(VT_EXT2FS, mp, ext2fs_vnodeop_p, &vp)) != 0) {
836 *vpp = NULL;
837 lockmgr(&ufs_hashlock, LK_RELEASE, 0, curproc);
838 return (error);
839 }
840 MALLOC(ip, struct inode *, sizeof(struct inode), M_EXT2FSNODE, M_WAITOK);
841 bzero((caddr_t)ip, sizeof(struct inode));
842 vp->v_data = ip;
843 ip->i_vnode = vp;
844 ip->i_e2fs = fs = ump->um_e2fs;
845 ip->i_dev = dev;
846 ip->i_number = ino;
847 ip->i_e2fs_last_lblk = 0;
848 ip->i_e2fs_last_blk = 0;
849
850 /*
851 * Put it onto its hash chain and lock it so that other requests for
852 * this inode will block if they arrive while we are sleeping waiting
853 * for old data structures to be purged or for the contents of the
854 * disk portion of this inode to be read.
855 */
856 ufs_ihashins(ip);
857 lockmgr(&ufs_hashlock, LK_RELEASE, 0, curproc);
858
859 /* Read in the disk contents for the inode, copy into the inode. */
860 error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
861 (int)fs->e2fs_bsize, NOCRED, &bp);
862 if (error) {
863 /*
864 * The inode does not contain anything useful, so it would
865 * be misleading to leave it on its hash chain. With mode
866 * still zero, it will be unlinked and returned to the free
867 * list by vput().
868 */
869 vput(vp);
870 brelse(bp);
871 *vpp = NULL;
872 return (error);
873 }
874 e2fs_iload((struct ext2fs_dinode*)bp->b_data + ino_to_fsbo(fs, ino),
875 &ip->i_din.e2fs_din);
876 brelse(bp);
877
878 /*
879 * Initialize the vnode from the inode, check for aliases.
880 * Note that the underlying vnode may have changed.
881 */
882 error = ufs_vinit(mp, ext2fs_specop_p, EXT2FS_FIFOOPS, &vp);
883 if (error) {
884 vput(vp);
885 *vpp = NULL;
886 return (error);
887 }
888 /*
889 * Finish inode initialization now that aliasing has been resolved.
890 */
891 ip->i_devvp = ump->um_devvp;
892 VREF(ip->i_devvp);
893 /*
894 * Set up a generation number for this inode if it does not
895 * already have one. This should only happen on old filesystems.
896 */
897 if (ip->i_e2fs_gen == 0) {
898 if (++ext2gennumber < (u_long)time.tv_sec)
899 ext2gennumber = time.tv_sec;
900 ip->i_e2fs_gen = ext2gennumber;
901 if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
902 ip->i_flag |= IN_MODIFIED;
903 }
904
905 *vpp = vp;
906 return (0);
907 }
908
909 /*
910 * File handle to vnode
911 *
912 * Have to be really careful about stale file handles:
913 * - check that the inode number is valid
914 * - call ext2fs_vget() to get the locked inode
915 * - check for an unallocated inode (i_mode == 0)
916 * - check that the given client host has export rights and return
917 * those rights via. exflagsp and credanonp
918 */
919 int
920 ext2fs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
921 register struct mount *mp;
922 struct fid *fhp;
923 struct mbuf *nam;
924 struct vnode **vpp;
925 int *exflagsp;
926 struct ucred **credanonp;
927 {
928 register struct ufid *ufhp;
929 struct m_ext2fs *fs;
930
931 ufhp = (struct ufid *)fhp;
932 fs = VFSTOUFS(mp)->um_e2fs;
933 if ((ufhp->ufid_ino < EXT2_FIRSTINO && ufhp->ufid_ino != EXT2_ROOTINO) ||
934 ufhp->ufid_ino >= fs->e2fs_ncg * fs->e2fs.e2fs_ipg)
935 return (ESTALE);
936 return (ext2fs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp));
937 }
938
939 /*
940 * Vnode pointer to File handle
941 */
942 /* ARGSUSED */
943 int
944 ext2fs_vptofh(vp, fhp)
945 struct vnode *vp;
946 struct fid *fhp;
947 {
948 register struct inode *ip;
949 register struct ufid *ufhp;
950
951 ip = VTOI(vp);
952 ufhp = (struct ufid *)fhp;
953 ufhp->ufid_len = sizeof(struct ufid);
954 ufhp->ufid_ino = ip->i_number;
955 ufhp->ufid_gen = ip->i_e2fs_gen;
956 return (0);
957 }
958
959 /*
960 * Write a superblock and associated information back to disk.
961 */
962 int
963 ext2fs_sbupdate(mp, waitfor)
964 struct ufsmount *mp;
965 int waitfor;
966 {
967 register struct m_ext2fs *fs = mp->um_e2fs;
968 register struct buf *bp;
969 int error = 0;
970
971 bp = getblk(mp->um_devvp, SBLOCK, SBSIZE, 0, 0);
972 e2fs_sbsave(&fs->e2fs, (struct ext2fs*)bp->b_data);
973 if (waitfor == MNT_WAIT)
974 error = bwrite(bp);
975 else
976 bawrite(bp);
977 return (error);
978 }
979
980 int
981 ext2fs_cgupdate(mp, waitfor)
982 struct ufsmount *mp;
983 int waitfor;
984 {
985 register struct m_ext2fs *fs = mp->um_e2fs;
986 register struct buf *bp;
987 int i, error = 0, allerror = 0;
988
989 allerror = ext2fs_sbupdate(mp, waitfor);
990 for (i = 0; i < fs->e2fs_ngdb; i++) {
991 bp = getblk(mp->um_devvp, fsbtodb(fs, ((fs->e2fs_bsize>1024)?0:1)+i+1),
992 fs->e2fs_bsize, 0, 0);
993 e2fs_cgsave(&fs->e2fs_gd[i* fs->e2fs_bsize / sizeof(struct ext2_gd)],
994 (struct ext2_gd*)bp->b_data, fs->e2fs_bsize);
995 if (waitfor == MNT_WAIT)
996 error = bwrite(bp);
997 else
998 bawrite(bp);
999 }
1000
1001 if (!allerror && error)
1002 allerror = error;
1003 return (allerror);
1004 }
1005