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