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