1*f63b58d1Sjmmv /* $NetBSD: tmpfs_vnops.c,v 1.11 2005/09/23 14:27:55 jmmv Exp $ */ 2ec933656Sjmmv 3ec933656Sjmmv /* 4ec933656Sjmmv * Copyright (c) 2005 The NetBSD Foundation, Inc. 5ec933656Sjmmv * All rights reserved. 6ec933656Sjmmv * 7ec933656Sjmmv * This code is derived from software contributed to The NetBSD Foundation 8ec933656Sjmmv * by Julio M. Merino Vidal. 9ec933656Sjmmv * 10ec933656Sjmmv * Redistribution and use in source and binary forms, with or without 11ec933656Sjmmv * modification, are permitted provided that the following conditions 12ec933656Sjmmv * are met: 13ec933656Sjmmv * 1. Redistributions of source code must retain the above copyright 14ec933656Sjmmv * notice, this list of conditions and the following disclaimer. 15ec933656Sjmmv * 2. Redistributions in binary form must reproduce the above copyright 16ec933656Sjmmv * notice, this list of conditions and the following disclaimer in the 17ec933656Sjmmv * documentation and/or other materials provided with the distribution. 18ec933656Sjmmv * 3. All advertising materials mentioning features or use of this software 19ec933656Sjmmv * must display the following acknowledgement: 20ec933656Sjmmv * This product includes software developed by the NetBSD 21ec933656Sjmmv * Foundation, Inc. and its contributors. 22ec933656Sjmmv * 4. Neither the name of The NetBSD Foundation nor the names of its 23ec933656Sjmmv * contributors may be used to endorse or promote products derived 24ec933656Sjmmv * from this software without specific prior written permission. 25ec933656Sjmmv * 26ec933656Sjmmv * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27ec933656Sjmmv * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28ec933656Sjmmv * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29ec933656Sjmmv * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30ec933656Sjmmv * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31ec933656Sjmmv * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32ec933656Sjmmv * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33ec933656Sjmmv * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34ec933656Sjmmv * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35ec933656Sjmmv * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36ec933656Sjmmv * POSSIBILITY OF SUCH DAMAGE. 37ec933656Sjmmv */ 38ec933656Sjmmv 39ec933656Sjmmv /* 40ec933656Sjmmv * tmpfs vnode interface. 41ec933656Sjmmv */ 42ec933656Sjmmv 43ec933656Sjmmv #include <sys/cdefs.h> 44*f63b58d1Sjmmv __KERNEL_RCSID(0, "$NetBSD: tmpfs_vnops.c,v 1.11 2005/09/23 14:27:55 jmmv Exp $"); 45ec933656Sjmmv 46ec933656Sjmmv #include <sys/param.h> 47ec933656Sjmmv #include <sys/dirent.h> 48ec933656Sjmmv #include <sys/fcntl.h> 49ec933656Sjmmv #include <sys/event.h> 50ec933656Sjmmv #include <sys/malloc.h> 51ec933656Sjmmv #include <sys/namei.h> 52ec933656Sjmmv #include <sys/proc.h> 53ec933656Sjmmv #include <sys/stat.h> 54ec933656Sjmmv #include <sys/uio.h> 55ec933656Sjmmv #include <sys/unistd.h> 56ec933656Sjmmv #include <sys/vnode.h> 57ec933656Sjmmv 58ec933656Sjmmv #include <uvm/uvm.h> 59ec933656Sjmmv 60ec933656Sjmmv #include <miscfs/fifofs/fifo.h> 61ec933656Sjmmv #include <fs/tmpfs/tmpfs_vnops.h> 62ec933656Sjmmv #include <fs/tmpfs/tmpfs.h> 63ec933656Sjmmv 64ec933656Sjmmv /* --------------------------------------------------------------------- */ 65ec933656Sjmmv 66ec933656Sjmmv /* 678e0a777aSjmmv * vnode operations vector used for files stored in a tmpfs file system. 68ec933656Sjmmv */ 69ec933656Sjmmv int (**tmpfs_vnodeop_p)(void *); 70ec933656Sjmmv const struct vnodeopv_entry_desc tmpfs_vnodeop_entries[] = { 71ec933656Sjmmv { &vop_default_desc, vn_default_error }, 72ec933656Sjmmv { &vop_lookup_desc, tmpfs_lookup }, 73ec933656Sjmmv { &vop_create_desc, tmpfs_create }, 74ec933656Sjmmv { &vop_mknod_desc, tmpfs_mknod }, 75ec933656Sjmmv { &vop_open_desc, tmpfs_open }, 76ec933656Sjmmv { &vop_close_desc, tmpfs_close }, 77ec933656Sjmmv { &vop_access_desc, tmpfs_access }, 78ec933656Sjmmv { &vop_getattr_desc, tmpfs_getattr }, 79ec933656Sjmmv { &vop_setattr_desc, tmpfs_setattr }, 80ec933656Sjmmv { &vop_read_desc, tmpfs_read }, 81ec933656Sjmmv { &vop_write_desc, tmpfs_write }, 82ec933656Sjmmv { &vop_ioctl_desc, tmpfs_ioctl }, 83ec933656Sjmmv { &vop_fcntl_desc, tmpfs_fcntl }, 84ec933656Sjmmv { &vop_poll_desc, tmpfs_poll }, 85ec933656Sjmmv { &vop_kqfilter_desc, tmpfs_kqfilter }, 86ec933656Sjmmv { &vop_revoke_desc, tmpfs_revoke }, 87ec933656Sjmmv { &vop_mmap_desc, tmpfs_mmap }, 88ec933656Sjmmv { &vop_fsync_desc, tmpfs_fsync }, 89ec933656Sjmmv { &vop_seek_desc, tmpfs_seek }, 90ec933656Sjmmv { &vop_remove_desc, tmpfs_remove }, 91ec933656Sjmmv { &vop_link_desc, tmpfs_link }, 92ec933656Sjmmv { &vop_rename_desc, tmpfs_rename }, 93ec933656Sjmmv { &vop_mkdir_desc, tmpfs_mkdir }, 94ec933656Sjmmv { &vop_rmdir_desc, tmpfs_rmdir }, 95ec933656Sjmmv { &vop_symlink_desc, tmpfs_symlink }, 96ec933656Sjmmv { &vop_readdir_desc, tmpfs_readdir }, 97ec933656Sjmmv { &vop_readlink_desc, tmpfs_readlink }, 98ec933656Sjmmv { &vop_abortop_desc, tmpfs_abortop }, 99ec933656Sjmmv { &vop_inactive_desc, tmpfs_inactive }, 100ec933656Sjmmv { &vop_reclaim_desc, tmpfs_reclaim }, 101ec933656Sjmmv { &vop_lock_desc, tmpfs_lock }, 102ec933656Sjmmv { &vop_unlock_desc, tmpfs_unlock }, 103ec933656Sjmmv { &vop_bmap_desc, tmpfs_bmap }, 104ec933656Sjmmv { &vop_strategy_desc, tmpfs_strategy }, 105ec933656Sjmmv { &vop_print_desc, tmpfs_print }, 106ec933656Sjmmv { &vop_pathconf_desc, tmpfs_pathconf }, 107ec933656Sjmmv { &vop_islocked_desc, tmpfs_islocked }, 108ec933656Sjmmv { &vop_advlock_desc, tmpfs_advlock }, 109ec933656Sjmmv { &vop_blkatoff_desc, tmpfs_blkatoff }, 110ec933656Sjmmv { &vop_valloc_desc, tmpfs_valloc }, 111ec933656Sjmmv { &vop_reallocblks_desc, tmpfs_reallocblks }, 112ec933656Sjmmv { &vop_vfree_desc, tmpfs_vfree }, 113ec933656Sjmmv { &vop_truncate_desc, tmpfs_truncate }, 114ec933656Sjmmv { &vop_update_desc, tmpfs_update }, 115ec933656Sjmmv { &vop_lease_desc, tmpfs_lease }, 116ec933656Sjmmv { &vop_bwrite_desc, tmpfs_bwrite }, 117ec933656Sjmmv { &vop_getpages_desc, tmpfs_getpages }, 118ec933656Sjmmv { &vop_putpages_desc, tmpfs_putpages }, 119ec933656Sjmmv { NULL, NULL } 120ec933656Sjmmv }; 121ec933656Sjmmv const struct vnodeopv_desc tmpfs_vnodeop_opv_desc = 122ec933656Sjmmv { &tmpfs_vnodeop_p, tmpfs_vnodeop_entries }; 123ec933656Sjmmv 124ec933656Sjmmv /* --------------------------------------------------------------------- */ 125ec933656Sjmmv 126ec933656Sjmmv int 127ec933656Sjmmv tmpfs_lookup(void *v) 128ec933656Sjmmv { 129ec933656Sjmmv struct vnode *dvp = ((struct vop_lookup_args *)v)->a_dvp; 130ec933656Sjmmv struct vnode **vpp = ((struct vop_lookup_args *)v)->a_vpp; 131ec933656Sjmmv struct componentname *cnp = ((struct vop_lookup_args *)v)->a_cnp; 132ec933656Sjmmv 133ec933656Sjmmv int error; 134ec933656Sjmmv struct tmpfs_dirent *de; 135ec933656Sjmmv struct tmpfs_node *dnode; 136ec933656Sjmmv 137ec933656Sjmmv KASSERT(VOP_ISLOCKED(dvp)); 138ec933656Sjmmv 139ec933656Sjmmv dnode = VP_TO_TMPFS_DIR(dvp); 140ec933656Sjmmv *vpp = NULL; 141ec933656Sjmmv 142ec933656Sjmmv /* Check accessibility of requested node as a first step. */ 143ec933656Sjmmv error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_proc); 144ec933656Sjmmv if (error != 0) 145ec933656Sjmmv goto out; 146ec933656Sjmmv 1478e0a777aSjmmv /* If requesting the last path component on a read-only file system 148ec933656Sjmmv * with a write operation, deny it. */ 149ec933656Sjmmv if ((cnp->cn_flags & ISLASTCN) && 150ec933656Sjmmv (dvp->v_mount->mnt_flag & MNT_RDONLY) && 151ec933656Sjmmv (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) { 152ec933656Sjmmv error = EROFS; 153ec933656Sjmmv goto out; 154ec933656Sjmmv } 155ec933656Sjmmv 156ec933656Sjmmv /* Avoid doing a linear scan of the directory if the requested 157ec933656Sjmmv * directory/name couple is already in the cache. */ 158ec933656Sjmmv error = cache_lookup(dvp, vpp, cnp); 159ec933656Sjmmv if (error >= 0) 160ec933656Sjmmv goto out; 161ec933656Sjmmv 162ec933656Sjmmv /* We cannot be requesting the parent directory of the root node. */ 163ec933656Sjmmv KASSERT(IMPLIES(dnode->tn_type == VDIR && 164ec933656Sjmmv dnode->tn_parent == dnode, !(cnp->cn_flags & ISDOTDOT))); 165ec933656Sjmmv 166ec933656Sjmmv if (cnp->cn_flags & ISDOTDOT) { 167ec933656Sjmmv VOP_UNLOCK(dvp, 0); 168ec933656Sjmmv 169ec933656Sjmmv /* Allocate a new vnode on the matching entry. */ 170ec933656Sjmmv error = tmpfs_alloc_vp(dvp->v_mount, dnode->tn_parent, vpp); 171ec933656Sjmmv 172ec933656Sjmmv if (cnp->cn_flags & LOCKPARENT && 173ec933656Sjmmv cnp->cn_flags & ISLASTCN) { 174ec933656Sjmmv if (vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY) != 0) 175ec933656Sjmmv cnp->cn_flags |= PDIRUNLOCK; 176ec933656Sjmmv } 177ec933656Sjmmv dnode->tn_parent->tn_lookup_dirent = NULL; 178ec933656Sjmmv } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { 179ec933656Sjmmv VREF(dvp); 180ec933656Sjmmv *vpp = dvp; 181ec933656Sjmmv dnode->tn_lookup_dirent = NULL; 182ec933656Sjmmv error = 0; 183ec933656Sjmmv } else { 184ec933656Sjmmv de = tmpfs_dir_lookup(dnode, cnp); 185ec933656Sjmmv if (de == NULL) { 186ec933656Sjmmv /* The entry was not found in the directory. 187ec933656Sjmmv * This is OK iff we are creating or renaming an 188ec933656Sjmmv * entry and are working on the last component of 189ec933656Sjmmv * the path name. */ 190ec933656Sjmmv if ((cnp->cn_flags & ISLASTCN) && 191ec933656Sjmmv (cnp->cn_nameiop == CREATE || \ 192ec933656Sjmmv cnp->cn_nameiop == RENAME)) { 193ec933656Sjmmv error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, 194ec933656Sjmmv cnp->cn_proc); 195ec933656Sjmmv if (error != 0) 196ec933656Sjmmv goto out; 197ec933656Sjmmv 198ec933656Sjmmv /* Keep the component name in the buffer for 199ec933656Sjmmv * future uses. */ 200ec933656Sjmmv cnp->cn_flags |= SAVENAME; 201ec933656Sjmmv 202ec933656Sjmmv error = EJUSTRETURN; 203ec933656Sjmmv } else 204ec933656Sjmmv error = ENOENT; 205ec933656Sjmmv } else { 206ec933656Sjmmv struct tmpfs_node *tnode; 207ec933656Sjmmv 208ec933656Sjmmv /* The entry was found, so get its associated 209ec933656Sjmmv * tmpfs_node. */ 210ec933656Sjmmv tnode = de->td_node; 211ec933656Sjmmv 212ec933656Sjmmv /* If we are not at the last path component and 213ec933656Sjmmv * found a non-directory entry, raise an error. */ 214ec933656Sjmmv if ((tnode->tn_type != VDIR) && 215ec933656Sjmmv !(cnp->cn_flags & ISLASTCN)) { 216ec933656Sjmmv error = ENOTDIR; 217ec933656Sjmmv goto out; 218ec933656Sjmmv } 219ec933656Sjmmv 220ec933656Sjmmv /* If we are deleting or renaming the entry, keep 221ec933656Sjmmv * track of its tmpfs_dirent so that it can be 222ec933656Sjmmv * easily deleted later. */ 223ec933656Sjmmv if ((cnp->cn_flags & ISLASTCN) && 224ec933656Sjmmv (cnp->cn_nameiop == DELETE || 225ec933656Sjmmv cnp->cn_nameiop == RENAME)) { 226ec933656Sjmmv error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, 227ec933656Sjmmv cnp->cn_proc); 228ec933656Sjmmv if (error != 0) 229ec933656Sjmmv goto out; 230ec933656Sjmmv /* TODO: Check sticky bit. */ 231ec933656Sjmmv tnode->tn_lookup_dirent = de; 232ec933656Sjmmv } 233ec933656Sjmmv 234ec933656Sjmmv /* Allocate a new vnode on the matching entry. */ 235ec933656Sjmmv error = tmpfs_alloc_vp(dvp->v_mount, tnode, vpp); 236ec933656Sjmmv 237ec933656Sjmmv if (error == 0 && (!(cnp->cn_flags & LOCKPARENT) || 238ec933656Sjmmv !(cnp->cn_flags & ISLASTCN))) 239ec933656Sjmmv VOP_UNLOCK(dvp, 0); 240ec933656Sjmmv } 241ec933656Sjmmv } 242ec933656Sjmmv 243ec933656Sjmmv /* Store the result of this lookup in the cache. Avoid this if the 244ec933656Sjmmv * request was for creation, as it does not improve timings on 245ec933656Sjmmv * emprical tests. */ 246ec933656Sjmmv if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE) 247ec933656Sjmmv cache_enter(dvp, *vpp, cnp); 248ec933656Sjmmv 249ec933656Sjmmv out: 250ec933656Sjmmv /* If there were no errors, *vpp cannot be null and it must be 251ec933656Sjmmv * locked. */ 252ec933656Sjmmv KASSERT(IFF(error == 0, *vpp != NULL && VOP_ISLOCKED(*vpp))); 253ec933656Sjmmv 254ec933656Sjmmv /* dvp has to be locked if: 255ec933656Sjmmv * - There were errors and relocking of dvp did not fail. 256ec933656Sjmmv * - We are doing a '..' lookup, relocking of dvp did not fail 257ec933656Sjmmv * (PDIRUNLOCK is unset) and LOCKPARENT or ISLASTCN are not set. 258ec933656Sjmmv * - LOCKPARENT and ISLASTCN are set. */ 259ec933656Sjmmv KASSERT(IMPLIES( 260ec933656Sjmmv (error != 0 && !(cnp->cn_flags & PDIRUNLOCK)) || 261ec933656Sjmmv (cnp->cn_flags & ISDOTDOT && !(cnp->cn_flags & PDIRUNLOCK) && 262ec933656Sjmmv ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))) || 263ec933656Sjmmv (cnp->cn_flags & LOCKPARENT && cnp->cn_flags & ISLASTCN) 264ec933656Sjmmv , 265ec933656Sjmmv VOP_ISLOCKED(dvp))); 266ec933656Sjmmv 267ec933656Sjmmv return error; 268ec933656Sjmmv } 269ec933656Sjmmv 270ec933656Sjmmv /* --------------------------------------------------------------------- */ 271ec933656Sjmmv 272ec933656Sjmmv int 273ec933656Sjmmv tmpfs_create(void *v) 274ec933656Sjmmv { 275ec933656Sjmmv struct vnode *dvp = ((struct vop_create_args *)v)->a_dvp; 276ec933656Sjmmv struct vnode **vpp = ((struct vop_create_args *)v)->a_vpp; 277ec933656Sjmmv struct componentname *cnp = ((struct vop_create_args *)v)->a_cnp; 278ec933656Sjmmv struct vattr *vap = ((struct vop_create_args *)v)->a_vap; 279ec933656Sjmmv 280ec933656Sjmmv KASSERT(vap->va_type == VREG || vap->va_type == VSOCK); 281ec933656Sjmmv 282ec933656Sjmmv return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL); 283ec933656Sjmmv } 284ec933656Sjmmv /* --------------------------------------------------------------------- */ 285ec933656Sjmmv 286ec933656Sjmmv int 287ec933656Sjmmv tmpfs_mknod(void *v) 288ec933656Sjmmv { 289ec933656Sjmmv struct vnode *dvp = ((struct vop_mknod_args *)v)->a_dvp; 290ec933656Sjmmv struct vnode **vpp = ((struct vop_mknod_args *)v)->a_vpp; 291ec933656Sjmmv struct componentname *cnp = ((struct vop_mknod_args *)v)->a_cnp; 292ec933656Sjmmv struct vattr *vap = ((struct vop_mknod_args *)v)->a_vap; 293ec933656Sjmmv 294ec933656Sjmmv if (vap->va_type != VBLK && vap->va_type != VCHR && 295ec933656Sjmmv vap->va_type != VFIFO) 296ec933656Sjmmv return EINVAL; 297ec933656Sjmmv 298ec933656Sjmmv return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL); 299ec933656Sjmmv } 300ec933656Sjmmv 301ec933656Sjmmv /* --------------------------------------------------------------------- */ 302ec933656Sjmmv 303ec933656Sjmmv int 304ec933656Sjmmv tmpfs_open(void *v) 305ec933656Sjmmv { 306ec933656Sjmmv struct vnode *vp = ((struct vop_open_args *)v)->a_vp; 307ec933656Sjmmv int mode = ((struct vop_open_args *)v)->a_mode; 308ec933656Sjmmv 309ec933656Sjmmv int error; 310ec933656Sjmmv struct tmpfs_node *node; 311ec933656Sjmmv 312ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 313ec933656Sjmmv 314ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 315ec933656Sjmmv KASSERT(node->tn_links > 0); 316ec933656Sjmmv 317ec933656Sjmmv /* If the file is marked append-only, deny write requests. */ 318ec933656Sjmmv if (node->tn_flags & APPEND && (mode & (FWRITE | O_APPEND)) == FWRITE) 319ec933656Sjmmv error = EPERM; 320ec933656Sjmmv else 321ec933656Sjmmv error = 0; 322ec933656Sjmmv 323ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 324ec933656Sjmmv 325ec933656Sjmmv return error; 326ec933656Sjmmv } 327ec933656Sjmmv 328ec933656Sjmmv /* --------------------------------------------------------------------- */ 329ec933656Sjmmv 330ec933656Sjmmv int 331ec933656Sjmmv tmpfs_close(void *v) 332ec933656Sjmmv { 333ec933656Sjmmv struct vnode *vp = ((struct vop_close_args *)v)->a_vp; 334ec933656Sjmmv 335ec933656Sjmmv int error; 336ec933656Sjmmv struct tmpfs_node *node; 337ec933656Sjmmv 338ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 339ec933656Sjmmv 340ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 341ec933656Sjmmv 342ec933656Sjmmv if (node->tn_links > 0) { 343ec933656Sjmmv /* Update node times. No need to do it if the node has 344ec933656Sjmmv * been deleted, because it will vanish after we return. */ 345ec933656Sjmmv error = VOP_UPDATE(vp, NULL, NULL, UPDATE_CLOSE); 346ec933656Sjmmv } else 347ec933656Sjmmv error = 0; 348ec933656Sjmmv 349ec933656Sjmmv return error; 350ec933656Sjmmv } 351ec933656Sjmmv 352ec933656Sjmmv /* --------------------------------------------------------------------- */ 353ec933656Sjmmv 354ec933656Sjmmv int 355ec933656Sjmmv tmpfs_access(void *v) 356ec933656Sjmmv { 357ec933656Sjmmv struct vnode *vp = ((struct vop_access_args *)v)->a_vp; 358ec933656Sjmmv int mode = ((struct vop_access_args *)v)->a_mode; 359ec933656Sjmmv struct ucred *cred = ((struct vop_access_args *)v)->a_cred; 360ec933656Sjmmv 361ec933656Sjmmv int error; 362ec933656Sjmmv struct tmpfs_node *node; 363ec933656Sjmmv 364ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 365ec933656Sjmmv 366ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 367ec933656Sjmmv 368ec933656Sjmmv switch (vp->v_type) { 369ec933656Sjmmv case VDIR: 370ec933656Sjmmv /* FALLTHROUGH */ 371ec933656Sjmmv case VLNK: 372ec933656Sjmmv /* FALLTHROUGH */ 373ec933656Sjmmv case VREG: 374ec933656Sjmmv if (mode & VWRITE && vp->v_mount->mnt_flag & MNT_RDONLY) { 375ec933656Sjmmv error = EROFS; 376ec933656Sjmmv goto out; 377ec933656Sjmmv } 378ec933656Sjmmv break; 379ec933656Sjmmv 380ec933656Sjmmv case VBLK: 381ec933656Sjmmv /* FALLTHROUGH */ 382ec933656Sjmmv case VCHR: 383ec933656Sjmmv /* FALLTHROUGH */ 384ec933656Sjmmv case VSOCK: 385ec933656Sjmmv /* FALLTHROUGH */ 386ec933656Sjmmv case VFIFO: 387ec933656Sjmmv break; 388ec933656Sjmmv 389ec933656Sjmmv default: 390ec933656Sjmmv error = EINVAL; 391ec933656Sjmmv goto out; 392ec933656Sjmmv } 393ec933656Sjmmv 394ec933656Sjmmv if (mode & VWRITE && node->tn_flags & IMMUTABLE) { 395ec933656Sjmmv error = EPERM; 396ec933656Sjmmv goto out; 397ec933656Sjmmv } 398ec933656Sjmmv 399ec933656Sjmmv error = vaccess(vp->v_type, node->tn_mode, node->tn_uid, 400ec933656Sjmmv node->tn_gid, mode, cred); 401ec933656Sjmmv 402ec933656Sjmmv out: 403ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 404ec933656Sjmmv 405ec933656Sjmmv return error; 406ec933656Sjmmv } 407ec933656Sjmmv 408ec933656Sjmmv /* --------------------------------------------------------------------- */ 409ec933656Sjmmv 410ec933656Sjmmv int 411ec933656Sjmmv tmpfs_getattr(void *v) 412ec933656Sjmmv { 413ec933656Sjmmv struct vnode *vp = ((struct vop_getattr_args *)v)->a_vp; 414ec933656Sjmmv struct vattr *vap = ((struct vop_getattr_args *)v)->a_vap; 415ec933656Sjmmv 416ec933656Sjmmv struct tmpfs_node *node; 417ec933656Sjmmv 418ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 419ec933656Sjmmv 420ec933656Sjmmv VATTR_NULL(vap); 421ec933656Sjmmv 422ec933656Sjmmv vap->va_type = vp->v_type; 423ec933656Sjmmv vap->va_mode = node->tn_mode; 424ec933656Sjmmv vap->va_nlink = node->tn_links; 425ec933656Sjmmv vap->va_uid = node->tn_uid; 426ec933656Sjmmv vap->va_gid = node->tn_gid; 427ec933656Sjmmv vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0]; 428ec933656Sjmmv vap->va_fileid = node->tn_id; 429ec933656Sjmmv vap->va_size = node->tn_size; 430ec933656Sjmmv vap->va_blocksize = PAGE_SIZE; 431ec933656Sjmmv vap->va_atime = node->tn_atime; 432ec933656Sjmmv vap->va_mtime = node->tn_mtime; 433ec933656Sjmmv vap->va_ctime = node->tn_ctime; 434ec933656Sjmmv vap->va_birthtime = node->tn_birthtime; 435ec933656Sjmmv vap->va_gen = node->tn_gen; 436ec933656Sjmmv vap->va_flags = node->tn_flags; 437ec933656Sjmmv vap->va_rdev = (vp->v_type == VBLK || vp->v_type == VCHR) ? 438ec933656Sjmmv node->tn_rdev : VNOVAL; 439ec933656Sjmmv vap->va_bytes = round_page(node->tn_size); 440ec933656Sjmmv vap->va_filerev = VNOVAL; 441ec933656Sjmmv vap->va_vaflags = 0; 442ec933656Sjmmv vap->va_spare = VNOVAL; /* XXX */ 443ec933656Sjmmv 444ec933656Sjmmv return 0; 445ec933656Sjmmv } 446ec933656Sjmmv 447ec933656Sjmmv /* --------------------------------------------------------------------- */ 448ec933656Sjmmv 449ec933656Sjmmv /* XXX Should this operation be atomic? I think it should, but code in 450ec933656Sjmmv * XXX other places (e.g., ufs) doesn't seem to be... */ 451ec933656Sjmmv int 452ec933656Sjmmv tmpfs_setattr(void *v) 453ec933656Sjmmv { 454ec933656Sjmmv struct vnode *vp = ((struct vop_setattr_args *)v)->a_vp; 455ec933656Sjmmv struct vattr *vap = ((struct vop_setattr_args *)v)->a_vap; 456ec933656Sjmmv struct ucred *cred = ((struct vop_setattr_args *)v)->a_cred; 457ec933656Sjmmv struct proc *p = ((struct vop_setattr_args *)v)->a_p; 458ec933656Sjmmv 459ec933656Sjmmv int error, error2; 460ec933656Sjmmv 461ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 462ec933656Sjmmv 463ec933656Sjmmv error = 0; 464ec933656Sjmmv 465ec933656Sjmmv /* Abort if any unsettable attribute is given. */ 466ec933656Sjmmv if (vap->va_type != VNON || 467ec933656Sjmmv vap->va_nlink != VNOVAL || 468ec933656Sjmmv vap->va_fsid != VNOVAL || 469ec933656Sjmmv vap->va_fileid != VNOVAL || 470ec933656Sjmmv vap->va_blocksize != VNOVAL || 471ec933656Sjmmv vap->va_ctime.tv_sec != VNOVAL || 472ec933656Sjmmv vap->va_ctime.tv_nsec != VNOVAL || 473ec933656Sjmmv vap->va_birthtime.tv_sec != VNOVAL || 474ec933656Sjmmv vap->va_birthtime.tv_nsec != VNOVAL || 475ec933656Sjmmv vap->va_gen != VNOVAL || 476ec933656Sjmmv vap->va_rdev != VNOVAL || 477ec933656Sjmmv vap->va_bytes != VNOVAL) 478ec933656Sjmmv error = EINVAL; 479ec933656Sjmmv 480ec933656Sjmmv if (error == 0 && (vap->va_flags != VNOVAL)) 481ec933656Sjmmv error = tmpfs_chflags(vp, vap->va_flags, cred, p); 482ec933656Sjmmv 483ec933656Sjmmv if (error == 0 && (vap->va_size != VNOVAL)) 484ec933656Sjmmv error = tmpfs_chsize(vp, vap->va_size, cred, p); 485ec933656Sjmmv 486ec933656Sjmmv if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL)) 487ec933656Sjmmv error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred, p); 488ec933656Sjmmv 489ec933656Sjmmv if (error == 0 && (vap->va_mode != VNOVAL)) 490ec933656Sjmmv error = tmpfs_chmod(vp, vap->va_mode, cred, p); 491ec933656Sjmmv 492ec933656Sjmmv if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL && 493ec933656Sjmmv vap->va_atime.tv_nsec != VNOVAL) || 494ec933656Sjmmv (vap->va_mtime.tv_sec != VNOVAL && 495ec933656Sjmmv vap->va_mtime.tv_nsec != VNOVAL))) 496ec933656Sjmmv error = tmpfs_chtimes(vp, &vap->va_atime, &vap->va_mtime, 497ec933656Sjmmv vap->va_vaflags, cred, p); 498ec933656Sjmmv 499ec933656Sjmmv /* Update the node times. We give preference to the error codes 500ec933656Sjmmv * generated by this function rather than the ones that may arise 501ec933656Sjmmv * from tmpfs_update. */ 502ec933656Sjmmv error2 = VOP_UPDATE(vp, NULL, NULL, 0); 503ec933656Sjmmv if (error == 0) 504ec933656Sjmmv error = error2; 505ec933656Sjmmv 506ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 507ec933656Sjmmv 508ec933656Sjmmv return error; 509ec933656Sjmmv } 510ec933656Sjmmv 511ec933656Sjmmv /* --------------------------------------------------------------------- */ 512ec933656Sjmmv 513ec933656Sjmmv int 514ec933656Sjmmv tmpfs_read(void *v) 515ec933656Sjmmv { 516ec933656Sjmmv struct vnode *vp = ((struct vop_read_args *)v)->a_vp; 517ec933656Sjmmv struct uio *uio = ((struct vop_read_args *)v)->a_uio; 518ec933656Sjmmv 5195f4b660eSjmmv int error; 5205f4b660eSjmmv int flags; 521ec933656Sjmmv struct tmpfs_node *node; 522647aa775Syamt struct uvm_object *uobj; 523ec933656Sjmmv 524ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 525ec933656Sjmmv 526ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 527ec933656Sjmmv 528a7ca1cc6Syamt if (vp->v_type != VREG) { 529a7ca1cc6Syamt error = EISDIR; 530a7ca1cc6Syamt goto out; 531a7ca1cc6Syamt } 532a7ca1cc6Syamt 533a7ca1cc6Syamt if (uio->uio_offset < 0) { 534ec933656Sjmmv error = EINVAL; 535ec933656Sjmmv goto out; 536ec933656Sjmmv } 537ec933656Sjmmv 538ec933656Sjmmv node->tn_status |= TMPFS_NODE_ACCESSED; 539ec933656Sjmmv 540647aa775Syamt uobj = node->tn_aobj; 541647aa775Syamt flags = UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0; 542ec933656Sjmmv error = 0; 5435f4b660eSjmmv while (error == 0 && uio->uio_resid > 0) { 544647aa775Syamt vsize_t len; 545647aa775Syamt void *win; 546ec933656Sjmmv 5477720dda1Syamt if (node->tn_size <= uio->uio_offset) 5487720dda1Syamt break; 5497720dda1Syamt 550ec933656Sjmmv len = MIN(node->tn_size - uio->uio_offset, uio->uio_resid); 5515f4b660eSjmmv if (len == 0) 552647aa775Syamt break; 5535f4b660eSjmmv 554647aa775Syamt win = ubc_alloc(uobj, uio->uio_offset, &len, UBC_READ); 555647aa775Syamt error = uiomove(win, len, uio); 556647aa775Syamt ubc_release(win, flags); 557647aa775Syamt } 558ec933656Sjmmv 559ec933656Sjmmv out: 560ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 561ec933656Sjmmv 562ec933656Sjmmv return error; 563ec933656Sjmmv } 564ec933656Sjmmv 565ec933656Sjmmv /* --------------------------------------------------------------------- */ 566ec933656Sjmmv 567ec933656Sjmmv int 568ec933656Sjmmv tmpfs_write(void *v) 569ec933656Sjmmv { 570ec933656Sjmmv struct vnode *vp = ((struct vop_write_args *)v)->a_vp; 571ec933656Sjmmv struct uio *uio = ((struct vop_write_args *)v)->a_uio; 572ec933656Sjmmv int ioflag = ((struct vop_write_args *)v)->a_ioflag; 573ec933656Sjmmv 574ec933656Sjmmv boolean_t extended; 575ec933656Sjmmv int error; 5765f4b660eSjmmv int flags; 577ec933656Sjmmv off_t oldsize; 578ec933656Sjmmv struct tmpfs_node *node; 579647aa775Syamt struct uvm_object *uobj; 580ec933656Sjmmv 581ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 582ec933656Sjmmv 583ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 584ec933656Sjmmv oldsize = node->tn_size; 585ec933656Sjmmv 586ec933656Sjmmv if (uio->uio_offset < 0 || vp->v_type != VREG) { 587ec933656Sjmmv error = EINVAL; 588ec933656Sjmmv goto out; 589ec933656Sjmmv } 590ec933656Sjmmv 591ec933656Sjmmv if (uio->uio_resid == 0) { 592ec933656Sjmmv error = 0; 593ec933656Sjmmv goto out; 594ec933656Sjmmv } 595ec933656Sjmmv 596ec933656Sjmmv if (ioflag & IO_APPEND) 597ec933656Sjmmv uio->uio_offset = node->tn_size; 598ec933656Sjmmv 599ec933656Sjmmv extended = uio->uio_offset + uio->uio_resid > node->tn_size; 600ec933656Sjmmv if (extended) { 601ec933656Sjmmv error = tmpfs_reg_resize(vp, uio->uio_offset + uio->uio_resid); 602ec933656Sjmmv if (error != 0) 603ec933656Sjmmv goto out; 604ec933656Sjmmv } 605ec933656Sjmmv 606647aa775Syamt uobj = node->tn_aobj; 607647aa775Syamt flags = UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0; 608647aa775Syamt error = 0; 6095f4b660eSjmmv while (error == 0 && uio->uio_resid > 0) { 610647aa775Syamt vsize_t len; 611647aa775Syamt void *win; 612647aa775Syamt 613647aa775Syamt len = MIN(node->tn_size - uio->uio_offset, uio->uio_resid); 6145f4b660eSjmmv if (len == 0) 615647aa775Syamt break; 6165f4b660eSjmmv 617647aa775Syamt win = ubc_alloc(uobj, uio->uio_offset, &len, UBC_WRITE); 618647aa775Syamt error = uiomove(win, len, uio); 619647aa775Syamt ubc_release(win, flags); 620647aa775Syamt } 621647aa775Syamt 622ec933656Sjmmv node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | 623ec933656Sjmmv (extended ? TMPFS_NODE_CHANGED : 0); 624ec933656Sjmmv 6255f4b660eSjmmv if (error != 0) 626647aa775Syamt (void)tmpfs_reg_resize(vp, oldsize); 627647aa775Syamt 628ec933656Sjmmv out: 629ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 630ec933656Sjmmv KASSERT(IMPLIES(error == 0, uio->uio_resid == 0)); 631ec933656Sjmmv KASSERT(IMPLIES(error != 0, oldsize == node->tn_size)); 632ec933656Sjmmv 633ec933656Sjmmv return error; 634ec933656Sjmmv } 635ec933656Sjmmv 636ec933656Sjmmv /* --------------------------------------------------------------------- */ 637ec933656Sjmmv 638ec933656Sjmmv int 639ec933656Sjmmv tmpfs_fsync(void *v) 640ec933656Sjmmv { 641ec933656Sjmmv struct vnode *vp = ((struct vop_fsync_args *)v)->a_vp; 642ec933656Sjmmv 643ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 644ec933656Sjmmv 645ec933656Sjmmv return VOP_UPDATE(vp, NULL, NULL, 0); 646ec933656Sjmmv } 647ec933656Sjmmv 648ec933656Sjmmv /* --------------------------------------------------------------------- */ 649ec933656Sjmmv 650ec933656Sjmmv int 651ec933656Sjmmv tmpfs_remove(void *v) 652ec933656Sjmmv { 653ec933656Sjmmv struct vnode *dvp = ((struct vop_remove_args *)v)->a_dvp; 654ec933656Sjmmv struct vnode *vp = ((struct vop_remove_args *)v)->a_vp; 655ec933656Sjmmv 656ec933656Sjmmv int error; 657ec933656Sjmmv struct tmpfs_dirent *de; 658ec933656Sjmmv struct tmpfs_mount *tmp; 659ec933656Sjmmv struct tmpfs_node *dnode; 660ec933656Sjmmv struct tmpfs_node *node; 661ec933656Sjmmv 662ec933656Sjmmv KASSERT(VOP_ISLOCKED(dvp)); 663ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 664ec933656Sjmmv 665ec933656Sjmmv dnode = VP_TO_TMPFS_DIR(dvp); 666ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 667ec933656Sjmmv tmp = VFS_TO_TMPFS(vp->v_mount); 668ec933656Sjmmv de = node->tn_lookup_dirent; 669ec933656Sjmmv KASSERT(de != NULL); 670ec933656Sjmmv 671ec933656Sjmmv /* XXX: Why isn't this done by the caller? */ 672ec933656Sjmmv if (vp->v_type == VDIR) { 673ec933656Sjmmv error = EISDIR; 674ec933656Sjmmv goto out; 675ec933656Sjmmv } 676ec933656Sjmmv 677ec933656Sjmmv /* Files marked as immutable or append-only cannot be deleted. */ 678ec933656Sjmmv if (node->tn_flags & (IMMUTABLE | APPEND)) { 679ec933656Sjmmv error = EPERM; 680ec933656Sjmmv goto out; 681ec933656Sjmmv } 682ec933656Sjmmv 683ec933656Sjmmv /* Remove the entry from the directory; as it is a file, we do not 684ec933656Sjmmv * have to change the number of hard links of the directory. */ 685ec933656Sjmmv tmpfs_dir_detach(dvp, de); 686ec933656Sjmmv 687ec933656Sjmmv /* Notify interested parties about the modification of dvp. 688ec933656Sjmmv * The removal of vp is notified when it is reclaimed. */ 689ec933656Sjmmv VN_KNOTE(dvp, NOTE_WRITE); 690ec933656Sjmmv 691ec933656Sjmmv /* Free the directory entry we just deleted. Note that the node 692ec933656Sjmmv * referred by it will not be removed until the vnode is really 693ec933656Sjmmv * reclaimed. */ 694ec933656Sjmmv tmpfs_free_dirent(tmp, de, TRUE); 695ec933656Sjmmv 696ec933656Sjmmv error = 0; 697ec933656Sjmmv 698ec933656Sjmmv out: 699ec933656Sjmmv vput(dvp); 700ec933656Sjmmv vput(vp); 701ec933656Sjmmv 702ec933656Sjmmv KASSERT(!VOP_ISLOCKED(dvp)); 703ec933656Sjmmv 704ec933656Sjmmv return error; 705ec933656Sjmmv } 706ec933656Sjmmv 707ec933656Sjmmv /* --------------------------------------------------------------------- */ 708ec933656Sjmmv 709ec933656Sjmmv int 710ec933656Sjmmv tmpfs_link(void *v) 711ec933656Sjmmv { 712ec933656Sjmmv struct vnode *dvp = ((struct vop_link_args *)v)->a_dvp; 713ec933656Sjmmv struct vnode *vp = ((struct vop_link_args *)v)->a_vp; 714ec933656Sjmmv struct componentname *cnp = ((struct vop_link_args *)v)->a_cnp; 715ec933656Sjmmv 716ec933656Sjmmv int error; 717ec933656Sjmmv struct tmpfs_dirent *de; 718ec933656Sjmmv struct tmpfs_node *dnode; 719ec933656Sjmmv struct tmpfs_node *node; 720ec933656Sjmmv 721ec933656Sjmmv KASSERT(VOP_ISLOCKED(dvp)); 722ec933656Sjmmv KASSERT(!VOP_ISLOCKED(vp)); 723ec933656Sjmmv KASSERT(cnp->cn_flags & HASBUF); 724ec933656Sjmmv KASSERT(dvp != vp); /* XXX When can this be false? */ 725ec933656Sjmmv 726ec933656Sjmmv dnode = VP_TO_TMPFS_DIR(dvp); 727ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 728ec933656Sjmmv 729ec933656Sjmmv /* Lock vp because we will need to run VOP_UPDATE over it, which 730ec933656Sjmmv * needs the vnode to be locked. */ 731ec933656Sjmmv error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 732ec933656Sjmmv if (error != 0) 733ec933656Sjmmv goto out; 734ec933656Sjmmv 735ec933656Sjmmv /* XXX: Why aren't the following two tests done by the caller? */ 736ec933656Sjmmv 737ec933656Sjmmv /* Hard links of directories are forbidden. */ 738ec933656Sjmmv if (vp->v_type == VDIR) { 739ec933656Sjmmv error = EPERM; 740ec933656Sjmmv goto out; 741ec933656Sjmmv } 742ec933656Sjmmv 743ec933656Sjmmv /* Cannot create cross-device links. */ 744ec933656Sjmmv if (dvp->v_mount != vp->v_mount) { 745ec933656Sjmmv error = EXDEV; 746ec933656Sjmmv goto out; 747ec933656Sjmmv } 748ec933656Sjmmv 749ec933656Sjmmv /* Ensure that we do not overflow the maximum number of links imposed 750ec933656Sjmmv * by the system. */ 751ec933656Sjmmv KASSERT(node->tn_links <= LINK_MAX); 752ec933656Sjmmv if (node->tn_links == LINK_MAX) { 753ec933656Sjmmv error = EMLINK; 754ec933656Sjmmv goto out; 755ec933656Sjmmv } 756ec933656Sjmmv 757ec933656Sjmmv /* We cannot create links of files marked immutable or append-only. */ 758ec933656Sjmmv if (node->tn_flags & (IMMUTABLE | APPEND)) { 759ec933656Sjmmv error = EPERM; 760ec933656Sjmmv goto out; 761ec933656Sjmmv } 762ec933656Sjmmv 763ec933656Sjmmv /* Allocate a new directory entry to represent the node. */ 764ec933656Sjmmv error = tmpfs_alloc_dirent(VFS_TO_TMPFS(vp->v_mount), node, 765ec933656Sjmmv cnp->cn_nameptr, cnp->cn_namelen, &de); 766ec933656Sjmmv if (error != 0) 767ec933656Sjmmv goto out; 768ec933656Sjmmv 769ec933656Sjmmv /* Insert the new directory entry into the appropriate directory. */ 770ec933656Sjmmv tmpfs_dir_attach(dvp, de); 771ec933656Sjmmv VN_KNOTE(dvp, NOTE_WRITE); 772ec933656Sjmmv 773ec933656Sjmmv /* vp link count has changed, so update node times. */ 774ec933656Sjmmv node->tn_status |= TMPFS_NODE_CHANGED; 775ec933656Sjmmv (void)VOP_UPDATE(vp, NULL, NULL, 0); 776ec933656Sjmmv 777ec933656Sjmmv error = 0; 778ec933656Sjmmv 779ec933656Sjmmv out: 780ec933656Sjmmv if (VOP_ISLOCKED(vp)) 781ec933656Sjmmv VOP_UNLOCK(vp, 0); 782ec933656Sjmmv 783ec933656Sjmmv PNBUF_PUT(cnp->cn_pnbuf); 784ec933656Sjmmv 785ec933656Sjmmv vput(dvp); 786ec933656Sjmmv 787ec933656Sjmmv /* XXX Locking status of dvp does not match manual page. */ 788ec933656Sjmmv KASSERT(!VOP_ISLOCKED(dvp)); 789ec933656Sjmmv KASSERT(!VOP_ISLOCKED(vp)); 790ec933656Sjmmv 791ec933656Sjmmv return error; 792ec933656Sjmmv } 793ec933656Sjmmv 794ec933656Sjmmv /* --------------------------------------------------------------------- */ 795ec933656Sjmmv 796ec933656Sjmmv int 797ec933656Sjmmv tmpfs_rename(void *v) 798ec933656Sjmmv { 799ec933656Sjmmv struct vnode *fdvp = ((struct vop_rename_args *)v)->a_fdvp; 800ec933656Sjmmv struct vnode *fvp = ((struct vop_rename_args *)v)->a_fvp; 801ec933656Sjmmv struct componentname *fcnp = ((struct vop_rename_args *)v)->a_fcnp; 802ec933656Sjmmv struct vnode *tdvp = ((struct vop_rename_args *)v)->a_tdvp; 803ec933656Sjmmv struct vnode *tvp = ((struct vop_rename_args *)v)->a_tvp; 804ec933656Sjmmv struct componentname *tcnp = ((struct vop_rename_args *)v)->a_tcnp; 805ec933656Sjmmv 806ec933656Sjmmv char *newname; 807ec933656Sjmmv int error; 808ec933656Sjmmv struct tmpfs_dirent *de; 809ec933656Sjmmv struct tmpfs_mount *tmp; 810ec933656Sjmmv struct tmpfs_node *fdnode; 811ec933656Sjmmv struct tmpfs_node *fnode; 812ec933656Sjmmv struct tmpfs_node *tdnode; 813ec933656Sjmmv 814ec933656Sjmmv KASSERT(VOP_ISLOCKED(tdvp)); 815ec933656Sjmmv KASSERT(IMPLIES(tvp != NULL, VOP_ISLOCKED(tvp))); 816ec933656Sjmmv KASSERT(fcnp->cn_flags & HASBUF); 817ec933656Sjmmv KASSERT(tcnp->cn_flags & HASBUF); 818ec933656Sjmmv 819ec933656Sjmmv fdnode = VP_TO_TMPFS_DIR(fdvp); 820ec933656Sjmmv fnode = VP_TO_TMPFS_NODE(fvp); 821ec933656Sjmmv de = fnode->tn_lookup_dirent; 822ec933656Sjmmv 823ec933656Sjmmv /* Disallow cross-device renames. 824ec933656Sjmmv * XXX Why isn't this done by the caller? */ 825ec933656Sjmmv if (fvp->v_mount != tdvp->v_mount || 826ec933656Sjmmv (tvp != NULL && fvp->v_mount != tvp->v_mount)) { 827ec933656Sjmmv error = EXDEV; 828ec933656Sjmmv goto out; 829ec933656Sjmmv } 830ec933656Sjmmv 831ec933656Sjmmv tmp = VFS_TO_TMPFS(tdvp->v_mount); 832ec933656Sjmmv tdnode = VP_TO_TMPFS_DIR(tdvp); 833ec933656Sjmmv 834ec933656Sjmmv /* If source and target are the same file, there is nothing to do. */ 835ec933656Sjmmv if (fvp == tvp) { 836ec933656Sjmmv error = 0; 837ec933656Sjmmv goto out; 838ec933656Sjmmv } 839ec933656Sjmmv 840ec933656Sjmmv /* Avoid manipulating '.' and '..' entries. */ 841ec933656Sjmmv if (de == NULL) { 842ec933656Sjmmv KASSERT(fvp->v_type == VDIR); 843ec933656Sjmmv error = EINVAL; 844ec933656Sjmmv goto out; 845ec933656Sjmmv } 846ec933656Sjmmv KASSERT(de->td_node == fnode); 847ec933656Sjmmv 848*f63b58d1Sjmmv /* If we need to move the directory between entries, lock the 849*f63b58d1Sjmmv * source so that we can safely operate on it. */ 850*f63b58d1Sjmmv if (fdnode != tdnode) { 851*f63b58d1Sjmmv error = vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY); 852*f63b58d1Sjmmv if (error != 0) 853*f63b58d1Sjmmv goto out_locked; 854*f63b58d1Sjmmv } 855*f63b58d1Sjmmv 856ec933656Sjmmv /* Ensure that we have enough memory to hold the new name, if it 857ec933656Sjmmv * has to be changed. */ 858ec933656Sjmmv if (fcnp->cn_namelen != tcnp->cn_namelen || 859ec933656Sjmmv memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen) != 0) { 860ec933656Sjmmv newname = tmpfs_str_pool_get(&tmp->tm_str_pool, 861ec933656Sjmmv tcnp->cn_namelen, 0); 862ec933656Sjmmv if (newname == NULL) { 863ec933656Sjmmv error = ENOSPC; 864ec933656Sjmmv goto out; 865ec933656Sjmmv } 866ec933656Sjmmv } else 867ec933656Sjmmv newname = NULL; 868ec933656Sjmmv 869ec933656Sjmmv /* If the node is being moved to another directory, we have to do 870ec933656Sjmmv * the move. */ 871ec933656Sjmmv if (fdnode != tdnode) { 872ec933656Sjmmv /* In case we are moving a directory, we have to adjust its 873ec933656Sjmmv * parent to point to the new parent. */ 874ec933656Sjmmv if (de->td_node->tn_type == VDIR) { 875ec933656Sjmmv struct tmpfs_node *n; 876ec933656Sjmmv 877ec933656Sjmmv /* Ensure the target directory is not a child of the 878ec933656Sjmmv * directory being moved. Otherwise, we'd end up 879ec933656Sjmmv * with stale nodes. */ 880ec933656Sjmmv n = tdnode; 881ec933656Sjmmv while (n != n->tn_parent) { 882ec933656Sjmmv if (n == fnode) { 883ec933656Sjmmv error = EINVAL; 884ec933656Sjmmv goto out; 885ec933656Sjmmv } 886ec933656Sjmmv n = n->tn_parent; 887ec933656Sjmmv } 888ec933656Sjmmv 889ec933656Sjmmv /* Adjust the parent pointer. */ 890ec933656Sjmmv TMPFS_VALIDATE_DIR(fnode); 891ec933656Sjmmv de->td_node->tn_parent = tdnode; 892ec933656Sjmmv 893ec933656Sjmmv /* As a result of changing the target of the '..' 894ec933656Sjmmv * entry, the link count of the source and target 895ec933656Sjmmv * directories has to be adjusted. */ 896ec933656Sjmmv fdnode->tn_links--; 897ec933656Sjmmv tdnode->tn_links++; 898ec933656Sjmmv } 899ec933656Sjmmv 900ec933656Sjmmv /* Do the move: just remove the entry from the source directory 901ec933656Sjmmv * and insert it into the target one. */ 902ec933656Sjmmv tmpfs_dir_detach(fdvp, de); 903ec933656Sjmmv tmpfs_dir_attach(tdvp, de); 904ec933656Sjmmv 905ec933656Sjmmv /* Notify listeners of fdvp about the change in the directory. 906ec933656Sjmmv * We can do it at this point because we aren't touching fdvp 907ec933656Sjmmv * any more below. */ 908ec933656Sjmmv VN_KNOTE(fdvp, NOTE_WRITE); 909ec933656Sjmmv } 910ec933656Sjmmv 911ec933656Sjmmv /* If the name has changed, we need to make it effective by changing 912ec933656Sjmmv * it in the directory entry. */ 913ec933656Sjmmv if (newname != NULL) { 914ec933656Sjmmv KASSERT(tcnp->cn_namelen < MAXNAMLEN); 915ec933656Sjmmv KASSERT(tcnp->cn_namelen < 0xffff); 916ec933656Sjmmv 917ec933656Sjmmv tmpfs_str_pool_put(&tmp->tm_str_pool, de->td_name, 918ec933656Sjmmv de->td_namelen); 919ec933656Sjmmv de->td_namelen = (uint16_t)tcnp->cn_namelen; 920ec933656Sjmmv memcpy(newname, tcnp->cn_nameptr, tcnp->cn_namelen); 921ec933656Sjmmv de->td_name = newname; 922ec933656Sjmmv 923ec933656Sjmmv fnode->tn_status |= TMPFS_NODE_MODIFIED; 924ec933656Sjmmv } 925ec933656Sjmmv 926ec933656Sjmmv /* If we are overwriting an entry, we have to remove the old one 927ec933656Sjmmv * from the target directory. */ 928ec933656Sjmmv if (tvp != NULL) { 929ec933656Sjmmv struct tmpfs_node *tnode; 930ec933656Sjmmv 931ec933656Sjmmv tnode = VP_TO_TMPFS_NODE(tvp); 932ec933656Sjmmv 933ec933656Sjmmv /* The source node cannot be a directory in this case. */ 934ec933656Sjmmv KASSERT(fnode->tn_type != VDIR); 935ec933656Sjmmv 936ec933656Sjmmv /* Remove the old entry from the target directory. */ 937ec933656Sjmmv de = tnode->tn_lookup_dirent; 938ec933656Sjmmv tmpfs_dir_detach(tdvp, de); 939ec933656Sjmmv 940ec933656Sjmmv /* Free the directory entry we just deleted. Note that the 941ec933656Sjmmv * node referred by it will not be removed until the vnode is 942ec933656Sjmmv * really reclaimed. */ 943ec933656Sjmmv tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), de, TRUE); 944ec933656Sjmmv } 945ec933656Sjmmv 946ec933656Sjmmv /* Notify listeners of tdvp about the change in the directory (either 947ec933656Sjmmv * because a new entry was added or because one was removed). */ 948ec933656Sjmmv VN_KNOTE(tdvp, NOTE_WRITE); 949ec933656Sjmmv 950ec933656Sjmmv error = 0; 951ec933656Sjmmv 952*f63b58d1Sjmmv out_locked: 953*f63b58d1Sjmmv if (fdnode != tdnode) 954*f63b58d1Sjmmv VOP_UNLOCK(fdvp, 0); 955*f63b58d1Sjmmv 956ec933656Sjmmv out: 957ec933656Sjmmv /* Release target nodes. */ 958ec933656Sjmmv /* XXX: I don't understand when tdvp can be the same as tvp, but 959ec933656Sjmmv * other code takes care of this... */ 960ec933656Sjmmv if (tdvp == tvp) 961ec933656Sjmmv vrele(tdvp); 962ec933656Sjmmv else 963ec933656Sjmmv vput(tdvp); 964ec933656Sjmmv if (tvp != NULL) 965ec933656Sjmmv vput(tvp); 966ec933656Sjmmv 967ec933656Sjmmv /* Release source nodes. */ 968ec933656Sjmmv vrele(fdvp); 969ec933656Sjmmv vrele(fvp); 970ec933656Sjmmv 971ec933656Sjmmv return error; 972ec933656Sjmmv } 973ec933656Sjmmv 974ec933656Sjmmv /* --------------------------------------------------------------------- */ 975ec933656Sjmmv 976ec933656Sjmmv int 977ec933656Sjmmv tmpfs_mkdir(void *v) 978ec933656Sjmmv { 979ec933656Sjmmv struct vnode *dvp = ((struct vop_mkdir_args *)v)->a_dvp; 980ec933656Sjmmv struct vnode **vpp = ((struct vop_mkdir_args *)v)->a_vpp; 981ec933656Sjmmv struct componentname *cnp = ((struct vop_mkdir_args *)v)->a_cnp; 982ec933656Sjmmv struct vattr *vap = ((struct vop_mkdir_args *)v)->a_vap; 983ec933656Sjmmv 984ec933656Sjmmv KASSERT(vap->va_type == VDIR); 985ec933656Sjmmv 986ec933656Sjmmv return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL); 987ec933656Sjmmv } 988ec933656Sjmmv 989ec933656Sjmmv /* --------------------------------------------------------------------- */ 990ec933656Sjmmv 991ec933656Sjmmv int 992ec933656Sjmmv tmpfs_rmdir(void *v) 993ec933656Sjmmv { 994ec933656Sjmmv struct vnode *dvp = ((struct vop_rmdir_args *)v)->a_dvp; 995ec933656Sjmmv struct vnode *vp = ((struct vop_rmdir_args *)v)->a_vp; 996ec933656Sjmmv 997ec933656Sjmmv int error; 998ec933656Sjmmv struct tmpfs_dirent *de; 999ec933656Sjmmv struct tmpfs_mount *tmp; 1000ec933656Sjmmv struct tmpfs_node *dnode; 1001ec933656Sjmmv struct tmpfs_node *node; 1002ec933656Sjmmv 1003ec933656Sjmmv KASSERT(VOP_ISLOCKED(dvp)); 1004ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 1005ec933656Sjmmv 1006ec933656Sjmmv tmp = VFS_TO_TMPFS(dvp->v_mount); 1007ec933656Sjmmv dnode = VP_TO_TMPFS_DIR(dvp); 1008ec933656Sjmmv node = VP_TO_TMPFS_DIR(vp); 1009ec933656Sjmmv KASSERT(node->tn_parent == dnode); 1010ec933656Sjmmv 1011ec933656Sjmmv /* Get the directory entry associated with node (vp). This was 1012ec933656Sjmmv * filled by tmpfs_lookup while looking up the entry. */ 1013ec933656Sjmmv de = node->tn_lookup_dirent; 1014ec933656Sjmmv KASSERT(TMPFS_DIRENT_MATCHES(de, 1015ec933656Sjmmv ((struct vop_rmdir_args *)v)->a_cnp->cn_nameptr, 1016ec933656Sjmmv ((struct vop_rmdir_args *)v)->a_cnp->cn_namelen)); 1017ec933656Sjmmv 1018ec933656Sjmmv /* Directories with more than two entries ('.' and '..') cannot be 1019ec933656Sjmmv * removed. */ 1020ec933656Sjmmv if (node->tn_size > 0) { 1021ec933656Sjmmv error = ENOTEMPTY; 1022ec933656Sjmmv goto out; 1023ec933656Sjmmv } 1024ec933656Sjmmv 1025ec933656Sjmmv /* Check flags to see if we are allowed to remove the directory. */ 1026ec933656Sjmmv if (dnode->tn_flags & APPEND || node->tn_flags & (IMMUTABLE | APPEND)) { 1027ec933656Sjmmv error = EPERM; 1028ec933656Sjmmv goto out; 1029ec933656Sjmmv } 1030ec933656Sjmmv 1031ec933656Sjmmv /* Detach the directory entry from the directory (dnode). */ 1032ec933656Sjmmv tmpfs_dir_detach(dvp, de); 1033ec933656Sjmmv 1034ec933656Sjmmv node->tn_links--; 1035ec933656Sjmmv node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \ 1036ec933656Sjmmv TMPFS_NODE_MODIFIED; 1037ec933656Sjmmv node->tn_parent->tn_links--; 1038ec933656Sjmmv node->tn_parent->tn_status |= TMPFS_NODE_ACCESSED | \ 1039ec933656Sjmmv TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED; 1040ec933656Sjmmv 1041ec933656Sjmmv /* Notify modification of parent directory and release it. */ 1042ec933656Sjmmv VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK); 1043ec933656Sjmmv cache_purge(dvp); /* XXX Is this needed? */ 1044ec933656Sjmmv vput(dvp); 1045ec933656Sjmmv 1046ec933656Sjmmv /* Free the directory entry we just deleted. Note that the node 1047ec933656Sjmmv * referred by it will not be removed until the vnode is really 1048ec933656Sjmmv * reclaimed. */ 1049ec933656Sjmmv tmpfs_free_dirent(tmp, de, TRUE); 1050ec933656Sjmmv 1051ec933656Sjmmv /* Release the deleted vnode (will destroy the node, notify 1052ec933656Sjmmv * interested parties and clean it from the cache). */ 1053ec933656Sjmmv vput(vp); 1054ec933656Sjmmv 1055ec933656Sjmmv error = 0; 1056ec933656Sjmmv 1057ec933656Sjmmv out: 1058ec933656Sjmmv if (error != 0) { 1059ec933656Sjmmv vput(dvp); 1060ec933656Sjmmv vput(vp); 1061ec933656Sjmmv } 1062ec933656Sjmmv 1063ec933656Sjmmv return error; 1064ec933656Sjmmv } 1065ec933656Sjmmv 1066ec933656Sjmmv /* --------------------------------------------------------------------- */ 1067ec933656Sjmmv 1068ec933656Sjmmv int 1069ec933656Sjmmv tmpfs_symlink(void *v) 1070ec933656Sjmmv { 1071ec933656Sjmmv struct vnode *dvp = ((struct vop_symlink_args *)v)->a_dvp; 1072ec933656Sjmmv struct vnode **vpp = ((struct vop_symlink_args *)v)->a_vpp; 1073ec933656Sjmmv struct componentname *cnp = ((struct vop_symlink_args *)v)->a_cnp; 1074ec933656Sjmmv struct vattr *vap = ((struct vop_symlink_args *)v)->a_vap; 1075ec933656Sjmmv char *target = ((struct vop_symlink_args *)v)->a_target; 1076ec933656Sjmmv 1077ec933656Sjmmv KASSERT(vap->va_type == VLNK); 1078ec933656Sjmmv 1079ec933656Sjmmv return tmpfs_alloc_file(dvp, vpp, vap, cnp, target); 1080ec933656Sjmmv } 1081ec933656Sjmmv 1082ec933656Sjmmv /* --------------------------------------------------------------------- */ 1083ec933656Sjmmv 1084ec933656Sjmmv int 1085ec933656Sjmmv tmpfs_readdir(void *v) 1086ec933656Sjmmv { 1087ec933656Sjmmv struct vnode *vp = ((struct vop_readdir_args *)v)->a_vp; 1088ec933656Sjmmv struct uio *uio = ((struct vop_readdir_args *)v)->a_uio; 1089ec933656Sjmmv int *eofflag = ((struct vop_readdir_args *)v)->a_eofflag; 1090ec933656Sjmmv off_t **cookies = ((struct vop_readdir_args *)v)->a_cookies; 1091ec933656Sjmmv int *ncookies = ((struct vop_readdir_args *)v)->a_ncookies; 1092ec933656Sjmmv 1093ec933656Sjmmv int error; 10948e6209cfSyamt off_t startoff; 10958e6209cfSyamt off_t cnt; 1096ec933656Sjmmv struct tmpfs_node *node; 1097ec933656Sjmmv 1098ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 1099ec933656Sjmmv 1100ec933656Sjmmv /* This operation only makes sense on directory nodes. */ 1101ec933656Sjmmv if (vp->v_type != VDIR) { 1102ec933656Sjmmv error = ENOTDIR; 1103ec933656Sjmmv goto out; 1104ec933656Sjmmv } 1105ec933656Sjmmv 1106ec933656Sjmmv node = VP_TO_TMPFS_DIR(vp); 1107ec933656Sjmmv 1108ec933656Sjmmv startoff = uio->uio_offset; 1109ec933656Sjmmv 11108e6209cfSyamt cnt = 0; 11118e6209cfSyamt if (uio->uio_offset == TMPFS_DIRCOOKIE_DOT) { 1112ec933656Sjmmv error = tmpfs_dir_getdotdent(node, uio); 1113ec933656Sjmmv if (error == -1) { 1114ec933656Sjmmv error = 0; 1115ec933656Sjmmv goto outok; 1116ec933656Sjmmv } else if (error != 0) 1117ec933656Sjmmv goto outok; 11188e6209cfSyamt cnt++; 1119ec933656Sjmmv } 1120ec933656Sjmmv 11218e6209cfSyamt if (uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT) { 1122ec933656Sjmmv error = tmpfs_dir_getdotdotdent(node, uio); 1123ec933656Sjmmv if (error == -1) { 1124ec933656Sjmmv error = 0; 1125ec933656Sjmmv goto outok; 1126ec933656Sjmmv } else if (error != 0) 1127ec933656Sjmmv goto outok; 11288e6209cfSyamt cnt++; 1129ec933656Sjmmv } 1130ec933656Sjmmv 11318e6209cfSyamt error = tmpfs_dir_getdents(node, uio, &cnt); 1132ec933656Sjmmv if (error == -1) 1133ec933656Sjmmv error = 0; 1134ec933656Sjmmv KASSERT(error >= 0); 1135ec933656Sjmmv 1136ec933656Sjmmv outok: 11378e6209cfSyamt /* This label assumes that startoff has been 1138ec933656Sjmmv * initialized. If the compiler didn't spit out warnings, we'd 1139ec933656Sjmmv * simply make this one be 'out' and drop 'outok'. */ 1140ec933656Sjmmv 1141ec933656Sjmmv if (eofflag != NULL) 1142ec933656Sjmmv *eofflag = 11438e6209cfSyamt (error == 0 && uio->uio_offset == TMPFS_DIRCOOKIE_EOF); 1144ec933656Sjmmv 1145ec933656Sjmmv /* Update NFS-related variables. */ 1146ec933656Sjmmv if (error == 0 && cookies != NULL && ncookies != NULL) { 1147ec933656Sjmmv off_t i; 11488e6209cfSyamt off_t off = startoff; 11498e6209cfSyamt struct tmpfs_dirent *de = NULL; 1150ec933656Sjmmv 11518e6209cfSyamt *ncookies = cnt; 11528e6209cfSyamt *cookies = malloc(cnt * sizeof(off_t), M_TEMP, M_WAITOK); 1153ec933656Sjmmv 11548e6209cfSyamt for (i = 0; i < cnt; i++) { 11558e6209cfSyamt KASSERT(off != TMPFS_DIRCOOKIE_EOF); 11568e6209cfSyamt if (off == TMPFS_DIRCOOKIE_DOT) { 11578e6209cfSyamt off = TMPFS_DIRCOOKIE_DOTDOT; 11588e6209cfSyamt } else { 11598e6209cfSyamt if (off == TMPFS_DIRCOOKIE_DOTDOT) { 11608e6209cfSyamt de = TAILQ_FIRST(&node->tn_dir); 11618e6209cfSyamt } else if (de != NULL) { 11628e6209cfSyamt de = TAILQ_NEXT(de, td_entries); 11638e6209cfSyamt } else { 11648e6209cfSyamt de = tmpfs_dir_lookupbycookie(node, 11658e6209cfSyamt off); 11668e6209cfSyamt KASSERT(de != NULL); 11678e6209cfSyamt de = TAILQ_NEXT(de, td_entries); 11688e6209cfSyamt } 11698e6209cfSyamt if (de == NULL) { 11708e6209cfSyamt off = TMPFS_DIRCOOKIE_EOF; 11718e6209cfSyamt } else { 11728e6209cfSyamt off = TMPFS_DIRCOOKIE(de); 11738e6209cfSyamt } 11748e6209cfSyamt } 11758e6209cfSyamt 11768e6209cfSyamt (*cookies)[i] = off; 11778e6209cfSyamt } 11788e6209cfSyamt KASSERT(uio->uio_offset == off); 1179ec933656Sjmmv } 1180ec933656Sjmmv 1181ec933656Sjmmv out: 1182ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 1183ec933656Sjmmv 1184ec933656Sjmmv return error; 1185ec933656Sjmmv } 1186ec933656Sjmmv 1187ec933656Sjmmv /* --------------------------------------------------------------------- */ 1188ec933656Sjmmv 1189ec933656Sjmmv int 1190ec933656Sjmmv tmpfs_readlink(void *v) 1191ec933656Sjmmv { 1192ec933656Sjmmv struct vnode *vp = ((struct vop_readlink_args *)v)->a_vp; 1193ec933656Sjmmv struct uio *uio = ((struct vop_readlink_args *)v)->a_uio; 1194ec933656Sjmmv 1195ec933656Sjmmv int error; 1196ec933656Sjmmv struct tmpfs_node *node; 1197ec933656Sjmmv 1198ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 1199ec933656Sjmmv KASSERT(uio->uio_offset == 0); 1200ec933656Sjmmv KASSERT(vp->v_type == VLNK); 1201ec933656Sjmmv 1202ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 1203ec933656Sjmmv 1204ec933656Sjmmv error = uiomove(node->tn_link, MIN(node->tn_size, uio->uio_resid), 1205ec933656Sjmmv uio); 1206ec933656Sjmmv node->tn_status |= TMPFS_NODE_ACCESSED; 1207ec933656Sjmmv 1208ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 1209ec933656Sjmmv 1210ec933656Sjmmv return error; 1211ec933656Sjmmv } 1212ec933656Sjmmv 1213ec933656Sjmmv /* --------------------------------------------------------------------- */ 1214ec933656Sjmmv 1215ec933656Sjmmv int 1216ec933656Sjmmv tmpfs_inactive(void *v) 1217ec933656Sjmmv { 1218ec933656Sjmmv struct vnode *vp = ((struct vop_inactive_args *)v)->a_vp; 1219ec933656Sjmmv struct proc *p = ((struct vop_inactive_args *)v)->a_p; 1220ec933656Sjmmv 1221ec933656Sjmmv struct tmpfs_node *node; 1222ec933656Sjmmv 1223ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 1224ec933656Sjmmv 1225ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 1226ec933656Sjmmv 1227ec933656Sjmmv VOP_UNLOCK(vp, 0); 1228ec933656Sjmmv 1229ec933656Sjmmv if (node->tn_links == 0) 1230ec933656Sjmmv vrecycle(vp, NULL, p); 1231ec933656Sjmmv 1232ec933656Sjmmv return 0; 1233ec933656Sjmmv } 1234ec933656Sjmmv 1235ec933656Sjmmv /* --------------------------------------------------------------------- */ 1236ec933656Sjmmv 1237ec933656Sjmmv int 1238ec933656Sjmmv tmpfs_reclaim(void *v) 1239ec933656Sjmmv { 1240ec933656Sjmmv struct vnode *vp = ((struct vop_reclaim_args *)v)->a_vp; 1241ec933656Sjmmv 1242ec933656Sjmmv struct tmpfs_mount *tmp; 1243ec933656Sjmmv struct tmpfs_node *node; 1244ec933656Sjmmv 1245ec933656Sjmmv KASSERT(!VOP_ISLOCKED(vp)); 1246ec933656Sjmmv 1247ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 1248ec933656Sjmmv tmp = VFS_TO_TMPFS(vp->v_mount); 1249ec933656Sjmmv 1250ec933656Sjmmv if (node->tn_links == 0) 1251ec933656Sjmmv VN_KNOTE(vp, NOTE_DELETE); 1252ec933656Sjmmv 1253ec933656Sjmmv cache_purge(vp); 1254ec933656Sjmmv tmpfs_free_vp(vp); 1255ec933656Sjmmv 1256ec933656Sjmmv /* If the node referenced by this vnode was deleted by the user, 1257ec933656Sjmmv * we must free its associated data structures (now that the vnode 1258ec933656Sjmmv * is being reclaimed). */ 1259ec933656Sjmmv if (node->tn_links == 0) 1260ec933656Sjmmv tmpfs_free_node(tmp, node); 1261ec933656Sjmmv 1262ec933656Sjmmv KASSERT(!VOP_ISLOCKED(vp)); 1263ec933656Sjmmv KASSERT(vp->v_data == NULL); 1264ec933656Sjmmv 1265ec933656Sjmmv return 0; 1266ec933656Sjmmv } 1267ec933656Sjmmv 1268ec933656Sjmmv /* --------------------------------------------------------------------- */ 1269ec933656Sjmmv 1270ec933656Sjmmv int 1271ec933656Sjmmv tmpfs_print(void *v) 1272ec933656Sjmmv { 1273ec933656Sjmmv struct vnode *vp = ((struct vop_print_args *)v)->a_vp; 1274ec933656Sjmmv 1275ec933656Sjmmv struct tmpfs_node *node; 1276ec933656Sjmmv 1277ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 1278ec933656Sjmmv 1279ec933656Sjmmv printf("tag VT_TMPFS, tmpfs_node %p, flags 0x%x, links %d\n", 1280ec933656Sjmmv node, node->tn_flags, node->tn_links); 1281ec933656Sjmmv printf("\tmode 0%o, owner %d, group %d, size %" PRIdMAX 1282ec933656Sjmmv ", status 0x%x\n", 1283ec933656Sjmmv node->tn_mode, node->tn_uid, node->tn_gid, 1284ec933656Sjmmv (uintmax_t)node->tn_size, node->tn_status); 1285ec933656Sjmmv 1286ec933656Sjmmv if (vp->v_type == VFIFO) 1287ec933656Sjmmv fifo_printinfo(vp); 1288ec933656Sjmmv lockmgr_printinfo(&vp->v_lock); 1289ec933656Sjmmv 1290ec933656Sjmmv printf("\n"); 1291ec933656Sjmmv 1292ec933656Sjmmv return 0; 1293ec933656Sjmmv } 1294ec933656Sjmmv 1295ec933656Sjmmv /* --------------------------------------------------------------------- */ 1296ec933656Sjmmv 1297ec933656Sjmmv int 1298ec933656Sjmmv tmpfs_pathconf(void *v) 1299ec933656Sjmmv { 1300ec933656Sjmmv int name = ((struct vop_pathconf_args *)v)->a_name; 1301ec933656Sjmmv register_t *retval = ((struct vop_pathconf_args *)v)->a_retval; 1302ec933656Sjmmv 1303ec933656Sjmmv int error; 1304ec933656Sjmmv 1305ec933656Sjmmv error = 0; 1306ec933656Sjmmv 1307ec933656Sjmmv switch (name) { 1308ec933656Sjmmv case _PC_LINK_MAX: 1309ec933656Sjmmv *retval = LINK_MAX; 1310ec933656Sjmmv break; 1311ec933656Sjmmv 1312ec933656Sjmmv case _PC_NAME_MAX: 1313ec933656Sjmmv *retval = NAME_MAX; 1314ec933656Sjmmv break; 1315ec933656Sjmmv 1316ec933656Sjmmv case _PC_PATH_MAX: 1317ec933656Sjmmv *retval = PATH_MAX; 1318ec933656Sjmmv break; 1319ec933656Sjmmv 1320ec933656Sjmmv case _PC_PIPE_BUF: 1321ec933656Sjmmv *retval = PIPE_BUF; 1322ec933656Sjmmv break; 1323ec933656Sjmmv 1324ec933656Sjmmv case _PC_CHOWN_RESTRICTED: 1325ec933656Sjmmv *retval = 1; 1326ec933656Sjmmv break; 1327ec933656Sjmmv 1328ec933656Sjmmv case _PC_NO_TRUNC: 1329ec933656Sjmmv *retval = 1; 1330ec933656Sjmmv break; 1331ec933656Sjmmv 1332ec933656Sjmmv case _PC_SYNC_IO: 1333ec933656Sjmmv *retval = 1; 1334ec933656Sjmmv break; 1335ec933656Sjmmv 1336ec933656Sjmmv case _PC_FILESIZEBITS: 1337ec933656Sjmmv *retval = 0; /* XXX Don't know which value should I return. */ 1338ec933656Sjmmv break; 1339ec933656Sjmmv 1340ec933656Sjmmv default: 1341ec933656Sjmmv error = EINVAL; 1342ec933656Sjmmv } 1343ec933656Sjmmv 1344ec933656Sjmmv return error; 1345ec933656Sjmmv } 1346ec933656Sjmmv 1347ec933656Sjmmv /* --------------------------------------------------------------------- */ 1348ec933656Sjmmv 1349ec933656Sjmmv int 1350ec933656Sjmmv tmpfs_truncate(void *v) 1351ec933656Sjmmv { 1352ec933656Sjmmv struct vnode *vp = ((struct vop_truncate_args *)v)->a_vp; 1353ec933656Sjmmv off_t length = ((struct vop_truncate_args *)v)->a_length; 1354ec933656Sjmmv 1355ec933656Sjmmv boolean_t extended; 1356ec933656Sjmmv int error; 1357ec933656Sjmmv struct tmpfs_node *node; 1358ec933656Sjmmv 1359ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 1360ec933656Sjmmv extended = length > node->tn_size; 1361ec933656Sjmmv 1362ec933656Sjmmv if (length < 0) { 1363ec933656Sjmmv error = EINVAL; 1364ec933656Sjmmv goto out; 1365ec933656Sjmmv } 1366ec933656Sjmmv 1367ec933656Sjmmv if (node->tn_size == length) { 1368ec933656Sjmmv error = 0; 1369ec933656Sjmmv goto out; 1370ec933656Sjmmv } 1371ec933656Sjmmv 1372ec933656Sjmmv error = tmpfs_reg_resize(vp, length); 1373ec933656Sjmmv if (error == 0) { 1374ec933656Sjmmv VN_KNOTE(vp, NOTE_ATTRIB | (extended ? NOTE_EXTEND : 0)); 1375ec933656Sjmmv node->tn_status |= TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED; 1376ec933656Sjmmv } 1377ec933656Sjmmv 1378ec933656Sjmmv out: 1379ec933656Sjmmv (void)VOP_UPDATE(vp, NULL, NULL, 0); 1380ec933656Sjmmv 1381ec933656Sjmmv return error; 1382ec933656Sjmmv } 1383ec933656Sjmmv 1384ec933656Sjmmv /* --------------------------------------------------------------------- */ 1385ec933656Sjmmv 1386ec933656Sjmmv int 1387ec933656Sjmmv tmpfs_update(void *v) 1388ec933656Sjmmv { 1389ec933656Sjmmv struct vnode *vp = ((struct vop_update_args *)v)->a_vp; 1390b9c29c4dSchristos struct timespec *acc = ((struct vop_update_args *)v)->a_access; 1391b9c29c4dSchristos struct timespec *mod = ((struct vop_update_args *)v)->a_modify; 1392ec933656Sjmmv int flags = ((struct vop_update_args *)v)->a_flags; 1393ec933656Sjmmv 1394b9c29c4dSchristos struct timespec *ts = NULL, tsb; 1395ec933656Sjmmv struct tmpfs_node *node; 1396ec933656Sjmmv 1397ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 1398ec933656Sjmmv 1399ec933656Sjmmv node = VP_TO_TMPFS_NODE(vp); 1400ec933656Sjmmv 1401ec933656Sjmmv if (flags & UPDATE_CLOSE) 1402ec933656Sjmmv ; /* XXX Need to do anything special? */ 1403ec933656Sjmmv 1404ec933656Sjmmv if (node->tn_status != 0) { 1405b9c29c4dSchristos if (node->tn_status & TMPFS_NODE_ACCESSED) { 1406b9c29c4dSchristos if (acc == NULL) 1407b9c29c4dSchristos acc = ts == NULL ? (ts = nanotime(&tsb)) : ts; 1408b9c29c4dSchristos node->tn_atime = *acc; 1409b9c29c4dSchristos } 1410b9c29c4dSchristos if (node->tn_status & TMPFS_NODE_MODIFIED) { 1411b9c29c4dSchristos if (mod == NULL) 1412b9c29c4dSchristos mod = ts == NULL ? (ts = nanotime(&tsb)) : ts; 1413b9c29c4dSchristos node->tn_mtime = *mod; 1414b9c29c4dSchristos } 1415b9c29c4dSchristos if (node->tn_status & TMPFS_NODE_CHANGED) { 1416b9c29c4dSchristos if (ts == NULL) 1417b9c29c4dSchristos ts = nanotime(&tsb); 1418b9c29c4dSchristos node->tn_ctime = *ts; 1419b9c29c4dSchristos } 1420ec933656Sjmmv node->tn_status &= 1421ec933656Sjmmv ~(TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | 1422ec933656Sjmmv TMPFS_NODE_CHANGED); 1423ec933656Sjmmv } 1424ec933656Sjmmv 1425ec933656Sjmmv KASSERT(VOP_ISLOCKED(vp)); 1426ec933656Sjmmv 1427ec933656Sjmmv return 0; 1428ec933656Sjmmv } 1429ec933656Sjmmv 1430ec933656Sjmmv /* --------------------------------------------------------------------- */ 1431ec933656Sjmmv 1432ec933656Sjmmv int 1433ec933656Sjmmv tmpfs_getpages(void *v) 1434ec933656Sjmmv { 14355f4b660eSjmmv struct vnode *vp = ((struct vop_getpages_args *)v)->a_vp; 14365f4b660eSjmmv voff_t offset = ((struct vop_getpages_args *)v)->a_offset; 14375f4b660eSjmmv struct vm_page **m = ((struct vop_getpages_args *)v)->a_m; 14385f4b660eSjmmv int *count = ((struct vop_getpages_args *)v)->a_count; 14395f4b660eSjmmv int centeridx = ((struct vop_getpages_args *)v)->a_centeridx; 14405f4b660eSjmmv vm_prot_t access_type = ((struct vop_getpages_args *)v)->a_access_type; 14415f4b660eSjmmv int advice = ((struct vop_getpages_args *)v)->a_advice; 14425f4b660eSjmmv int flags = ((struct vop_getpages_args *)v)->a_flags; 14435f4b660eSjmmv 1444ec933656Sjmmv int error; 14455f4b660eSjmmv struct tmpfs_node *node; 14465f4b660eSjmmv struct uvm_object *uobj; 144720bb9654Syamt int npages = *count; 1448ec933656Sjmmv 1449647aa775Syamt KASSERT(vp->v_type == VREG); 1450647aa775Syamt LOCK_ASSERT(simple_lock_held(&vp->v_interlock)); 1451ec933656Sjmmv 14525f4b660eSjmmv node = VP_TO_TMPFS_NODE(vp); 14535f4b660eSjmmv uobj = node->tn_aobj; 14545f4b660eSjmmv 145520bb9654Syamt /* We currently don't rely on PGO_PASTEOF. */ 145620bb9654Syamt 145720bb9654Syamt if (vp->v_size <= offset + (centeridx << PAGE_SHIFT)) { 145820bb9654Syamt if ((flags & PGO_LOCKED) == 0) 145920bb9654Syamt simple_unlock(&vp->v_interlock); 146020bb9654Syamt return EINVAL; 146120bb9654Syamt } 146220bb9654Syamt 146320bb9654Syamt if (vp->v_size < offset + (npages << PAGE_SHIFT)) { 146420bb9654Syamt npages = (round_page(vp->v_size) - offset) >> PAGE_SHIFT; 146520bb9654Syamt } 146620bb9654Syamt 14675f4b660eSjmmv if ((flags & PGO_LOCKED) != 0) 1468647aa775Syamt return EBUSY; 1469ec933656Sjmmv 1470647aa775Syamt if ((flags & PGO_NOTIMESTAMP) == 0) { 14715f4b660eSjmmv if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0) 1472ec933656Sjmmv node->tn_status |= TMPFS_NODE_ACCESSED; 14735f4b660eSjmmv 14745f4b660eSjmmv if ((access_type & VM_PROT_WRITE) != 0) 1475647aa775Syamt node->tn_status |= TMPFS_NODE_MODIFIED; 1476647aa775Syamt } 1477ec933656Sjmmv 1478647aa775Syamt simple_unlock(&vp->v_interlock); 1479647aa775Syamt 1480647aa775Syamt simple_lock(&uobj->vmobjlock); 148120bb9654Syamt error = (*uobj->pgops->pgo_get)(uobj, offset, m, &npages, centeridx, 14825f4b660eSjmmv access_type, advice, flags); 1483647aa775Syamt 1484647aa775Syamt return error; 1485647aa775Syamt } 1486647aa775Syamt 1487647aa775Syamt /* --------------------------------------------------------------------- */ 1488647aa775Syamt 1489647aa775Syamt int 1490647aa775Syamt tmpfs_putpages(void *v) 1491647aa775Syamt { 14925f4b660eSjmmv struct vnode *vp = ((struct vop_putpages_args *)v)->a_vp; 14935f4b660eSjmmv voff_t offlo = ((struct vop_putpages_args *)v)->a_offlo; 14945f4b660eSjmmv voff_t offhi = ((struct vop_putpages_args *)v)->a_offhi; 14955f4b660eSjmmv int flags = ((struct vop_putpages_args *)v)->a_flags; 14965f4b660eSjmmv 1497647aa775Syamt int error; 14985f4b660eSjmmv struct tmpfs_node *node; 14995f4b660eSjmmv struct uvm_object *uobj; 1500647aa775Syamt 1501647aa775Syamt LOCK_ASSERT(simple_lock_held(&vp->v_interlock)); 1502647aa775Syamt 15035f4b660eSjmmv node = VP_TO_TMPFS_NODE(vp); 15045f4b660eSjmmv 1505647aa775Syamt if (vp->v_type != VREG) { 1506647aa775Syamt simple_unlock(&vp->v_interlock); 1507647aa775Syamt return 0; 1508647aa775Syamt } 1509647aa775Syamt 1510647aa775Syamt uobj = node->tn_aobj; 1511647aa775Syamt simple_unlock(&vp->v_interlock); 1512647aa775Syamt 1513647aa775Syamt simple_lock(&uobj->vmobjlock); 15145f4b660eSjmmv error = (*uobj->pgops->pgo_put)(uobj, offlo, offhi, flags); 1515647aa775Syamt 1516647aa775Syamt /* XXX mtime */ 1517647aa775Syamt 1518ec933656Sjmmv return error; 1519ec933656Sjmmv } 1520