1/* 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* Copyright (c) 1998 Apple Computer, Inc. All Rights Reserved */ 29/* 30 * Change History: 31 * 32 * 17-Aug-1999 Pat Dirks New today. 33 * 34 */ 35 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/namei.h> 39#include <sys/filedesc.h> 40#include <sys/proc_internal.h> 41#include <sys/kernel.h> 42#include <mach/machine/vm_types.h> 43#include <sys/vnode_internal.h> 44#include <sys/socket.h> 45#include <sys/mount_internal.h> 46#include <sys/mbuf.h> 47#include <sys/file.h> 48#include <sys/disk.h> 49#include <sys/ioctl.h> 50#include <sys/errno.h> 51#include <sys/malloc.h> 52#include <sys/attr.h> 53#include <sys/uio_internal.h> 54 55#include <miscfs/specfs/specdev.h> 56 57#include "synthfs.h" 58 59#define LOADABLE_FS 0 60 61typedef int (*PFI)(); 62 63struct vfsops synthfs_vfsops = { 64 synthfs_mount, 65 synthfs_start, 66 synthfs_unmount, 67 synthfs_root, 68 NULL, /* quotactl */ 69 synthfs_vfs_getattr, 70 synthfs_sync, 71 synthfs_vget, 72 synthfs_fhtovp, 73 synthfs_vptofh, 74 synthfs_init, 75 synthfs_sysctl 76}; 77 78#define ROOTMPMODE 0755 79#define ROOTPLACEHOLDERMODE 0700 80static char synthfs_fs_name[MFSTYPENAMELEN] = "synthfs"; 81static char synthfs_fake_mntfromname[] = "<synthfs>"; 82 83 84extern struct vnodeopv_desc synthfs_vnodeop_opv_desc; 85 86/* The following refer to kernel global variables used in the loading/initialization: */ 87extern int maxvfsslots; /* Total number of slots in the system's vfsconf table */ 88extern int maxvfsconf; /* The highest fs type number [old-style ID] in use [dispite its name] */ 89extern int vfs_opv_numops; /* The total number of defined vnode operations */ 90 91int vn_mkdir(struct proc *p, char *path, int mode); 92int vn_symlink(struct proc *p, char *path, char *link); 93 94 95 96 97#if LOADABLE_FS 98void 99synthfs_load(int loadArgument) { 100 /* Should use vfs_fsadd kpi */ 101} 102 103 104 105int synthfs_unload(void) { 106 107 /* should use fs_fsremove kpi */ 108 return 0; 109} 110#endif 111 112 113 114/* 115 * VFS Operations. 116 * 117 * mount system call 118 */ 119int 120synthfs_mount_fs(struct mount *mp, vnode_t devvp, __unused user_addr_t data, struct proc *p) 121{ 122 struct synthfs_mntdata *priv_mnt_data; 123 int error; 124 size_t size; 125 126 DBG_VOP(("synthfs_mount_fs called.\n")); 127 MALLOC(priv_mnt_data, struct synthfs_mntdata *, sizeof(struct synthfs_mntdata), M_SYNTHFS, M_WAITOK); 128 DBG_VOP(("MALLOC succeeded...\n")); 129 130 strlcpy(mp->mnt_vfsstat.f_fstypename, synthfs_fs_name, sizeof(mp->mnt_vfsstat.f_fstypename)); 131 strlcpy(mp->mnt_vfsstat.f_mntfromname, synthfs_fake_mntfromname, sizeof(mp->mnt_vfsstat.f_mntfromname)); 132 priv_mnt_data->synthfs_mounteddev = (dev_t)0; 133 priv_mnt_data->synthfs_nextid = FIRST_SYNTHFS_ID; 134 priv_mnt_data->synthfs_filecount = 0; 135 priv_mnt_data->synthfs_dircount = 0; 136 priv_mnt_data->synthfs_encodingsused = 0x00000001; 137 138 /* 139 Set up the root vnode for fast reference in the future. 140 Note that synthfs_new_directory() returns the vnode with a refcount of +2. 141 The root vnode's refcount is maintained unlocked but with a pos. ref count until unmount. 142 */ 143 error = synthfs_new_directory(mp, NULL, "", ROOT_DIRID, (S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH), p, &priv_mnt_data->synthfs_rootvp); 144 if (error) { 145 DBG_VOP(("Attempt to create root directory failed with error %d.\n", error)); 146 return error; 147 }; 148 priv_mnt_data->synthfs_rootvp->v_flag |= VROOT; 149 150 priv_mnt_data->synthfs_mp = mp; 151 mp->mnt_data = (void *)priv_mnt_data; 152 153 /* Drop the freshly acquired reference on the root, leaving v_usecount=1 to prevent 154 the vnode from beeing freed: */ 155 vnode_put(priv_mnt_data->synthfs_rootvp); 156 157 return (0); 158} 159 160 161 162int 163synthfs_mount(mp, devvp, data, context) 164 register struct mount *mp; 165 vnode_t devvp; 166 user_addr_t data; 167 vfs_context_t context; 168{ 169 size_t size; 170 171 return (synthfs_mount_fs(mp, devvp, data, vfs_context_proc(context))); 172} 173 174 175 176 177 178 179/* 180 * Initialize the filesystem 181 */ 182int 183synthfs_init(vfsp) 184 struct vfsconf *vfsp; 185{ 186 DBG_VOP(("synthfs_init called.\n")); 187 return 0; 188} 189 190int 191synthfs_start(mp, flags, context) 192struct mount * mp; 193int flags; 194vfs_context_t context; 195{ 196 DBG_VOP(("synthfs_start called.\n")); 197 return 0; 198} 199 200/* 201 * Return the root of a filesystem. 202 */ 203int 204synthfs_root(mp, vpp, context) 205 struct mount *mp; 206 struct vnode **vpp; 207 vfs_context_t context; 208{ 209 unsigned long root_nodeid = ROOT_DIRID; 210 211 DBG_VOP(("synthfs_root called.\n")); 212 213 *vpp = VFSTOSFS(mp)->synthfs_rootvp; 214 return vnode_get(VFSTOSFS(mp)->synthfs_rootvp); 215} 216 217/* 218 * unmount system call 219 */ 220int 221synthfs_unmount(mp, mntflags, context) 222 struct mount *mp; 223 int mntflags; 224 vfs_context_t context; 225{ 226 struct synthfs_mntdata *synth; 227 struct vnode *root_vp; 228 int retval; 229 230 DBG_VOP(("synthfs_unmount called.\n")); 231 synth = (struct synthfs_mntdata *)mp->mnt_data; 232 233 root_vp = synth->synthfs_rootvp; 234 retval = vflush(mp, root_vp, (mntflags & MNT_FORCE) ? FORCECLOSE : 0); 235 if (retval && ((mntflags & MNT_FORCE) == 0)) goto Err_Exit; 236 237 /* Free the root vnode. 238 the ref. count has been maintained at +1 ever since mount time. */ 239 if (root_vp) { 240 if ((mntflags & MNT_FORCE) == 0) { 241 if (retval) goto Err_Exit; 242 243 if (root_vp->v_usecount > 1) { 244 DBG_VOP(("synthfs ERROR: root vnode = %x, usecount = %d\n", (int)root_vp, synth->synthfs_rootvp->v_usecount)); 245 retval = EBUSY; 246 goto Err_Exit; 247 }; 248 }; 249 250 synth->synthfs_rootvp = NULL; 251 252 if (retval == 0) { 253 vnode_get(root_vp); 254 vnode_rele(root_vp); 255 vnode_recycle(root_vp); 256 vnode_put(root_vp); /* This drops synthfs's own refcount */ 257 }; 258 }; 259 260 /* All vnodes should be gone, and no errors, clean up the last */ 261 262 mp->mnt_data = NULL; 263 FREE(synth, M_SYNTHFS); 264 265Err_Exit: 266 267 if (mntflags & MNT_FORCE) retval = 0; 268 269 return(retval); 270} 271 272/* 273 * Get file system statistics. 274 */ 275int 276synthfs_vfs_getattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t context) 277{ 278 struct synthfs_mntdata *synthfs_mp = VFSTOSFS(mp); 279 DBG_VOP(("synthfs_vfs_getattr called.\n")); 280 281 VFSATTR_RETURN(fsap, f_bsize, 512); 282 VFSATTR_RETURN(fsap, f_iosize, 512); 283 VFSATTR_RETURN(fsap, f_blocks, 1024); 284 VFSATTR_RETURN(fsap, f_bfree, 0); 285 VFSATTR_RETURN(fsap, f_bavail, 0); 286 VFSATTR_RETURN(fsap, f_bused, 1024); 287 VFSATTR_RETURN(fsap, f_files, synthfs_mp->synthfs_filecount + synthfs_mp->synthfs_dircount); 288 VFSATTR_RETURN(fsap, f_ffree, 0); 289 VFSATTR_RETURN(fsap, f_fssubtype, 0); 290 291 return 0; 292} 293 294/* 295 * synthfs doesn't have any data or backing store and you can't write into any of the synthfs 296 * structures, so don't do anything 297 */ 298int 299synthfs_sync(mp, waitfor, context) 300 struct mount *mp; 301 int waitfor; 302 vfs_context_t context; 303{ 304// DBG_VOP(("synthfs_sync called\n")); 305 return 0; 306} 307/* 308 * Look up a synthfs node by node number. 309 */ 310int 311synthfs_vget(mp, ino, vpp, context) 312 struct mount *mp; 313 ino64_t ino; 314 struct vnode **vpp; 315 vfs_context_t context; 316{ 317 struct vnode *vp; 318 int vid = 0; 319 320// DBG_VOP(("synthfs_vget called\n")); 321 322 /* Check for unmount in progress */ 323 if (mp->mnt_kern_flag & MNTK_UNMOUNT) { 324 *vpp = NULL; 325 return (EPERM); 326 } 327 328loop: 329 TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) { 330 if (VTOS(vp)->s_nodeid == (unsigned long)ino) { 331 /* 332 * doing a vnode_getwithvid isn't technically 333 * necessary since synthfs is an unsafe filesystem 334 * and we're running behind a funnel at this point 335 * however, vnode_get always succeeds, which isn't 336 * what we want if this vnode is in the process of 337 * being terminated 338 */ 339 vid = vnode_vid(vp); 340 341 if (vnode_getwithvid(vp, vid) != 0) { 342 goto loop; 343 }; 344 *vpp = vp; 345 return 0; 346 }; 347 }; 348 *vpp = NULL; 349 return -1; 350} 351 352/* 353 * fast filesystem related variables. 354 */ 355int 356synthfs_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp, 357 user_addr_t newp, size_t newlen, vfs_context_t context) 358{ 359 DBG_VOP(("synthfs_sysctl called.\n")); 360 return (ENOTSUP); 361} 362 363/* 364 * File handle to vnode 365 * 366 */ 367int 368synthfs_fhtovp(mp, fhlen, fhp, vpp, context) 369 register struct mount *mp; 370 int fhlen; 371 unsigned char *fhp; 372 struct vnode **vpp; 373 vfs_context_t context; 374{ 375 DBG_VOP(("synthfs_fhtovp called.\n")); 376 return ENOTSUP; 377} 378 379/* 380 * Vnode pointer to File handle 381 */ 382/* ARGSUSED */ 383int 384synthfs_vptofh(vp, fhlenp, fhp, context) 385 struct vnode *vp; 386 int *fhlenp; 387 unsigned char *fhp; 388 vfs_context_t context; 389{ 390 DBG_VOP(("synthfs_vptofh called.\n")); 391 return ENOTSUP; 392} 393 394 395 396 397 398 399int 400vn_mkdir(struct proc *p, char *path, int mode) 401{ 402 struct nameidata nd; 403 struct vnode *vp; 404 struct vnode_attr va; 405 vfs_context_t ctx = vfs_context_kernel(); 406 int error; 407 408 409 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE32, CAST_USER_ADDR_T(path), ctx); 410 error = namei(&nd); 411 if (error) { 412 DBG_VOP(("vn_mkdir: error from namei, error = %d.\n", error)); 413 return (error); 414 }; 415 vp = nd.ni_vp; 416 417 if (vp == NULL) { 418 VATTR_INIT(&va); 419 VATTR_SET(&va, va_type, VDIR); 420 VATTR_SET(&va, va_mode, (mode & ACCESSPERMS) &~ p->p_fd->fd_cmask); 421 422 error = vn_create(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, 0, ctx); 423 if (error) 424 DBG_VOP(("vn_mkdir: error from vnop_mkdir (%d).\n", error)); 425 } else { 426 DBG_VOP(("vn_mkdir: target already exists; returning EEXIST.\n")); 427 error = EEXIST; 428 } 429 vnode_put(nd.ni_dvp); 430 if (nd.ni_vp) 431 vnode_put(nd.ni_vp); 432 nameidone(&nd); 433 434 return (error); 435} 436 437 438 439int 440vn_symlink(struct proc *p, char *path, char *link) { 441 struct nameidata nd; 442 struct vnode_attr va; 443 vfs_context_t ctx = vfs_context_kernel(); 444 int error; 445 446 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE32, CAST_USER_ADDR_T(link), ctx); 447 if ((error = namei(&nd))) { 448 return error; 449 } 450 451 if (nd.ni_vp == NULL) { 452 VATTR_INIT(&va); 453 VATTR_SET(&va, va_type, VLNK); 454 VATTR_SET(&va, va_mode, ACCESSPERMS &~ p->p_fd->fd_cmask); 455 456 error = VNOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, path, ctx); 457 } else 458 error = EEXIST; 459 460 vnode_put(nd.ni_dvp); 461 if (nd.ni_vp) 462 vnode_put(nd.ni_vp); 463 nameidone(&nd); 464 465 return (error); 466} 467 468 469