1 /*- 2 * Copyright (c) 2001 Dag-Erling Co�dan Sm�rgrav 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/kernel.h> 33 #include <sys/systm.h> 34 #include <sys/lock.h> 35 #include <sys/malloc.h> 36 #include <sys/module.h> 37 #include <sys/mount.h> 38 #include <sys/mutex.h> 39 #include <sys/proc.h> 40 #include <sys/sbuf.h> 41 #include <sys/sysctl.h> 42 #include <sys/vnode.h> 43 44 #include <fs/pseudofs/pseudofs.h> 45 #include <fs/pseudofs/pseudofs_internal.h> 46 47 static MALLOC_DEFINE(M_PFSNODES, "pfs_nodes", "pseudofs nodes"); 48 49 SYSCTL_NODE(_vfs, OID_AUTO, pfs, CTLFLAG_RW, 0, 50 "pseudofs"); 51 52 /* 53 * Add a node to a directory 54 */ 55 static int 56 _pfs_add_node(struct pfs_node *parent, struct pfs_node *node) 57 { 58 KASSERT(parent != NULL, 59 (__FUNCTION__ "(): parent is NULL")); 60 KASSERT(parent->pn_info != NULL, 61 (__FUNCTION__ "(): parent has no pn_info")); 62 KASSERT(parent->pn_type == pfstype_dir || 63 parent->pn_type == pfstype_procdir || 64 parent->pn_type == pfstype_root, 65 (__FUNCTION__ "(): parent is not a directory")); 66 67 /* XXX should check for duplicate names etc. */ 68 69 mtx_lock(&parent->pn_info->pi_mutex); 70 node->pn_info = parent->pn_info; 71 node->pn_parent = parent; 72 node->pn_next = parent->pn_nodes; 73 parent->pn_nodes = node; 74 mtx_unlock(&parent->pn_info->pi_mutex); 75 76 return (0); 77 } 78 79 /* 80 * Add . and .. to a directory 81 */ 82 static int 83 _pfs_fixup_dir(struct pfs_node *parent) 84 { 85 struct pfs_node *dir; 86 87 MALLOC(dir, struct pfs_node *, sizeof *dir, 88 M_PFSNODES, M_WAITOK|M_ZERO); 89 dir->pn_name[0] = '.'; 90 dir->pn_type = pfstype_this; 91 92 if (_pfs_add_node(parent, dir) != 0) { 93 FREE(dir, M_PFSNODES); 94 return (-1); 95 } 96 97 MALLOC(dir, struct pfs_node *, sizeof *dir, 98 M_PFSNODES, M_WAITOK|M_ZERO); 99 dir->pn_name[0] = dir->pn_name[1] = '.'; 100 dir->pn_type = pfstype_parent; 101 102 if (_pfs_add_node(parent, dir) != 0) { 103 FREE(dir, M_PFSNODES); 104 return (-1); 105 } 106 107 return (0); 108 } 109 110 /* 111 * Create a directory 112 */ 113 struct pfs_node * 114 pfs_create_dir(struct pfs_node *parent, char *name, 115 pfs_attr_t attr, pfs_vis_t vis, int flags) 116 { 117 struct pfs_node *dir; 118 119 KASSERT(strlen(name) < PFS_NAMELEN, 120 (__FUNCTION__ "(): node name is too long")); 121 122 MALLOC(dir, struct pfs_node *, sizeof *dir, 123 M_PFSNODES, M_WAITOK|M_ZERO); 124 strcpy(dir->pn_name, name); 125 dir->pn_type = (flags & PFS_PROCDEP) ? pfstype_procdir : pfstype_dir; 126 dir->pn_attr = attr; 127 dir->pn_vis = vis; 128 dir->pn_flags = flags & ~PFS_PROCDEP; 129 130 if (_pfs_add_node(parent, dir) != 0) { 131 FREE(dir, M_PFSNODES); 132 return (NULL); 133 } 134 135 if (_pfs_fixup_dir(dir) != 0) { 136 pfs_destroy(dir); 137 return (NULL); 138 } 139 140 return (dir); 141 } 142 143 /* 144 * Create a file 145 */ 146 struct pfs_node * 147 pfs_create_file(struct pfs_node *parent, char *name, pfs_fill_t fill, 148 pfs_attr_t attr, pfs_vis_t vis, int flags) 149 { 150 struct pfs_node *node; 151 152 KASSERT(strlen(name) < PFS_NAMELEN, 153 (__FUNCTION__ "(): node name is too long")); 154 155 MALLOC(node, struct pfs_node *, sizeof *node, 156 M_PFSNODES, M_WAITOK|M_ZERO); 157 strcpy(node->pn_name, name); 158 node->pn_type = pfstype_file; 159 node->pn_func = fill; 160 node->pn_attr = attr; 161 node->pn_vis = vis; 162 node->pn_flags = flags; 163 164 if (_pfs_add_node(parent, node) != 0) { 165 FREE(node, M_PFSNODES); 166 return (NULL); 167 } 168 169 return (node); 170 } 171 172 /* 173 * Create a symlink 174 */ 175 struct pfs_node * 176 pfs_create_link(struct pfs_node *parent, char *name, pfs_fill_t fill, 177 pfs_attr_t attr, pfs_vis_t vis, int flags) 178 { 179 struct pfs_node *node; 180 181 node = pfs_create_file(parent, name, fill, attr, vis, flags); 182 if (node == NULL) 183 return (NULL); 184 node->pn_type = pfstype_symlink; 185 return (node); 186 } 187 188 /* 189 * Destroy a node or a tree of nodes 190 */ 191 int 192 pfs_destroy(struct pfs_node *node) 193 { 194 struct pfs_node *parent, *rover; 195 196 KASSERT(node != NULL, 197 (__FUNCTION__ "(): node is NULL")); 198 KASSERT(node->pn_info != NULL, 199 (__FUNCTION__ "(): node has no pn_info")); 200 201 /* destroy children */ 202 if (node->pn_type == pfstype_dir || 203 node->pn_type == pfstype_procdir || 204 node->pn_type == pfstype_root) 205 while (node->pn_nodes != NULL) 206 pfs_destroy(node->pn_nodes); 207 208 /* unlink from parent */ 209 if ((parent = node->pn_parent) != NULL) { 210 KASSERT(parent->pn_info == node->pn_info, 211 (__FUNCTION__ "(): parent has different pn_info")); 212 mtx_lock(&node->pn_info->pi_mutex); 213 if (parent->pn_nodes == node) { 214 parent->pn_nodes = node->pn_next; 215 } else { 216 rover = parent->pn_nodes; 217 while (rover->pn_next != NULL) { 218 if (rover->pn_next == node) { 219 rover->pn_next = node->pn_next; 220 break; 221 } 222 rover = rover->pn_next; 223 } 224 } 225 mtx_unlock(&node->pn_info->pi_mutex); 226 } 227 228 /* revoke vnodes and release memory */ 229 pfs_disable(node); 230 FREE(node, M_PFSNODES); 231 232 return (0); 233 } 234 235 /* 236 * Mount a pseudofs instance 237 */ 238 int 239 pfs_mount(struct pfs_info *pi, struct mount *mp, char *path, caddr_t data, 240 struct nameidata *ndp, struct thread *td) 241 { 242 struct statfs *sbp; 243 244 if (mp->mnt_flag & MNT_UPDATE) 245 return (EOPNOTSUPP); 246 247 mp->mnt_flag |= MNT_LOCAL; 248 mp->mnt_data = (qaddr_t)pi; 249 vfs_getnewfsid(mp); 250 251 sbp = &mp->mnt_stat; 252 bcopy(pi->pi_name, sbp->f_mntfromname, sizeof pi->pi_name); 253 sbp->f_bsize = PAGE_SIZE; 254 sbp->f_iosize = PAGE_SIZE; 255 sbp->f_blocks = 1; 256 sbp->f_bfree = 0; 257 sbp->f_bavail = 0; 258 sbp->f_files = 1; 259 sbp->f_ffree = 0; 260 261 return (0); 262 } 263 264 /* 265 * Unmount a pseudofs instance 266 */ 267 int 268 pfs_unmount(struct mount *mp, int mntflags, struct thread *td) 269 { 270 struct pfs_info *pi; 271 int error; 272 273 pi = (struct pfs_info *)mp->mnt_data; 274 275 /* XXX do stuff with pi... */ 276 277 error = vflush(mp, 0, (mntflags & MNT_FORCE) ? FORCECLOSE : 0); 278 return (error); 279 } 280 281 /* 282 * Return a root vnode 283 */ 284 int 285 pfs_root(struct mount *mp, struct vnode **vpp) 286 { 287 struct pfs_info *pi; 288 289 pi = (struct pfs_info *)mp->mnt_data; 290 return pfs_vncache_alloc(mp, vpp, pi->pi_root, NO_PID); 291 } 292 293 /* 294 * Return filesystem stats 295 */ 296 int 297 pfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td) 298 { 299 bcopy(&mp->mnt_stat, sbp, sizeof *sbp); 300 return (0); 301 } 302 303 /* 304 * Initialize a pseudofs instance 305 */ 306 int 307 pfs_init(struct pfs_info *pi, struct vfsconf *vfc) 308 { 309 struct pfs_node *root; 310 int error; 311 312 mtx_init(&pi->pi_mutex, "pseudofs", MTX_DEF); 313 314 /* set up the root diretory */ 315 MALLOC(root, struct pfs_node *, sizeof *root, 316 M_PFSNODES, M_WAITOK|M_ZERO); 317 root->pn_type = pfstype_root; 318 root->pn_name[0] = '/'; 319 root->pn_info = pi; 320 if (_pfs_fixup_dir(root) != 0) { 321 FREE(root, M_PFSNODES); 322 return (ENODEV); /* XXX not really the right errno */ 323 } 324 pi->pi_root = root; 325 326 /* construct file hierarchy */ 327 error = (pi->pi_init)(pi, vfc); 328 if (error) { 329 pfs_destroy(root); 330 pi->pi_root = NULL; 331 mtx_destroy(&pi->pi_mutex); 332 return (error); 333 } 334 335 pfs_fileno_init(pi); 336 if (bootverbose) 337 printf("%s registered\n", pi->pi_name); 338 return (0); 339 } 340 341 /* 342 * Destroy a pseudofs instance 343 */ 344 int 345 pfs_uninit(struct pfs_info *pi, struct vfsconf *vfc) 346 { 347 int error; 348 349 pfs_fileno_uninit(pi); 350 pfs_destroy(pi->pi_root); 351 pi->pi_root = NULL; 352 mtx_destroy(&pi->pi_mutex); 353 if (bootverbose) 354 printf("%s unregistered\n", pi->pi_name); 355 error = (pi->pi_uninit)(pi, vfc); 356 return (error); 357 } 358 359 /* 360 * Handle load / unload events 361 */ 362 static int 363 pfs_modevent(module_t mod, int evt, void *arg) 364 { 365 switch (evt) { 366 case MOD_LOAD: 367 pfs_fileno_load(); 368 pfs_vncache_load(); 369 break; 370 case MOD_UNLOAD: 371 case MOD_SHUTDOWN: 372 pfs_vncache_unload(); 373 pfs_fileno_unload(); 374 break; 375 default: 376 printf("pseudofs: unexpected event type %d\n", evt); 377 break; 378 } 379 return 0; 380 } 381 382 /* 383 * Module declaration 384 */ 385 static moduledata_t pseudofs_data = { 386 "pseudofs", 387 pfs_modevent, 388 NULL 389 }; 390 DECLARE_MODULE(pseudofs, pseudofs_data, SI_SUB_EXEC, SI_ORDER_FIRST); 391 MODULE_VERSION(pseudofs, 3); 392