| @@ -1,602 +1,601 @@ | | | @@ -1,602 +1,601 @@ |
1 | /* $NetBSD: efs_vfsops.c,v 1.15 2008/05/10 02:26:09 rumble Exp $ */ | | 1 | /* $NetBSD: efs_vfsops.c,v 1.16 2008/09/24 09:37:13 ad Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2006 Stephen M. Rumble <rumble@ephemeral.org> | | 4 | * Copyright (c) 2006 Stephen M. Rumble <rumble@ephemeral.org> |
5 | * | | 5 | * |
6 | * Permission to use, copy, modify, and distribute this software for any | | 6 | * Permission to use, copy, modify, and distribute this software for any |
7 | * purpose with or without fee is hereby granted, provided that the above | | 7 | * purpose with or without fee is hereby granted, provided that the above |
8 | * copyright notice and this permission notice appear in all copies. | | 8 | * copyright notice and this permission notice appear in all copies. |
9 | * | | 9 | * |
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | | 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | | 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | | 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | | 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | | 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | | 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 | */ | | 17 | */ |
18 | | | 18 | |
19 | #include <sys/cdefs.h> | | 19 | #include <sys/cdefs.h> |
20 | __KERNEL_RCSID(0, "$NetBSD: efs_vfsops.c,v 1.15 2008/05/10 02:26:09 rumble Exp $"); | | 20 | __KERNEL_RCSID(0, "$NetBSD: efs_vfsops.c,v 1.16 2008/09/24 09:37:13 ad Exp $"); |
21 | | | 21 | |
22 | #include <sys/param.h> | | 22 | #include <sys/param.h> |
23 | #include <sys/systm.h> | | 23 | #include <sys/systm.h> |
24 | #include <sys/malloc.h> | | 24 | #include <sys/malloc.h> |
25 | #include <sys/mount.h> | | 25 | #include <sys/mount.h> |
26 | #include <sys/fstypes.h> | | 26 | #include <sys/fstypes.h> |
27 | #include <sys/vnode.h> | | 27 | #include <sys/vnode.h> |
28 | #include <sys/buf.h> | | 28 | #include <sys/buf.h> |
29 | #include <sys/namei.h> | | 29 | #include <sys/namei.h> |
30 | #include <sys/fcntl.h> | | 30 | #include <sys/fcntl.h> |
31 | #include <sys/stat.h> | | 31 | #include <sys/stat.h> |
32 | #include <sys/kauth.h> | | 32 | #include <sys/kauth.h> |
33 | #include <sys/proc.h> | | 33 | #include <sys/proc.h> |
34 | #include <sys/module.h> | | 34 | #include <sys/module.h> |
35 | | | 35 | |
36 | #include <miscfs/genfs/genfs_node.h> | | 36 | #include <miscfs/genfs/genfs_node.h> |
37 | | | 37 | |
38 | #include <miscfs/specfs/specdev.h> | | 38 | #include <miscfs/specfs/specdev.h> |
39 | | | 39 | |
40 | #include <fs/efs/efs.h> | | 40 | #include <fs/efs/efs.h> |
41 | #include <fs/efs/efs_sb.h> | | 41 | #include <fs/efs/efs_sb.h> |
42 | #include <fs/efs/efs_dir.h> | | 42 | #include <fs/efs/efs_dir.h> |
43 | #include <fs/efs/efs_genfs.h> | | 43 | #include <fs/efs/efs_genfs.h> |
44 | #include <fs/efs/efs_mount.h> | | 44 | #include <fs/efs/efs_mount.h> |
45 | #include <fs/efs/efs_extent.h> | | 45 | #include <fs/efs/efs_extent.h> |
46 | #include <fs/efs/efs_dinode.h> | | 46 | #include <fs/efs/efs_dinode.h> |
47 | #include <fs/efs/efs_inode.h> | | 47 | #include <fs/efs/efs_inode.h> |
48 | #include <fs/efs/efs_subr.h> | | 48 | #include <fs/efs/efs_subr.h> |
49 | #include <fs/efs/efs_ihash.h> | | 49 | #include <fs/efs/efs_ihash.h> |
50 | | | 50 | |
51 | MODULE(MODULE_CLASS_VFS, efs, NULL); | | 51 | MODULE(MODULE_CLASS_VFS, efs, NULL); |
52 | | | 52 | |
53 | MALLOC_JUSTDEFINE(M_EFSMNT, "efsmnt", "efs mount structure"); | | 53 | MALLOC_JUSTDEFINE(M_EFSMNT, "efsmnt", "efs mount structure"); |
54 | MALLOC_JUSTDEFINE(M_EFSINO, "efsino", "efs in-core inode structure"); | | 54 | MALLOC_JUSTDEFINE(M_EFSINO, "efsino", "efs in-core inode structure"); |
55 | MALLOC_JUSTDEFINE(M_EFSTMP, "efstmp", "efs temporary allocations"); | | 55 | MALLOC_JUSTDEFINE(M_EFSTMP, "efstmp", "efs temporary allocations"); |
56 | | | 56 | |
57 | extern int (**efs_vnodeop_p)(void *); /* for getnewvnode() */ | | 57 | extern int (**efs_vnodeop_p)(void *); /* for getnewvnode() */ |
58 | static int efs_statvfs(struct mount *, struct statvfs *); | | 58 | static int efs_statvfs(struct mount *, struct statvfs *); |
59 | | | 59 | |
60 | /* | | 60 | /* |
61 | * efs_mount and efs_mountroot common functions. | | 61 | * efs_mount and efs_mountroot common functions. |
62 | */ | | 62 | */ |
63 | static int | | 63 | static int |
64 | efs_mount_common(struct mount *mp, const char *path, struct vnode *devvp, | | 64 | efs_mount_common(struct mount *mp, const char *path, struct vnode *devvp, |
65 | struct efs_args *args) | | 65 | struct efs_args *args) |
66 | { | | 66 | { |
67 | int err; | | 67 | int err; |
68 | struct buf *bp; | | 68 | struct buf *bp; |
69 | const char *why; | | 69 | const char *why; |
70 | struct efs_mount *emp; | | 70 | struct efs_mount *emp; |
71 | struct lwp *l = curlwp; | | 71 | struct lwp *l = curlwp; |
72 | | | 72 | |
73 | emp = malloc(sizeof(*emp), M_EFSMNT, M_WAITOK); | | 73 | emp = malloc(sizeof(*emp), M_EFSMNT, M_WAITOK); |
74 | emp->em_dev = devvp->v_rdev; | | 74 | emp->em_dev = devvp->v_rdev; |
75 | emp->em_devvp = devvp; | | 75 | emp->em_devvp = devvp; |
76 | emp->em_mnt = mp; | | 76 | emp->em_mnt = mp; |
77 | | | 77 | |
78 | /* read in the superblock */ | | 78 | /* read in the superblock */ |
79 | err = efs_bread(emp, EFS_BB_SB, l, &bp); | | 79 | err = efs_bread(emp, EFS_BB_SB, l, &bp); |
80 | if (err) { | | 80 | if (err) { |
81 | EFS_DPRINTF(("superblock read failed\n")); | | 81 | EFS_DPRINTF(("superblock read failed\n")); |
82 | free(emp, M_EFSMNT); | | 82 | free(emp, M_EFSMNT); |
83 | brelse(bp, 0); | | 83 | brelse(bp, 0); |
84 | return (err); | | 84 | return (err); |
85 | } | | 85 | } |
86 | memcpy(&emp->em_sb, bp->b_data, sizeof(emp->em_sb)); | | 86 | memcpy(&emp->em_sb, bp->b_data, sizeof(emp->em_sb)); |
87 | brelse(bp, 0); | | 87 | brelse(bp, 0); |
88 | | | 88 | |
89 | /* validate the superblock */ | | 89 | /* validate the superblock */ |
90 | if (efs_sb_validate(&emp->em_sb, &why)) { | | 90 | if (efs_sb_validate(&emp->em_sb, &why)) { |
91 | printf("efs: invalid superblock: %s\n", why); | | 91 | printf("efs: invalid superblock: %s\n", why); |
92 | if (!(mp->mnt_flag & MNT_FORCE)) { | | 92 | if (!(mp->mnt_flag & MNT_FORCE)) { |
93 | free(emp, M_EFSMNT); | | 93 | free(emp, M_EFSMNT); |
94 | return (EIO); | | 94 | return (EIO); |
95 | } | | 95 | } |
96 | } | | 96 | } |
97 | | | 97 | |
98 | /* check that it's clean */ | | 98 | /* check that it's clean */ |
99 | if (be16toh(emp->em_sb.sb_dirty) != EFS_SB_CLEAN) { | | 99 | if (be16toh(emp->em_sb.sb_dirty) != EFS_SB_CLEAN) { |
100 | printf("efs: filesystem is dirty (sb_dirty = 0x%x); please " | | 100 | printf("efs: filesystem is dirty (sb_dirty = 0x%x); please " |
101 | "run fsck_efs(8)\n", be16toh(emp->em_sb.sb_dirty)); | | 101 | "run fsck_efs(8)\n", be16toh(emp->em_sb.sb_dirty)); |
102 | /* XXX - default to readonly unless forced?? */ | | 102 | /* XXX - default to readonly unless forced?? */ |
103 | } | | 103 | } |
104 | | | 104 | |
105 | /* if the superblock was replicated, verify that it is the same */ | | 105 | /* if the superblock was replicated, verify that it is the same */ |
106 | if (be32toh(emp->em_sb.sb_replsb) != 0) { | | 106 | if (be32toh(emp->em_sb.sb_replsb) != 0) { |
107 | struct buf *rbp; | | 107 | struct buf *rbp; |
108 | bool skip = false; | | 108 | bool skip = false; |
109 | | | 109 | |
110 | err = efs_bread(emp, be32toh(emp->em_sb.sb_replsb), l, &rbp); | | 110 | err = efs_bread(emp, be32toh(emp->em_sb.sb_replsb), l, &rbp); |
111 | if (err) { | | 111 | if (err) { |
112 | printf("efs: read of superblock replicant failed; " | | 112 | printf("efs: read of superblock replicant failed; " |
113 | "please run fsck_efs(8)\n"); | | 113 | "please run fsck_efs(8)\n"); |
114 | if (mp->mnt_flag & MNT_FORCE) { | | 114 | if (mp->mnt_flag & MNT_FORCE) { |
115 | skip = true; | | 115 | skip = true; |
116 | } else { | | 116 | } else { |
117 | free(emp, M_EFSMNT); | | 117 | free(emp, M_EFSMNT); |
118 | brelse(rbp, 0); | | 118 | brelse(rbp, 0); |
119 | return (err); | | 119 | return (err); |
120 | } | | 120 | } |
121 | } | | 121 | } |
122 | | | 122 | |
123 | if (!skip) { | | 123 | if (!skip) { |
124 | if (memcmp(rbp->b_data, &emp->em_sb, | | 124 | if (memcmp(rbp->b_data, &emp->em_sb, |
125 | sizeof(emp->em_sb))) { | | 125 | sizeof(emp->em_sb))) { |
126 | printf("efs: superblock differs from " | | 126 | printf("efs: superblock differs from " |
127 | "replicant; please run fsck_efs(8)\n"); | | 127 | "replicant; please run fsck_efs(8)\n"); |
128 | if (!(mp->mnt_flag & MNT_FORCE)) { | | 128 | if (!(mp->mnt_flag & MNT_FORCE)) { |
129 | brelse(rbp, 0); | | 129 | brelse(rbp, 0); |
130 | free(emp, M_EFSMNT); | | 130 | free(emp, M_EFSMNT); |
131 | return (EIO); | | 131 | return (EIO); |
132 | } | | 132 | } |
133 | } | | 133 | } |
134 | } | | 134 | } |
135 | brelse(rbp, 0); | | 135 | brelse(rbp, 0); |
136 | } | | 136 | } |
137 | | | 137 | |
138 | /* ensure we can read last block */ | | 138 | /* ensure we can read last block */ |
139 | err = efs_bread(emp, be32toh(emp->em_sb.sb_size) - 1, l, &bp); | | 139 | err = efs_bread(emp, be32toh(emp->em_sb.sb_size) - 1, l, &bp); |
140 | if (err) { | | 140 | if (err) { |
141 | printf("efs: cannot access all filesystem blocks; please run " | | 141 | printf("efs: cannot access all filesystem blocks; please run " |
142 | "fsck_efs(8)\n"); | | 142 | "fsck_efs(8)\n"); |
143 | if (!(mp->mnt_flag & MNT_FORCE)) { | | 143 | if (!(mp->mnt_flag & MNT_FORCE)) { |
144 | free(emp, M_EFSMNT); | | 144 | free(emp, M_EFSMNT); |
145 | brelse(bp, 0); | | 145 | brelse(bp, 0); |
146 | return (err); | | 146 | return (err); |
147 | } | | 147 | } |
148 | } | | 148 | } |
149 | brelse(bp, 0); | | 149 | brelse(bp, 0); |
150 | | | 150 | |
151 | mp->mnt_data = emp; | | 151 | mp->mnt_data = emp; |
152 | mp->mnt_flag |= MNT_LOCAL; | | 152 | mp->mnt_flag |= MNT_LOCAL; |
153 | mp->mnt_fs_bshift = EFS_BB_SHFT; | | 153 | mp->mnt_fs_bshift = EFS_BB_SHFT; |
154 | mp->mnt_dev_bshift = DEV_BSHIFT; | | 154 | mp->mnt_dev_bshift = DEV_BSHIFT; |
155 | vfs_getnewfsid(mp); | | 155 | vfs_getnewfsid(mp); |
156 | efs_statvfs(mp, &mp->mnt_stat); | | 156 | efs_statvfs(mp, &mp->mnt_stat); |
157 | | | 157 | |
158 | err = set_statvfs_info(path, UIO_USERSPACE, args->fspec, | | 158 | err = set_statvfs_info(path, UIO_USERSPACE, args->fspec, |
159 | UIO_USERSPACE, mp->mnt_op->vfs_name, mp, l); | | 159 | UIO_USERSPACE, mp->mnt_op->vfs_name, mp, l); |
160 | if (err) | | 160 | if (err) |
161 | free(emp, M_EFSMNT); | | 161 | free(emp, M_EFSMNT); |
162 | | | 162 | |
163 | return (err); | | 163 | return (err); |
164 | } | | 164 | } |
165 | | | 165 | |
166 | /* | | 166 | /* |
167 | * mount syscall vfsop. | | 167 | * mount syscall vfsop. |
168 | * | | 168 | * |
169 | * Returns 0 on success. | | 169 | * Returns 0 on success. |
170 | */ | | 170 | */ |
171 | static int | | 171 | static int |
172 | efs_mount(struct mount *mp, const char *path, void *data, size_t *data_len) | | 172 | efs_mount(struct mount *mp, const char *path, void *data, size_t *data_len) |
173 | { | | 173 | { |
174 | struct lwp *l = curlwp; | | 174 | struct lwp *l = curlwp; |
175 | struct efs_args *args = data; | | 175 | struct efs_args *args = data; |
176 | struct nameidata devndp; | | 176 | struct nameidata devndp; |
177 | struct efs_mount *emp; | | 177 | struct efs_mount *emp; |
178 | struct vnode *devvp; | | 178 | struct vnode *devvp; |
179 | int err, mode; | | 179 | int err, mode; |
180 | | | 180 | |
181 | if (*data_len < sizeof *args) | | 181 | if (*data_len < sizeof *args) |
182 | return EINVAL; | | 182 | return EINVAL; |
183 | | | 183 | |
184 | if (mp->mnt_flag & MNT_GETARGS) { | | 184 | if (mp->mnt_flag & MNT_GETARGS) { |
185 | if ((emp = VFSTOEFS(mp)) == NULL) | | 185 | if ((emp = VFSTOEFS(mp)) == NULL) |
186 | return (EIO); | | 186 | return (EIO); |
187 | args->fspec = NULL; | | 187 | args->fspec = NULL; |
188 | args->version = EFS_MNT_VERSION; | | 188 | args->version = EFS_MNT_VERSION; |
189 | *data_len = sizeof *args; | | 189 | *data_len = sizeof *args; |
190 | return 0; | | 190 | return 0; |
191 | } | | 191 | } |
192 | | | 192 | |
193 | if (mp->mnt_flag & MNT_UPDATE) | | 193 | if (mp->mnt_flag & MNT_UPDATE) |
194 | return (EOPNOTSUPP); /* XXX read-only */ | | 194 | return (EOPNOTSUPP); /* XXX read-only */ |
195 | | | 195 | |
196 | /* look up our device's vnode. it is returned locked */ | | 196 | /* look up our device's vnode. it is returned locked */ |
197 | NDINIT(&devndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, args->fspec); | | 197 | NDINIT(&devndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, args->fspec); |
198 | if ((err = namei(&devndp))) | | 198 | if ((err = namei(&devndp))) |
199 | return (err); | | 199 | return (err); |
200 | | | 200 | |
201 | devvp = devndp.ni_vp; | | 201 | devvp = devndp.ni_vp; |
202 | if (devvp->v_type != VBLK) { | | 202 | if (devvp->v_type != VBLK) { |
203 | vput(devvp); | | 203 | vput(devvp); |
204 | return (ENOTBLK); | | 204 | return (ENOTBLK); |
205 | } | | 205 | } |
206 | | | 206 | |
207 | /* XXX - rdonly */ | | 207 | /* XXX - rdonly */ |
208 | mode = FREAD; | | 208 | mode = FREAD; |
209 | | | 209 | |
210 | /* | | 210 | /* |
211 | * If mount by non-root, then verify that user has necessary | | 211 | * If mount by non-root, then verify that user has necessary |
212 | * permissions on the device. | | 212 | * permissions on the device. |
213 | */ | | 213 | */ |
214 | if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL)) { | | 214 | if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL)) { |
215 | err = VOP_ACCESS(devvp, mode, l->l_cred); | | 215 | err = VOP_ACCESS(devvp, mode, l->l_cred); |
216 | if (err) { | | 216 | if (err) { |
217 | vput(devvp); | | 217 | vput(devvp); |
218 | return (err); | | 218 | return (err); |
219 | } | | 219 | } |
220 | } | | 220 | } |
221 | | | 221 | |
222 | if ((err = VOP_OPEN(devvp, mode, l->l_cred))) { | | 222 | if ((err = VOP_OPEN(devvp, mode, l->l_cred))) { |
223 | vput(devvp); | | 223 | vput(devvp); |
224 | return (err); | | 224 | return (err); |
225 | } | | 225 | } |
226 | | | 226 | |
227 | err = efs_mount_common(mp, path, devvp, args); | | 227 | err = efs_mount_common(mp, path, devvp, args); |
228 | if (err) { | | 228 | if (err) { |
229 | VOP_CLOSE(devvp, mode, l->l_cred); | | 229 | VOP_CLOSE(devvp, mode, l->l_cred); |
230 | vput(devvp); | | 230 | vput(devvp); |
231 | return (err); | | 231 | return (err); |
232 | } | | 232 | } |
233 | | | 233 | |
234 | VOP_UNLOCK(devvp, 0); | | 234 | VOP_UNLOCK(devvp, 0); |
235 | | | 235 | |
236 | return (0); | | 236 | return (0); |
237 | } | | 237 | } |
238 | | | 238 | |
239 | /* | | 239 | /* |
240 | * Initialisation routine. | | 240 | * Initialisation routine. |
241 | * | | 241 | * |
242 | * Returns 0 on success. | | 242 | * Returns 0 on success. |
243 | */ | | 243 | */ |
244 | static int | | 244 | static int |
245 | efs_start(struct mount *mp, int flags) | | 245 | efs_start(struct mount *mp, int flags) |
246 | { | | 246 | { |
247 | | | 247 | |
248 | return (0); | | 248 | return (0); |
249 | } | | 249 | } |
250 | | | 250 | |
251 | /* | | 251 | /* |
252 | * unmount syscall vfsop. | | 252 | * unmount syscall vfsop. |
253 | * | | 253 | * |
254 | * Returns 0 on success. | | 254 | * Returns 0 on success. |
255 | */ | | 255 | */ |
256 | static int | | 256 | static int |
257 | efs_unmount(struct mount *mp, int mntflags) | | 257 | efs_unmount(struct mount *mp, int mntflags) |
258 | { | | 258 | { |
259 | struct efs_mount *emp; | | 259 | struct efs_mount *emp; |
260 | struct lwp *l = curlwp; | | 260 | struct lwp *l = curlwp; |
261 | int err; | | 261 | int err; |
262 | | | 262 | |
263 | emp = VFSTOEFS(mp); | | 263 | emp = VFSTOEFS(mp); |
264 | | | 264 | |
265 | err = vflush(mp, NULL, (mntflags & MNT_FORCE) ? FORCECLOSE : 0); | | 265 | err = vflush(mp, NULL, (mntflags & MNT_FORCE) ? FORCECLOSE : 0); |
266 | if (err) | | 266 | if (err) |
267 | return (err); | | 267 | return (err); |
268 | | | 268 | |
269 | cache_purgevfs(mp); | | 269 | cache_purgevfs(mp); |
270 | | | 270 | |
271 | vn_lock(emp->em_devvp, LK_EXCLUSIVE | LK_RETRY); | | 271 | vn_lock(emp->em_devvp, LK_EXCLUSIVE | LK_RETRY); |
272 | err = VOP_CLOSE(emp->em_devvp, FREAD, l->l_cred); | | 272 | err = VOP_CLOSE(emp->em_devvp, FREAD, l->l_cred); |
273 | vput(emp->em_devvp); | | 273 | vput(emp->em_devvp); |
274 | | | 274 | |
275 | free(mp->mnt_data, M_EFSMNT); | | 275 | free(mp->mnt_data, M_EFSMNT); |
276 | mp->mnt_data = NULL; | | 276 | mp->mnt_data = NULL; |
277 | mp->mnt_flag &= ~MNT_LOCAL; | | 277 | mp->mnt_flag &= ~MNT_LOCAL; |
278 | | | 278 | |
279 | return (err); | | 279 | return (err); |
280 | } | | 280 | } |
281 | | | 281 | |
282 | /* | | 282 | /* |
283 | * Return the root vnode. | | 283 | * Return the root vnode. |
284 | * | | 284 | * |
285 | * Returns 0 on success. | | 285 | * Returns 0 on success. |
286 | */ | | 286 | */ |
287 | static int | | 287 | static int |
288 | efs_root(struct mount *mp, struct vnode **vpp) | | 288 | efs_root(struct mount *mp, struct vnode **vpp) |
289 | { | | 289 | { |
290 | int err; | | 290 | int err; |
291 | struct vnode *vp; | | 291 | struct vnode *vp; |
292 | | | 292 | |
293 | if ((err = VFS_VGET(mp, EFS_ROOTINO, &vp))) | | 293 | if ((err = VFS_VGET(mp, EFS_ROOTINO, &vp))) |
294 | return (err); | | 294 | return (err); |
295 | | | 295 | |
296 | *vpp = vp; | | 296 | *vpp = vp; |
297 | return (0); | | 297 | return (0); |
298 | } | | 298 | } |
299 | | | 299 | |
300 | /* | | 300 | /* |
301 | * statvfs syscall vfsop. | | 301 | * statvfs syscall vfsop. |
302 | * | | 302 | * |
303 | * Returns 0 on success. | | 303 | * Returns 0 on success. |
304 | */ | | 304 | */ |
305 | static int | | 305 | static int |
306 | efs_statvfs(struct mount *mp, struct statvfs *sbp) | | 306 | efs_statvfs(struct mount *mp, struct statvfs *sbp) |
307 | { | | 307 | { |
308 | struct efs_mount *emp; | | 308 | struct efs_mount *emp; |
309 | | | 309 | |
310 | emp = VFSTOEFS(mp); | | 310 | emp = VFSTOEFS(mp); |
311 | sbp->f_bsize = EFS_BB_SIZE; | | 311 | sbp->f_bsize = EFS_BB_SIZE; |
312 | sbp->f_frsize = EFS_BB_SIZE; | | 312 | sbp->f_frsize = EFS_BB_SIZE; |
313 | sbp->f_iosize = EFS_BB_SIZE; | | 313 | sbp->f_iosize = EFS_BB_SIZE; |
314 | sbp->f_blocks = be32toh(emp->em_sb.sb_size); | | 314 | sbp->f_blocks = be32toh(emp->em_sb.sb_size); |
315 | sbp->f_bfree = be32toh(emp->em_sb.sb_tfree); | | 315 | sbp->f_bfree = be32toh(emp->em_sb.sb_tfree); |
316 | sbp->f_bavail = sbp->f_bfree; // XXX same?? | | 316 | sbp->f_bavail = sbp->f_bfree; // XXX same?? |
317 | sbp->f_bresvd = 0; | | 317 | sbp->f_bresvd = 0; |
318 | sbp->f_files = be32toh(emp->em_sb.sb_tinode); | | 318 | sbp->f_files = be32toh(emp->em_sb.sb_tinode); |
319 | sbp->f_ffree = be16toh(emp->em_sb.sb_cgisize) * | | 319 | sbp->f_ffree = be16toh(emp->em_sb.sb_cgisize) * |
320 | be16toh(emp->em_sb.sb_ncg) * | | 320 | be16toh(emp->em_sb.sb_ncg) * |
321 | EFS_DINODES_PER_BB; | | 321 | EFS_DINODES_PER_BB; |
322 | sbp->f_favail = sbp->f_ffree; // XXX same?? | | 322 | sbp->f_favail = sbp->f_ffree; // XXX same?? |
323 | sbp->f_fresvd = 0; | | 323 | sbp->f_fresvd = 0; |
324 | sbp->f_namemax = EFS_DIRENT_NAMELEN_MAX; | | 324 | sbp->f_namemax = EFS_DIRENT_NAMELEN_MAX; |
325 | copy_statvfs_info(sbp, mp); | | 325 | copy_statvfs_info(sbp, mp); |
326 | | | 326 | |
327 | return (0); | | 327 | return (0); |
328 | } | | 328 | } |
329 | | | 329 | |
330 | /* | | 330 | /* |
331 | * Obtain a locked vnode for the given on-disk inode number. | | 331 | * Obtain a locked vnode for the given on-disk inode number. |
332 | * | | 332 | * |
333 | * We currently allocate a new vnode from getnewnode(), tack it with | | 333 | * We currently allocate a new vnode from getnewnode(), tack it with |
334 | * our in-core inode structure (efs_inode), and read in the inode from | | 334 | * our in-core inode structure (efs_inode), and read in the inode from |
335 | * disk. The returned inode must be locked. | | 335 | * disk. The returned inode must be locked. |
336 | * | | 336 | * |
337 | * Returns 0 on success. | | 337 | * Returns 0 on success. |
338 | */ | | 338 | */ |
339 | static int | | 339 | static int |
340 | efs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) | | 340 | efs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) |
341 | { | | 341 | { |
342 | int err; | | 342 | int err; |
343 | struct vnode *vp; | | 343 | struct vnode *vp; |
344 | struct efs_inode *eip; | | 344 | struct efs_inode *eip; |
345 | struct efs_mount *emp; | | 345 | struct efs_mount *emp; |
346 | | | 346 | |
347 | emp = VFSTOEFS(mp); | | 347 | emp = VFSTOEFS(mp); |
348 | | | 348 | |
349 | while (true) { | | 349 | while (true) { |
350 | *vpp = efs_ihashget(emp->em_dev, ino, LK_EXCLUSIVE); | | 350 | *vpp = efs_ihashget(emp->em_dev, ino, LK_EXCLUSIVE); |
351 | if (*vpp != NULL) | | 351 | if (*vpp != NULL) |
352 | return (0); | | 352 | return (0); |
353 | | | 353 | |
354 | err = getnewvnode(VT_EFS, mp, efs_vnodeop_p, &vp); | | 354 | err = getnewvnode(VT_EFS, mp, efs_vnodeop_p, &vp); |
355 | if (err) | | 355 | if (err) |
356 | return (err); | | 356 | return (err); |
357 | | | 357 | |
358 | eip = pool_get(&efs_inode_pool, PR_WAITOK); | | 358 | eip = pool_get(&efs_inode_pool, PR_WAITOK); |
359 | | | 359 | |
360 | /* | | 360 | /* |
361 | * See if anybody has raced us here. If not, continue | | 361 | * See if anybody has raced us here. If not, continue |
362 | * setting up the new inode, otherwise start over. | | 362 | * setting up the new inode, otherwise start over. |
363 | */ | | 363 | */ |
364 | efs_ihashlock(); | | 364 | efs_ihashlock(); |
365 | | | 365 | |
366 | if (efs_ihashget(emp->em_dev, ino, 0) == NULL) | | 366 | if (efs_ihashget(emp->em_dev, ino, 0) == NULL) |
367 | break; | | 367 | break; |
368 | | | 368 | |
369 | efs_ihashunlock(); | | 369 | efs_ihashunlock(); |
370 | ungetnewvnode(vp); | | 370 | ungetnewvnode(vp); |
371 | pool_put(&efs_inode_pool, eip); | | 371 | pool_put(&efs_inode_pool, eip); |
372 | } | | 372 | } |
373 | | | 373 | |
374 | vp->v_vflag |= VV_LOCKSWORK; | | 374 | vp->v_vflag |= VV_LOCKSWORK; |
375 | eip->ei_mode = 0; | | 375 | eip->ei_mode = 0; |
376 | eip->ei_lockf = NULL; | | 376 | eip->ei_lockf = NULL; |
377 | eip->ei_number = ino; | | 377 | eip->ei_number = ino; |
378 | eip->ei_dev = emp->em_dev; | | 378 | eip->ei_dev = emp->em_dev; |
379 | eip->ei_vp = vp; | | 379 | eip->ei_vp = vp; |
380 | vp->v_data = eip; | | 380 | vp->v_data = eip; |
381 | vp->v_mount = mp; | | | |
382 | | | 381 | |
383 | /* | | 382 | /* |
384 | * Place the vnode on the hash chain. Doing so will lock the | | 383 | * Place the vnode on the hash chain. Doing so will lock the |
385 | * vnode, so it's okay to drop the global lock and read in | | 384 | * vnode, so it's okay to drop the global lock and read in |
386 | * the inode from disk. | | 385 | * the inode from disk. |
387 | */ | | 386 | */ |
388 | efs_ihashins(eip); | | 387 | efs_ihashins(eip); |
389 | efs_ihashunlock(); | | 388 | efs_ihashunlock(); |
390 | | | 389 | |
391 | /* | | 390 | /* |
392 | * Init genfs early, otherwise we'll trip up on genfs_node_destroy | | 391 | * Init genfs early, otherwise we'll trip up on genfs_node_destroy |
393 | * in efs_reclaim when vput()ing in an error branch here. | | 392 | * in efs_reclaim when vput()ing in an error branch here. |
394 | */ | | 393 | */ |
395 | genfs_node_init(vp, &efs_genfsops); | | 394 | genfs_node_init(vp, &efs_genfsops); |
396 | | | 395 | |
397 | err = efs_read_inode(emp, ino, NULL, &eip->ei_di); | | 396 | err = efs_read_inode(emp, ino, NULL, &eip->ei_di); |
398 | if (err) { | | 397 | if (err) { |
399 | vput(vp); | | 398 | vput(vp); |
400 | *vpp = NULL; | | 399 | *vpp = NULL; |
401 | return (err); | | 400 | return (err); |
402 | } | | 401 | } |
403 | | | 402 | |
404 | efs_sync_dinode_to_inode(eip); | | 403 | efs_sync_dinode_to_inode(eip); |
405 | | | 404 | |
406 | if (ino == EFS_ROOTINO && !S_ISDIR(eip->ei_mode)) { | | 405 | if (ino == EFS_ROOTINO && !S_ISDIR(eip->ei_mode)) { |
407 | printf("efs: root inode (%lu) is not a directory!\n", | | 406 | printf("efs: root inode (%lu) is not a directory!\n", |
408 | (ulong)EFS_ROOTINO); | | 407 | (ulong)EFS_ROOTINO); |
409 | vput(vp); | | 408 | vput(vp); |
410 | *vpp = NULL; | | 409 | *vpp = NULL; |
411 | return (EIO); | | 410 | return (EIO); |
412 | } | | 411 | } |
413 | | | 412 | |
414 | switch (eip->ei_mode & S_IFMT) { | | 413 | switch (eip->ei_mode & S_IFMT) { |
415 | case S_IFIFO: | | 414 | case S_IFIFO: |
416 | vp->v_type = VFIFO; | | 415 | vp->v_type = VFIFO; |
417 | break; | | 416 | break; |
418 | case S_IFCHR: | | 417 | case S_IFCHR: |
419 | vp->v_type = VCHR; | | 418 | vp->v_type = VCHR; |
420 | break; | | 419 | break; |
421 | case S_IFDIR: | | 420 | case S_IFDIR: |
422 | vp->v_type = VDIR; | | 421 | vp->v_type = VDIR; |
423 | if (ino == EFS_ROOTINO) | | 422 | if (ino == EFS_ROOTINO) |
424 | vp->v_vflag |= VV_ROOT; | | 423 | vp->v_vflag |= VV_ROOT; |
425 | break; | | 424 | break; |
426 | case S_IFBLK: | | 425 | case S_IFBLK: |
427 | vp->v_type = VBLK; | | 426 | vp->v_type = VBLK; |
428 | break; | | 427 | break; |
429 | case S_IFREG: | | 428 | case S_IFREG: |
430 | vp->v_type = VREG; | | 429 | vp->v_type = VREG; |
431 | break; | | 430 | break; |
432 | case S_IFLNK: | | 431 | case S_IFLNK: |
433 | vp->v_type = VLNK; | | 432 | vp->v_type = VLNK; |
434 | break; | | 433 | break; |
435 | case S_IFSOCK: | | 434 | case S_IFSOCK: |
436 | vp->v_type = VSOCK; | | 435 | vp->v_type = VSOCK; |
437 | break; | | 436 | break; |
438 | default: | | 437 | default: |
439 | printf("efs: invalid mode 0x%x in inode %lu on mount %s\n", | | 438 | printf("efs: invalid mode 0x%x in inode %lu on mount %s\n", |
440 | eip->ei_mode, (ulong)ino, mp->mnt_stat.f_mntonname); | | 439 | eip->ei_mode, (ulong)ino, mp->mnt_stat.f_mntonname); |
441 | vput(vp); | | 440 | vput(vp); |
442 | *vpp = NULL; | | 441 | *vpp = NULL; |
443 | return (EIO); | | 442 | return (EIO); |
444 | } | | 443 | } |
445 | | | 444 | |
446 | uvm_vnp_setsize(vp, eip->ei_size); | | 445 | uvm_vnp_setsize(vp, eip->ei_size); |
447 | *vpp = vp; | | 446 | *vpp = vp; |
448 | | | 447 | |
449 | KASSERT(VOP_ISLOCKED(vp)); | | 448 | KASSERT(VOP_ISLOCKED(vp)); |
450 | | | 449 | |
451 | return (0); | | 450 | return (0); |
452 | } | | 451 | } |
453 | | | 452 | |
454 | /* | | 453 | /* |
455 | * Convert the provided opaque, unique file handle into a vnode. | | 454 | * Convert the provided opaque, unique file handle into a vnode. |
456 | * | | 455 | * |
457 | * Returns 0 on success. | | 456 | * Returns 0 on success. |
458 | */ | | 457 | */ |
459 | static int | | 458 | static int |
460 | efs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) | | 459 | efs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) |
461 | { | | 460 | { |
462 | int err; | | 461 | int err; |
463 | struct vnode *vp; | | 462 | struct vnode *vp; |
464 | struct efs_fid *efp; | | 463 | struct efs_fid *efp; |
465 | struct efs_inode *eip; | | 464 | struct efs_inode *eip; |
466 | | | 465 | |
467 | if (fhp->fid_len != sizeof(struct efs_fid)) | | 466 | if (fhp->fid_len != sizeof(struct efs_fid)) |
468 | return (EINVAL); | | 467 | return (EINVAL); |
469 | | | 468 | |
470 | efp = (struct efs_fid *)fhp; | | 469 | efp = (struct efs_fid *)fhp; |
471 | | | 470 | |
472 | if ((err = VFS_VGET(mp, efp->ef_ino, &vp))) { | | 471 | if ((err = VFS_VGET(mp, efp->ef_ino, &vp))) { |
473 | *vpp = NULL; | | 472 | *vpp = NULL; |
474 | return (err); | | 473 | return (err); |
475 | } | | 474 | } |
476 | | | 475 | |
477 | eip = EFS_VTOI(vp); | | 476 | eip = EFS_VTOI(vp); |
478 | if (eip->ei_mode == 0 || eip->ei_gen != efp->ef_gen) { | | 477 | if (eip->ei_mode == 0 || eip->ei_gen != efp->ef_gen) { |
479 | vput(vp); | | 478 | vput(vp); |
480 | *vpp = NULL; | | 479 | *vpp = NULL; |
481 | return (ESTALE); | | 480 | return (ESTALE); |
482 | } | | 481 | } |
483 | | | 482 | |
484 | *vpp = vp; | | 483 | *vpp = vp; |
485 | return (0); | | 484 | return (0); |
486 | } | | 485 | } |
487 | | | 486 | |
488 | /* | | 487 | /* |
489 | * Convert the provided vnode into an opaque, unique file handle. | | 488 | * Convert the provided vnode into an opaque, unique file handle. |
490 | * | | 489 | * |
491 | * Returns 0 on success. | | 490 | * Returns 0 on success. |
492 | */ | | 491 | */ |
493 | static int | | 492 | static int |
494 | efs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size) | | 493 | efs_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size) |
495 | { | | 494 | { |
496 | struct efs_fid *efp; | | 495 | struct efs_fid *efp; |
497 | struct efs_inode *eip; | | 496 | struct efs_inode *eip; |
498 | | | 497 | |
499 | if (*fh_size < sizeof(struct efs_fid)) { | | 498 | if (*fh_size < sizeof(struct efs_fid)) { |
500 | *fh_size = sizeof(struct efs_fid); | | 499 | *fh_size = sizeof(struct efs_fid); |
501 | return (E2BIG); | | 500 | return (E2BIG); |
502 | } | | 501 | } |
503 | *fh_size = sizeof(struct efs_fid); | | 502 | *fh_size = sizeof(struct efs_fid); |
504 | | | 503 | |
505 | eip = EFS_VTOI(vp); | | 504 | eip = EFS_VTOI(vp); |
506 | efp = (struct efs_fid *)fhp; | | 505 | efp = (struct efs_fid *)fhp; |
507 | | | 506 | |
508 | fhp->fid_len = sizeof(struct efs_fid); | | 507 | fhp->fid_len = sizeof(struct efs_fid); |
509 | efp->ef_ino = eip->ei_number; | | 508 | efp->ef_ino = eip->ei_number; |
510 | efp->ef_gen = eip->ei_gen; | | 509 | efp->ef_gen = eip->ei_gen; |
511 | | | 510 | |
512 | return (0); | | 511 | return (0); |
513 | } | | 512 | } |
514 | | | 513 | |
515 | /* | | 514 | /* |
516 | * Globally initialise the filesystem. | | 515 | * Globally initialise the filesystem. |
517 | */ | | 516 | */ |
518 | static void | | 517 | static void |
519 | efs_init(void) | | 518 | efs_init(void) |
520 | { | | 519 | { |
521 | | | 520 | |
522 | malloc_type_attach(M_EFSMNT); | | 521 | malloc_type_attach(M_EFSMNT); |
523 | malloc_type_attach(M_EFSINO); | | 522 | malloc_type_attach(M_EFSINO); |
524 | malloc_type_attach(M_EFSTMP); | | 523 | malloc_type_attach(M_EFSTMP); |
525 | efs_ihashinit(); | | 524 | efs_ihashinit(); |
526 | pool_init(&efs_inode_pool, sizeof(struct efs_inode), 0, 0, 0, | | 525 | pool_init(&efs_inode_pool, sizeof(struct efs_inode), 0, 0, 0, |
527 | "efsinopl", &pool_allocator_nointr, IPL_NONE); | | 526 | "efsinopl", &pool_allocator_nointr, IPL_NONE); |
528 | } | | 527 | } |
529 | | | 528 | |
530 | /* | | 529 | /* |
531 | * Globally reinitialise the filesystem. | | 530 | * Globally reinitialise the filesystem. |
532 | */ | | 531 | */ |
533 | static void | | 532 | static void |
534 | efs_reinit(void) | | 533 | efs_reinit(void) |
535 | { | | 534 | { |
536 | | | 535 | |
537 | efs_ihashreinit(); | | 536 | efs_ihashreinit(); |
538 | } | | 537 | } |
539 | | | 538 | |
540 | /* | | 539 | /* |
541 | * Globally clean up the filesystem. | | 540 | * Globally clean up the filesystem. |
542 | */ | | 541 | */ |
543 | static void | | 542 | static void |
544 | efs_done(void) | | 543 | efs_done(void) |
545 | { | | 544 | { |
546 | | | 545 | |
547 | pool_destroy(&efs_inode_pool); | | 546 | pool_destroy(&efs_inode_pool); |
548 | efs_ihashdone(); | | 547 | efs_ihashdone(); |
549 | malloc_type_detach(M_EFSMNT); | | 548 | malloc_type_detach(M_EFSMNT); |
550 | malloc_type_detach(M_EFSINO); | | 549 | malloc_type_detach(M_EFSINO); |
551 | malloc_type_detach(M_EFSTMP); | | 550 | malloc_type_detach(M_EFSTMP); |
552 | } | | 551 | } |
553 | | | 552 | |
554 | extern const struct vnodeopv_desc efs_vnodeop_opv_desc; | | 553 | extern const struct vnodeopv_desc efs_vnodeop_opv_desc; |
555 | //extern const struct vnodeopv_desc efs_specop_opv_desc; | | 554 | //extern const struct vnodeopv_desc efs_specop_opv_desc; |
556 | //extern const struct vnodeopv_desc efs_fifoop_opv_desc; | | 555 | //extern const struct vnodeopv_desc efs_fifoop_opv_desc; |
557 | | | 556 | |
558 | const struct vnodeopv_desc * const efs_vnodeopv_descs[] = { | | 557 | const struct vnodeopv_desc * const efs_vnodeopv_descs[] = { |
559 | &efs_vnodeop_opv_desc, | | 558 | &efs_vnodeop_opv_desc, |
560 | // &efs_specop_opv_desc, | | 559 | // &efs_specop_opv_desc, |
561 | // &efs_fifoop_opv_desc, | | 560 | // &efs_fifoop_opv_desc, |
562 | NULL | | 561 | NULL |
563 | }; | | 562 | }; |
564 | | | 563 | |
565 | struct vfsops efs_vfsops = { | | 564 | struct vfsops efs_vfsops = { |
566 | .vfs_name = MOUNT_EFS, | | 565 | .vfs_name = MOUNT_EFS, |
567 | .vfs_min_mount_data = sizeof (struct efs_args), | | 566 | .vfs_min_mount_data = sizeof (struct efs_args), |
568 | .vfs_mount = efs_mount, | | 567 | .vfs_mount = efs_mount, |
569 | .vfs_start = efs_start, | | 568 | .vfs_start = efs_start, |
570 | .vfs_unmount = efs_unmount, | | 569 | .vfs_unmount = efs_unmount, |
571 | .vfs_root = efs_root, | | 570 | .vfs_root = efs_root, |
572 | .vfs_quotactl = (void *)eopnotsupp, | | 571 | .vfs_quotactl = (void *)eopnotsupp, |
573 | .vfs_statvfs = efs_statvfs, | | 572 | .vfs_statvfs = efs_statvfs, |
574 | .vfs_sync = (void *)nullop, | | 573 | .vfs_sync = (void *)nullop, |
575 | .vfs_vget = efs_vget, | | 574 | .vfs_vget = efs_vget, |
576 | .vfs_fhtovp = efs_fhtovp, | | 575 | .vfs_fhtovp = efs_fhtovp, |
577 | .vfs_vptofh = efs_vptofh, | | 576 | .vfs_vptofh = efs_vptofh, |
578 | .vfs_init = efs_init, | | 577 | .vfs_init = efs_init, |
579 | .vfs_reinit = efs_reinit, | | 578 | .vfs_reinit = efs_reinit, |
580 | .vfs_done = efs_done, | | 579 | .vfs_done = efs_done, |
581 | .vfs_mountroot = (void *)eopnotsupp, | | 580 | .vfs_mountroot = (void *)eopnotsupp, |
582 | .vfs_snapshot = (void *)eopnotsupp, | | 581 | .vfs_snapshot = (void *)eopnotsupp, |
583 | .vfs_extattrctl = vfs_stdextattrctl, | | 582 | .vfs_extattrctl = vfs_stdextattrctl, |
584 | .vfs_suspendctl = (void *)eopnotsupp, | | 583 | .vfs_suspendctl = (void *)eopnotsupp, |
585 | .vfs_opv_descs = efs_vnodeopv_descs | | 584 | .vfs_opv_descs = efs_vnodeopv_descs |
586 | /* .vfs_refcount */ | | 585 | /* .vfs_refcount */ |
587 | /* .vfs_list */ | | 586 | /* .vfs_list */ |
588 | }; | | 587 | }; |
589 | | | 588 | |
590 | static int | | 589 | static int |
591 | efs_modcmd(modcmd_t cmd, void *arg) | | 590 | efs_modcmd(modcmd_t cmd, void *arg) |
592 | { | | 591 | { |
593 | | | 592 | |
594 | switch (cmd) { | | 593 | switch (cmd) { |
595 | case MODULE_CMD_INIT: | | 594 | case MODULE_CMD_INIT: |
596 | return vfs_attach(&efs_vfsops); | | 595 | return vfs_attach(&efs_vfsops); |
597 | case MODULE_CMD_FINI: | | 596 | case MODULE_CMD_FINI: |
598 | return vfs_detach(&efs_vfsops); | | 597 | return vfs_detach(&efs_vfsops); |
599 | default: | | 598 | default: |
600 | return ENOTTY; | | 599 | return ENOTTY; |
601 | } | | 600 | } |
602 | } | | 601 | } |