1 /* $OpenBSD: ext2fs_vfsops.c,v 1.121 2024/09/04 07:54:53 mglocker Exp $ */
2 /* $NetBSD: ext2fs_vfsops.c,v 1.1 1997/06/11 09:34:07 bouyer Exp $ */
3
4 /*
5 * Copyright (c) 1997 Manuel Bouyer.
6 * Copyright (c) 1989, 1991, 1993, 1994
7 * The Regents of the University of California. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)ffs_vfsops.c 8.14 (Berkeley) 11/28/94
34 * Modified for ext2fs by Manuel Bouyer.
35 */
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/namei.h>
40 #include <sys/proc.h>
41 #include <sys/kernel.h>
42 #include <sys/vnode.h>
43 #include <sys/socket.h>
44 #include <sys/mount.h>
45 #include <sys/buf.h>
46 #include <sys/disk.h>
47 #include <sys/mbuf.h>
48 #include <sys/fcntl.h>
49 #include <sys/disklabel.h>
50 #include <sys/ioctl.h>
51 #include <sys/errno.h>
52 #include <sys/malloc.h>
53 #include <sys/pool.h>
54 #include <sys/lock.h>
55 #include <sys/dkio.h>
56 #include <sys/specdev.h>
57
58 #include <ufs/ufs/quota.h>
59 #include <ufs/ufs/ufsmount.h>
60 #include <ufs/ufs/inode.h>
61 #include <ufs/ufs/dir.h>
62 #include <ufs/ufs/ufs_extern.h>
63
64 #include <ufs/ext2fs/ext2fs.h>
65 #include <ufs/ext2fs/ext2fs_extern.h>
66
67 int ext2fs_sbupdate(struct ufsmount *, int);
68 static int e2fs_sbcheck(struct ext2fs *, int);
69
70 const struct vfsops ext2fs_vfsops = {
71 .vfs_mount = ext2fs_mount,
72 .vfs_start = ufs_start,
73 .vfs_unmount = ext2fs_unmount,
74 .vfs_root = ufs_root,
75 .vfs_quotactl = ufs_quotactl,
76 .vfs_statfs = ext2fs_statfs,
77 .vfs_sync = ext2fs_sync,
78 .vfs_vget = ext2fs_vget,
79 .vfs_fhtovp = ext2fs_fhtovp,
80 .vfs_vptofh = ext2fs_vptofh,
81 .vfs_init = ext2fs_init,
82 .vfs_sysctl = ext2fs_sysctl,
83 .vfs_checkexp = ufs_check_export,
84 };
85
86 struct pool ext2fs_inode_pool;
87 struct pool ext2fs_dinode_pool;
88
89 extern u_long ext2gennumber;
90
91 int
ext2fs_init(struct vfsconf * vfsp)92 ext2fs_init(struct vfsconf *vfsp)
93 {
94 pool_init(&ext2fs_inode_pool, sizeof(struct inode), 0,
95 IPL_NONE, PR_WAITOK, "ext2inopl", NULL);
96 pool_init(&ext2fs_dinode_pool, sizeof(struct ext2fs_dinode), 0,
97 IPL_NONE, PR_WAITOK, "ext2dinopl", NULL);
98
99 return (ufs_init(vfsp));
100 }
101
102 /*
103 * Called by main() when ext2fs is going to be mounted as root.
104 */
105
106 int
ext2fs_mountroot(void)107 ext2fs_mountroot(void)
108 {
109 struct m_ext2fs *fs;
110 struct mount *mp;
111 struct proc *p = curproc; /* XXX */
112 struct ufsmount *ump;
113 int error;
114
115 /*
116 * Get vnodes for swapdev and rootdev.
117 */
118 if (bdevvp(swapdev, &swapdev_vp) || bdevvp(rootdev, &rootvp))
119 panic("ext2fs_mountroot: can't setup bdevvp's");
120
121 if ((error = vfs_rootmountalloc("ext2fs", "root_device", &mp)) != 0) {
122 vrele(rootvp);
123 return (error);
124 }
125
126 if ((error = ext2fs_mountfs(rootvp, mp, p)) != 0) {
127 vfs_unbusy(mp);
128 vfs_mount_free(mp);
129 vrele(rootvp);
130 return (error);
131 }
132
133 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
134 ump = VFSTOUFS(mp);
135 fs = ump->um_e2fs;
136 memset(fs->e2fs_fsmnt, 0, sizeof(fs->e2fs_fsmnt));
137 strlcpy(fs->e2fs_fsmnt, mp->mnt_stat.f_mntonname, sizeof(fs->e2fs_fsmnt));
138 if (fs->e2fs.e2fs_rev > E2FS_REV0) {
139 memset(fs->e2fs.e2fs_fsmnt, 0, sizeof(fs->e2fs.e2fs_fsmnt));
140 strlcpy(fs->e2fs.e2fs_fsmnt, mp->mnt_stat.f_mntonname,
141 sizeof(fs->e2fs.e2fs_fsmnt));
142 }
143 (void)ext2fs_statfs(mp, &mp->mnt_stat, p);
144 vfs_unbusy(mp);
145 inittodr(fs->e2fs.e2fs_wtime);
146 return (0);
147 }
148
149 /*
150 * VFS Operations.
151 *
152 * mount system call
153 */
154 int
ext2fs_mount(struct mount * mp,const char * path,void * data,struct nameidata * ndp,struct proc * p)155 ext2fs_mount(struct mount *mp, const char *path, void *data,
156 struct nameidata *ndp, struct proc *p)
157 {
158 struct vnode *devvp;
159 struct ufs_args *args = data;
160 struct ufsmount *ump = NULL;
161 struct m_ext2fs *fs;
162 char fname[MNAMELEN];
163 char fspec[MNAMELEN];
164 int error, flags;
165
166 /*
167 * If updating, check whether changing from read-only to
168 * read/write; if there is no device name, that's all we do.
169 */
170 if (mp->mnt_flag & MNT_UPDATE) {
171 ump = VFSTOUFS(mp);
172 fs = ump->um_e2fs;
173 if (fs->e2fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
174 flags = WRITECLOSE;
175 if (mp->mnt_flag & MNT_FORCE)
176 flags |= FORCECLOSE;
177 error = ext2fs_flushfiles(mp, flags, p);
178 if (error == 0 &&
179 ext2fs_cgupdate(ump, MNT_WAIT) == 0 &&
180 (fs->e2fs.e2fs_state & E2FS_ERRORS) == 0) {
181 fs->e2fs.e2fs_state = E2FS_ISCLEAN;
182 (void)ext2fs_sbupdate(ump, MNT_WAIT);
183 }
184 if (error)
185 return (error);
186 fs->e2fs_ronly = 1;
187 }
188 if (mp->mnt_flag & MNT_RELOAD) {
189 error = ext2fs_reload(mp, ndp->ni_cnd.cn_cred, p);
190 if (error)
191 return (error);
192 }
193 if (fs->e2fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) {
194 fs->e2fs_ronly = 0;
195 if (fs->e2fs.e2fs_state == E2FS_ISCLEAN)
196 fs->e2fs.e2fs_state = 0;
197 else
198 fs->e2fs.e2fs_state = E2FS_ERRORS;
199 fs->e2fs_fmod = 1;
200 }
201 if (args && args->fspec == NULL) {
202 /*
203 * Process export requests.
204 */
205 return (vfs_export(mp, &ump->um_export,
206 &args->export_info));
207 }
208 if (args == NULL)
209 goto success;
210 }
211 /*
212 * Not an update, or updating the name: look up the name
213 * and verify that it refers to a sensible block device.
214 */
215 error = copyinstr(args->fspec, fspec, sizeof(fspec), NULL);
216 if (error)
217 goto error;
218
219 if (disk_map(fspec, fname, MNAMELEN, DM_OPENBLCK) == -1)
220 memcpy(fname, fspec, sizeof(fname));
221
222 NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fname, p);
223 if ((error = namei(ndp)) != 0)
224 goto error;
225 devvp = ndp->ni_vp;
226
227 if (devvp->v_type != VBLK) {
228 error = ENOTBLK;
229 goto error_devvp;
230 }
231 if (major(devvp->v_rdev) >= nblkdev) {
232 error = ENXIO;
233 goto error_devvp;
234 }
235 if ((mp->mnt_flag & MNT_UPDATE) == 0)
236 error = ext2fs_mountfs(devvp, mp, p);
237 else {
238 if (devvp != ump->um_devvp)
239 error = EINVAL; /* XXX needs translation */
240 else
241 vrele(devvp);
242 }
243 if (error)
244 goto error_devvp;
245 ump = VFSTOUFS(mp);
246 fs = ump->um_e2fs;
247
248 memset(fs->e2fs_fsmnt, 0, sizeof(fs->e2fs_fsmnt));
249 strlcpy(fs->e2fs_fsmnt, path, sizeof(fs->e2fs_fsmnt));
250 if (fs->e2fs.e2fs_rev > E2FS_REV0) {
251 memset(fs->e2fs.e2fs_fsmnt, 0, sizeof(fs->e2fs.e2fs_fsmnt));
252 strlcpy(fs->e2fs.e2fs_fsmnt, mp->mnt_stat.f_mntonname,
253 sizeof(fs->e2fs.e2fs_fsmnt));
254 }
255 memcpy(mp->mnt_stat.f_mntonname, fs->e2fs_fsmnt, MNAMELEN);
256 memset(mp->mnt_stat.f_mntfromname, 0, MNAMELEN);
257 strlcpy(mp->mnt_stat.f_mntfromname, fname, MNAMELEN);
258 memset(mp->mnt_stat.f_mntfromspec, 0, MNAMELEN);
259 strlcpy(mp->mnt_stat.f_mntfromspec, fspec, MNAMELEN);
260 memcpy(&mp->mnt_stat.mount_info.ufs_args, args, sizeof(*args));
261
262 if (fs->e2fs_fmod != 0) { /* XXX */
263 fs->e2fs_fmod = 0;
264 if (fs->e2fs.e2fs_state == 0)
265 fs->e2fs.e2fs_wtime = gettime();
266 else
267 printf("%s: file system not clean; please fsck(8)\n",
268 mp->mnt_stat.f_mntfromname);
269 ext2fs_cgupdate(ump, MNT_WAIT);
270 }
271
272 goto success;
273
274 error_devvp:
275 /* Error with devvp held. */
276 vrele(devvp);
277
278 error:
279 /* Error with no state to backout. */
280
281 success:
282 return (error);
283 }
284
285 int ext2fs_reload_vnode(struct vnode *, void *args);
286
287 struct ext2fs_reload_args {
288 struct m_ext2fs *fs;
289 struct proc *p;
290 struct ucred *cred;
291 struct vnode *devvp;
292 };
293
294 int
ext2fs_reload_vnode(struct vnode * vp,void * args)295 ext2fs_reload_vnode(struct vnode *vp, void *args)
296 {
297 struct ext2fs_reload_args *era = args;
298 struct buf *bp;
299 struct inode *ip;
300 int error;
301 caddr_t cp;
302
303 /*
304 * Step 4: invalidate all inactive vnodes.
305 */
306 if (vp->v_usecount == 0) {
307 vgonel(vp, era->p);
308 return (0);
309 }
310
311 /*
312 * Step 5: invalidate all cached file data.
313 */
314 if (vget(vp, LK_EXCLUSIVE))
315 return (0);
316
317 if (vinvalbuf(vp, 0, era->cred, era->p, 0, INFSLP))
318 panic("ext2fs_reload: dirty2");
319 /*
320 * Step 6: re-read inode data for all active vnodes.
321 */
322 ip = VTOI(vp);
323 error = bread(era->devvp,
324 fsbtodb(era->fs, ino_to_fsba(era->fs, ip->i_number)),
325 (int)era->fs->e2fs_bsize, &bp);
326 if (error) {
327 vput(vp);
328 return (error);
329 }
330 cp = (caddr_t)bp->b_data +
331 (ino_to_fsbo(era->fs, ip->i_number) * EXT2_DINODE_SIZE(era->fs));
332 e2fs_iload(era->fs, (struct ext2fs_dinode *)cp, ip->i_e2din);
333 brelse(bp);
334 vput(vp);
335 return (0);
336 }
337
338 static off_t
ext2fs_maxfilesize(struct m_ext2fs * fs)339 ext2fs_maxfilesize(struct m_ext2fs *fs)
340 {
341 bool huge = fs->e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_HUGE_FILE;
342 off_t b = fs->e2fs_bsize / 4;
343 off_t physically, logically;
344
345 physically = dbtob(huge ? ((1ULL << 48) - 1) : UINT_MAX);
346 logically = (12ULL + b + b*b + b*b*b) * fs->e2fs_bsize;
347
348 return MIN(logically, physically);
349 }
350
351 static int
e2fs_sbfill(struct vnode * devvp,struct m_ext2fs * fs)352 e2fs_sbfill(struct vnode *devvp, struct m_ext2fs *fs)
353 {
354 struct buf *bp = NULL;
355 int i, error;
356
357 /* XXX assume hardware block size == 512 */
358 fs->e2fs_ncg = howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock,
359 fs->e2fs.e2fs_bpg);
360 fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1;
361 fs->e2fs_bsize = 1024 << fs->e2fs.e2fs_log_bsize;
362 fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize;
363 fs->e2fs_fsize = 1024 << fs->e2fs.e2fs_log_fsize;
364
365 fs->e2fs_qbmask = fs->e2fs_bsize - 1;
366 fs->e2fs_bmask = ~fs->e2fs_qbmask;
367
368 fs->e2fs_ipb = fs->e2fs_bsize / EXT2_DINODE_SIZE(fs);
369 fs->e2fs_itpg = fs->e2fs.e2fs_ipg / fs->e2fs_ipb;
370
371 /* Re-read group descriptors from the disk. */
372 fs->e2fs_ngdb = howmany(fs->e2fs_ncg,
373 fs->e2fs_bsize / sizeof(struct ext2_gd));
374 fs->e2fs_gd = mallocarray(fs->e2fs_ngdb, fs->e2fs_bsize,
375 M_UFSMNT, M_WAITOK);
376
377 for (i = 0; i < fs->e2fs_ngdb; ++i) {
378 daddr_t dblk = ((fs->e2fs_bsize > 1024) ? 0 : 1) + i + 1;
379 size_t gdesc = i * fs->e2fs_bsize / sizeof(struct ext2_gd);
380 struct ext2_gd *gd;
381
382 error = bread(devvp, fsbtodb(fs, dblk), fs->e2fs_bsize, &bp);
383 if (error) {
384 size_t gdescs_space = fs->e2fs_ngdb * fs->e2fs_bsize;
385
386 free(fs->e2fs_gd, M_UFSMNT, gdescs_space);
387 fs->e2fs_gd = NULL;
388 brelse(bp);
389 return (error);
390 }
391
392 gd = (struct ext2_gd *) bp->b_data;
393 e2fs_cgload(gd, fs->e2fs_gd + gdesc, fs->e2fs_bsize);
394 brelse(bp);
395 bp = NULL;
396 }
397
398 if (!(fs->e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_LARGE_FILE) ||
399 (fs->e2fs.e2fs_rev == E2FS_REV0))
400 fs->e2fs_maxfilesize = INT_MAX;
401 else
402 fs->e2fs_maxfilesize = ext2fs_maxfilesize(fs);
403
404 if (fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_EXTENTS)
405 fs->e2fs_maxfilesize *= 4;
406
407 return (0);
408 }
409
410 /*
411 * Reload all incore data for a filesystem (used after running fsck on
412 * the root filesystem and finding things to fix). The filesystem must
413 * be mounted read-only.
414 *
415 * Things to do to update the mount:
416 * 1) invalidate all cached meta-data.
417 * 2) re-read superblock from disk.
418 * 3) re-read summary information from disk.
419 * 4) invalidate all inactive vnodes.
420 * 5) invalidate all cached file data.
421 * 6) re-read inode data for all active vnodes.
422 */
423 int
ext2fs_reload(struct mount * mountp,struct ucred * cred,struct proc * p)424 ext2fs_reload(struct mount *mountp, struct ucred *cred, struct proc *p)
425 {
426 struct vnode *devvp;
427 struct buf *bp;
428 struct m_ext2fs *fs;
429 struct ext2fs *newfs;
430 int error;
431 struct ext2fs_reload_args era;
432
433 if ((mountp->mnt_flag & MNT_RDONLY) == 0)
434 return (EINVAL);
435 /*
436 * Step 1: invalidate all cached meta-data.
437 */
438 devvp = VFSTOUFS(mountp)->um_devvp;
439 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
440 error = vinvalbuf(devvp, 0, cred, p, 0, INFSLP);
441 VOP_UNLOCK(devvp);
442 if (error != 0)
443 panic("ext2fs_reload: dirty1");
444
445 /*
446 * Step 2: re-read superblock from disk.
447 */
448 error = bread(devvp, (daddr_t)(SBOFF / DEV_BSIZE), SBSIZE, &bp);
449 if (error) {
450 brelse(bp);
451 return (error);
452 }
453 newfs = (struct ext2fs *)bp->b_data;
454 error = e2fs_sbcheck(newfs, (mountp->mnt_flag & MNT_RDONLY));
455 if (error) {
456 brelse(bp);
457 return (error);
458 }
459
460 fs = VFSTOUFS(mountp)->um_e2fs;
461 /*
462 * Copy in the new superblock, compute in-memory values
463 * and load group descriptors.
464 */
465 e2fs_sbload(newfs, &fs->e2fs);
466 if ((error = e2fs_sbfill(devvp, fs)) != 0)
467 return (error);
468
469 era.p = p;
470 era.cred = cred;
471 era.fs = fs;
472 era.devvp = devvp;
473
474 error = vfs_mount_foreach_vnode(mountp, ext2fs_reload_vnode, &era);
475
476 return (error);
477 }
478
479 /*
480 * Common code for mount and mountroot
481 */
482 int
ext2fs_mountfs(struct vnode * devvp,struct mount * mp,struct proc * p)483 ext2fs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p)
484 {
485 struct ufsmount *ump;
486 struct buf *bp;
487 struct ext2fs *fs;
488 dev_t dev;
489 int error, ronly;
490 struct ucred *cred;
491
492 dev = devvp->v_rdev;
493 cred = p ? p->p_ucred : NOCRED;
494 /*
495 * Disallow multiple mounts of the same device.
496 * Disallow mounting of a device that is currently in use
497 * (except for root, which might share swap device for miniroot).
498 * Flush out any old buffers remaining from a previous use.
499 */
500 if ((error = vfs_mountedon(devvp)) != 0)
501 return (error);
502 if (vcount(devvp) > 1 && devvp != rootvp)
503 return (EBUSY);
504 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
505 error = vinvalbuf(devvp, V_SAVE, cred, p, 0, INFSLP);
506 VOP_UNLOCK(devvp);
507 if (error != 0)
508 return (error);
509
510 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
511 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
512 if (error)
513 return (error);
514
515 bp = NULL;
516 ump = NULL;
517
518 /*
519 * Read the superblock from disk.
520 */
521 error = bread(devvp, (daddr_t)(SBOFF / DEV_BSIZE), SBSIZE, &bp);
522 if (error)
523 goto out;
524 fs = (struct ext2fs *)bp->b_data;
525 error = e2fs_sbcheck(fs, ronly);
526 if (error)
527 goto out;
528
529 ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK | M_ZERO);
530 ump->um_e2fs = malloc(sizeof(struct m_ext2fs), M_UFSMNT,
531 M_WAITOK | M_ZERO);
532
533 /*
534 * Copy in the superblock, compute in-memory values
535 * and load group descriptors.
536 */
537 e2fs_sbload(fs, &ump->um_e2fs->e2fs);
538 if ((error = e2fs_sbfill(devvp, ump->um_e2fs)) != 0)
539 goto out;
540 brelse(bp);
541 bp = NULL;
542 fs = &ump->um_e2fs->e2fs;
543 ump->um_e2fs->e2fs_ronly = ronly;
544 ump->um_fstype = UM_EXT2FS;
545
546 if (ronly == 0) {
547 if (fs->e2fs_state == E2FS_ISCLEAN)
548 fs->e2fs_state = 0;
549 else
550 fs->e2fs_state = E2FS_ERRORS;
551 ump->um_e2fs->e2fs_fmod = 1;
552 }
553
554 mp->mnt_data = ump;
555 mp->mnt_stat.f_fsid.val[0] = (long)dev;
556 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
557 mp->mnt_stat.f_namemax = MAXNAMLEN;
558 mp->mnt_flag |= MNT_LOCAL;
559 ump->um_mountp = mp;
560 ump->um_dev = dev;
561 ump->um_devvp = devvp;
562 ump->um_nindir = NINDIR(ump->um_e2fs);
563 ump->um_bptrtodb = ump->um_e2fs->e2fs_fsbtodb;
564 ump->um_seqinc = 1; /* no frags */
565 ump->um_maxsymlinklen = EXT2_MAXSYMLINKLEN;
566 devvp->v_specmountpoint = mp;
567 return (0);
568 out:
569 if (devvp->v_specinfo)
570 devvp->v_specmountpoint = NULL;
571 if (bp)
572 brelse(bp);
573 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
574 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
575 VOP_UNLOCK(devvp);
576 if (ump) {
577 free(ump->um_e2fs, M_UFSMNT, sizeof *ump->um_e2fs);
578 free(ump, M_UFSMNT, sizeof *ump);
579 mp->mnt_data = NULL;
580 }
581 return (error);
582 }
583
584 /*
585 * unmount system call
586 */
587 int
ext2fs_unmount(struct mount * mp,int mntflags,struct proc * p)588 ext2fs_unmount(struct mount *mp, int mntflags, struct proc *p)
589 {
590 struct ufsmount *ump;
591 struct m_ext2fs *fs;
592 int error, flags;
593 size_t gdescs_space;
594
595 flags = 0;
596 if (mntflags & MNT_FORCE)
597 flags |= FORCECLOSE;
598 if ((error = ext2fs_flushfiles(mp, flags, p)) != 0)
599 return (error);
600 ump = VFSTOUFS(mp);
601 fs = ump->um_e2fs;
602 gdescs_space = fs->e2fs_ngdb * fs->e2fs_bsize;
603
604 if (!fs->e2fs_ronly && ext2fs_cgupdate(ump, MNT_WAIT) == 0 &&
605 (fs->e2fs.e2fs_state & E2FS_ERRORS) == 0) {
606 fs->e2fs.e2fs_state = E2FS_ISCLEAN;
607 (void) ext2fs_sbupdate(ump, MNT_WAIT);
608 }
609
610 if (ump->um_devvp->v_type != VBAD)
611 ump->um_devvp->v_specmountpoint = NULL;
612 vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
613 (void)VOP_CLOSE(ump->um_devvp, fs->e2fs_ronly ? FREAD : FREAD|FWRITE,
614 NOCRED, p);
615 vput(ump->um_devvp);
616 free(fs->e2fs_gd, M_UFSMNT, gdescs_space);
617 free(fs, M_UFSMNT, sizeof *fs);
618 free(ump, M_UFSMNT, sizeof *ump);
619 mp->mnt_data = NULL;
620 mp->mnt_flag &= ~MNT_LOCAL;
621 return (0);
622 }
623
624 /*
625 * Flush out all the files in a filesystem.
626 */
627 int
ext2fs_flushfiles(struct mount * mp,int flags,struct proc * p)628 ext2fs_flushfiles(struct mount *mp, int flags, struct proc *p)
629 {
630 struct ufsmount *ump;
631 int error;
632
633 ump = VFSTOUFS(mp);
634 /*
635 * Flush all the files.
636 */
637 if ((error = vflush(mp, NULL, flags)) != 0)
638 return (error);
639 /*
640 * Flush filesystem metadata.
641 */
642 vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
643 error = VOP_FSYNC(ump->um_devvp, p->p_ucred, MNT_WAIT, p);
644 VOP_UNLOCK(ump->um_devvp);
645 return (error);
646 }
647
648 /*
649 * Get file system statistics.
650 */
651 int
ext2fs_statfs(struct mount * mp,struct statfs * sbp,struct proc * p)652 ext2fs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
653 {
654 struct ufsmount *ump;
655 struct m_ext2fs *fs;
656 u_int32_t overhead, overhead_per_group;
657 int i, ngroups;
658
659 ump = VFSTOUFS(mp);
660 fs = ump->um_e2fs;
661 if (fs->e2fs.e2fs_magic != E2FS_MAGIC)
662 panic("ext2fs_statfs");
663
664 /*
665 * Compute the overhead (FS structures)
666 */
667 overhead_per_group = 1 /* block bitmap */ + 1 /* inode bitmap */ +
668 fs->e2fs_itpg;
669 overhead = fs->e2fs.e2fs_first_dblock +
670 fs->e2fs_ncg * overhead_per_group;
671 if (fs->e2fs.e2fs_rev > E2FS_REV0 &&
672 fs->e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_SPARSE_SUPER) {
673 for (i = 0, ngroups = 0; i < fs->e2fs_ncg; i++) {
674 if (cg_has_sb(i))
675 ngroups++;
676 }
677 } else {
678 ngroups = fs->e2fs_ncg;
679 }
680 overhead += ngroups * (1 + fs->e2fs_ngdb);
681
682 sbp->f_bsize = fs->e2fs_bsize;
683 sbp->f_iosize = fs->e2fs_bsize;
684 sbp->f_blocks = fs->e2fs.e2fs_bcount - overhead;
685 sbp->f_bfree = fs->e2fs.e2fs_fbcount;
686 sbp->f_bavail = sbp->f_bfree - fs->e2fs.e2fs_rbcount;
687 sbp->f_files = fs->e2fs.e2fs_icount;
688 sbp->f_favail = sbp->f_ffree = fs->e2fs.e2fs_ficount;
689 copy_statfs_info(sbp, mp);
690
691 return (0);
692 }
693
694 int ext2fs_sync_vnode(struct vnode *vp, void *);
695
696 struct ext2fs_sync_args {
697 int allerror;
698 int waitfor;
699 int nlink0;
700 int inflight;
701 struct proc *p;
702 struct ucred *cred;
703 };
704
705 int
ext2fs_sync_vnode(struct vnode * vp,void * args)706 ext2fs_sync_vnode(struct vnode *vp, void *args)
707 {
708 struct ext2fs_sync_args *esa = args;
709 struct inode *ip;
710 int error, nlink0 = 0;
711 int s, skip = 0;
712
713 if (vp->v_type == VNON)
714 return (0);
715
716 ip = VTOI(vp);
717
718 if (ip->i_e2fs_nlink == 0)
719 nlink0 = 1;
720
721 s = splbio();
722 if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 &&
723 LIST_EMPTY(&vp->v_dirtyblkhd)) {
724 skip = 1;
725 }
726 splx(s);
727
728 if (skip)
729 goto end;
730
731 if (vget(vp, LK_EXCLUSIVE | LK_NOWAIT)) {
732 esa->inflight = MIN(esa->inflight+1, 65536);
733 goto end;
734 }
735
736 if ((error = VOP_FSYNC(vp, esa->cred, esa->waitfor, esa->p)) != 0)
737 esa->allerror = error;
738 vput(vp);
739 end:
740 esa->nlink0 = MIN(esa->nlink0 + nlink0, 65536);
741 return (0);
742 }
743
744 /*
745 * Go through the disk queues to initiate sandbagged IO;
746 * go through the inodes to write those that have been modified;
747 * initiate the writing of the super block if it has been modified.
748 *
749 * Should always be called with the mount point locked.
750 */
751 int
ext2fs_sync(struct mount * mp,int waitfor,int stall,struct ucred * cred,struct proc * p)752 ext2fs_sync(struct mount *mp, int waitfor, int stall,
753 struct ucred *cred, struct proc *p)
754 {
755 struct ufsmount *ump = VFSTOUFS(mp);
756 struct m_ext2fs *fs;
757 int error, allerror = 0, state, fmod;
758 struct ext2fs_sync_args esa;
759
760 fs = ump->um_e2fs;
761 if (fs->e2fs_ronly != 0) { /* XXX */
762 printf("fs = %s\n", fs->e2fs_fsmnt);
763 panic("update: rofs mod");
764 }
765
766 /*
767 * Write back each (modified) inode.
768 */
769 esa.p = p;
770 esa.cred = cred;
771 esa.allerror = 0;
772 esa.waitfor = waitfor;
773 esa.nlink0 = 0;
774 esa.inflight = 0;
775
776 vfs_mount_foreach_vnode(mp, ext2fs_sync_vnode, &esa);
777 if (esa.allerror != 0)
778 allerror = esa.allerror;
779
780 /*
781 * Force stale file system control information to be flushed.
782 */
783 if (waitfor != MNT_LAZY) {
784 vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY);
785 if ((error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) != 0)
786 allerror = error;
787 VOP_UNLOCK(ump->um_devvp);
788 }
789 /*
790 * Write back modified superblock.
791 */
792 state = fs->e2fs.e2fs_state;
793 fmod = fs->e2fs_fmod;
794 if (stall && fs->e2fs_ronly == 0) {
795 fs->e2fs_fmod = 1;
796 if (allerror == 0 && esa.nlink0 == 0 && esa.inflight == 0) {
797 if ((fs->e2fs.e2fs_state & E2FS_ERRORS) == 0)
798 fs->e2fs.e2fs_state = E2FS_ISCLEAN;
799 #if 0
800 printf("%s force clean (dangling %d inflight %d)\n",
801 mp->mnt_stat.f_mntonname, esa.nlink0, esa.inflight);
802 #endif
803 } else {
804 fs->e2fs.e2fs_state = 0;
805 #if 0
806 printf("%s force dirty (dangling %d inflight %d)\n",
807 mp->mnt_stat.f_mntonname, esa.nlink0, esa.inflight);
808 #endif
809 }
810 }
811 if (fs->e2fs_fmod != 0) {
812 fs->e2fs_fmod = 0;
813 fs->e2fs.e2fs_wtime = gettime();
814 if ((error = ext2fs_cgupdate(ump, waitfor)))
815 allerror = error;
816 }
817 fs->e2fs.e2fs_state = state;
818 fs->e2fs_fmod = fmod;
819 return (allerror);
820 }
821
822 /*
823 * Look up a EXT2FS dinode number to find its incore vnode, otherwise read it
824 * in from disk. If it is in core, wait for the lock bit to clear, then
825 * return the inode locked. Detection and handling of mount points must be
826 * done by the calling routine.
827 */
828 int
ext2fs_vget(struct mount * mp,ino_t ino,struct vnode ** vpp)829 ext2fs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
830 {
831 struct m_ext2fs *fs;
832 struct inode *ip;
833 struct ext2fs_dinode *dp;
834 struct ufsmount *ump;
835 struct buf *bp;
836 struct vnode *vp;
837 dev_t dev;
838 int error;
839
840 if (ino > (ufsino_t)-1)
841 panic("ext2fs_vget: alien ino_t %llu",
842 (unsigned long long)ino);
843
844 ump = VFSTOUFS(mp);
845 dev = ump->um_dev;
846
847 retry:
848 if ((*vpp = ufs_ihashget(dev, ino)) != NULL)
849 return (0);
850
851 /* Allocate a new vnode/inode. */
852 if ((error = getnewvnode(VT_EXT2FS, mp, &ext2fs_vops, &vp)) != 0) {
853 *vpp = NULL;
854 return (error);
855 }
856
857 ip = pool_get(&ext2fs_inode_pool, PR_WAITOK|PR_ZERO);
858 rrw_init_flags(&ip->i_lock, "inode", RWL_DUPOK | RWL_IS_VNODE);
859 vp->v_data = ip;
860 ip->i_vnode = vp;
861 ip->i_ump = ump;
862 ip->i_e2fs = fs = ump->um_e2fs;
863 ip->i_dev = dev;
864 ip->i_number = ino;
865 ip->i_e2fs_last_lblk = 0;
866 ip->i_e2fs_last_blk = 0;
867
868 /*
869 * Put it onto its hash chain and lock it so that other requests for
870 * this inode will block if they arrive while we are sleeping waiting
871 * for old data structures to be purged or for the contents of the
872 * disk portion of this inode to be read.
873 */
874 error = ufs_ihashins(ip);
875
876 if (error) {
877 vrele(vp);
878
879 if (error == EEXIST)
880 goto retry;
881
882 return (error);
883 }
884
885 /* Read in the disk contents for the inode, copy into the inode. */
886 error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)),
887 (int)fs->e2fs_bsize, &bp);
888 if (error) {
889 /*
890 * The inode does not contain anything useful, so it would
891 * be misleading to leave it on its hash chain. With mode
892 * still zero, it will be unlinked and returned to the free
893 * list by vput().
894 */
895 vput(vp);
896 brelse(bp);
897 *vpp = NULL;
898 return (error);
899 }
900
901 dp = (struct ext2fs_dinode *) ((char *)bp->b_data
902 + EXT2_DINODE_SIZE(fs) * ino_to_fsbo(fs, ino));
903
904 ip->i_e2din = pool_get(&ext2fs_dinode_pool, PR_WAITOK);
905 e2fs_iload(fs, dp, ip->i_e2din);
906 brelse(bp);
907
908 ip->i_effnlink = ip->i_e2fs_nlink;
909
910 /*
911 * The fields for storing the UID and GID of an ext2fs inode are
912 * limited to 16 bits. To overcome this limitation, Linux decided to
913 * scatter the highest bits of these values into a previously reserved
914 * area on the disk inode. We deal with this situation by having two
915 * 32-bit fields *out* of the disk inode to hold the complete values.
916 * Now that we are reading in the inode, compute these fields.
917 */
918 ip->i_e2fs_uid = ip->i_e2fs_uid_low | (ip->i_e2fs_uid_high << 16);
919 ip->i_e2fs_gid = ip->i_e2fs_gid_low | (ip->i_e2fs_gid_high << 16);
920
921 /* If the inode was deleted, reset all fields */
922 if (ip->i_e2fs_dtime != 0) {
923 ip->i_e2fs_mode = ip->i_e2fs_nblock = 0;
924 (void)ext2fs_setsize(ip, 0);
925 }
926
927 /*
928 * Initialize the vnode from the inode, check for aliases.
929 * Note that the underlying vnode may have changed.
930 */
931 error = ext2fs_vinit(mp, &vp);
932 if (error) {
933 vput(vp);
934 *vpp = NULL;
935 return (error);
936 }
937
938 /*
939 * Finish inode initialization now that aliasing has been resolved.
940 */
941 vref(ip->i_devvp);
942 /*
943 * Set up a generation number for this inode if it does not
944 * already have one. This should only happen on old filesystems.
945 */
946 if (ip->i_e2fs_gen == 0) {
947 if (++ext2gennumber < (u_long)gettime())
948 ext2gennumber = gettime();
949 ip->i_e2fs_gen = ext2gennumber;
950 if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
951 ip->i_flag |= IN_MODIFIED;
952 }
953
954 *vpp = vp;
955 return (0);
956 }
957
958 /*
959 * File handle to vnode
960 *
961 * Have to be really careful about stale file handles:
962 * - check that the inode number is valid
963 * - call ext2fs_vget() to get the locked inode
964 * - check for an unallocated inode (i_mode == 0)
965 * - check that the given client host has export rights and return
966 * those rights via. exflagsp and credanonp
967 */
968 int
ext2fs_fhtovp(struct mount * mp,struct fid * fhp,struct vnode ** vpp)969 ext2fs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
970 {
971 struct inode *ip;
972 struct vnode *nvp;
973 int error;
974 struct ufid *ufhp;
975 struct m_ext2fs *fs;
976
977 ufhp = (struct ufid *)fhp;
978 fs = VFSTOUFS(mp)->um_e2fs;
979 if ((ufhp->ufid_ino < EXT2_FIRSTINO && ufhp->ufid_ino != EXT2_ROOTINO) ||
980 ufhp->ufid_ino > fs->e2fs_ncg * fs->e2fs.e2fs_ipg)
981 return (ESTALE);
982
983 if ((error = VFS_VGET(mp, ufhp->ufid_ino, &nvp)) != 0) {
984 *vpp = NULLVP;
985 return (error);
986 }
987 ip = VTOI(nvp);
988 if (ip->i_e2fs_mode == 0 || ip->i_e2fs_dtime != 0 ||
989 ip->i_e2fs_gen != ufhp->ufid_gen) {
990 vput(nvp);
991 *vpp = NULLVP;
992 return (ESTALE);
993 }
994 *vpp = nvp;
995 return (0);
996 }
997
998 /*
999 * Vnode pointer to File handle
1000 */
1001 int
ext2fs_vptofh(struct vnode * vp,struct fid * fhp)1002 ext2fs_vptofh(struct vnode *vp, struct fid *fhp)
1003 {
1004 struct inode *ip;
1005 struct ufid *ufhp;
1006
1007 ip = VTOI(vp);
1008 ufhp = (struct ufid *)fhp;
1009 ufhp->ufid_len = sizeof(struct ufid);
1010 ufhp->ufid_ino = ip->i_number;
1011 ufhp->ufid_gen = ip->i_e2fs_gen;
1012 return (0);
1013 }
1014
1015 /*
1016 * no sysctl for ext2fs
1017 */
1018
1019 int
ext2fs_sysctl(int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen,struct proc * p)1020 ext2fs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
1021 void *newp, size_t newlen, struct proc *p)
1022 {
1023 return (EOPNOTSUPP);
1024 }
1025
1026 /*
1027 * Write a superblock and associated information back to disk.
1028 */
1029 int
ext2fs_sbupdate(struct ufsmount * mp,int waitfor)1030 ext2fs_sbupdate(struct ufsmount *mp, int waitfor)
1031 {
1032 struct m_ext2fs *fs = mp->um_e2fs;
1033 struct buf *bp;
1034 int error = 0;
1035
1036 bp = getblk(mp->um_devvp, SBLOCK, SBSIZE, 0, INFSLP);
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 fs->e2fs_fmod = 0;
1043 return (error);
1044 }
1045
1046 int
ext2fs_cgupdate(struct ufsmount * mp,int waitfor)1047 ext2fs_cgupdate(struct ufsmount *mp, int waitfor)
1048 {
1049 struct m_ext2fs *fs = mp->um_e2fs;
1050 struct buf *bp;
1051 int i, error = 0, allerror = 0;
1052
1053 allerror = ext2fs_sbupdate(mp, waitfor);
1054 for (i = 0; i < fs->e2fs_ngdb; i++) {
1055 bp = getblk(mp->um_devvp, fsbtodb(fs, ((fs->e2fs_bsize>1024)?0:1)+i+1),
1056 fs->e2fs_bsize, 0, INFSLP);
1057 e2fs_cgsave(&fs->e2fs_gd[i* fs->e2fs_bsize / sizeof(struct ext2_gd)], (struct ext2_gd*)bp->b_data, fs->e2fs_bsize);
1058 if (waitfor == MNT_WAIT)
1059 error = bwrite(bp);
1060 else
1061 bawrite(bp);
1062 }
1063
1064 if (!allerror && error)
1065 allerror = error;
1066 return (allerror);
1067 }
1068
1069 /* This is called before the superblock is copied. Watch out for endianness! */
1070 static int
e2fs_sbcheck(struct ext2fs * fs,int ronly)1071 e2fs_sbcheck(struct ext2fs *fs, int ronly)
1072 {
1073 u_int32_t mask, tmp;
1074 int i;
1075
1076 tmp = letoh16(fs->e2fs_magic);
1077 if (tmp != E2FS_MAGIC) {
1078 printf("ext2fs: wrong magic number 0x%x\n", tmp);
1079 return (EIO); /* XXX needs translation */
1080 }
1081
1082 tmp = letoh32(fs->e2fs_log_bsize);
1083 if (tmp > 2) {
1084 /* skewed log(block size): 1024 -> 0 | 2048 -> 1 | 4096 -> 2 */
1085 tmp += 10;
1086 printf("ext2fs: wrong log2(block size) %d\n", tmp);
1087 return (EIO); /* XXX needs translation */
1088 }
1089
1090 if (fs->e2fs_bpg == 0) {
1091 printf("ext2fs: zero blocks per group\n");
1092 return (EIO);
1093 }
1094
1095 tmp = letoh32(fs->e2fs_rev);
1096 if (tmp > E2FS_REV1) {
1097 printf("ext2fs: wrong revision number 0x%x\n", tmp);
1098 return (EIO); /* XXX needs translation */
1099 }
1100 else if (tmp == E2FS_REV0)
1101 return (0);
1102
1103 tmp = letoh32(fs->e2fs_first_ino);
1104 if (tmp != EXT2_FIRSTINO) {
1105 printf("ext2fs: first inode at 0x%x\n", tmp);
1106 return (EINVAL); /* XXX needs translation */
1107 }
1108
1109 tmp = letoh32(fs->e2fs_features_incompat);
1110 mask = tmp & ~(EXT2F_INCOMPAT_SUPP | EXT4F_RO_INCOMPAT_SUPP);
1111 if (mask) {
1112 printf("ext2fs: unsupported incompat features: ");
1113 for (i = 0; i < nitems(incompat); i++)
1114 if (mask & incompat[i].mask)
1115 printf("%s ", incompat[i].name);
1116 printf("\n");
1117 return (EINVAL); /* XXX needs translation */
1118 }
1119
1120 if (!ronly && (tmp & EXT4F_RO_INCOMPAT_SUPP)) {
1121 printf("ext4fs: only read-only support right now\n");
1122 return (EROFS); /* XXX needs translation */
1123 }
1124
1125 if (tmp & EXT2F_INCOMPAT_RECOVER) {
1126 printf("ext2fs: your file system says it needs recovery\n");
1127 if (!ronly)
1128 return (EROFS); /* XXX needs translation */
1129 }
1130
1131 tmp = letoh32(fs->e2fs_features_rocompat) & ~EXT2F_ROCOMPAT_SUPP;
1132 if (!ronly && tmp) {
1133 printf("ext2fs: unsupported R/O compat features: ");
1134 for (i = 0; i < nitems(ro_compat); i++)
1135 if (tmp & ro_compat[i].mask)
1136 printf("%s ", ro_compat[i].name);
1137 printf("\n");
1138 return (EROFS); /* XXX needs translation */
1139 }
1140
1141 return (0);
1142 }
1143