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