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