1*ccb670c8Sjmmv /* $NetBSD: tmpfs_vnops.c,v 1.32 2006/11/09 15:36:30 jmmv Exp $ */ 2ec933656Sjmmv 3ec933656Sjmmv /* 4064fbe7eSjmmv * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc. 5ec933656Sjmmv * All rights reserved. 6ec933656Sjmmv * 7ec933656Sjmmv * This code is derived from software contributed to The NetBSD Foundation 8b0085cabSjmmv * by Julio M. Merino Vidal, developed as part of Google's Summer of Code 9b0085cabSjmmv * 2005 program. 10ec933656Sjmmv * 11ec933656Sjmmv * Redistribution and use in source and binary forms, with or without 12ec933656Sjmmv * modification, are permitted provided that the following conditions 13ec933656Sjmmv * are met: 14ec933656Sjmmv * 1. Redistributions of source code must retain the above copyright 15ec933656Sjmmv * notice, this list of conditions and the following disclaimer. 16ec933656Sjmmv * 2. Redistributions in binary form must reproduce the above copyright 17ec933656Sjmmv * notice, this list of conditions and the following disclaimer in the 18ec933656Sjmmv * documentation and/or other materials provided with the distribution. 19ec933656Sjmmv * 3. All advertising materials mentioning features or use of this software 20ec933656Sjmmv * must display the following acknowledgement: 21ec933656Sjmmv * This product includes software developed by the NetBSD 22ec933656Sjmmv * Foundation, Inc. and its contributors. 23ec933656Sjmmv * 4. Neither the name of The NetBSD Foundation nor the names of its 24ec933656Sjmmv * contributors may be used to endorse or promote products derived 25ec933656Sjmmv * from this software without specific prior written permission. 26ec933656Sjmmv * 27ec933656Sjmmv * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28ec933656Sjmmv * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29ec933656Sjmmv * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30ec933656Sjmmv * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31ec933656Sjmmv * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32ec933656Sjmmv * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33ec933656Sjmmv * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34ec933656Sjmmv * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35ec933656Sjmmv * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36ec933656Sjmmv * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37ec933656Sjmmv * POSSIBILITY OF SUCH DAMAGE. 38ec933656Sjmmv */ 39ec933656Sjmmv 40ec933656Sjmmv /* 41ec933656Sjmmv * tmpfs vnode interface. 42ec933656Sjmmv */ 43ec933656Sjmmv 44ec933656Sjmmv #include <sys/cdefs.h> 45*ccb670c8Sjmmv __KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.32 2006/11/09 15:36:30 jmmv Exp $"); 46ec933656Sjmmv 47ec933656Sjmmv #include <sys/param.h> 48ec933656Sjmmv #include <sys/dirent.h> 49ec933656Sjmmv #include <sys/fcntl.h> 50ec933656Sjmmv #include <sys/event.h> 51ec933656Sjmmv #include <sys/malloc.h> 52ec933656Sjmmv #include <sys/namei.h> 53ec933656Sjmmv #include <sys/proc.h> 54ec933656Sjmmv #include <sys/stat.h> 55ec933656Sjmmv #include <sys/uio.h> 56ec933656Sjmmv #include <sys/unistd.h> 57ec933656Sjmmv #include <sys/vnode.h> 58b6d141c7Sjmmv #include <sys/lockf.h> 59fc6d984bSchristos #include <sys/kauth.h> 60ec933656Sjmmv 61ec933656Sjmmv #include <uvm/uvm.h> 62ec933656Sjmmv 63ec933656Sjmmv #include <miscfs/fifofs/fifo.h> 64ec933656Sjmmv #include <fs/tmpfs/tmpfs_vnops.h> 65ec933656Sjmmv #include <fs/tmpfs/tmpfs.h> 66ec933656Sjmmv 67ec933656Sjmmv /* --------------------------------------------------------------------- */ 68ec933656Sjmmv 69ec933656Sjmmv /* 708e0a777aSjmmv * vnode operations vector used for files stored in a tmpfs file system. 71ec933656Sjmmv */ 72ec933656Sjmmv int (**tmpfs_vnodeop_p)(void *); 73ec933656Sjmmv const struct vnodeopv_entry_desc tmpfs_vnodeop_entries[] = { 74ec933656Sjmmv { &vop_default_desc, vn_default_error }, 75ec933656Sjmmv { &vop_lookup_desc, tmpfs_lookup }, 76ec933656Sjmmv { &vop_create_desc, tmpfs_create }, 77ec933656Sjmmv { &vop_mknod_desc, tmpfs_mknod }, 78ec933656Sjmmv { &vop_open_desc, tmpfs_open }, 79ec933656Sjmmv { &vop_close_desc, tmpfs_close }, 80ec933656Sjmmv { &vop_access_desc, tmpfs_access }, 81ec933656Sjmmv { &vop_getattr_desc, tmpfs_getattr }, 82ec933656Sjmmv { &vop_setattr_desc, tmpfs_setattr }, 83ec933656Sjmmv { &vop_read_desc, tmpfs_read }, 84ec933656Sjmmv { &vop_write_desc, tmpfs_write }, 85ec933656Sjmmv { &vop_ioctl_desc, tmpfs_ioctl }, 86ec933656Sjmmv { &vop_fcntl_desc, tmpfs_fcntl }, 87ec933656Sjmmv { &vop_poll_desc, tmpfs_poll }, 88ec933656Sjmmv { &vop_kqfilter_desc, tmpfs_kqfilter }, 89ec933656Sjmmv { &vop_revoke_desc, tmpfs_revoke }, 90ec933656Sjmmv { &vop_mmap_desc, tmpfs_mmap }, 91ec933656Sjmmv { &vop_fsync_desc, tmpfs_fsync }, 92ec933656Sjmmv { &vop_seek_desc, tmpfs_seek }, 93ec933656Sjmmv { &vop_remove_desc, tmpfs_remove }, 94ec933656Sjmmv { &vop_link_desc, tmpfs_link }, 95ec933656Sjmmv { &vop_rename_desc, tmpfs_rename }, 96ec933656Sjmmv { &vop_mkdir_desc, tmpfs_mkdir }, 97ec933656Sjmmv { &vop_rmdir_desc, tmpfs_rmdir }, 98ec933656Sjmmv { &vop_symlink_desc, tmpfs_symlink }, 99ec933656Sjmmv { &vop_readdir_desc, tmpfs_readdir }, 100ec933656Sjmmv { &vop_readlink_desc, tmpfs_readlink }, 101ec933656Sjmmv { &vop_abortop_desc, tmpfs_abortop }, 102ec933656Sjmmv { &vop_inactive_desc, tmpfs_inactive }, 103ec933656Sjmmv { &vop_reclaim_desc, tmpfs_reclaim }, 104ec933656Sjmmv { &vop_lock_desc, tmpfs_lock }, 105ec933656Sjmmv { &vop_unlock_desc, tmpfs_unlock }, 106ec933656Sjmmv { &vop_bmap_desc, tmpfs_bmap }, 107ec933656Sjmmv { &vop_strategy_desc, tmpfs_strategy }, 108ec933656Sjmmv { &vop_print_desc, tmpfs_print }, 109ec933656Sjmmv { &vop_pathconf_desc, tmpfs_pathconf }, 110ec933656Sjmmv { &vop_islocked_desc, tmpfs_islocked }, 111ec933656Sjmmv { &vop_advlock_desc, tmpfs_advlock }, 112ec933656Sjmmv { &vop_lease_desc, tmpfs_lease }, 113ec933656Sjmmv { &vop_bwrite_desc, tmpfs_bwrite }, 114ec933656Sjmmv { &vop_getpages_desc, tmpfs_getpages }, 115ec933656Sjmmv { &vop_putpages_desc, tmpfs_putpages }, 116ec933656Sjmmv { NULL, NULL } 117ec933656Sjmmv }; 118ec933656Sjmmv const struct vnodeopv_desc tmpfs_vnodeop_opv_desc = 119ec933656Sjmmv { &tmpfs_vnodeop_p, tmpfs_vnodeop_entries }; 120ec933656Sjmmv 121ec933656Sjmmv /* --------------------------------------------------------------------- */ 122ec933656Sjmmv 123ec933656Sjmmv int 124ec933656Sjmmv tmpfs_lookup(void *v) 125ec933656Sjmmv { 126ec933656Sjmmv struct vnode *dvp = ((struct vop_lookup_args *)v)->a_dvp; 127ec933656Sjmmv struct vnode **vpp = ((struct vop_lookup_args *)v)->a_vpp; 128ec933656Sjmmv struct componentname *cnp = ((struct vop_lookup_args *)v)->a_cnp; 129ec933656Sjmmv 130ec933656Sjmmv int error; 131ec933656Sjmmv struct tmpfs_dirent *de; 132ec933656Sjmmv struct tmpfs_node *dnode; 133ec933656Sjmmv 134ec933656Sjmmv KASSERT(VOP_ISLOCKED(dvp)); 135ec933656Sjmmv 136ec933656Sjmmv dnode = VP_TO_TMPFS_DIR(dvp); 137ec933656Sjmmv *vpp = NULL; 138ec933656Sjmmv 139ec933656Sjmmv /* Check accessibility of requested node as a first step. */ 14095e1ffb1Schristos error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_lwp); 141ec933656Sjmmv if (error != 0) 142ec933656Sjmmv goto out; 143ec933656Sjmmv 1448e0a777aSjmmv /* If requesting the last path component on a read-only file system 145ec933656Sjmmv * with a write operation, deny it. */ 146ec933656Sjmmv if ((cnp->cn_flags & ISLASTCN) && 147ec933656Sjmmv (dvp->v_mount->mnt_flag & MNT_RDONLY) && 148ec933656Sjmmv (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 149ec933656Sjmmv error = EROFS; 150ec933656Sjmmv goto out; 151ec933656Sjmmv } 152ec933656Sjmmv 153ec933656Sjmmv /* Avoid doing a linear scan of the directory if the requested 154ec933656Sjmmv * directory/name couple is already in the cache. */ 155ec933656Sjmmv error = cache_lookup(dvp, vpp, cnp); 156ec933656Sjmmv if (error >= 0) 157ec933656Sjmmv goto out; 158ec933656Sjmmv 159ec933656Sjmmv /* We cannot be requesting the parent directory of the root node. */ 160ec933656Sjmmv KASSERT(IMPLIES(dnode->tn_type == VDIR && 161064fbe7eSjmmv dnode->tn_spec.tn_dir.tn_parent == dnode, 162064fbe7eSjmmv !(cnp->cn_flags & ISDOTDOT))); 163ec933656Sjmmv 164ec933656Sjmmv if (cnp->cn_flags & ISDOTDOT) { 165ec933656Sjmmv VOP_UNLOCK(dvp, 0); 166ec933656Sjmmv 167ec933656Sjmmv /* Allocate a new vnode on the matching entry. */ 168064fbe7eSjmmv error = tmpfs_alloc_vp(dvp->v_mount, 169064fbe7eSjmmv dnode->tn_spec.tn_dir.tn_parent, vpp); 170ec933656Sjmmv 171ec933656Sjmmv if (cnp->cn_flags & LOCKPARENT && 172ec933656Sjmmv cnp->cn_flags & ISLASTCN) { 173ec933656Sjmmv if (vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY) != 0) 174ec933656Sjmmv cnp->cn_flags |= PDIRUNLOCK; 175ec933656Sjmmv } 176064fbe7eSjmmv dnode->tn_spec.tn_dir.tn_parent->tn_lookup_dirent = NULL; 177ec933656Sjmmv } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { 178ec933656Sjmmv VREF(dvp); 179ec933656Sjmmv *vpp = dvp; 180ec933656Sjmmv dnode->tn_lookup_dirent = NULL; 181ec933656Sjmmv error = 0; 182ec933656Sjmmv } else { 183ec933656Sjmmv de = tmpfs_dir_lookup(dnode, cnp); 184ec933656Sjmmv if (de == NULL) { 185ec933656Sjmmv /* The entry was not found in the directory. 186ec933656Sjmmv * This is OK iff we are creating or renaming an 187ec933656Sjmmv * entry and are working on the last component of 188ec933656Sjmmv * the path name. */ 189ec933656Sjmmv if ((cnp->cn_flags & ISLASTCN) && 190ec933656Sjmmv (cnp->cn_nameiop == CREATE || \ 191ec933656Sjmmv cnp->cn_nameiop == RENAME)) { 192ec933656Sjmmv error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, 19395e1ffb1Schristos cnp->cn_lwp); 194ec933656Sjmmv if (error != 0) 195ec933656Sjmmv goto out; 196ec933656Sjmmv 197ec933656Sjmmv /* Keep the component name in the buffer for 198ec933656Sjmmv * future uses. */ 199ec933656Sjmmv cnp->cn_flags |= SAVENAME; 200ec933656Sjmmv 201ec933656Sjmmv error = EJUSTRETURN; 202ec933656Sjmmv } else 203ec933656Sjmmv error = ENOENT; 204ec933656Sjmmv } else { 205ec933656Sjmmv struct tmpfs_node *tnode; 206ec933656Sjmmv 207ec933656Sjmmv /* The entry was found, so get its associated 208ec933656Sjmmv * tmpfs_node. */ 209ec933656Sjmmv tnode = de->td_node; 210ec933656Sjmmv 211ec933656Sjmmv /* If we are not at the last path component and 212ab7e099bSjmmv * found a non-directory or non-link entry (which 213ab7e099bSjmmv * may itself be pointing to a directory), raise 214ab7e099bSjmmv * an error. */ 215ab7e099bSjmmv if ((tnode->tn_type != VDIR && 216ab7e099bSjmmv tnode->tn_type != VLNK) && 217ec933656Sjmmv !(cnp->cn_flags & ISLASTCN)) { 218ec933656Sjmmv error = ENOTDIR; 219ec933656Sjmmv goto out; 220ec933656Sjmmv } 221ec933656Sjmmv 222ec933656Sjmmv /* If we are deleting or renaming the entry, keep 223ec933656Sjmmv * track of its tmpfs_dirent so that it can be 224ec933656Sjmmv * easily deleted later. */ 225ec933656Sjmmv if ((cnp->cn_flags & ISLASTCN) && 226ec933656Sjmmv (cnp->cn_nameiop == DELETE || 227ec933656Sjmmv cnp->cn_nameiop == RENAME)) { 22861315901Schristos if ((dnode->tn_mode & S_ISTXT) != 0 && 229fc9422c9Selad kauth_cred_geteuid(cnp->cn_cred) != 0 && 230fc9422c9Selad kauth_cred_geteuid(cnp->cn_cred) != dnode->tn_uid && 231fc9422c9Selad kauth_cred_geteuid(cnp->cn_cred) != tnode->tn_uid) 23261315901Schristos return EPERM; 233ec933656Sjmmv error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, 23495e1ffb1Schristos cnp->cn_lwp); 235ec933656Sjmmv if (error != 0) 236ec933656Sjmmv goto out; 237ec933656Sjmmv tnode->tn_lookup_dirent = de; 238ec933656Sjmmv } 239ec933656Sjmmv 240ec933656Sjmmv /* Allocate a new vnode on the matching entry. */ 241ec933656Sjmmv error = tmpfs_alloc_vp(dvp->v_mount, tnode, vpp); 242ec933656Sjmmv 243ec933656Sjmmv if (error == 0 && (!(cnp->cn_flags & LOCKPARENT) || 244ec933656Sjmmv !(cnp->cn_flags & ISLASTCN))) 245ec933656Sjmmv VOP_UNLOCK(dvp, 0); 246ec933656Sjmmv } 247ec933656Sjmmv } 248ec933656Sjmmv 249ec933656Sjmmv /* Store the result of this lookup in the cache. Avoid this if the 250ec933656Sjmmv * request was for creation, as it does not improve timings on 251ec933656Sjmmv * emprical tests. */ 252ec933656Sjmmv if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE) 253ec933656Sjmmv cache_enter(dvp, *vpp, cnp); 254ec933656Sjmmv 255ec933656Sjmmv out: 256ec933656Sjmmv /* If there were no errors, *vpp cannot be null and it must be 257ec933656Sjmmv * locked. */ 258ec933656Sjmmv KASSERT(IFF(error == 0, *vpp != NULL && VOP_ISLOCKED(*vpp))); 259ec933656Sjmmv 260ec933656Sjmmv /* dvp has to be locked if: 261ec933656Sjmmv * - There were errors and relocking of dvp did not fail. 262ec933656Sjmmv * - We are doing a '..' lookup, relocking of dvp did not fail 263ec933656Sjmmv * (PDIRUNLOCK is unset) and LOCKPARENT or ISLASTCN are not set. 264ec933656Sjmmv * - LOCKPARENT and ISLASTCN are set. */ 265ec933656Sjmmv KASSERT(IMPLIES( 266ec933656Sjmmv (error != 0 && !(cnp->cn_flags & PDIRUNLOCK)) || 267ec933656Sjmmv (cnp->cn_flags & ISDOTDOT && !(cnp->cn_flags & PDIRUNLOCK) && 268ec933656Sjmmv ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))) || 269ec933656Sjmmv (cnp->cn_flags & LOCKPARENT && cnp->cn_flags & ISLASTCN) 270ec933656Sjmmv , 271ec933656Sjmmv VOP_ISLOCKED(dvp))); 272ec933656Sjmmv 273ec933656Sjmmv return error; 274ec933656Sjmmv } 275ec933656Sjmmv 276ec933656Sjmmv /* --------------------------------------------------------------------- */ 277ec933656Sjmmv 278ec933656Sjmmv int 279ec933656Sjmmv tmpfs_create(void *v) 280ec933656Sjmmv { 281ec933656Sjmmv struct vnode *dvp = ((struct vop_create_args *)v)->a_dvp; 282ec933656Sjmmv struct vnode **vpp = ((struct vop_create_args *)v)->a_vpp; 283ec933656Sjmmv struct componentname *cnp = ((struct vop_create_args *)v)->a_cnp; 284ec933656Sjmmv struct vattr *vap = ((struct vop_create_args *)v)->a_vap; 285ec933656Sjmmv 286ec933656Sjmmv KASSERT(vap->va_type == VREG || vap->va_type == VSOCK); 287ec933656Sjmmv 288ec933656Sjmmv return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL); 289ec933656Sjmmv } 290ec933656Sjmmv /* --------------------------------------------------------------------- */ 291ec933656Sjmmv 292ec933656Sjmmv int 293ec933656Sjmmv tmpfs_mknod(void *v) 294ec933656Sjmmv { 295ec933656Sjmmv struct vnode *dvp = ((struct vop_mknod_args *)v)->a_dvp; 296ec933656Sjmmv struct vnode **vpp = ((struct vop_mknod_args *)v)->a_vpp; 297ec933656Sjmmv struct componentname *cnp = ((struct vop_mknod_args *)v)->a_cnp; 298ec933656Sjmmv struct vattr *vap = ((struct vop_mknod_args *)v)->a_vap; 299ec933656Sjmmv 300ec933656Sjmmv if (vap->va_type != VBLK && vap->va_type != VCHR && 301ec933656Sjmmv vap->va_type != VFIFO) 302ec933656Sjmmv return EINVAL; 303ec933656Sjmmv 304ec933656Sjmmv return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL); 305ec933656Sjmmv } 306ec933656Sjmmv 307ec933656Sjmmv /* --------------------------------------------------------------------- */ 308ec933656Sjmmv 309ec933656Sjmmv int 310ec933656Sjmmv tmpfs_open(void *v) 311ec933656Sjmmv { 312ec933656Sjmmv struct vnode *vp = ((struct vop_open_args *)v)->a_vp; 313ec933656Sjmmv int mode = ((struct vop_open_args *)v)->a_mode; 314ec933656Sjmmv 315ec933656Sjmmv int error; 316ec933656Sjmmv struct tmpfs_node *node; 317ec933656Sjmmv 318ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 319ec933656Sjmmv 320ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 321ec933656Sjmmv 322*ccb670c8Sjmmv /* The file is still active but all its names have been removed 323*ccb670c8Sjmmv * (e.g. by a "rmdir $(pwd)"). It cannot be opened any more as 324*ccb670c8Sjmmv * it is about to die. */ 325*ccb670c8Sjmmv if (node->tn_links < 1) { 326*ccb670c8Sjmmv error = ENOENT; 327*ccb670c8Sjmmv goto out; 328*ccb670c8Sjmmv } 329*ccb670c8Sjmmv 330ec933656Sjmmv /* If the file is marked append-only, deny write requests. */ 331ec933656Sjmmv if (node->tn_flags & APPEND && (mode & (FWRITE | O_APPEND)) == FWRITE) 332ec933656Sjmmv error = EPERM; 333ec933656Sjmmv else 334ec933656Sjmmv error = 0; 335ec933656Sjmmv 336*ccb670c8Sjmmv out: 337ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 338ec933656Sjmmv 339ec933656Sjmmv return error; 340ec933656Sjmmv } 341ec933656Sjmmv 342ec933656Sjmmv /* --------------------------------------------------------------------- */ 343ec933656Sjmmv 344ec933656Sjmmv int 345ec933656Sjmmv tmpfs_close(void *v) 346ec933656Sjmmv { 347ec933656Sjmmv struct vnode *vp = ((struct vop_close_args *)v)->a_vp; 348ec933656Sjmmv 349ec933656Sjmmv struct tmpfs_node *node; 350ec933656Sjmmv 351ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 352ec933656Sjmmv 353ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 354ec933656Sjmmv 355ec933656Sjmmv if (node->tn_links > 0) { 356ec933656Sjmmv /* Update node times. No need to do it if the node has 357ec933656Sjmmv * been deleted, because it will vanish after we return. */ 358a748ea88Syamt tmpfs_update(vp, NULL, NULL, UPDATE_CLOSE); 359a748ea88Syamt } 360ec933656Sjmmv 361a748ea88Syamt return 0; 362ec933656Sjmmv } 363ec933656Sjmmv 364ec933656Sjmmv /* --------------------------------------------------------------------- */ 365ec933656Sjmmv 366ec933656Sjmmv int 367ec933656Sjmmv tmpfs_access(void *v) 368ec933656Sjmmv { 369ec933656Sjmmv struct vnode *vp = ((struct vop_access_args *)v)->a_vp; 370ec933656Sjmmv int mode = ((struct vop_access_args *)v)->a_mode; 371fc9422c9Selad kauth_cred_t cred = ((struct vop_access_args *)v)->a_cred; 372ec933656Sjmmv 373ec933656Sjmmv int error; 374ec933656Sjmmv struct tmpfs_node *node; 375ec933656Sjmmv 376ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 377ec933656Sjmmv 378ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 379ec933656Sjmmv 380ec933656Sjmmv switch (vp->v_type) { 381ec933656Sjmmv case VDIR: 382ec933656Sjmmv /* FALLTHROUGH */ 383ec933656Sjmmv case VLNK: 384ec933656Sjmmv /* FALLTHROUGH */ 385ec933656Sjmmv case VREG: 386ec933656Sjmmv if (mode & VWRITE && vp->v_mount->mnt_flag & MNT_RDONLY) { 387ec933656Sjmmv error = EROFS; 388ec933656Sjmmv goto out; 389ec933656Sjmmv } 390ec933656Sjmmv break; 391ec933656Sjmmv 392ec933656Sjmmv case VBLK: 393ec933656Sjmmv /* FALLTHROUGH */ 394ec933656Sjmmv case VCHR: 395ec933656Sjmmv /* FALLTHROUGH */ 396ec933656Sjmmv case VSOCK: 397ec933656Sjmmv /* FALLTHROUGH */ 398ec933656Sjmmv case VFIFO: 399ec933656Sjmmv break; 400ec933656Sjmmv 401ec933656Sjmmv default: 402ec933656Sjmmv error = EINVAL; 403ec933656Sjmmv goto out; 404ec933656Sjmmv } 405ec933656Sjmmv 406ec933656Sjmmv if (mode & VWRITE && node->tn_flags & IMMUTABLE) { 407ec933656Sjmmv error = EPERM; 408ec933656Sjmmv goto out; 409ec933656Sjmmv } 410ec933656Sjmmv 411ec933656Sjmmv error = vaccess(vp->v_type, node->tn_mode, node->tn_uid, 412ec933656Sjmmv node->tn_gid, mode, cred); 413ec933656Sjmmv 414ec933656Sjmmv out: 415ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 416ec933656Sjmmv 417ec933656Sjmmv return error; 418ec933656Sjmmv } 419ec933656Sjmmv 420ec933656Sjmmv /* --------------------------------------------------------------------- */ 421ec933656Sjmmv 422ec933656Sjmmv int 423ec933656Sjmmv tmpfs_getattr(void *v) 424ec933656Sjmmv { 425ec933656Sjmmv struct vnode *vp = ((struct vop_getattr_args *)v)->a_vp; 426ec933656Sjmmv struct vattr *vap = ((struct vop_getattr_args *)v)->a_vap; 427ec933656Sjmmv 428ec933656Sjmmv struct tmpfs_node *node; 429ec933656Sjmmv 430ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 431ec933656Sjmmv 432ec933656Sjmmv VATTR_NULL(vap); 433ec933656Sjmmv 4345ce7d987Syamt tmpfs_itimes(vp, NULL, NULL); 4355ce7d987Syamt 436ec933656Sjmmv vap->va_type = vp->v_type; 437ec933656Sjmmv vap->va_mode = node->tn_mode; 438ec933656Sjmmv vap->va_nlink = node->tn_links; 439ec933656Sjmmv vap->va_uid = node->tn_uid; 440ec933656Sjmmv vap->va_gid = node->tn_gid; 441ec933656Sjmmv vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0]; 442ec933656Sjmmv vap->va_fileid = node->tn_id; 443ec933656Sjmmv vap->va_size = node->tn_size; 444ec933656Sjmmv vap->va_blocksize = PAGE_SIZE; 445ec933656Sjmmv vap->va_atime = node->tn_atime; 446ec933656Sjmmv vap->va_mtime = node->tn_mtime; 447ec933656Sjmmv vap->va_ctime = node->tn_ctime; 448ec933656Sjmmv vap->va_birthtime = node->tn_birthtime; 449ec933656Sjmmv vap->va_gen = node->tn_gen; 450ec933656Sjmmv vap->va_flags = node->tn_flags; 451ec933656Sjmmv vap->va_rdev = (vp->v_type == VBLK || vp->v_type == VCHR) ? 452064fbe7eSjmmv node->tn_spec.tn_dev.tn_rdev : VNOVAL; 453ec933656Sjmmv vap->va_bytes = round_page(node->tn_size); 454ec933656Sjmmv vap->va_filerev = VNOVAL; 455ec933656Sjmmv vap->va_vaflags = 0; 456ec933656Sjmmv vap->va_spare = VNOVAL; /* XXX */ 457ec933656Sjmmv 458ec933656Sjmmv return 0; 459ec933656Sjmmv } 460ec933656Sjmmv 461ec933656Sjmmv /* --------------------------------------------------------------------- */ 462ec933656Sjmmv 463ec933656Sjmmv /* XXX Should this operation be atomic? I think it should, but code in 464ec933656Sjmmv * XXX other places (e.g., ufs) doesn't seem to be... */ 465ec933656Sjmmv int 466ec933656Sjmmv tmpfs_setattr(void *v) 467ec933656Sjmmv { 468ec933656Sjmmv struct vnode *vp = ((struct vop_setattr_args *)v)->a_vp; 469ec933656Sjmmv struct vattr *vap = ((struct vop_setattr_args *)v)->a_vap; 470fc9422c9Selad kauth_cred_t cred = ((struct vop_setattr_args *)v)->a_cred; 47195e1ffb1Schristos struct lwp *l = ((struct vop_setattr_args *)v)->a_l; 472ec933656Sjmmv 473a748ea88Syamt int error; 474ec933656Sjmmv 475ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 476ec933656Sjmmv 477ec933656Sjmmv error = 0; 478ec933656Sjmmv 479ec933656Sjmmv /* Abort if any unsettable attribute is given. */ 480ec933656Sjmmv if (vap->va_type != VNON || 481ec933656Sjmmv vap->va_nlink != VNOVAL || 482ec933656Sjmmv vap->va_fsid != VNOVAL || 483ec933656Sjmmv vap->va_fileid != VNOVAL || 484ec933656Sjmmv vap->va_blocksize != VNOVAL || 485ec933656Sjmmv vap->va_ctime.tv_sec != VNOVAL || 486ec933656Sjmmv vap->va_ctime.tv_nsec != VNOVAL || 487ec933656Sjmmv vap->va_birthtime.tv_sec != VNOVAL || 488ec933656Sjmmv vap->va_birthtime.tv_nsec != VNOVAL || 489ec933656Sjmmv vap->va_gen != VNOVAL || 490ec933656Sjmmv vap->va_rdev != VNOVAL || 491ec933656Sjmmv vap->va_bytes != VNOVAL) 492ec933656Sjmmv error = EINVAL; 493ec933656Sjmmv 494ec933656Sjmmv if (error == 0 && (vap->va_flags != VNOVAL)) 495f474dcebSad error = tmpfs_chflags(vp, vap->va_flags, cred, l); 496ec933656Sjmmv 497ec933656Sjmmv if (error == 0 && (vap->va_size != VNOVAL)) 498f474dcebSad error = tmpfs_chsize(vp, vap->va_size, cred, l); 499ec933656Sjmmv 500ec933656Sjmmv if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL)) 501f474dcebSad error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred, l); 502ec933656Sjmmv 503ec933656Sjmmv if (error == 0 && (vap->va_mode != VNOVAL)) 504f474dcebSad error = tmpfs_chmod(vp, vap->va_mode, cred, l); 505ec933656Sjmmv 506ec933656Sjmmv if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL && 507ec933656Sjmmv vap->va_atime.tv_nsec != VNOVAL) || 508ec933656Sjmmv (vap->va_mtime.tv_sec != VNOVAL && 509ec933656Sjmmv vap->va_mtime.tv_nsec != VNOVAL))) 510ec933656Sjmmv error = tmpfs_chtimes(vp, &vap->va_atime, &vap->va_mtime, 51195e1ffb1Schristos vap->va_vaflags, cred, l); 512ec933656Sjmmv 513ec933656Sjmmv /* Update the node times. We give preference to the error codes 514ec933656Sjmmv * generated by this function rather than the ones that may arise 515ec933656Sjmmv * from tmpfs_update. */ 516a748ea88Syamt tmpfs_update(vp, NULL, NULL, 0); 517ec933656Sjmmv 518ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 519ec933656Sjmmv 520ec933656Sjmmv return error; 521ec933656Sjmmv } 522ec933656Sjmmv 523ec933656Sjmmv /* --------------------------------------------------------------------- */ 524ec933656Sjmmv 525ec933656Sjmmv int 526ec933656Sjmmv tmpfs_read(void *v) 527ec933656Sjmmv { 528ec933656Sjmmv struct vnode *vp = ((struct vop_read_args *)v)->a_vp; 529ec933656Sjmmv struct uio *uio = ((struct vop_read_args *)v)->a_uio; 530ec933656Sjmmv 5315f4b660eSjmmv int error; 5325f4b660eSjmmv int flags; 533ec933656Sjmmv struct tmpfs_node *node; 534647aa775Syamt struct uvm_object *uobj; 535ec933656Sjmmv 536ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 537ec933656Sjmmv 538ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 539ec933656Sjmmv 540a7ca1cc6Syamt if (vp->v_type != VREG) { 541a7ca1cc6Syamt error = EISDIR; 542a7ca1cc6Syamt goto out; 543a7ca1cc6Syamt } 544a7ca1cc6Syamt 545a7ca1cc6Syamt if (uio->uio_offset < 0) { 546ec933656Sjmmv error = EINVAL; 547ec933656Sjmmv goto out; 548ec933656Sjmmv } 549ec933656Sjmmv 550ec933656Sjmmv node->tn_status |= TMPFS_NODE_ACCESSED; 551ec933656Sjmmv 552064fbe7eSjmmv uobj = node->tn_spec.tn_reg.tn_aobj; 553647aa775Syamt flags = UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0; 554ec933656Sjmmv error = 0; 5555f4b660eSjmmv while (error == 0 && uio->uio_resid > 0) { 556647aa775Syamt vsize_t len; 557647aa775Syamt void *win; 558ec933656Sjmmv 5597720dda1Syamt if (node->tn_size <= uio->uio_offset) 5607720dda1Syamt break; 5617720dda1Syamt 562ec933656Sjmmv len = MIN(node->tn_size - uio->uio_offset, uio->uio_resid); 5635f4b660eSjmmv if (len == 0) 564647aa775Syamt break; 5655f4b660eSjmmv 56622161687Syamt win = ubc_alloc(uobj, uio->uio_offset, &len, UVM_ADV_NORMAL, 56722161687Syamt UBC_READ); 568647aa775Syamt error = uiomove(win, len, uio); 569647aa775Syamt ubc_release(win, flags); 570647aa775Syamt } 571ec933656Sjmmv 572ec933656Sjmmv out: 573ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 574ec933656Sjmmv 575ec933656Sjmmv return error; 576ec933656Sjmmv } 577ec933656Sjmmv 578ec933656Sjmmv /* --------------------------------------------------------------------- */ 579ec933656Sjmmv 580ec933656Sjmmv int 581ec933656Sjmmv tmpfs_write(void *v) 582ec933656Sjmmv { 583ec933656Sjmmv struct vnode *vp = ((struct vop_write_args *)v)->a_vp; 584ec933656Sjmmv struct uio *uio = ((struct vop_write_args *)v)->a_uio; 585ec933656Sjmmv int ioflag = ((struct vop_write_args *)v)->a_ioflag; 586ec933656Sjmmv 587ec933656Sjmmv boolean_t extended; 588ec933656Sjmmv int error; 5895f4b660eSjmmv int flags; 590ec933656Sjmmv off_t oldsize; 591ec933656Sjmmv struct tmpfs_node *node; 592647aa775Syamt struct uvm_object *uobj; 593ec933656Sjmmv 594ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 595ec933656Sjmmv 596ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 597ec933656Sjmmv oldsize = node->tn_size; 598ec933656Sjmmv 599ec933656Sjmmv if (uio->uio_offset < 0 || vp->v_type != VREG) { 600ec933656Sjmmv error = EINVAL; 601ec933656Sjmmv goto out; 602ec933656Sjmmv } 603ec933656Sjmmv 604ec933656Sjmmv if (uio->uio_resid == 0) { 605ec933656Sjmmv error = 0; 606ec933656Sjmmv goto out; 607ec933656Sjmmv } 608ec933656Sjmmv 609ec933656Sjmmv if (ioflag & IO_APPEND) 610ec933656Sjmmv uio->uio_offset = node->tn_size; 611ec933656Sjmmv 612ec933656Sjmmv extended = uio->uio_offset + uio->uio_resid > node->tn_size; 613ec933656Sjmmv if (extended) { 614ec933656Sjmmv error = tmpfs_reg_resize(vp, uio->uio_offset + uio->uio_resid); 615ec933656Sjmmv if (error != 0) 616ec933656Sjmmv goto out; 617ec933656Sjmmv } 618ec933656Sjmmv 619064fbe7eSjmmv uobj = node->tn_spec.tn_reg.tn_aobj; 620647aa775Syamt flags = UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0; 621647aa775Syamt error = 0; 6225f4b660eSjmmv while (error == 0 && uio->uio_resid > 0) { 623647aa775Syamt vsize_t len; 624647aa775Syamt void *win; 625647aa775Syamt 626647aa775Syamt len = MIN(node->tn_size - uio->uio_offset, uio->uio_resid); 6275f4b660eSjmmv if (len == 0) 628647aa775Syamt break; 6295f4b660eSjmmv 63022161687Syamt win = ubc_alloc(uobj, uio->uio_offset, &len, UVM_ADV_NORMAL, 63122161687Syamt UBC_WRITE); 632647aa775Syamt error = uiomove(win, len, uio); 633647aa775Syamt ubc_release(win, flags); 634647aa775Syamt } 635647aa775Syamt 636ec933656Sjmmv node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | 637ec933656Sjmmv (extended ? TMPFS_NODE_CHANGED : 0); 638ec933656Sjmmv 6395f4b660eSjmmv if (error != 0) 640647aa775Syamt (void)tmpfs_reg_resize(vp, oldsize); 641647aa775Syamt 642117b5f51Sjmmv VN_KNOTE(vp, NOTE_WRITE); 643117b5f51Sjmmv 644ec933656Sjmmv out: 645ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 646ec933656Sjmmv KASSERT(IMPLIES(error == 0, uio->uio_resid == 0)); 647ec933656Sjmmv KASSERT(IMPLIES(error != 0, oldsize == node->tn_size)); 648ec933656Sjmmv 649ec933656Sjmmv return error; 650ec933656Sjmmv } 651ec933656Sjmmv 652ec933656Sjmmv /* --------------------------------------------------------------------- */ 653ec933656Sjmmv 654ec933656Sjmmv int 655ec933656Sjmmv tmpfs_fsync(void *v) 656ec933656Sjmmv { 657ec933656Sjmmv struct vnode *vp = ((struct vop_fsync_args *)v)->a_vp; 658ec933656Sjmmv 659ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 660ec933656Sjmmv 661a748ea88Syamt tmpfs_update(vp, NULL, NULL, 0); 662a748ea88Syamt 663a748ea88Syamt return 0; 664ec933656Sjmmv } 665ec933656Sjmmv 666ec933656Sjmmv /* --------------------------------------------------------------------- */ 667ec933656Sjmmv 668ec933656Sjmmv int 669ec933656Sjmmv tmpfs_remove(void *v) 670ec933656Sjmmv { 671ec933656Sjmmv struct vnode *dvp = ((struct vop_remove_args *)v)->a_dvp; 672ec933656Sjmmv struct vnode *vp = ((struct vop_remove_args *)v)->a_vp; 673ec933656Sjmmv 674ec933656Sjmmv int error; 675ec933656Sjmmv struct tmpfs_dirent *de; 676ec933656Sjmmv struct tmpfs_mount *tmp; 677ec933656Sjmmv struct tmpfs_node *dnode; 678ec933656Sjmmv struct tmpfs_node *node; 679ec933656Sjmmv 680ec933656Sjmmv KASSERT(VOP_ISLOCKED(dvp)); 681ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 682ec933656Sjmmv 683ec933656Sjmmv dnode = VP_TO_TMPFS_DIR(dvp); 684ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 685ec933656Sjmmv tmp = VFS_TO_TMPFS(vp->v_mount); 686ec933656Sjmmv de = node->tn_lookup_dirent; 687ec933656Sjmmv KASSERT(de != NULL); 688ec933656Sjmmv 689ec933656Sjmmv /* XXX: Why isn't this done by the caller? */ 690ec933656Sjmmv if (vp->v_type == VDIR) { 691ec933656Sjmmv error = EISDIR; 692ec933656Sjmmv goto out; 693ec933656Sjmmv } 694ec933656Sjmmv 695ec933656Sjmmv /* Files marked as immutable or append-only cannot be deleted. */ 696ec933656Sjmmv if (node->tn_flags & (IMMUTABLE | APPEND)) { 697ec933656Sjmmv error = EPERM; 698ec933656Sjmmv goto out; 699ec933656Sjmmv } 700ec933656Sjmmv 701ec933656Sjmmv /* Remove the entry from the directory; as it is a file, we do not 702ec933656Sjmmv * have to change the number of hard links of the directory. */ 703ec933656Sjmmv tmpfs_dir_detach(dvp, de); 704ec933656Sjmmv 705ec933656Sjmmv /* Free the directory entry we just deleted. Note that the node 706ec933656Sjmmv * referred by it will not be removed until the vnode is really 707ec933656Sjmmv * reclaimed. */ 708ec933656Sjmmv tmpfs_free_dirent(tmp, de, TRUE); 709ec933656Sjmmv 710ec933656Sjmmv error = 0; 711ec933656Sjmmv 712ec933656Sjmmv out: 713ec933656Sjmmv vput(dvp); 714ec933656Sjmmv vput(vp); 715ec933656Sjmmv 716ec933656Sjmmv KASSERT(!VOP_ISLOCKED(dvp)); 717ec933656Sjmmv 718ec933656Sjmmv return error; 719ec933656Sjmmv } 720ec933656Sjmmv 721ec933656Sjmmv /* --------------------------------------------------------------------- */ 722ec933656Sjmmv 723ec933656Sjmmv int 724ec933656Sjmmv tmpfs_link(void *v) 725ec933656Sjmmv { 726ec933656Sjmmv struct vnode *dvp = ((struct vop_link_args *)v)->a_dvp; 727ec933656Sjmmv struct vnode *vp = ((struct vop_link_args *)v)->a_vp; 728ec933656Sjmmv struct componentname *cnp = ((struct vop_link_args *)v)->a_cnp; 729ec933656Sjmmv 730ec933656Sjmmv int error; 731ec933656Sjmmv struct tmpfs_dirent *de; 732ec933656Sjmmv struct tmpfs_node *dnode; 733ec933656Sjmmv struct tmpfs_node *node; 734ec933656Sjmmv 735ec933656Sjmmv KASSERT(VOP_ISLOCKED(dvp)); 736ec933656Sjmmv KASSERT(!VOP_ISLOCKED(vp)); 737ec933656Sjmmv KASSERT(cnp->cn_flags & HASBUF); 738ec933656Sjmmv KASSERT(dvp != vp); /* XXX When can this be false? */ 739ec933656Sjmmv 740ec933656Sjmmv dnode = VP_TO_TMPFS_DIR(dvp); 741ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 742ec933656Sjmmv 743a748ea88Syamt /* Lock vp because we will need to run tmpfs_update over it, which 744ec933656Sjmmv * needs the vnode to be locked. */ 745ec933656Sjmmv error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 746ec933656Sjmmv if (error != 0) 747ec933656Sjmmv goto out; 748ec933656Sjmmv 749ec933656Sjmmv /* XXX: Why aren't the following two tests done by the caller? */ 750ec933656Sjmmv 751ec933656Sjmmv /* Hard links of directories are forbidden. */ 752ec933656Sjmmv if (vp->v_type == VDIR) { 753ec933656Sjmmv error = EPERM; 754ec933656Sjmmv goto out; 755ec933656Sjmmv } 756ec933656Sjmmv 757ec933656Sjmmv /* Cannot create cross-device links. */ 758ec933656Sjmmv if (dvp->v_mount != vp->v_mount) { 759ec933656Sjmmv error = EXDEV; 760ec933656Sjmmv goto out; 761ec933656Sjmmv } 762ec933656Sjmmv 763ec933656Sjmmv /* Ensure that we do not overflow the maximum number of links imposed 764ec933656Sjmmv * by the system. */ 765ec933656Sjmmv KASSERT(node->tn_links <= LINK_MAX); 766ec933656Sjmmv if (node->tn_links == LINK_MAX) { 767ec933656Sjmmv error = EMLINK; 768ec933656Sjmmv goto out; 769ec933656Sjmmv } 770ec933656Sjmmv 771ec933656Sjmmv /* We cannot create links of files marked immutable or append-only. */ 772ec933656Sjmmv if (node->tn_flags & (IMMUTABLE | APPEND)) { 773ec933656Sjmmv error = EPERM; 774ec933656Sjmmv goto out; 775ec933656Sjmmv } 776ec933656Sjmmv 777ec933656Sjmmv /* Allocate a new directory entry to represent the node. */ 778ec933656Sjmmv error = tmpfs_alloc_dirent(VFS_TO_TMPFS(vp->v_mount), node, 779ec933656Sjmmv cnp->cn_nameptr, cnp->cn_namelen, &de); 780ec933656Sjmmv if (error != 0) 781ec933656Sjmmv goto out; 782ec933656Sjmmv 783ec933656Sjmmv /* Insert the new directory entry into the appropriate directory. */ 784ec933656Sjmmv tmpfs_dir_attach(dvp, de); 785ec933656Sjmmv 786ec933656Sjmmv /* vp link count has changed, so update node times. */ 787ec933656Sjmmv node->tn_status |= TMPFS_NODE_CHANGED; 788a748ea88Syamt tmpfs_update(vp, NULL, NULL, 0); 789ec933656Sjmmv 790ec933656Sjmmv error = 0; 791ec933656Sjmmv 792ec933656Sjmmv out: 793ec933656Sjmmv if (VOP_ISLOCKED(vp)) 794ec933656Sjmmv VOP_UNLOCK(vp, 0); 795ec933656Sjmmv 796ec933656Sjmmv PNBUF_PUT(cnp->cn_pnbuf); 797ec933656Sjmmv 798ec933656Sjmmv vput(dvp); 799ec933656Sjmmv 800ec933656Sjmmv /* XXX Locking status of dvp does not match manual page. */ 801ec933656Sjmmv KASSERT(!VOP_ISLOCKED(dvp)); 802ec933656Sjmmv KASSERT(!VOP_ISLOCKED(vp)); 803ec933656Sjmmv 804ec933656Sjmmv return error; 805ec933656Sjmmv } 806ec933656Sjmmv 807ec933656Sjmmv /* --------------------------------------------------------------------- */ 808ec933656Sjmmv 809ec933656Sjmmv int 810ec933656Sjmmv tmpfs_rename(void *v) 811ec933656Sjmmv { 812ec933656Sjmmv struct vnode *fdvp = ((struct vop_rename_args *)v)->a_fdvp; 813ec933656Sjmmv struct vnode *fvp = ((struct vop_rename_args *)v)->a_fvp; 814ec933656Sjmmv struct componentname *fcnp = ((struct vop_rename_args *)v)->a_fcnp; 815ec933656Sjmmv struct vnode *tdvp = ((struct vop_rename_args *)v)->a_tdvp; 816ec933656Sjmmv struct vnode *tvp = ((struct vop_rename_args *)v)->a_tvp; 817ec933656Sjmmv struct componentname *tcnp = ((struct vop_rename_args *)v)->a_tcnp; 818ec933656Sjmmv 819ec933656Sjmmv char *newname; 820ec933656Sjmmv int error; 821ec933656Sjmmv struct tmpfs_dirent *de; 822ec933656Sjmmv struct tmpfs_mount *tmp; 823ec933656Sjmmv struct tmpfs_node *fdnode; 824ec933656Sjmmv struct tmpfs_node *fnode; 825ec933656Sjmmv struct tmpfs_node *tdnode; 826ec933656Sjmmv 827ec933656Sjmmv KASSERT(VOP_ISLOCKED(tdvp)); 828ec933656Sjmmv KASSERT(IMPLIES(tvp != NULL, VOP_ISLOCKED(tvp))); 829ec933656Sjmmv KASSERT(fcnp->cn_flags & HASBUF); 830ec933656Sjmmv KASSERT(tcnp->cn_flags & HASBUF); 831ec933656Sjmmv 832ec933656Sjmmv fdnode = VP_TO_TMPFS_DIR(fdvp); 833ec933656Sjmmv fnode = VP_TO_TMPFS_NODE(fvp); 834ec933656Sjmmv de = fnode->tn_lookup_dirent; 835ec933656Sjmmv 836ec933656Sjmmv /* Disallow cross-device renames. 837ec933656Sjmmv * XXX Why isn't this done by the caller? */ 838ec933656Sjmmv if (fvp->v_mount != tdvp->v_mount || 839ec933656Sjmmv (tvp != NULL && fvp->v_mount != tvp->v_mount)) { 840ec933656Sjmmv error = EXDEV; 841ec933656Sjmmv goto out; 842ec933656Sjmmv } 843ec933656Sjmmv 844ec933656Sjmmv tmp = VFS_TO_TMPFS(tdvp->v_mount); 845ec933656Sjmmv tdnode = VP_TO_TMPFS_DIR(tdvp); 846ec933656Sjmmv 847ec933656Sjmmv /* If source and target are the same file, there is nothing to do. */ 848ec933656Sjmmv if (fvp == tvp) { 849ec933656Sjmmv error = 0; 850ec933656Sjmmv goto out; 851ec933656Sjmmv } 852ec933656Sjmmv 853ec933656Sjmmv /* Avoid manipulating '.' and '..' entries. */ 854ec933656Sjmmv if (de == NULL) { 855ec933656Sjmmv KASSERT(fvp->v_type == VDIR); 856ec933656Sjmmv error = EINVAL; 857ec933656Sjmmv goto out; 858ec933656Sjmmv } 859ec933656Sjmmv KASSERT(de->td_node == fnode); 860ec933656Sjmmv 861f63b58d1Sjmmv /* If we need to move the directory between entries, lock the 862f63b58d1Sjmmv * source so that we can safely operate on it. */ 863f63b58d1Sjmmv if (fdnode != tdnode) { 864f63b58d1Sjmmv error = vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY); 865f63b58d1Sjmmv if (error != 0) 86658e607b9Syamt goto out; 867f63b58d1Sjmmv } 868f63b58d1Sjmmv 869ec933656Sjmmv /* Ensure that we have enough memory to hold the new name, if it 870ec933656Sjmmv * has to be changed. */ 871ec933656Sjmmv if (fcnp->cn_namelen != tcnp->cn_namelen || 872ec933656Sjmmv memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen) != 0) { 873ec933656Sjmmv newname = tmpfs_str_pool_get(&tmp->tm_str_pool, 874ec933656Sjmmv tcnp->cn_namelen, 0); 875ec933656Sjmmv if (newname == NULL) { 876ec933656Sjmmv error = ENOSPC; 87758e607b9Syamt goto out_locked; 878ec933656Sjmmv } 879ec933656Sjmmv } else 880ec933656Sjmmv newname = NULL; 881ec933656Sjmmv 882ec933656Sjmmv /* If the node is being moved to another directory, we have to do 883ec933656Sjmmv * the move. */ 884ec933656Sjmmv if (fdnode != tdnode) { 885ec933656Sjmmv /* In case we are moving a directory, we have to adjust its 886ec933656Sjmmv * parent to point to the new parent. */ 887ec933656Sjmmv if (de->td_node->tn_type == VDIR) { 888ec933656Sjmmv struct tmpfs_node *n; 889ec933656Sjmmv 890ec933656Sjmmv /* Ensure the target directory is not a child of the 891ec933656Sjmmv * directory being moved. Otherwise, we'd end up 892ec933656Sjmmv * with stale nodes. */ 893ec933656Sjmmv n = tdnode; 894064fbe7eSjmmv while (n != n->tn_spec.tn_dir.tn_parent) { 895ec933656Sjmmv if (n == fnode) { 896ec933656Sjmmv error = EINVAL; 89758e607b9Syamt goto out_locked; 898ec933656Sjmmv } 899064fbe7eSjmmv n = n->tn_spec.tn_dir.tn_parent; 900ec933656Sjmmv } 901ec933656Sjmmv 902ec933656Sjmmv /* Adjust the parent pointer. */ 903ec933656Sjmmv TMPFS_VALIDATE_DIR(fnode); 904064fbe7eSjmmv de->td_node->tn_spec.tn_dir.tn_parent = tdnode; 905ec933656Sjmmv 906ec933656Sjmmv /* As a result of changing the target of the '..' 907ec933656Sjmmv * entry, the link count of the source and target 908ec933656Sjmmv * directories has to be adjusted. */ 909ec933656Sjmmv fdnode->tn_links--; 910ec933656Sjmmv tdnode->tn_links++; 911ec933656Sjmmv } 912ec933656Sjmmv 913ec933656Sjmmv /* Do the move: just remove the entry from the source directory 914ec933656Sjmmv * and insert it into the target one. */ 915ec933656Sjmmv tmpfs_dir_detach(fdvp, de); 916ec933656Sjmmv tmpfs_dir_attach(tdvp, de); 917ec933656Sjmmv 918ec933656Sjmmv /* Notify listeners of fdvp about the change in the directory. 919ec933656Sjmmv * We can do it at this point because we aren't touching fdvp 920ec933656Sjmmv * any more below. */ 921ec933656Sjmmv VN_KNOTE(fdvp, NOTE_WRITE); 922ec933656Sjmmv } 923ec933656Sjmmv 924ec933656Sjmmv /* If the name has changed, we need to make it effective by changing 925ec933656Sjmmv * it in the directory entry. */ 926ec933656Sjmmv if (newname != NULL) { 927ec933656Sjmmv KASSERT(tcnp->cn_namelen < MAXNAMLEN); 928ec933656Sjmmv KASSERT(tcnp->cn_namelen < 0xffff); 929ec933656Sjmmv 930ec933656Sjmmv tmpfs_str_pool_put(&tmp->tm_str_pool, de->td_name, 931ec933656Sjmmv de->td_namelen); 932ec933656Sjmmv de->td_namelen = (uint16_t)tcnp->cn_namelen; 933ec933656Sjmmv memcpy(newname, tcnp->cn_nameptr, tcnp->cn_namelen); 934ec933656Sjmmv de->td_name = newname; 935ec933656Sjmmv 93671f9a077Sjmmv fnode->tn_status |= TMPFS_NODE_CHANGED; 9372185c988Sjmmv tdnode->tn_status |= TMPFS_NODE_MODIFIED; 938ec933656Sjmmv } 939ec933656Sjmmv 940ec933656Sjmmv /* If we are overwriting an entry, we have to remove the old one 941ec933656Sjmmv * from the target directory. */ 942ec933656Sjmmv if (tvp != NULL) { 943ec933656Sjmmv struct tmpfs_node *tnode; 944ec933656Sjmmv 945ec933656Sjmmv tnode = VP_TO_TMPFS_NODE(tvp); 946ec933656Sjmmv 947ec933656Sjmmv /* The source node cannot be a directory in this case. */ 948ec933656Sjmmv KASSERT(fnode->tn_type != VDIR); 949ec933656Sjmmv 950ec933656Sjmmv /* Remove the old entry from the target directory. */ 951ec933656Sjmmv de = tnode->tn_lookup_dirent; 952ec933656Sjmmv tmpfs_dir_detach(tdvp, de); 953ec933656Sjmmv 954ec933656Sjmmv /* Free the directory entry we just deleted. Note that the 955ec933656Sjmmv * node referred by it will not be removed until the vnode is 956ec933656Sjmmv * really reclaimed. */ 957ec933656Sjmmv tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), de, TRUE); 958ec933656Sjmmv } 959ec933656Sjmmv 960ec933656Sjmmv /* Notify listeners of tdvp about the change in the directory (either 961117b5f51Sjmmv * because a new entry was added or because one was removed) and 962117b5f51Sjmmv * listeners of fvp about the rename. */ 963ec933656Sjmmv VN_KNOTE(tdvp, NOTE_WRITE); 964117b5f51Sjmmv VN_KNOTE(fvp, NOTE_RENAME); 965ec933656Sjmmv 966ec933656Sjmmv error = 0; 967ec933656Sjmmv 968f63b58d1Sjmmv out_locked: 969f63b58d1Sjmmv if (fdnode != tdnode) 970f63b58d1Sjmmv VOP_UNLOCK(fdvp, 0); 971f63b58d1Sjmmv 972ec933656Sjmmv out: 973ec933656Sjmmv /* Release target nodes. */ 974ec933656Sjmmv /* XXX: I don't understand when tdvp can be the same as tvp, but 975ec933656Sjmmv * other code takes care of this... */ 976ec933656Sjmmv if (tdvp == tvp) 977ec933656Sjmmv vrele(tdvp); 978ec933656Sjmmv else 979ec933656Sjmmv vput(tdvp); 980ec933656Sjmmv if (tvp != NULL) 981ec933656Sjmmv vput(tvp); 982ec933656Sjmmv 983ec933656Sjmmv /* Release source nodes. */ 984ec933656Sjmmv vrele(fdvp); 985ec933656Sjmmv vrele(fvp); 986ec933656Sjmmv 987ec933656Sjmmv return error; 988ec933656Sjmmv } 989ec933656Sjmmv 990ec933656Sjmmv /* --------------------------------------------------------------------- */ 991ec933656Sjmmv 992ec933656Sjmmv int 993ec933656Sjmmv tmpfs_mkdir(void *v) 994ec933656Sjmmv { 995ec933656Sjmmv struct vnode *dvp = ((struct vop_mkdir_args *)v)->a_dvp; 996ec933656Sjmmv struct vnode **vpp = ((struct vop_mkdir_args *)v)->a_vpp; 997ec933656Sjmmv struct componentname *cnp = ((struct vop_mkdir_args *)v)->a_cnp; 998ec933656Sjmmv struct vattr *vap = ((struct vop_mkdir_args *)v)->a_vap; 999ec933656Sjmmv 1000ec933656Sjmmv KASSERT(vap->va_type == VDIR); 1001ec933656Sjmmv 1002ec933656Sjmmv return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL); 1003ec933656Sjmmv } 1004ec933656Sjmmv 1005ec933656Sjmmv /* --------------------------------------------------------------------- */ 1006ec933656Sjmmv 1007ec933656Sjmmv int 1008ec933656Sjmmv tmpfs_rmdir(void *v) 1009ec933656Sjmmv { 1010ec933656Sjmmv struct vnode *dvp = ((struct vop_rmdir_args *)v)->a_dvp; 1011ec933656Sjmmv struct vnode *vp = ((struct vop_rmdir_args *)v)->a_vp; 1012ec933656Sjmmv 1013ec933656Sjmmv int error; 1014ec933656Sjmmv struct tmpfs_dirent *de; 1015ec933656Sjmmv struct tmpfs_mount *tmp; 1016ec933656Sjmmv struct tmpfs_node *dnode; 1017ec933656Sjmmv struct tmpfs_node *node; 1018ec933656Sjmmv 1019ec933656Sjmmv KASSERT(VOP_ISLOCKED(dvp)); 1020ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 1021ec933656Sjmmv 1022ec933656Sjmmv tmp = VFS_TO_TMPFS(dvp->v_mount); 1023ec933656Sjmmv dnode = VP_TO_TMPFS_DIR(dvp); 1024ec933656Sjmmv node = VP_TO_TMPFS_DIR(vp); 1025064fbe7eSjmmv KASSERT(node->tn_spec.tn_dir.tn_parent == dnode); 1026ec933656Sjmmv 1027ec933656Sjmmv /* Get the directory entry associated with node (vp). This was 1028ec933656Sjmmv * filled by tmpfs_lookup while looking up the entry. */ 1029ec933656Sjmmv de = node->tn_lookup_dirent; 1030ec933656Sjmmv KASSERT(TMPFS_DIRENT_MATCHES(de, 1031ec933656Sjmmv ((struct vop_rmdir_args *)v)->a_cnp->cn_nameptr, 1032ec933656Sjmmv ((struct vop_rmdir_args *)v)->a_cnp->cn_namelen)); 1033ec933656Sjmmv 1034ec933656Sjmmv /* Directories with more than two entries ('.' and '..') cannot be 1035ec933656Sjmmv * removed. */ 1036ec933656Sjmmv if (node->tn_size > 0) { 1037ec933656Sjmmv error = ENOTEMPTY; 1038ec933656Sjmmv goto out; 1039ec933656Sjmmv } 1040ec933656Sjmmv 1041ec933656Sjmmv /* Check flags to see if we are allowed to remove the directory. */ 1042ec933656Sjmmv if (dnode->tn_flags & APPEND || node->tn_flags & (IMMUTABLE | APPEND)) { 1043ec933656Sjmmv error = EPERM; 1044ec933656Sjmmv goto out; 1045ec933656Sjmmv } 1046ec933656Sjmmv 1047ec933656Sjmmv /* Detach the directory entry from the directory (dnode). */ 1048ec933656Sjmmv tmpfs_dir_detach(dvp, de); 1049ec933656Sjmmv 1050ec933656Sjmmv node->tn_links--; 1051ec933656Sjmmv node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \ 1052ec933656Sjmmv TMPFS_NODE_MODIFIED; 1053064fbe7eSjmmv node->tn_spec.tn_dir.tn_parent->tn_links--; 1054064fbe7eSjmmv node->tn_spec.tn_dir.tn_parent->tn_status |= TMPFS_NODE_ACCESSED | \ 1055ec933656Sjmmv TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED; 1056ec933656Sjmmv 1057117b5f51Sjmmv /* Release the parent. */ 1058ec933656Sjmmv cache_purge(dvp); /* XXX Is this needed? */ 1059ec933656Sjmmv vput(dvp); 1060ec933656Sjmmv 1061ec933656Sjmmv /* Free the directory entry we just deleted. Note that the node 1062ec933656Sjmmv * referred by it will not be removed until the vnode is really 1063ec933656Sjmmv * reclaimed. */ 1064ec933656Sjmmv tmpfs_free_dirent(tmp, de, TRUE); 1065ec933656Sjmmv 1066ec933656Sjmmv /* Release the deleted vnode (will destroy the node, notify 1067ec933656Sjmmv * interested parties and clean it from the cache). */ 1068ec933656Sjmmv vput(vp); 1069ec933656Sjmmv 1070ec933656Sjmmv error = 0; 1071ec933656Sjmmv 1072ec933656Sjmmv out: 1073ec933656Sjmmv if (error != 0) { 1074ec933656Sjmmv vput(dvp); 1075ec933656Sjmmv vput(vp); 1076ec933656Sjmmv } 1077ec933656Sjmmv 1078ec933656Sjmmv return error; 1079ec933656Sjmmv } 1080ec933656Sjmmv 1081ec933656Sjmmv /* --------------------------------------------------------------------- */ 1082ec933656Sjmmv 1083ec933656Sjmmv int 1084ec933656Sjmmv tmpfs_symlink(void *v) 1085ec933656Sjmmv { 1086ec933656Sjmmv struct vnode *dvp = ((struct vop_symlink_args *)v)->a_dvp; 1087ec933656Sjmmv struct vnode **vpp = ((struct vop_symlink_args *)v)->a_vpp; 1088ec933656Sjmmv struct componentname *cnp = ((struct vop_symlink_args *)v)->a_cnp; 1089ec933656Sjmmv struct vattr *vap = ((struct vop_symlink_args *)v)->a_vap; 1090ec933656Sjmmv char *target = ((struct vop_symlink_args *)v)->a_target; 1091ec933656Sjmmv 1092ec933656Sjmmv KASSERT(vap->va_type == VLNK); 1093ec933656Sjmmv 1094ec933656Sjmmv return tmpfs_alloc_file(dvp, vpp, vap, cnp, target); 1095ec933656Sjmmv } 1096ec933656Sjmmv 1097ec933656Sjmmv /* --------------------------------------------------------------------- */ 1098ec933656Sjmmv 1099ec933656Sjmmv int 1100ec933656Sjmmv tmpfs_readdir(void *v) 1101ec933656Sjmmv { 1102ec933656Sjmmv struct vnode *vp = ((struct vop_readdir_args *)v)->a_vp; 1103ec933656Sjmmv struct uio *uio = ((struct vop_readdir_args *)v)->a_uio; 1104ec933656Sjmmv int *eofflag = ((struct vop_readdir_args *)v)->a_eofflag; 1105ec933656Sjmmv off_t **cookies = ((struct vop_readdir_args *)v)->a_cookies; 1106ec933656Sjmmv int *ncookies = ((struct vop_readdir_args *)v)->a_ncookies; 1107ec933656Sjmmv 1108ec933656Sjmmv int error; 11098e6209cfSyamt off_t startoff; 11108e6209cfSyamt off_t cnt; 1111ec933656Sjmmv struct tmpfs_node *node; 1112ec933656Sjmmv 1113ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 1114ec933656Sjmmv 1115ec933656Sjmmv /* This operation only makes sense on directory nodes. */ 1116ec933656Sjmmv if (vp->v_type != VDIR) { 1117ec933656Sjmmv error = ENOTDIR; 1118ec933656Sjmmv goto out; 1119ec933656Sjmmv } 1120ec933656Sjmmv 1121ec933656Sjmmv node = VP_TO_TMPFS_DIR(vp); 1122ec933656Sjmmv 1123ec933656Sjmmv startoff = uio->uio_offset; 1124ec933656Sjmmv 11258e6209cfSyamt cnt = 0; 11268e6209cfSyamt if (uio->uio_offset == TMPFS_DIRCOOKIE_DOT) { 1127ec933656Sjmmv error = tmpfs_dir_getdotdent(node, uio); 1128ec933656Sjmmv if (error == -1) { 1129ec933656Sjmmv error = 0; 1130ec933656Sjmmv goto outok; 1131ec933656Sjmmv } else if (error != 0) 1132ec933656Sjmmv goto outok; 11338e6209cfSyamt cnt++; 1134ec933656Sjmmv } 1135ec933656Sjmmv 11368e6209cfSyamt if (uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT) { 1137ec933656Sjmmv error = tmpfs_dir_getdotdotdent(node, uio); 1138ec933656Sjmmv if (error == -1) { 1139ec933656Sjmmv error = 0; 1140ec933656Sjmmv goto outok; 1141ec933656Sjmmv } else if (error != 0) 1142ec933656Sjmmv goto outok; 11438e6209cfSyamt cnt++; 1144ec933656Sjmmv } 1145ec933656Sjmmv 11468e6209cfSyamt error = tmpfs_dir_getdents(node, uio, &cnt); 1147ec933656Sjmmv if (error == -1) 1148ec933656Sjmmv error = 0; 1149ec933656Sjmmv KASSERT(error >= 0); 1150ec933656Sjmmv 1151ec933656Sjmmv outok: 11528e6209cfSyamt /* This label assumes that startoff has been 1153ec933656Sjmmv * initialized. If the compiler didn't spit out warnings, we'd 1154ec933656Sjmmv * simply make this one be 'out' and drop 'outok'. */ 1155ec933656Sjmmv 1156ec933656Sjmmv if (eofflag != NULL) 1157ec933656Sjmmv *eofflag = 11588e6209cfSyamt (error == 0 && uio->uio_offset == TMPFS_DIRCOOKIE_EOF); 1159ec933656Sjmmv 1160ec933656Sjmmv /* Update NFS-related variables. */ 1161ec933656Sjmmv if (error == 0 && cookies != NULL && ncookies != NULL) { 1162ec933656Sjmmv off_t i; 11638e6209cfSyamt off_t off = startoff; 11648e6209cfSyamt struct tmpfs_dirent *de = NULL; 1165ec933656Sjmmv 11668e6209cfSyamt *ncookies = cnt; 11678e6209cfSyamt *cookies = malloc(cnt * sizeof(off_t), M_TEMP, M_WAITOK); 1168ec933656Sjmmv 11698e6209cfSyamt for (i = 0; i < cnt; i++) { 11708e6209cfSyamt KASSERT(off != TMPFS_DIRCOOKIE_EOF); 11718e6209cfSyamt if (off == TMPFS_DIRCOOKIE_DOT) { 11728e6209cfSyamt off = TMPFS_DIRCOOKIE_DOTDOT; 11738e6209cfSyamt } else { 11748e6209cfSyamt if (off == TMPFS_DIRCOOKIE_DOTDOT) { 1175064fbe7eSjmmv de = TAILQ_FIRST(&node->tn_spec. 1176064fbe7eSjmmv tn_dir.tn_dir); 11778e6209cfSyamt } else if (de != NULL) { 11788e6209cfSyamt de = TAILQ_NEXT(de, td_entries); 11798e6209cfSyamt } else { 11808e6209cfSyamt de = tmpfs_dir_lookupbycookie(node, 11818e6209cfSyamt off); 11828e6209cfSyamt KASSERT(de != NULL); 11838e6209cfSyamt de = TAILQ_NEXT(de, td_entries); 11848e6209cfSyamt } 11858e6209cfSyamt if (de == NULL) { 11868e6209cfSyamt off = TMPFS_DIRCOOKIE_EOF; 11878e6209cfSyamt } else { 1188b2603104Sjmmv off = tmpfs_dircookie(de); 11898e6209cfSyamt } 11908e6209cfSyamt } 11918e6209cfSyamt 11928e6209cfSyamt (*cookies)[i] = off; 11938e6209cfSyamt } 11948e6209cfSyamt KASSERT(uio->uio_offset == off); 1195ec933656Sjmmv } 1196ec933656Sjmmv 1197ec933656Sjmmv out: 1198ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 1199ec933656Sjmmv 1200ec933656Sjmmv return error; 1201ec933656Sjmmv } 1202ec933656Sjmmv 1203ec933656Sjmmv /* --------------------------------------------------------------------- */ 1204ec933656Sjmmv 1205ec933656Sjmmv int 1206ec933656Sjmmv tmpfs_readlink(void *v) 1207ec933656Sjmmv { 1208ec933656Sjmmv struct vnode *vp = ((struct vop_readlink_args *)v)->a_vp; 1209ec933656Sjmmv struct uio *uio = ((struct vop_readlink_args *)v)->a_uio; 1210ec933656Sjmmv 1211ec933656Sjmmv int error; 1212ec933656Sjmmv struct tmpfs_node *node; 1213ec933656Sjmmv 1214ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 1215ec933656Sjmmv KASSERT(uio->uio_offset == 0); 1216ec933656Sjmmv KASSERT(vp->v_type == VLNK); 1217ec933656Sjmmv 1218ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 1219ec933656Sjmmv 1220064fbe7eSjmmv error = uiomove(node->tn_spec.tn_lnk.tn_link, 1221064fbe7eSjmmv MIN(node->tn_size, uio->uio_resid), uio); 1222ec933656Sjmmv node->tn_status |= TMPFS_NODE_ACCESSED; 1223ec933656Sjmmv 1224ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 1225ec933656Sjmmv 1226ec933656Sjmmv return error; 1227ec933656Sjmmv } 1228ec933656Sjmmv 1229ec933656Sjmmv /* --------------------------------------------------------------------- */ 1230ec933656Sjmmv 1231ec933656Sjmmv int 1232ec933656Sjmmv tmpfs_inactive(void *v) 1233ec933656Sjmmv { 1234ec933656Sjmmv struct vnode *vp = ((struct vop_inactive_args *)v)->a_vp; 123595e1ffb1Schristos struct lwp *l = ((struct vop_inactive_args *)v)->a_l; 1236ec933656Sjmmv 1237ec933656Sjmmv struct tmpfs_node *node; 1238ec933656Sjmmv 1239ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 1240ec933656Sjmmv 1241ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 1242ec933656Sjmmv 1243ec933656Sjmmv VOP_UNLOCK(vp, 0); 1244ec933656Sjmmv 1245ec933656Sjmmv if (node->tn_links == 0) 124695e1ffb1Schristos vrecycle(vp, NULL, l); 1247ec933656Sjmmv 1248ec933656Sjmmv return 0; 1249ec933656Sjmmv } 1250ec933656Sjmmv 1251ec933656Sjmmv /* --------------------------------------------------------------------- */ 1252ec933656Sjmmv 1253ec933656Sjmmv int 1254ec933656Sjmmv tmpfs_reclaim(void *v) 1255ec933656Sjmmv { 1256ec933656Sjmmv struct vnode *vp = ((struct vop_reclaim_args *)v)->a_vp; 1257ec933656Sjmmv 1258ec933656Sjmmv struct tmpfs_mount *tmp; 1259ec933656Sjmmv struct tmpfs_node *node; 1260ec933656Sjmmv 1261ec933656Sjmmv KASSERT(!VOP_ISLOCKED(vp)); 1262ec933656Sjmmv 1263ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 1264ec933656Sjmmv tmp = VFS_TO_TMPFS(vp->v_mount); 1265ec933656Sjmmv 1266ec933656Sjmmv cache_purge(vp); 1267ec933656Sjmmv tmpfs_free_vp(vp); 1268ec933656Sjmmv 1269ec933656Sjmmv /* If the node referenced by this vnode was deleted by the user, 1270ec933656Sjmmv * we must free its associated data structures (now that the vnode 1271ec933656Sjmmv * is being reclaimed). */ 1272ec933656Sjmmv if (node->tn_links == 0) 1273ec933656Sjmmv tmpfs_free_node(tmp, node); 1274ec933656Sjmmv 1275ec933656Sjmmv KASSERT(!VOP_ISLOCKED(vp)); 1276ec933656Sjmmv KASSERT(vp->v_data == NULL); 1277ec933656Sjmmv 1278ec933656Sjmmv return 0; 1279ec933656Sjmmv } 1280ec933656Sjmmv 1281ec933656Sjmmv /* --------------------------------------------------------------------- */ 1282ec933656Sjmmv 1283ec933656Sjmmv int 1284ec933656Sjmmv tmpfs_print(void *v) 1285ec933656Sjmmv { 1286ec933656Sjmmv struct vnode *vp = ((struct vop_print_args *)v)->a_vp; 1287ec933656Sjmmv 1288ec933656Sjmmv struct tmpfs_node *node; 1289ec933656Sjmmv 1290ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 1291ec933656Sjmmv 1292ec933656Sjmmv printf("tag VT_TMPFS, tmpfs_node %p, flags 0x%x, links %d\n", 1293ec933656Sjmmv node, node->tn_flags, node->tn_links); 1294ec933656Sjmmv printf("\tmode 0%o, owner %d, group %d, size %" PRIdMAX 1295ec933656Sjmmv ", status 0x%x\n", 1296ec933656Sjmmv node->tn_mode, node->tn_uid, node->tn_gid, 1297ec933656Sjmmv (uintmax_t)node->tn_size, node->tn_status); 1298ec933656Sjmmv 1299ec933656Sjmmv if (vp->v_type == VFIFO) 1300ec933656Sjmmv fifo_printinfo(vp); 1301ec933656Sjmmv lockmgr_printinfo(&vp->v_lock); 1302ec933656Sjmmv 1303ec933656Sjmmv printf("\n"); 1304ec933656Sjmmv 1305ec933656Sjmmv return 0; 1306ec933656Sjmmv } 1307ec933656Sjmmv 1308ec933656Sjmmv /* --------------------------------------------------------------------- */ 1309ec933656Sjmmv 1310ec933656Sjmmv int 1311ec933656Sjmmv tmpfs_pathconf(void *v) 1312ec933656Sjmmv { 1313ec933656Sjmmv int name = ((struct vop_pathconf_args *)v)->a_name; 1314ec933656Sjmmv register_t *retval = ((struct vop_pathconf_args *)v)->a_retval; 1315ec933656Sjmmv 1316ec933656Sjmmv int error; 1317ec933656Sjmmv 1318ec933656Sjmmv error = 0; 1319ec933656Sjmmv 1320ec933656Sjmmv switch (name) { 1321ec933656Sjmmv case _PC_LINK_MAX: 1322ec933656Sjmmv *retval = LINK_MAX; 1323ec933656Sjmmv break; 1324ec933656Sjmmv 1325ec933656Sjmmv case _PC_NAME_MAX: 1326ec933656Sjmmv *retval = NAME_MAX; 1327ec933656Sjmmv break; 1328ec933656Sjmmv 1329ec933656Sjmmv case _PC_PATH_MAX: 1330ec933656Sjmmv *retval = PATH_MAX; 1331ec933656Sjmmv break; 1332ec933656Sjmmv 1333ec933656Sjmmv case _PC_PIPE_BUF: 1334ec933656Sjmmv *retval = PIPE_BUF; 1335ec933656Sjmmv break; 1336ec933656Sjmmv 1337ec933656Sjmmv case _PC_CHOWN_RESTRICTED: 1338ec933656Sjmmv *retval = 1; 1339ec933656Sjmmv break; 1340ec933656Sjmmv 1341ec933656Sjmmv case _PC_NO_TRUNC: 1342ec933656Sjmmv *retval = 1; 1343ec933656Sjmmv break; 1344ec933656Sjmmv 1345ec933656Sjmmv case _PC_SYNC_IO: 1346ec933656Sjmmv *retval = 1; 1347ec933656Sjmmv break; 1348ec933656Sjmmv 1349ec933656Sjmmv case _PC_FILESIZEBITS: 1350ec933656Sjmmv *retval = 0; /* XXX Don't know which value should I return. */ 1351ec933656Sjmmv break; 1352ec933656Sjmmv 1353ec933656Sjmmv default: 1354ec933656Sjmmv error = EINVAL; 1355ec933656Sjmmv } 1356ec933656Sjmmv 1357ec933656Sjmmv return error; 1358ec933656Sjmmv } 1359ec933656Sjmmv 1360ec933656Sjmmv /* --------------------------------------------------------------------- */ 1361ec933656Sjmmv 1362ec933656Sjmmv int 1363b6d141c7Sjmmv tmpfs_advlock(void *v) 1364b6d141c7Sjmmv { 1365b6d141c7Sjmmv struct vnode *vp = ((struct vop_advlock_args *)v)->a_vp; 1366b6d141c7Sjmmv 1367b6d141c7Sjmmv struct tmpfs_node *node; 1368b6d141c7Sjmmv 1369b6d141c7Sjmmv node = VP_TO_TMPFS_NODE(vp); 1370b6d141c7Sjmmv 1371b6d141c7Sjmmv return lf_advlock(v, &node->tn_lockf, node->tn_size); 1372b6d141c7Sjmmv } 1373b6d141c7Sjmmv 1374b6d141c7Sjmmv /* --------------------------------------------------------------------- */ 1375b6d141c7Sjmmv 1376b6d141c7Sjmmv int 1377ec933656Sjmmv tmpfs_getpages(void *v) 1378ec933656Sjmmv { 13795f4b660eSjmmv struct vnode *vp = ((struct vop_getpages_args *)v)->a_vp; 13805f4b660eSjmmv voff_t offset = ((struct vop_getpages_args *)v)->a_offset; 13815f4b660eSjmmv struct vm_page **m = ((struct vop_getpages_args *)v)->a_m; 13825f4b660eSjmmv int *count = ((struct vop_getpages_args *)v)->a_count; 13835f4b660eSjmmv int centeridx = ((struct vop_getpages_args *)v)->a_centeridx; 13845f4b660eSjmmv vm_prot_t access_type = ((struct vop_getpages_args *)v)->a_access_type; 13855f4b660eSjmmv int advice = ((struct vop_getpages_args *)v)->a_advice; 13865f4b660eSjmmv int flags = ((struct vop_getpages_args *)v)->a_flags; 13875f4b660eSjmmv 1388ec933656Sjmmv int error; 138951634dfdSjmmv int i; 13905f4b660eSjmmv struct tmpfs_node *node; 13915f4b660eSjmmv struct uvm_object *uobj; 139220bb9654Syamt int npages = *count; 1393ec933656Sjmmv 1394647aa775Syamt KASSERT(vp->v_type == VREG); 1395647aa775Syamt LOCK_ASSERT(simple_lock_held(&vp->v_interlock)); 1396ec933656Sjmmv 13975f4b660eSjmmv node = VP_TO_TMPFS_NODE(vp); 1398064fbe7eSjmmv uobj = node->tn_spec.tn_reg.tn_aobj; 13995f4b660eSjmmv 140020bb9654Syamt /* We currently don't rely on PGO_PASTEOF. */ 140120bb9654Syamt 140220bb9654Syamt if (vp->v_size <= offset + (centeridx << PAGE_SHIFT)) { 140320bb9654Syamt if ((flags & PGO_LOCKED) == 0) 140420bb9654Syamt simple_unlock(&vp->v_interlock); 140520bb9654Syamt return EINVAL; 140620bb9654Syamt } 140720bb9654Syamt 140820bb9654Syamt if (vp->v_size < offset + (npages << PAGE_SHIFT)) { 140920bb9654Syamt npages = (round_page(vp->v_size) - offset) >> PAGE_SHIFT; 141020bb9654Syamt } 141120bb9654Syamt 14125f4b660eSjmmv if ((flags & PGO_LOCKED) != 0) 1413647aa775Syamt return EBUSY; 1414ec933656Sjmmv 1415647aa775Syamt if ((flags & PGO_NOTIMESTAMP) == 0) { 14165f4b660eSjmmv if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0) 1417ec933656Sjmmv node->tn_status |= TMPFS_NODE_ACCESSED; 14185f4b660eSjmmv 14195f4b660eSjmmv if ((access_type & VM_PROT_WRITE) != 0) 1420647aa775Syamt node->tn_status |= TMPFS_NODE_MODIFIED; 1421647aa775Syamt } 1422ec933656Sjmmv 1423647aa775Syamt simple_unlock(&vp->v_interlock); 1424647aa775Syamt 142551634dfdSjmmv /* 142651634dfdSjmmv * Make sure that the array on which we will store the 142751634dfdSjmmv * gotten pages is clean. Otherwise uao_get (pointed to by 142851634dfdSjmmv * the pgo_get below) gets confused and does not return the 142951634dfdSjmmv * appropriate pages. 143051634dfdSjmmv * 143151634dfdSjmmv * XXX This shall be revisited when kern/32166 is addressed 143251634dfdSjmmv * because the loop to clean m[i] will most likely be redundant 143351634dfdSjmmv * as well as the PGO_ALLPAGES flag. 143451634dfdSjmmv */ 143551634dfdSjmmv if (m != NULL) 143651634dfdSjmmv for (i = 0; i < npages; i++) 143751634dfdSjmmv m[i] = NULL; 1438647aa775Syamt simple_lock(&uobj->vmobjlock); 143920bb9654Syamt error = (*uobj->pgops->pgo_get)(uobj, offset, m, &npages, centeridx, 144051634dfdSjmmv access_type, advice, flags | PGO_ALLPAGES); 144151634dfdSjmmv #if defined(DEBUG) 144251634dfdSjmmv { 144351634dfdSjmmv /* Make sure that all the pages we return are valid. */ 144451634dfdSjmmv int dbgi; 144551634dfdSjmmv if (error == 0 && m != NULL) 144651634dfdSjmmv for (dbgi = 0; dbgi < npages; dbgi++) 144751634dfdSjmmv KASSERT(m[dbgi] != NULL); 144851634dfdSjmmv } 144951634dfdSjmmv #endif 1450647aa775Syamt 1451647aa775Syamt return error; 1452647aa775Syamt } 1453647aa775Syamt 1454647aa775Syamt /* --------------------------------------------------------------------- */ 1455647aa775Syamt 1456647aa775Syamt int 1457647aa775Syamt tmpfs_putpages(void *v) 1458647aa775Syamt { 14595f4b660eSjmmv struct vnode *vp = ((struct vop_putpages_args *)v)->a_vp; 14605f4b660eSjmmv voff_t offlo = ((struct vop_putpages_args *)v)->a_offlo; 14615f4b660eSjmmv voff_t offhi = ((struct vop_putpages_args *)v)->a_offhi; 14625f4b660eSjmmv int flags = ((struct vop_putpages_args *)v)->a_flags; 14635f4b660eSjmmv 1464647aa775Syamt int error; 14655f4b660eSjmmv struct tmpfs_node *node; 14665f4b660eSjmmv struct uvm_object *uobj; 1467647aa775Syamt 1468647aa775Syamt LOCK_ASSERT(simple_lock_held(&vp->v_interlock)); 1469647aa775Syamt 14705f4b660eSjmmv node = VP_TO_TMPFS_NODE(vp); 14715f4b660eSjmmv 1472647aa775Syamt if (vp->v_type != VREG) { 1473647aa775Syamt simple_unlock(&vp->v_interlock); 1474647aa775Syamt return 0; 1475647aa775Syamt } 1476647aa775Syamt 1477064fbe7eSjmmv uobj = node->tn_spec.tn_reg.tn_aobj; 1478647aa775Syamt simple_unlock(&vp->v_interlock); 1479647aa775Syamt 1480647aa775Syamt simple_lock(&uobj->vmobjlock); 14815f4b660eSjmmv error = (*uobj->pgops->pgo_put)(uobj, offlo, offhi, flags); 1482647aa775Syamt 1483647aa775Syamt /* XXX mtime */ 1484647aa775Syamt 1485ec933656Sjmmv return error; 1486ec933656Sjmmv } 1487