1 /* $NetBSD: kernfs_vfsops.c,v 1.99 2020/03/16 21:20:11 pgoyette Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993, 1995 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software donated to Berkeley by 8 * Jan-Simon Pendry. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)kernfs_vfsops.c 8.10 (Berkeley) 5/14/95 35 */ 36 37 /* 38 * Kernel params Filesystem 39 */ 40 41 #include <sys/cdefs.h> 42 __KERNEL_RCSID(0, "$NetBSD: kernfs_vfsops.c,v 1.99 2020/03/16 21:20:11 pgoyette Exp $"); 43 44 #ifdef _KERNEL_OPT 45 #include "opt_compat_netbsd.h" 46 #endif 47 48 #include <sys/param.h> 49 #include <sys/systm.h> 50 #include <sys/sysctl.h> 51 #include <sys/conf.h> 52 #include <sys/proc.h> 53 #include <sys/vnode.h> 54 #include <sys/mount.h> 55 #include <sys/namei.h> 56 #include <sys/dirent.h> 57 #include <sys/malloc.h> 58 #include <sys/syslog.h> 59 #include <sys/kauth.h> 60 #include <sys/module.h> 61 62 #include <miscfs/genfs/genfs.h> 63 #include <miscfs/specfs/specdev.h> 64 #include <miscfs/kernfs/kernfs.h> 65 66 MODULE(MODULE_CLASS_VFS, kernfs, NULL); 67 68 MALLOC_JUSTDEFINE(M_KERNFSMNT, "kernfs mount", "kernfs mount structures"); 69 70 dev_t rrootdev = NODEV; 71 kmutex_t kfs_lock; 72 73 VFS_PROTOS(kernfs); 74 75 void kernfs_get_rrootdev(void); 76 77 void 78 kernfs_init(void) 79 { 80 81 malloc_type_attach(M_KERNFSMNT); 82 mutex_init(&kfs_lock, MUTEX_DEFAULT, IPL_NONE); 83 } 84 85 void 86 kernfs_reinit(void) 87 { 88 89 } 90 91 void 92 kernfs_done(void) 93 { 94 95 mutex_destroy(&kfs_lock); 96 malloc_type_detach(M_KERNFSMNT); 97 } 98 99 void 100 kernfs_get_rrootdev(void) 101 { 102 static int tried = 0; 103 104 if (tried) { 105 /* Already did it once. */ 106 return; 107 } 108 tried = 1; 109 110 if (rootdev == NODEV) 111 return; 112 rrootdev = devsw_blk2chr(rootdev); 113 if (rrootdev != NODEV) 114 return; 115 rrootdev = NODEV; 116 printf("kernfs_get_rrootdev: no raw root device\n"); 117 } 118 119 /* 120 * Mount the Kernel params filesystem 121 */ 122 int 123 kernfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len) 124 { 125 struct lwp *l = curlwp; 126 int error = 0; 127 struct kernfs_mount *fmp; 128 129 if (UIO_MX & (UIO_MX - 1)) { 130 log(LOG_ERR, "kernfs: invalid directory entry size"); 131 return (EINVAL); 132 } 133 134 if (mp->mnt_flag & MNT_GETARGS) { 135 *data_len = 0; 136 return 0; 137 } 138 /* 139 * Update is a no-op 140 */ 141 if (mp->mnt_flag & MNT_UPDATE) 142 return (EOPNOTSUPP); 143 144 fmp = malloc(sizeof(struct kernfs_mount), M_KERNFSMNT, M_WAITOK|M_ZERO); 145 TAILQ_INIT(&fmp->nodelist); 146 147 mp->mnt_stat.f_namemax = KERNFS_MAXNAMLEN; 148 mp->mnt_flag |= MNT_LOCAL; 149 mp->mnt_data = fmp; 150 vfs_getnewfsid(mp); 151 152 if ((error = set_statvfs_info(path, UIO_USERSPACE, "kernfs", 153 UIO_SYSSPACE, mp->mnt_op->vfs_name, mp, l)) != 0) { 154 free(fmp, M_KERNFSMNT); 155 return error; 156 } 157 158 kernfs_get_rrootdev(); 159 return 0; 160 } 161 162 int 163 kernfs_start(struct mount *mp, int flags) 164 { 165 166 return (0); 167 } 168 169 int 170 kernfs_unmount(struct mount *mp, int mntflags) 171 { 172 int error; 173 int flags = 0; 174 175 if (mntflags & MNT_FORCE) 176 flags |= FORCECLOSE; 177 178 if ((error = vflush(mp, 0, flags)) != 0) 179 return (error); 180 181 /* 182 * Finally, throw away the kernfs_mount structure 183 */ 184 free(mp->mnt_data, M_KERNFSMNT); 185 mp->mnt_data = NULL; 186 return (0); 187 } 188 189 int 190 kernfs_root(struct mount *mp, int lktype, struct vnode **vpp) 191 { 192 const struct kern_target *root_target = &kern_targets[0]; 193 int error; 194 195 /* setup "." */ 196 error = vcache_get(mp, &root_target, sizeof(root_target), vpp); 197 if (error) 198 return error; 199 error = vn_lock(*vpp, lktype); 200 if (error) { 201 vrele(*vpp); 202 *vpp = NULL; 203 return error; 204 } 205 return 0; 206 } 207 208 /*ARGSUSED*/ 209 int 210 kernfs_sync(struct mount *mp, int waitfor, 211 kauth_cred_t uc) 212 { 213 214 return (0); 215 } 216 217 /* 218 * Kernfs flat namespace lookup. 219 * Currently unsupported. 220 */ 221 int 222 kernfs_vget(struct mount *mp, ino_t ino, int lktype, 223 struct vnode **vpp) 224 { 225 226 return (EOPNOTSUPP); 227 } 228 229 int 230 kernfs_loadvnode(struct mount *mp, struct vnode *vp, 231 const void *key, size_t key_len, const void **new_key) 232 { 233 const struct kern_target *kt; 234 struct kernfs_node *kfs, *kfsp; 235 long *cookie; 236 237 KASSERT(key_len == sizeof(kt)); 238 memcpy(&kt, key, key_len); 239 240 kfs = kmem_zalloc(sizeof(struct kernfs_node), KM_SLEEP); 241 cookie = &(VFSTOKERNFS(mp)->fileno_cookie); 242 mutex_enter(&kfs_lock); 243 again: 244 TAILQ_FOREACH(kfsp, &VFSTOKERNFS(mp)->nodelist, kfs_list) { 245 if (kfsp->kfs_cookie == *cookie) { 246 (*cookie) ++; 247 goto again; 248 } 249 if (TAILQ_NEXT(kfsp, kfs_list)) { 250 if (kfsp->kfs_cookie < *cookie && 251 *cookie < TAILQ_NEXT(kfsp, kfs_list)->kfs_cookie) 252 break; 253 if (kfsp->kfs_cookie + 1 < 254 TAILQ_NEXT(kfsp, kfs_list)->kfs_cookie) { 255 *cookie = kfsp->kfs_cookie + 1; 256 break; 257 } 258 } 259 } 260 261 kfs->kfs_cookie = *cookie; 262 263 if (kfsp) 264 TAILQ_INSERT_AFTER(&VFSTOKERNFS(mp)->nodelist, kfsp, kfs, 265 kfs_list); 266 else 267 TAILQ_INSERT_TAIL(&VFSTOKERNFS(mp)->nodelist, kfs, kfs_list); 268 269 kfs->kfs_type = kt->kt_tag; 270 kfs->kfs_vnode = vp; 271 kfs->kfs_fileno = KERNFS_FILENO(kt, kt->kt_tag, kfs->kfs_cookie); 272 kfs->kfs_kt = kt; 273 kfs->kfs_mode = kt->kt_mode; 274 vp->v_tag = VT_KERNFS; 275 vp->v_op = kernfs_vnodeop_p; 276 vp->v_data = kfs; 277 vp->v_type = kt->kt_vtype; 278 mutex_exit(&kfs_lock); 279 280 if (kt->kt_tag == KFSkern) 281 vp->v_vflag = VV_ROOT; 282 283 if (kt->kt_tag == KFSdevice) { 284 vp->v_op = kernfs_specop_p; 285 spec_node_init(vp, *(dev_t *)kt->kt_data); 286 } 287 288 uvm_vnp_setsize(vp, 0); 289 290 *new_key = &kfs->kfs_kt; 291 return 0; 292 } 293 294 extern const struct vnodeopv_desc kernfs_vnodeop_opv_desc; 295 extern const struct vnodeopv_desc kernfs_specop_opv_desc; 296 297 const struct vnodeopv_desc * const kernfs_vnodeopv_descs[] = { 298 &kernfs_vnodeop_opv_desc, 299 &kernfs_specop_opv_desc, 300 NULL, 301 }; 302 303 struct vfsops kernfs_vfsops = { 304 .vfs_name = MOUNT_KERNFS, 305 .vfs_min_mount_data = 0, 306 .vfs_mount = kernfs_mount, 307 .vfs_start = kernfs_start, 308 .vfs_unmount = kernfs_unmount, 309 .vfs_root = kernfs_root, 310 .vfs_quotactl = (void *)eopnotsupp, 311 .vfs_statvfs = genfs_statvfs, 312 .vfs_sync = kernfs_sync, 313 .vfs_vget = kernfs_vget, 314 .vfs_loadvnode = kernfs_loadvnode, 315 .vfs_fhtovp = (void *)eopnotsupp, 316 .vfs_vptofh = (void *)eopnotsupp, 317 .vfs_init = kernfs_init, 318 .vfs_reinit = kernfs_reinit, 319 .vfs_done = kernfs_done, 320 .vfs_snapshot = (void *)eopnotsupp, 321 .vfs_extattrctl = vfs_stdextattrctl, 322 .vfs_suspendctl = genfs_suspendctl, 323 .vfs_renamelock_enter = genfs_renamelock_enter, 324 .vfs_renamelock_exit = genfs_renamelock_exit, 325 .vfs_fsync = (void *)eopnotsupp, 326 .vfs_opv_descs = kernfs_vnodeopv_descs 327 }; 328 329 SYSCTL_SETUP(kernfs_sysctl_setup, "kernfs sysctl") 330 { 331 332 sysctl_createv(clog, 0, NULL, NULL, 333 CTLFLAG_PERMANENT, 334 CTLTYPE_NODE, "kernfs", 335 SYSCTL_DESCR("/kern file system"), 336 NULL, 0, NULL, 0, 337 CTL_VFS, 11, CTL_EOL); 338 /* 339 * XXX the "11" above could be dynamic, thereby eliminating one 340 * more instance of the "number to vfs" mapping problem, but 341 * "11" is the order as taken from sys/mount.h 342 */ 343 } 344 345 static int 346 kernfs_modcmd(modcmd_t cmd, void *arg) 347 { 348 int error; 349 350 switch (cmd) { 351 case MODULE_CMD_INIT: 352 error = vfs_attach(&kernfs_vfsops); 353 if (error != 0) 354 break; 355 break; 356 case MODULE_CMD_FINI: 357 error = vfs_detach(&kernfs_vfsops); 358 if (error != 0) 359 break; 360 break; 361 default: 362 error = ENOTTY; 363 break; 364 } 365 366 return (error); 367 } 368