1 /* $NetBSD: kernfs_vfsops.c,v 1.100 2020/04/07 08:35:49 jdolecek 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.100 2020/04/07 08:35:49 jdolecek 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/syslog.h> 58 #include <sys/kauth.h> 59 #include <sys/module.h> 60 61 #include <miscfs/genfs/genfs.h> 62 #include <miscfs/specfs/specdev.h> 63 #include <miscfs/kernfs/kernfs.h> 64 65 MODULE(MODULE_CLASS_VFS, kernfs, NULL); 66 67 dev_t rrootdev = NODEV; 68 kmutex_t kfs_lock; 69 70 VFS_PROTOS(kernfs); 71 72 void kernfs_get_rrootdev(void); 73 74 void 75 kernfs_init(void) 76 { 77 78 mutex_init(&kfs_lock, MUTEX_DEFAULT, IPL_NONE); 79 } 80 81 void 82 kernfs_reinit(void) 83 { 84 85 } 86 87 void 88 kernfs_done(void) 89 { 90 91 mutex_destroy(&kfs_lock); 92 } 93 94 void 95 kernfs_get_rrootdev(void) 96 { 97 static int tried = 0; 98 99 if (tried) { 100 /* Already did it once. */ 101 return; 102 } 103 tried = 1; 104 105 if (rootdev == NODEV) 106 return; 107 rrootdev = devsw_blk2chr(rootdev); 108 if (rrootdev != NODEV) 109 return; 110 rrootdev = NODEV; 111 printf("kernfs_get_rrootdev: no raw root device\n"); 112 } 113 114 /* 115 * Mount the Kernel params filesystem 116 */ 117 int 118 kernfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len) 119 { 120 struct lwp *l = curlwp; 121 int error = 0; 122 struct kernfs_mount *fmp; 123 124 if (UIO_MX & (UIO_MX - 1)) { 125 log(LOG_ERR, "kernfs: invalid directory entry size"); 126 return (EINVAL); 127 } 128 129 if (mp->mnt_flag & MNT_GETARGS) { 130 *data_len = 0; 131 return 0; 132 } 133 /* 134 * Update is a no-op 135 */ 136 if (mp->mnt_flag & MNT_UPDATE) 137 return (EOPNOTSUPP); 138 139 fmp = kmem_zalloc(sizeof(struct kernfs_mount), KM_SLEEP); 140 TAILQ_INIT(&fmp->nodelist); 141 142 mp->mnt_stat.f_namemax = KERNFS_MAXNAMLEN; 143 mp->mnt_flag |= MNT_LOCAL; 144 mp->mnt_data = fmp; 145 vfs_getnewfsid(mp); 146 147 if ((error = set_statvfs_info(path, UIO_USERSPACE, "kernfs", 148 UIO_SYSSPACE, mp->mnt_op->vfs_name, mp, l)) != 0) { 149 kmem_free(fmp, sizeof(struct kernfs_mount)); 150 return error; 151 } 152 153 kernfs_get_rrootdev(); 154 return 0; 155 } 156 157 int 158 kernfs_start(struct mount *mp, int flags) 159 { 160 161 return (0); 162 } 163 164 int 165 kernfs_unmount(struct mount *mp, int mntflags) 166 { 167 int error; 168 int flags = 0; 169 170 if (mntflags & MNT_FORCE) 171 flags |= FORCECLOSE; 172 173 if ((error = vflush(mp, 0, flags)) != 0) 174 return (error); 175 176 /* 177 * Finally, throw away the kernfs_mount structure 178 */ 179 kmem_free(mp->mnt_data, sizeof(struct kernfs_mount)); 180 mp->mnt_data = NULL; 181 return (0); 182 } 183 184 int 185 kernfs_root(struct mount *mp, int lktype, struct vnode **vpp) 186 { 187 const struct kern_target *root_target = &kern_targets[0]; 188 int error; 189 190 /* setup "." */ 191 error = vcache_get(mp, &root_target, sizeof(root_target), vpp); 192 if (error) 193 return error; 194 error = vn_lock(*vpp, lktype); 195 if (error) { 196 vrele(*vpp); 197 *vpp = NULL; 198 return error; 199 } 200 return 0; 201 } 202 203 /*ARGSUSED*/ 204 int 205 kernfs_sync(struct mount *mp, int waitfor, 206 kauth_cred_t uc) 207 { 208 209 return (0); 210 } 211 212 /* 213 * Kernfs flat namespace lookup. 214 * Currently unsupported. 215 */ 216 int 217 kernfs_vget(struct mount *mp, ino_t ino, int lktype, 218 struct vnode **vpp) 219 { 220 221 return (EOPNOTSUPP); 222 } 223 224 int 225 kernfs_loadvnode(struct mount *mp, struct vnode *vp, 226 const void *key, size_t key_len, const void **new_key) 227 { 228 const struct kern_target *kt; 229 struct kernfs_node *kfs, *kfsp; 230 long *cookie; 231 232 KASSERT(key_len == sizeof(kt)); 233 memcpy(&kt, key, key_len); 234 235 kfs = kmem_zalloc(sizeof(struct kernfs_node), KM_SLEEP); 236 cookie = &(VFSTOKERNFS(mp)->fileno_cookie); 237 mutex_enter(&kfs_lock); 238 again: 239 TAILQ_FOREACH(kfsp, &VFSTOKERNFS(mp)->nodelist, kfs_list) { 240 if (kfsp->kfs_cookie == *cookie) { 241 (*cookie) ++; 242 goto again; 243 } 244 if (TAILQ_NEXT(kfsp, kfs_list)) { 245 if (kfsp->kfs_cookie < *cookie && 246 *cookie < TAILQ_NEXT(kfsp, kfs_list)->kfs_cookie) 247 break; 248 if (kfsp->kfs_cookie + 1 < 249 TAILQ_NEXT(kfsp, kfs_list)->kfs_cookie) { 250 *cookie = kfsp->kfs_cookie + 1; 251 break; 252 } 253 } 254 } 255 256 kfs->kfs_cookie = *cookie; 257 258 if (kfsp) 259 TAILQ_INSERT_AFTER(&VFSTOKERNFS(mp)->nodelist, kfsp, kfs, 260 kfs_list); 261 else 262 TAILQ_INSERT_TAIL(&VFSTOKERNFS(mp)->nodelist, kfs, kfs_list); 263 264 kfs->kfs_type = kt->kt_tag; 265 kfs->kfs_vnode = vp; 266 kfs->kfs_fileno = KERNFS_FILENO(kt, kt->kt_tag, kfs->kfs_cookie); 267 kfs->kfs_kt = kt; 268 kfs->kfs_mode = kt->kt_mode; 269 vp->v_tag = VT_KERNFS; 270 vp->v_op = kernfs_vnodeop_p; 271 vp->v_data = kfs; 272 vp->v_type = kt->kt_vtype; 273 mutex_exit(&kfs_lock); 274 275 if (kt->kt_tag == KFSkern) 276 vp->v_vflag = VV_ROOT; 277 278 if (kt->kt_tag == KFSdevice) { 279 vp->v_op = kernfs_specop_p; 280 spec_node_init(vp, *(dev_t *)kt->kt_data); 281 } 282 283 uvm_vnp_setsize(vp, 0); 284 285 *new_key = &kfs->kfs_kt; 286 return 0; 287 } 288 289 extern const struct vnodeopv_desc kernfs_vnodeop_opv_desc; 290 extern const struct vnodeopv_desc kernfs_specop_opv_desc; 291 292 const struct vnodeopv_desc * const kernfs_vnodeopv_descs[] = { 293 &kernfs_vnodeop_opv_desc, 294 &kernfs_specop_opv_desc, 295 NULL, 296 }; 297 298 struct vfsops kernfs_vfsops = { 299 .vfs_name = MOUNT_KERNFS, 300 .vfs_min_mount_data = 0, 301 .vfs_mount = kernfs_mount, 302 .vfs_start = kernfs_start, 303 .vfs_unmount = kernfs_unmount, 304 .vfs_root = kernfs_root, 305 .vfs_quotactl = (void *)eopnotsupp, 306 .vfs_statvfs = genfs_statvfs, 307 .vfs_sync = kernfs_sync, 308 .vfs_vget = kernfs_vget, 309 .vfs_loadvnode = kernfs_loadvnode, 310 .vfs_fhtovp = (void *)eopnotsupp, 311 .vfs_vptofh = (void *)eopnotsupp, 312 .vfs_init = kernfs_init, 313 .vfs_reinit = kernfs_reinit, 314 .vfs_done = kernfs_done, 315 .vfs_snapshot = (void *)eopnotsupp, 316 .vfs_extattrctl = vfs_stdextattrctl, 317 .vfs_suspendctl = genfs_suspendctl, 318 .vfs_renamelock_enter = genfs_renamelock_enter, 319 .vfs_renamelock_exit = genfs_renamelock_exit, 320 .vfs_fsync = (void *)eopnotsupp, 321 .vfs_opv_descs = kernfs_vnodeopv_descs 322 }; 323 324 SYSCTL_SETUP(kernfs_sysctl_setup, "kernfs sysctl") 325 { 326 327 sysctl_createv(clog, 0, NULL, NULL, 328 CTLFLAG_PERMANENT, 329 CTLTYPE_NODE, "kernfs", 330 SYSCTL_DESCR("/kern file system"), 331 NULL, 0, NULL, 0, 332 CTL_VFS, 11, CTL_EOL); 333 /* 334 * XXX the "11" above could be dynamic, thereby eliminating one 335 * more instance of the "number to vfs" mapping problem, but 336 * "11" is the order as taken from sys/mount.h 337 */ 338 } 339 340 static int 341 kernfs_modcmd(modcmd_t cmd, void *arg) 342 { 343 int error; 344 345 switch (cmd) { 346 case MODULE_CMD_INIT: 347 error = vfs_attach(&kernfs_vfsops); 348 if (error != 0) 349 break; 350 break; 351 case MODULE_CMD_FINI: 352 error = vfs_detach(&kernfs_vfsops); 353 if (error != 0) 354 break; 355 break; 356 default: 357 error = ENOTTY; 358 break; 359 } 360 361 return (error); 362 } 363