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 | } |