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