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