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