ext2fs_vfsops.c revision 1.3 1 /* $NetBSD: ext2fs_vfsops.c,v 1.3 1997/07/17 16:56:44 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 (newfs->e2fs_magic != E2FS_MAGIC || newfs->e2fs_rev != E2FS_REV) {
392 #ifdef DIAGNOSTIC
393 printf("Wrong magic number: %x (expected %x for ext2 fs)",
394 newfs->e2fs_magic, E2FS_MAGIC);
395 printf("or wrong revision number: %x (expected %x for ext2 fs)",
396 newfs->e2fs_rev, E2FS_REV);
397 #endif
398 brelse(bp);
399 return (EIO); /* XXX needs translation */
400 }
401 if (newfs->e2fs_log_bsize > 2) { /* block size = 1024|2048|4096 */
402 #ifdef DIAGNOSTIC
403 printf("wrong block size: %d (expected <=2 for ext2 fs)\n",
404 newfs->e2fs_log_bsize);
405 #endif
406 brelse(bp);
407 return (EIO); /* XXX needs translation */
408 }
409
410
411 fs = VFSTOUFS(mountp)->um_e2fs;
412 /*
413 * copy in new superblock, and compute in-memory values
414 */
415 bcopy(newfs, &fs->e2fs, SBSIZE);
416 fs->e2fs_ncg = howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock,
417 fs->e2fs.e2fs_bpg);
418 /* XXX assume hw bsize = 512 */
419 fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1;
420 fs->e2fs_bsize = 1024 << fs->e2fs.e2fs_log_bsize;
421 fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize;
422 fs->e2fs_qbmask = fs->e2fs_bsize - 1;
423 fs->e2fs_bmask = ~fs->e2fs_qbmask;
424 fs->e2fs_ngdb = howmany(fs->e2fs_ncg,
425 fs->e2fs_bsize / sizeof(struct ext2_gd));
426 fs->e2fs_ipb = fs->e2fs_bsize / sizeof(struct ext2fs_dinode);
427 fs->e2fs_itpg = fs->e2fs.e2fs_ipg/fs->e2fs_ipb;
428
429 /*
430 * Step 3: re-read summary information from disk.
431 */
432
433 for (i=0; i < fs->e2fs_ngdb; i++) {
434 error = bread(devvp , fsbtodb(fs, ((fs->e2fs_bsize>1024)?0:1)+i+1),
435 fs->e2fs_bsize, NOCRED, &bp);
436 if (error)
437 return (error);
438 bcopy(bp->b_data,
439 &fs->e2fs_gd[i* fs->e2fs_bsize / sizeof(struct ext2_gd)],
440 fs->e2fs_bsize);
441 brelse(bp);
442 }
443
444 loop:
445 for (vp = mountp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
446 nvp = vp->v_mntvnodes.le_next;
447 /*
448 * Step 4: invalidate all inactive vnodes.
449 */
450 if (vp->v_usecount == 0) {
451 vgone(vp);
452 continue;
453 }
454 /*
455 * Step 5: invalidate all cached file data.
456 */
457 if (vget(vp, 1))
458 goto loop;
459 if (vinvalbuf(vp, 0, cred, p, 0, 0))
460 panic("ext2fs_reload: dirty2");
461 /*
462 * Step 6: re-read inode data for all active vnodes.
463 */
464 ip = VTOI(vp);
465 error = bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
466 (int)fs->e2fs_bsize, NOCRED, &bp);
467 if (error) {
468 vput(vp);
469 return (error);
470 }
471 bcopy((struct ext2fs_dinode *)bp->b_data +
472 ino_to_fsbo(fs, ip->i_number),
473 &ip->i_din.e2fs_din, sizeof(struct ext2fs_dinode));
474 brelse(bp);
475 vput(vp);
476 if (vp->v_mount != mountp)
477 goto loop;
478 }
479 return (0);
480 }
481
482 /*
483 * Common code for mount and mountroot
484 */
485 int
486 ext2fs_mountfs(devvp, mp, p)
487 register struct vnode *devvp;
488 struct mount *mp;
489 struct proc *p;
490 {
491 register struct ufsmount *ump;
492 struct buf *bp;
493 register struct ext2fs *fs;
494 register struct m_ext2fs *m_fs;
495 dev_t dev;
496 struct partinfo dpart;
497 int error, i, size, ronly;
498 struct ucred *cred;
499 extern struct vnode *rootvp;
500
501 dev = devvp->v_rdev;
502 cred = p ? p->p_ucred : NOCRED;
503 /*
504 * Disallow multiple mounts of the same device.
505 * Disallow mounting of a device that is currently in use
506 * (except for root, which might share swap device for miniroot).
507 * Flush out any old buffers remaining from a previous use.
508 */
509 if ((error = vfs_mountedon(devvp)) != 0)
510 return (error);
511 if (vcount(devvp) > 1 && devvp != rootvp)
512 return (EBUSY);
513 if ((error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)) != 0)
514 return (error);
515
516 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
517 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
518 if (error)
519 return (error);
520 if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0)
521 size = DEV_BSIZE;
522 else
523 size = dpart.disklab->d_secsize;
524
525 bp = NULL;
526 ump = NULL;
527
528 #ifdef DEBUG_EXT2
529 printf("sb size: %d ino size %d\n", sizeof(struct ext2fs),
530 sizeof(struct ext2fs_dinode));
531 #endif
532 error = bread(devvp, (SBOFF / DEV_BSIZE), SBSIZE, cred, &bp);
533 if (error)
534 goto out;
535 fs = (struct ext2fs *)bp->b_data;
536 if (fs->e2fs_magic != E2FS_MAGIC || fs->e2fs_rev != E2FS_REV) {
537 #ifdef DIAGNOSTIC
538 printf("Wrong magic number: %x (expected %x for ext2 fs)",
539 fs->e2fs_magic, E2FS_MAGIC);
540 printf(" or wrong revision number: %x (expected %x for ext2 fs)\n",
541 fs->e2fs_rev, E2FS_REV);
542 #endif
543 error = EINVAL; /* XXX needs translation */
544 goto out;
545 }
546
547 if (fs->e2fs_log_bsize > 2) { /* block size = 1024|2048|4096 */
548 #ifdef DIAGNOSTIC
549 printf("wrong block size: %d (expected <2 for ext2 fs)\n",
550 fs->e2fs_log_bsize);
551 #endif
552 error = EINVAL; /* XXX needs translation */
553 goto out;
554 }
555
556 ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
557 bzero((caddr_t)ump, sizeof *ump);
558 ump->um_e2fs = malloc(sizeof(struct m_ext2fs), M_UFSMNT, M_WAITOK);
559 bcopy(bp->b_data, ump->um_e2fs, SBSIZE);
560 brelse(bp);
561 bp = NULL;
562 m_fs = ump->um_e2fs;
563 m_fs->e2fs_ronly = ronly;
564 if (ronly == 0) {
565 if (m_fs->e2fs.e2fs_state == E2FS_ISCLEAN)
566 m_fs->e2fs.e2fs_state = 0;
567 else
568 m_fs->e2fs.e2fs_state = E2FS_ERRORS;
569 m_fs->e2fs_fmod = 1;
570 }
571
572 /* compute dynamic sb infos */
573 m_fs->e2fs_ncg =
574 howmany(m_fs->e2fs.e2fs_bcount - m_fs->e2fs.e2fs_first_dblock,
575 m_fs->e2fs.e2fs_bpg);
576 /* XXX assume hw bsize = 512 */
577 m_fs->e2fs_fsbtodb = m_fs->e2fs.e2fs_log_bsize + 1;
578 m_fs->e2fs_bsize = 1024 << m_fs->e2fs.e2fs_log_bsize;
579 m_fs->e2fs_bshift = LOG_MINBSIZE + m_fs->e2fs.e2fs_log_bsize;
580 m_fs->e2fs_qbmask = m_fs->e2fs_bsize - 1;
581 m_fs->e2fs_bmask = ~m_fs->e2fs_qbmask;
582 m_fs->e2fs_ngdb = howmany(m_fs->e2fs_ncg,
583 m_fs->e2fs_bsize / sizeof(struct ext2_gd));
584 m_fs->e2fs_ipb = m_fs->e2fs_bsize / sizeof(struct ext2fs_dinode);
585 m_fs->e2fs_itpg = m_fs->e2fs.e2fs_ipg/m_fs->e2fs_ipb;
586
587 m_fs->e2fs_gd = malloc(m_fs->e2fs_ngdb * m_fs->e2fs_bsize,
588 M_UFSMNT, M_WAITOK);
589 for (i=0; i < m_fs->e2fs_ngdb; i++) {
590 error = bread(devvp , fsbtodb(m_fs, ((m_fs->e2fs_bsize>1024)?0:1)+i+1),
591 m_fs->e2fs_bsize, NOCRED, &bp);
592 if (error) {
593 free(m_fs->e2fs_gd, M_UFSMNT);
594 goto out;
595 }
596 bcopy(bp->b_data,
597 &m_fs->e2fs_gd[i* m_fs->e2fs_bsize / sizeof(struct ext2_gd)],
598 m_fs->e2fs_bsize);
599 brelse(bp);
600 bp = NULL;
601 }
602
603 mp->mnt_data = (qaddr_t)ump;
604 mp->mnt_stat.f_fsid.val[0] = (long)dev;
605 mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_EXT2FS);
606 mp->mnt_maxsymlinklen = EXT2_MAXSYMLINKLEN;
607 mp->mnt_flag |= MNT_LOCAL;
608 ump->um_mountp = mp;
609 ump->um_dev = dev;
610 ump->um_devvp = devvp;
611 ump->um_nindir = NINDIR(m_fs);
612 ump->um_bptrtodb = m_fs->e2fs_fsbtodb;
613 ump->um_seqinc = 1; /* no frags */
614 devvp->v_specflags |= SI_MOUNTEDON;
615 return (0);
616 out:
617 if (bp)
618 brelse(bp);
619 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
620 if (ump) {
621 free(ump->um_e2fs, M_UFSMNT);
622 free(ump, M_UFSMNT);
623 mp->mnt_data = (qaddr_t)0;
624 }
625 return (error);
626 }
627
628 /*
629 * unmount system call
630 */
631 int
632 ext2fs_unmount(mp, mntflags, p)
633 struct mount *mp;
634 int mntflags;
635 struct proc *p;
636 {
637 register struct ufsmount *ump;
638 register struct m_ext2fs *fs;
639 int error, flags;
640
641 flags = 0;
642 if (mntflags & MNT_FORCE)
643 flags |= FORCECLOSE;
644 if ((error = ext2fs_flushfiles(mp, flags, p)) != 0)
645 return (error);
646 ump = VFSTOUFS(mp);
647 fs = ump->um_e2fs;
648 if (fs->e2fs_ronly == 0 &&
649 ext2fs_cgupdate(ump, MNT_WAIT) == 0 &&
650 (fs->e2fs.e2fs_state & E2FS_ERRORS) == 0) {
651 fs->e2fs.e2fs_state = E2FS_ISCLEAN;
652 (void) ext2fs_sbupdate(ump, MNT_WAIT);
653 }
654 ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
655 error = VOP_CLOSE(ump->um_devvp, fs->e2fs_ronly ? FREAD : FREAD|FWRITE,
656 NOCRED, p);
657 vrele(ump->um_devvp);
658 free(fs->e2fs_gd, M_UFSMNT);
659 free(fs, M_UFSMNT);
660 free(ump, M_UFSMNT);
661 mp->mnt_data = (qaddr_t)0;
662 mp->mnt_flag &= ~MNT_LOCAL;
663 return (error);
664 }
665
666 /*
667 * Flush out all the files in a filesystem.
668 */
669 int
670 ext2fs_flushfiles(mp, flags, p)
671 register struct mount *mp;
672 int flags;
673 struct proc *p;
674 {
675 extern int doforce;
676 register struct ufsmount *ump;
677 int error;
678
679 if (!doforce)
680 flags &= ~FORCECLOSE;
681 ump = VFSTOUFS(mp);
682 error = vflush(mp, NULLVP, flags);
683 return (error);
684 }
685
686 /*
687 * Get file system statistics.
688 */
689 int
690 ext2fs_statfs(mp, sbp, p)
691 struct mount *mp;
692 register struct statfs *sbp;
693 struct proc *p;
694 {
695 register struct ufsmount *ump;
696 register struct m_ext2fs *fs;
697 u_int32_t overhead, overhead_per_group;
698
699 ump = VFSTOUFS(mp);
700 fs = ump->um_e2fs;
701 if (fs->e2fs.e2fs_magic != E2FS_MAGIC)
702 panic("ext2fs_statfs");
703 #ifdef COMPAT_09
704 sbp->f_type = 1;
705 #else
706 sbp->f_type = 0;
707 #endif
708
709 /*
710 * Compute the overhead (FS structures)
711 */
712 overhead_per_group = 1 /* super block */ +
713 fs->e2fs_ngdb +
714 1 /* block bitmap */ +
715 1 /* inode bitmap */ +
716 fs->e2fs_itpg;
717 overhead = fs->e2fs.e2fs_first_dblock +
718 fs->e2fs_ncg * overhead_per_group;
719
720
721 sbp->f_bsize = fs->e2fs_bsize;
722 sbp->f_iosize = fs->e2fs_bsize;
723 sbp->f_blocks = fs->e2fs.e2fs_bcount - overhead;
724 sbp->f_bfree = fs->e2fs.e2fs_fbcount;
725 sbp->f_bavail = sbp->f_bfree - fs->e2fs.e2fs_rbcount;
726 sbp->f_files = fs->e2fs.e2fs_icount;
727 sbp->f_ffree = fs->e2fs.e2fs_ficount;
728 if (sbp != &mp->mnt_stat) {
729 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
730 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
731 }
732 strncpy(sbp->f_fstypename, mp->mnt_op->vfs_name, MFSNAMELEN);
733 return (0);
734 }
735
736 /*
737 * Go through the disk queues to initiate sandbagged IO;
738 * go through the inodes to write those that have been modified;
739 * initiate the writing of the super block if it has been modified.
740 *
741 * Note: we are always called with the filesystem marked `MPBUSY'.
742 */
743 int
744 ext2fs_sync(mp, waitfor, cred, p)
745 struct mount *mp;
746 int waitfor;
747 struct ucred *cred;
748 struct proc *p;
749 {
750 register struct vnode *vp;
751 register struct inode *ip;
752 register struct ufsmount *ump = VFSTOUFS(mp);
753 register struct m_ext2fs *fs;
754 int error, allerror = 0;
755
756 fs = ump->um_e2fs;
757 /*
758 * Write back modified superblock.
759 * Consistency check that the superblock
760 * is still in the buffer cache.
761 */
762 if (fs->e2fs_fmod != 0) {
763 if (fs->e2fs_ronly != 0) { /* XXX */
764 printf("fs = %s\n", fs->e2fs_fsmnt);
765 panic("update: rofs mod");
766 }
767 fs->e2fs_fmod = 0;
768 fs->e2fs.e2fs_wtime = time.tv_sec;
769 allerror = ext2fs_cgupdate(ump, waitfor);
770 }
771 /*
772 * Write back each (modified) inode.
773 */
774 loop:
775 for (vp = mp->mnt_vnodelist.lh_first;
776 vp != NULL;
777 vp = vp->v_mntvnodes.le_next) {
778 /*
779 * If the vnode that we are about to sync is no longer
780 * associated with this mount point, start over.
781 */
782 if (vp->v_mount != mp)
783 goto loop;
784 if (VOP_ISLOCKED(vp))
785 continue;
786 ip = VTOI(vp);
787 if ((ip->i_flag &
788 (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
789 vp->v_dirtyblkhd.lh_first == NULL)
790 continue;
791 if (vget(vp, 1))
792 goto loop;
793 if ((error = VOP_FSYNC(vp, cred, waitfor, p)) != 0)
794 allerror = error;
795 vput(vp);
796 }
797 /*
798 * Force stale file system control information to be flushed.
799 */
800 if ((error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) != 0)
801 allerror = error;
802 return (allerror);
803 }
804
805 /*
806 * Look up a EXT2FS dinode number to find its incore vnode, otherwise read it
807 * in from disk. If it is in core, wait for the lock bit to clear, then
808 * return the inode locked. Detection and handling of mount points must be
809 * done by the calling routine.
810 */
811 int
812 ext2fs_vget(mp, ino, vpp)
813 struct mount *mp;
814 ino_t ino;
815 struct vnode **vpp;
816 {
817 register struct m_ext2fs *fs;
818 register struct inode *ip;
819 struct ufsmount *ump;
820 struct buf *bp;
821 struct vnode *vp;
822 dev_t dev;
823 int error;
824
825 ump = VFSTOUFS(mp);
826 dev = ump->um_dev;
827 do {
828 if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
829 return (0);
830 } while (lockmgr(&ufs_hashlock, LK_EXCLUSIVE|LK_SLEEPFAIL, 0, curproc));
831
832 /* Allocate a new vnode/inode. */
833 if ((error = getnewvnode(VT_EXT2FS, mp, ext2fs_vnodeop_p, &vp)) != 0) {
834 *vpp = NULL;
835 lockmgr(&ufs_hashlock, LK_RELEASE, 0, curproc);
836 return (error);
837 }
838 MALLOC(ip, struct inode *, sizeof(struct inode), M_EXT2FSNODE, M_WAITOK);
839 bzero((caddr_t)ip, sizeof(struct inode));
840 vp->v_data = ip;
841 ip->i_vnode = vp;
842 ip->i_e2fs = fs = ump->um_e2fs;
843 ip->i_dev = dev;
844 ip->i_number = ino;
845 ip->i_e2fs_last_lblk = 0;
846 ip->i_e2fs_last_blk = 0;
847
848 /*
849 * Put it onto its hash chain and lock it so that other requests for
850 * this inode will block if they arrive while we are sleeping waiting
851 * for old data structures to be purged or for the contents of the
852 * disk portion of this inode to be read.
853 */
854 ufs_ihashins(ip);
855 lockmgr(&ufs_hashlock, LK_RELEASE, 0, curproc);
856
857 /* Read in the disk contents for the inode, copy into the inode. */
858 error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
859 (int)fs->e2fs_bsize, NOCRED, &bp);
860 if (error) {
861 /*
862 * The inode does not contain anything useful, so it would
863 * be misleading to leave it on its hash chain. With mode
864 * still zero, it will be unlinked and returned to the free
865 * list by vput().
866 */
867 vput(vp);
868 brelse(bp);
869 *vpp = NULL;
870 return (error);
871 }
872 bcopy(((struct ext2fs_dinode*)bp->b_data + ino_to_fsbo(fs, ino)),
873 &ip->i_din, sizeof(struct ext2fs_dinode));
874
875 brelse(bp);
876
877 /*
878 * Initialize the vnode from the inode, check for aliases.
879 * Note that the underlying vnode may have changed.
880 */
881 error = ufs_vinit(mp, ext2fs_specop_p, EXT2FS_FIFOOPS, &vp);
882 if (error) {
883 vput(vp);
884 *vpp = NULL;
885 return (error);
886 }
887 /*
888 * Finish inode initialization now that aliasing has been resolved.
889 */
890 ip->i_devvp = ump->um_devvp;
891 VREF(ip->i_devvp);
892 /*
893 * Set up a generation number for this inode if it does not
894 * already have one. This should only happen on old filesystems.
895 */
896 if (ip->i_e2fs_gen == 0) {
897 if (++ext2gennumber < (u_long)time.tv_sec)
898 ext2gennumber = time.tv_sec;
899 ip->i_e2fs_gen = ext2gennumber;
900 if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
901 ip->i_flag |= IN_MODIFIED;
902 }
903
904 *vpp = vp;
905 return (0);
906 }
907
908 /*
909 * File handle to vnode
910 *
911 * Have to be really careful about stale file handles:
912 * - check that the inode number is valid
913 * - call ext2fs_vget() to get the locked inode
914 * - check for an unallocated inode (i_mode == 0)
915 * - check that the given client host has export rights and return
916 * those rights via. exflagsp and credanonp
917 */
918 int
919 ext2fs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
920 register struct mount *mp;
921 struct fid *fhp;
922 struct mbuf *nam;
923 struct vnode **vpp;
924 int *exflagsp;
925 struct ucred **credanonp;
926 {
927 register struct ufid *ufhp;
928 struct m_ext2fs *fs;
929
930 ufhp = (struct ufid *)fhp;
931 fs = VFSTOUFS(mp)->um_e2fs;
932 if ((ufhp->ufid_ino < EXT2_FIRSTINO && ufhp->ufid_ino != EXT2_ROOTINO) ||
933 ufhp->ufid_ino >= fs->e2fs_ncg * fs->e2fs.e2fs_ipg)
934 return (ESTALE);
935 return (ext2fs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp));
936 }
937
938 /*
939 * Vnode pointer to File handle
940 */
941 /* ARGSUSED */
942 int
943 ext2fs_vptofh(vp, fhp)
944 struct vnode *vp;
945 struct fid *fhp;
946 {
947 register struct inode *ip;
948 register struct ufid *ufhp;
949
950 ip = VTOI(vp);
951 ufhp = (struct ufid *)fhp;
952 ufhp->ufid_len = sizeof(struct ufid);
953 ufhp->ufid_ino = ip->i_number;
954 ufhp->ufid_gen = ip->i_e2fs_gen;
955 return (0);
956 }
957
958 /*
959 * Write a superblock and associated information back to disk.
960 */
961 int
962 ext2fs_sbupdate(mp, waitfor)
963 struct ufsmount *mp;
964 int waitfor;
965 {
966 register struct m_ext2fs *fs = mp->um_e2fs;
967 register struct buf *bp;
968 int error = 0;
969
970 bp = getblk(mp->um_devvp, SBLOCK, SBSIZE, 0, 0);
971 bcopy((caddr_t)(&fs->e2fs), bp->b_data, SBSIZE);
972 if (waitfor == MNT_WAIT)
973 error = bwrite(bp);
974 else
975 bawrite(bp);
976 return (error);
977 }
978
979 int
980 ext2fs_cgupdate(mp, waitfor)
981 struct ufsmount *mp;
982 int waitfor;
983 {
984 register struct m_ext2fs *fs = mp->um_e2fs;
985 register struct buf *bp;
986 int i, error = 0, allerror = 0;
987
988 allerror = ext2fs_sbupdate(mp, waitfor);
989 for (i = 0; i < fs->e2fs_ngdb; i++) {
990 bp = getblk(mp->um_devvp, fsbtodb(fs, ((fs->e2fs_bsize>1024)?0:1)+i+1),
991 fs->e2fs_bsize, 0, 0);
992 bcopy(&fs->e2fs_gd[i* fs->e2fs_bsize / sizeof(struct ext2_gd)],
993 bp->b_data, fs->e2fs_bsize);
994 if (waitfor == MNT_WAIT)
995 error = bwrite(bp);
996 else
997 bawrite(bp);
998 }
999
1000 if (!allerror && error)
1001 allerror = error;
1002 return (allerror);
1003 }
1004