tmpfs_vnops.c revision 175294
1228940Sdelphij/* $NetBSD: tmpfs_vnops.c,v 1.39 2007/07/23 15:41:01 jmmv Exp $ */ 2228940Sdelphij 3228940Sdelphij/* 4228940Sdelphij * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc. 5228940Sdelphij * All rights reserved. 6228940Sdelphij * 7228940Sdelphij * This code is derived from software contributed to The NetBSD Foundation 8228940Sdelphij * by Julio M. Merino Vidal, developed as part of Google's Summer of Code 9228940Sdelphij * 2005 program. 10228940Sdelphij * 11228940Sdelphij * Redistribution and use in source and binary forms, with or without 12228940Sdelphij * modification, are permitted provided that the following conditions 13228940Sdelphij * are met: 14228940Sdelphij * 1. Redistributions of source code must retain the above copyright 15228940Sdelphij * notice, this list of conditions and the following disclaimer. 16228940Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 17228940Sdelphij * notice, this list of conditions and the following disclaimer in the 18228940Sdelphij * documentation and/or other materials provided with the distribution. 19228940Sdelphij * 3. All advertising materials mentioning features or use of this software 20228940Sdelphij * must display the following acknowledgement: 21228940Sdelphij * This product includes software developed by the NetBSD 22228940Sdelphij * Foundation, Inc. and its contributors. 23228940Sdelphij * 4. Neither the name of The NetBSD Foundation nor the names of its 24228940Sdelphij * contributors may be used to endorse or promote products derived 25228940Sdelphij * from this software without specific prior written permission. 26228940Sdelphij * 27228940Sdelphij * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28228940Sdelphij * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29228940Sdelphij * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30228940Sdelphij * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31228940Sdelphij * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32228940Sdelphij * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33228940Sdelphij * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34228940Sdelphij * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35228940Sdelphij * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36228940Sdelphij * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37228940Sdelphij * POSSIBILITY OF SUCH DAMAGE. 38228940Sdelphij */ 39228940Sdelphij 40228940Sdelphij/* 41228940Sdelphij * tmpfs vnode interface. 42228940Sdelphij */ 43228940Sdelphij#include <sys/cdefs.h> 44228940Sdelphij__FBSDID("$FreeBSD: head/sys/fs/tmpfs/tmpfs_vnops.c 175294 2008-01-13 14:44:15Z attilio $"); 45228940Sdelphij 46228940Sdelphij#include <sys/param.h> 47228940Sdelphij#include <sys/fcntl.h> 48228940Sdelphij#include <sys/lockf.h> 49228940Sdelphij#include <sys/namei.h> 50228940Sdelphij#include <sys/priv.h> 51228940Sdelphij#include <sys/proc.h> 52228940Sdelphij#include <sys/resourcevar.h> 53228940Sdelphij#include <sys/stat.h> 54228940Sdelphij#include <sys/systm.h> 55255320Sdelphij#include <sys/unistd.h> 56228940Sdelphij#include <sys/vnode.h> 57228940Sdelphij 58228940Sdelphij#include <vm/vm.h> 59228940Sdelphij#include <vm/vm_object.h> 60228940Sdelphij#include <vm/vm_page.h> 61228940Sdelphij#include <vm/vm_pager.h> 62228940Sdelphij#include <sys/sched.h> 63228940Sdelphij#include <sys/sf_buf.h> 64228940Sdelphij#include <machine/_inttypes.h> 65228940Sdelphij 66228940Sdelphij#include <fs/fifofs/fifo.h> 67228940Sdelphij#include <fs/tmpfs/tmpfs_vnops.h> 68228940Sdelphij#include <fs/tmpfs/tmpfs.h> 69228940Sdelphij 70228940Sdelphij/* --------------------------------------------------------------------- */ 71228940Sdelphij 72228940Sdelphijstatic int 73228940Sdelphijtmpfs_lookup(struct vop_cachedlookup_args *v) 74228940Sdelphij{ 75228940Sdelphij struct vnode *dvp = v->a_dvp; 76228940Sdelphij struct vnode **vpp = v->a_vpp; 77228940Sdelphij struct componentname *cnp = v->a_cnp; 78228940Sdelphij struct thread *td = cnp->cn_thread; 79228940Sdelphij 80228940Sdelphij int error; 81228940Sdelphij struct tmpfs_dirent *de; 82228940Sdelphij struct tmpfs_node *dnode; 83228940Sdelphij 84228940Sdelphij dnode = VP_TO_TMPFS_DIR(dvp); 85228940Sdelphij *vpp = NULLVP; 86228940Sdelphij 87228940Sdelphij /* Check accessibility of requested node as a first step. */ 88228940Sdelphij error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td); 89228940Sdelphij if (error != 0) 90228940Sdelphij goto out; 91228940Sdelphij 92228940Sdelphij /* We cannot be requesting the parent directory of the root node. */ 93228940Sdelphij MPASS(IMPLIES(dnode->tn_type == VDIR && 94228940Sdelphij dnode->tn_dir.tn_parent == dnode, 95228940Sdelphij !(cnp->cn_flags & ISDOTDOT))); 96228940Sdelphij 97228940Sdelphij if (cnp->cn_flags & ISDOTDOT) { 98228940Sdelphij int ltype = 0; 99228940Sdelphij 100228940Sdelphij ltype = VOP_ISLOCKED(dvp, td); 101228940Sdelphij vhold(dvp); 102228940Sdelphij VOP_UNLOCK(dvp, 0); 103228940Sdelphij /* Allocate a new vnode on the matching entry. */ 104228940Sdelphij error = tmpfs_alloc_vp(dvp->v_mount, dnode->tn_dir.tn_parent, 105228940Sdelphij cnp->cn_lkflags, vpp, td); 106228940Sdelphij 107228940Sdelphij vn_lock(dvp, ltype | LK_RETRY); 108228940Sdelphij vdrop(dvp); 109228940Sdelphij } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { 110228940Sdelphij VREF(dvp); 111228940Sdelphij *vpp = dvp; 112228940Sdelphij error = 0; 113228940Sdelphij } else { 114228940Sdelphij de = tmpfs_dir_lookup(dnode, cnp); 115228940Sdelphij if (de == NULL) { 116228940Sdelphij /* The entry was not found in the directory. 117228940Sdelphij * This is OK if we are creating or renaming an 118228940Sdelphij * entry and are working on the last component of 119228940Sdelphij * the path name. */ 120228940Sdelphij if ((cnp->cn_flags & ISLASTCN) && 121228940Sdelphij (cnp->cn_nameiop == CREATE || \ 122228940Sdelphij cnp->cn_nameiop == RENAME)) { 123228940Sdelphij error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, 124228940Sdelphij cnp->cn_thread); 125228940Sdelphij if (error != 0) 126228940Sdelphij goto out; 127228940Sdelphij 128228940Sdelphij /* Keep the component name in the buffer for 129228940Sdelphij * future uses. */ 130228940Sdelphij cnp->cn_flags |= SAVENAME; 131228940Sdelphij 132228940Sdelphij error = EJUSTRETURN; 133228940Sdelphij } else 134228940Sdelphij error = ENOENT; 135228940Sdelphij } else { 136228940Sdelphij struct tmpfs_node *tnode; 137228940Sdelphij 138228940Sdelphij /* The entry was found, so get its associated 139228940Sdelphij * tmpfs_node. */ 140228940Sdelphij tnode = de->td_node; 141228940Sdelphij 142228940Sdelphij /* If we are not at the last path component and 143228940Sdelphij * found a non-directory or non-link entry (which 144228940Sdelphij * may itself be pointing to a directory), raise 145228940Sdelphij * an error. */ 146228940Sdelphij if ((tnode->tn_type != VDIR && 147228940Sdelphij tnode->tn_type != VLNK) && 148228940Sdelphij !(cnp->cn_flags & ISLASTCN)) { 149228940Sdelphij error = ENOTDIR; 150228940Sdelphij goto out; 151228940Sdelphij } 152228940Sdelphij 153228940Sdelphij /* If we are deleting or renaming the entry, keep 154228940Sdelphij * track of its tmpfs_dirent so that it can be 155228940Sdelphij * easily deleted later. */ 156228940Sdelphij if ((cnp->cn_flags & ISLASTCN) && 157228940Sdelphij (cnp->cn_nameiop == DELETE || 158228940Sdelphij cnp->cn_nameiop == RENAME)) { 159228940Sdelphij error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, 160228940Sdelphij cnp->cn_thread); 161228940Sdelphij if (error != 0) 162228940Sdelphij goto out; 163228940Sdelphij 164228940Sdelphij /* Allocate a new vnode on the matching entry. */ 165228940Sdelphij error = tmpfs_alloc_vp(dvp->v_mount, tnode, 166228940Sdelphij cnp->cn_lkflags, vpp, td); 167228940Sdelphij if (error != 0) 168228940Sdelphij goto out; 169228940Sdelphij 170245768Sdelphij if ((dnode->tn_mode & S_ISTXT) && 171245768Sdelphij VOP_ACCESS(dvp, VADMIN, cnp->cn_cred, cnp->cn_thread) && 172228940Sdelphij VOP_ACCESS(*vpp, VADMIN, cnp->cn_cred, cnp->cn_thread)) { 173228940Sdelphij error = EPERM; 174228940Sdelphij vput(*vpp); 175228940Sdelphij *vpp = NULL; 176228940Sdelphij goto out; 177228940Sdelphij } 178228940Sdelphij cnp->cn_flags |= SAVENAME; 179228940Sdelphij } else { 180228940Sdelphij error = tmpfs_alloc_vp(dvp->v_mount, tnode, 181228940Sdelphij cnp->cn_lkflags, vpp, td); 182228940Sdelphij } 183228940Sdelphij } 184228940Sdelphij } 185228940Sdelphij 186228940Sdelphij /* Store the result of this lookup in the cache. Avoid this if the 187228940Sdelphij * request was for creation, as it does not improve timings on 188228940Sdelphij * emprical tests. */ 189228940Sdelphij if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE) 190228940Sdelphij cache_enter(dvp, *vpp, cnp); 191228940Sdelphij 192228940Sdelphijout: 193228940Sdelphij /* If there were no errors, *vpp cannot be null and it must be 194228940Sdelphij * locked. */ 195228940Sdelphij MPASS(IFF(error == 0, *vpp != NULLVP && VOP_ISLOCKED(*vpp, td))); 196228940Sdelphij 197228940Sdelphij return error; 198228940Sdelphij} 199228940Sdelphij 200228940Sdelphij/* --------------------------------------------------------------------- */ 201228940Sdelphij 202228940Sdelphijstatic int 203228940Sdelphijtmpfs_create(struct vop_create_args *v) 204228940Sdelphij{ 205228940Sdelphij struct vnode *dvp = v->a_dvp; 206228940Sdelphij struct vnode **vpp = v->a_vpp; 207228940Sdelphij struct componentname *cnp = v->a_cnp; 208228940Sdelphij struct vattr *vap = v->a_vap; 209228940Sdelphij 210228940Sdelphij MPASS(vap->va_type == VREG || vap->va_type == VSOCK); 211228940Sdelphij 212228940Sdelphij return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL); 213228940Sdelphij} 214228940Sdelphij/* --------------------------------------------------------------------- */ 215228940Sdelphij 216228940Sdelphijstatic int 217228940Sdelphijtmpfs_mknod(struct vop_mknod_args *v) 218228940Sdelphij{ 219228940Sdelphij struct vnode *dvp = v->a_dvp; 220228940Sdelphij struct vnode **vpp = v->a_vpp; 221228940Sdelphij struct componentname *cnp = v->a_cnp; 222228940Sdelphij struct vattr *vap = v->a_vap; 223228940Sdelphij 224228940Sdelphij if (vap->va_type != VBLK && vap->va_type != VCHR && 225228940Sdelphij vap->va_type != VFIFO) 226228940Sdelphij return EINVAL; 227228940Sdelphij 228228940Sdelphij return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL); 229228940Sdelphij} 230228940Sdelphij 231228940Sdelphij/* --------------------------------------------------------------------- */ 232228940Sdelphij 233228940Sdelphijstatic int 234228940Sdelphijtmpfs_open(struct vop_open_args *v) 235228940Sdelphij{ 236228940Sdelphij struct vnode *vp = v->a_vp; 237228940Sdelphij int mode = v->a_mode; 238228940Sdelphij 239228940Sdelphij int error; 240228940Sdelphij struct tmpfs_node *node; 241228940Sdelphij 242228940Sdelphij MPASS(VOP_ISLOCKED(vp, v->a_td)); 243228940Sdelphij 244228940Sdelphij node = VP_TO_TMPFS_NODE(vp); 245228940Sdelphij 246228940Sdelphij /* The file is still active but all its names have been removed 247228940Sdelphij * (e.g. by a "rmdir $(pwd)"). It cannot be opened any more as 248228940Sdelphij * it is about to die. */ 249228940Sdelphij if (node->tn_links < 1) 250228940Sdelphij return (ENOENT); 251228940Sdelphij 252228940Sdelphij /* If the file is marked append-only, deny write requests. */ 253228940Sdelphij if (node->tn_flags & APPEND && (mode & (FWRITE | O_APPEND)) == FWRITE) 254228940Sdelphij error = EPERM; 255228940Sdelphij else { 256228940Sdelphij error = 0; 257228940Sdelphij vnode_create_vobject(vp, node->tn_size, v->a_td); 258228940Sdelphij } 259228940Sdelphij 260228940Sdelphij MPASS(VOP_ISLOCKED(vp, v->a_td)); 261228940Sdelphij return error; 262228940Sdelphij} 263228940Sdelphij 264228940Sdelphij/* --------------------------------------------------------------------- */ 265228940Sdelphij 266228940Sdelphijstatic int 267228940Sdelphijtmpfs_close(struct vop_close_args *v) 268228940Sdelphij{ 269228940Sdelphij struct vnode *vp = v->a_vp; 270228940Sdelphij 271228940Sdelphij struct tmpfs_node *node; 272228940Sdelphij 273228940Sdelphij MPASS(VOP_ISLOCKED(vp, v->a_td)); 274228940Sdelphij 275228940Sdelphij node = VP_TO_TMPFS_NODE(vp); 276228940Sdelphij 277228940Sdelphij if (node->tn_links > 0) { 278228940Sdelphij /* Update node times. No need to do it if the node has 279228940Sdelphij * been deleted, because it will vanish after we return. */ 280228940Sdelphij tmpfs_update(vp); 281228940Sdelphij } 282228940Sdelphij 283228940Sdelphij return 0; 284228940Sdelphij} 285228940Sdelphij 286228940Sdelphij/* --------------------------------------------------------------------- */ 287228940Sdelphij 288228940Sdelphijint 289228940Sdelphijtmpfs_access(struct vop_access_args *v) 290228940Sdelphij{ 291228940Sdelphij struct vnode *vp = v->a_vp; 292228940Sdelphij int mode = v->a_mode; 293228940Sdelphij struct ucred *cred = v->a_cred; 294228940Sdelphij 295228940Sdelphij int error; 296228940Sdelphij struct tmpfs_node *node; 297228940Sdelphij 298228940Sdelphij MPASS(VOP_ISLOCKED(vp, v->a_td)); 299228940Sdelphij 300228940Sdelphij node = VP_TO_TMPFS_NODE(vp); 301228940Sdelphij 302228940Sdelphij switch (vp->v_type) { 303228940Sdelphij case VDIR: 304228940Sdelphij /* FALLTHROUGH */ 305228940Sdelphij case VLNK: 306228940Sdelphij /* FALLTHROUGH */ 307228940Sdelphij case VREG: 308228940Sdelphij if (mode & VWRITE && vp->v_mount->mnt_flag & MNT_RDONLY) { 309228940Sdelphij error = EROFS; 310228940Sdelphij goto out; 311228940Sdelphij } 312228940Sdelphij break; 313228940Sdelphij 314228940Sdelphij case VBLK: 315228940Sdelphij /* FALLTHROUGH */ 316228940Sdelphij case VCHR: 317228940Sdelphij /* FALLTHROUGH */ 318228940Sdelphij case VSOCK: 319228940Sdelphij /* FALLTHROUGH */ 320228940Sdelphij case VFIFO: 321228940Sdelphij break; 322228940Sdelphij 323228940Sdelphij default: 324228940Sdelphij error = EINVAL; 325228940Sdelphij goto out; 326228940Sdelphij } 327228940Sdelphij 328228940Sdelphij if (mode & VWRITE && node->tn_flags & IMMUTABLE) { 329228940Sdelphij error = EPERM; 330228940Sdelphij goto out; 331228940Sdelphij } 332228940Sdelphij 333228940Sdelphij error = vaccess(vp->v_type, node->tn_mode, node->tn_uid, 334228940Sdelphij node->tn_gid, mode, cred, NULL); 335228940Sdelphij 336228940Sdelphijout: 337228940Sdelphij MPASS(VOP_ISLOCKED(vp, v->a_td)); 338228940Sdelphij 339228940Sdelphij return error; 340228940Sdelphij} 341228940Sdelphij 342228940Sdelphij/* --------------------------------------------------------------------- */ 343228940Sdelphij 344228940Sdelphijint 345228940Sdelphijtmpfs_getattr(struct vop_getattr_args *v) 346228940Sdelphij{ 347228940Sdelphij struct vnode *vp = v->a_vp; 348228940Sdelphij struct vattr *vap = v->a_vap; 349228940Sdelphij 350228940Sdelphij struct tmpfs_node *node; 351228940Sdelphij 352228940Sdelphij node = VP_TO_TMPFS_NODE(vp); 353228940Sdelphij 354228940Sdelphij VATTR_NULL(vap); 355228940Sdelphij 356228940Sdelphij tmpfs_update(vp); 357228940Sdelphij 358228940Sdelphij vap->va_type = vp->v_type; 359228940Sdelphij vap->va_mode = node->tn_mode; 360228940Sdelphij vap->va_nlink = node->tn_links; 361228940Sdelphij vap->va_uid = node->tn_uid; 362228940Sdelphij vap->va_gid = node->tn_gid; 363228940Sdelphij vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 364228940Sdelphij vap->va_fileid = node->tn_id; 365228940Sdelphij vap->va_size = node->tn_size; 366228940Sdelphij vap->va_blocksize = PAGE_SIZE; 367228940Sdelphij vap->va_atime = node->tn_atime; 368228940Sdelphij vap->va_mtime = node->tn_mtime; 369228940Sdelphij vap->va_ctime = node->tn_ctime; 370228940Sdelphij vap->va_birthtime = node->tn_birthtime; 371228940Sdelphij vap->va_gen = node->tn_gen; 372228940Sdelphij vap->va_flags = node->tn_flags; 373228940Sdelphij vap->va_rdev = (vp->v_type == VBLK || vp->v_type == VCHR) ? 374228940Sdelphij node->tn_rdev : VNOVAL; 375228940Sdelphij vap->va_bytes = round_page(node->tn_size); 376228940Sdelphij vap->va_filerev = VNOVAL; 377228940Sdelphij vap->va_vaflags = 0; 378228940Sdelphij vap->va_spare = VNOVAL; /* XXX */ 379228940Sdelphij 380228940Sdelphij return 0; 381228940Sdelphij} 382228940Sdelphij 383228940Sdelphij/* --------------------------------------------------------------------- */ 384228940Sdelphij 385228940Sdelphij/* XXX Should this operation be atomic? I think it should, but code in 386228940Sdelphij * XXX other places (e.g., ufs) doesn't seem to be... */ 387228940Sdelphijint 388228940Sdelphijtmpfs_setattr(struct vop_setattr_args *v) 389228940Sdelphij{ 390228940Sdelphij struct vnode *vp = v->a_vp; 391228940Sdelphij struct vattr *vap = v->a_vap; 392228940Sdelphij struct ucred *cred = v->a_cred; 393228940Sdelphij struct thread *l = v->a_td; 394228940Sdelphij 395228940Sdelphij int error; 396228940Sdelphij 397228940Sdelphij MPASS(VOP_ISLOCKED(vp, l)); 398228940Sdelphij 399228940Sdelphij error = 0; 400228940Sdelphij 401228940Sdelphij /* Abort if any unsettable attribute is given. */ 402228940Sdelphij if (vap->va_type != VNON || 403228940Sdelphij vap->va_nlink != VNOVAL || 404228940Sdelphij vap->va_fsid != VNOVAL || 405228940Sdelphij vap->va_fileid != VNOVAL || 406228940Sdelphij vap->va_blocksize != VNOVAL || 407228940Sdelphij vap->va_gen != VNOVAL || 408228940Sdelphij vap->va_rdev != VNOVAL || 409228940Sdelphij vap->va_bytes != VNOVAL) 410228940Sdelphij error = EINVAL; 411228940Sdelphij 412228940Sdelphij if (error == 0 && (vap->va_flags != VNOVAL)) 413228940Sdelphij error = tmpfs_chflags(vp, vap->va_flags, cred, l); 414228940Sdelphij 415228940Sdelphij if (error == 0 && (vap->va_size != VNOVAL)) 416228940Sdelphij error = tmpfs_chsize(vp, vap->va_size, cred, l); 417228940Sdelphij 418228940Sdelphij if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL)) 419228940Sdelphij error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred, 420228940Sdelphij l); 421228940Sdelphij 422228940Sdelphij if (error == 0 && (vap->va_mode != (mode_t)VNOVAL)) 423228940Sdelphij error = tmpfs_chmod(vp, vap->va_mode, cred, l); 424228940Sdelphij 425228940Sdelphij if (error == 0 && ((vap->va_atime.tv_sec != VNOVAL && 426228940Sdelphij vap->va_atime.tv_nsec != VNOVAL) || 427228940Sdelphij (vap->va_mtime.tv_sec != VNOVAL && 428228940Sdelphij vap->va_mtime.tv_nsec != VNOVAL) || 429228940Sdelphij (vap->va_birthtime.tv_sec != VNOVAL && 430228940Sdelphij vap->va_birthtime.tv_nsec != VNOVAL))) 431228940Sdelphij error = tmpfs_chtimes(vp, &vap->va_atime, &vap->va_mtime, 432228940Sdelphij &vap->va_birthtime, vap->va_vaflags, cred, l); 433228940Sdelphij 434228940Sdelphij /* Update the node times. We give preference to the error codes 435255871Sscottl * generated by this function rather than the ones that may arise 436228940Sdelphij * from tmpfs_update. */ 437228940Sdelphij tmpfs_update(vp); 438228940Sdelphij 439228940Sdelphij MPASS(VOP_ISLOCKED(vp, l)); 440228940Sdelphij 441228940Sdelphij return error; 442228940Sdelphij} 443228940Sdelphij 444228940Sdelphij/* --------------------------------------------------------------------- */ 445228940Sdelphij 446228940Sdelphijstatic int 447228940Sdelphijtmpfs_mappedread(vm_object_t vobj, vm_object_t tobj, size_t len, struct uio *uio) 448228940Sdelphij{ 449228940Sdelphij vm_pindex_t idx; 450228940Sdelphij vm_page_t m; 451228940Sdelphij struct sf_buf *sf; 452228940Sdelphij off_t offset, addr; 453228940Sdelphij size_t tlen; 454228940Sdelphij caddr_t va; 455228940Sdelphij int error; 456228940Sdelphij 457228940Sdelphij addr = uio->uio_offset; 458228940Sdelphij idx = OFF_TO_IDX(addr); 459228940Sdelphij offset = addr & PAGE_MASK; 460228940Sdelphij tlen = MIN(PAGE_SIZE - offset, len); 461228940Sdelphij 462228940Sdelphij if ((vobj == NULL) || (vobj->resident_page_count == 0)) 463228940Sdelphij goto nocache; 464228940Sdelphij 465228940Sdelphij VM_OBJECT_LOCK(vobj); 466228940Sdelphijlookupvpg: 467228940Sdelphij if (((m = vm_page_lookup(vobj, idx)) != NULL) && 468228940Sdelphij vm_page_is_valid(m, offset, tlen)) { 469228940Sdelphij if (vm_page_sleep_if_busy(m, FALSE, "tmfsmr")) 470228940Sdelphij goto lookupvpg; 471228940Sdelphij vm_page_busy(m); 472228940Sdelphij VM_OBJECT_UNLOCK(vobj); 473228940Sdelphij sched_pin(); 474228940Sdelphij sf = sf_buf_alloc(m, SFB_CPUPRIVATE); 475228940Sdelphij va = (caddr_t)sf_buf_kva(sf); 476228940Sdelphij error = uiomove(va + offset, tlen, uio); 477228940Sdelphij sf_buf_free(sf); 478228940Sdelphij sched_unpin(); 479228940Sdelphij VM_OBJECT_LOCK(vobj); 480228940Sdelphij vm_page_wakeup(m); 481228940Sdelphij VM_OBJECT_UNLOCK(vobj); 482228940Sdelphij return (error); 483228940Sdelphij } 484228940Sdelphij VM_OBJECT_UNLOCK(vobj); 485228940Sdelphijnocache: 486228940Sdelphij VM_OBJECT_LOCK(tobj); 487228940Sdelphij vm_object_pip_add(tobj, 1); 488228940Sdelphij m = vm_page_grab(tobj, idx, VM_ALLOC_WIRED | 489228940Sdelphij VM_ALLOC_ZERO | VM_ALLOC_NORMAL | VM_ALLOC_RETRY); 490228940Sdelphij if (m->valid != VM_PAGE_BITS_ALL) { 491246713Skib int behind, ahead; 492228940Sdelphij if (vm_pager_has_page(tobj, idx, &behind, &ahead)) { 493228940Sdelphij error = vm_pager_get_pages(tobj, &m, 1, 0); 494228940Sdelphij if (error != 0) { 495228940Sdelphij printf("tmpfs get pages from pager error [read]\n"); 496246713Skib goto out; 497246713Skib } 498246713Skib } else 499246713Skib vm_page_zero_invalid(m, TRUE); 500246713Skib } 501246713Skib VM_OBJECT_UNLOCK(tobj); 502246713Skib sched_pin(); 503228940Sdelphij sf = sf_buf_alloc(m, SFB_CPUPRIVATE); 504246713Skib va = (caddr_t)sf_buf_kva(sf); 505246713Skib error = uiomove(va + offset, tlen, uio); 506246713Skib sf_buf_free(sf); 507246713Skib sched_unpin(); 508246713Skib VM_OBJECT_LOCK(tobj); 509246713Skibout: 510246713Skib vm_page_lock_queues(); 511246713Skib vm_page_unwire(m, 0); 512228940Sdelphij vm_page_activate(m); 513255871Sscottl vm_page_unlock_queues(); 514228940Sdelphij vm_page_wakeup(m); 515228940Sdelphij vm_object_pip_subtract(tobj, 1); 516228940Sdelphij VM_OBJECT_UNLOCK(tobj); 517228940Sdelphij 518228940Sdelphij return (error); 519228940Sdelphij} 520228940Sdelphij 521228940Sdelphijstatic int 522228940Sdelphijtmpfs_read(struct vop_read_args *v) 523228940Sdelphij{ 524228940Sdelphij struct vnode *vp = v->a_vp; 525228940Sdelphij struct uio *uio = v->a_uio; 526228940Sdelphij 527228940Sdelphij struct tmpfs_node *node; 528228940Sdelphij vm_object_t uobj; 529228940Sdelphij size_t len; 530228940Sdelphij int resid; 531228940Sdelphij 532228940Sdelphij int error = 0; 533228940Sdelphij 534228940Sdelphij node = VP_TO_TMPFS_NODE(vp); 535228940Sdelphij 536228940Sdelphij if (vp->v_type != VREG) { 537228940Sdelphij error = EISDIR; 538228940Sdelphij goto out; 539228940Sdelphij } 540228940Sdelphij 541228940Sdelphij if (uio->uio_offset < 0) { 542228940Sdelphij error = EINVAL; 543228940Sdelphij goto out; 544228940Sdelphij } 545228940Sdelphij 546228940Sdelphij node->tn_status |= TMPFS_NODE_ACCESSED; 547228940Sdelphij 548228940Sdelphij uobj = node->tn_reg.tn_aobj; 549228940Sdelphij while ((resid = uio->uio_resid) > 0) { 550228940Sdelphij error = 0; 551228940Sdelphij if (node->tn_size <= uio->uio_offset) 552228940Sdelphij break; 553228940Sdelphij len = MIN(node->tn_size - uio->uio_offset, resid); 554228940Sdelphij if (len == 0) 555228940Sdelphij break; 556228940Sdelphij error = tmpfs_mappedread(vp->v_object, uobj, len, uio); 557228940Sdelphij if ((error != 0) || (resid == uio->uio_resid)) 558228940Sdelphij break; 559228940Sdelphij } 560228940Sdelphij 561228940Sdelphijout: 562228940Sdelphij 563228940Sdelphij return error; 564228940Sdelphij} 565228940Sdelphij 566228940Sdelphij/* --------------------------------------------------------------------- */ 567228940Sdelphij 568228940Sdelphijstatic int 569228940Sdelphijtmpfs_mappedwrite(vm_object_t vobj, vm_object_t tobj, size_t len, struct uio *uio) 570228940Sdelphij{ 571228940Sdelphij vm_pindex_t idx; 572228940Sdelphij vm_page_t vpg, tpg; 573228940Sdelphij struct sf_buf *sf; 574228940Sdelphij off_t offset, addr; 575228940Sdelphij size_t tlen; 576228940Sdelphij caddr_t va; 577228940Sdelphij int error; 578228940Sdelphij 579228940Sdelphij error = 0; 580228940Sdelphij 581228940Sdelphij addr = uio->uio_offset; 582228940Sdelphij idx = OFF_TO_IDX(addr); 583228940Sdelphij offset = addr & PAGE_MASK; 584228940Sdelphij tlen = MIN(PAGE_SIZE - offset, len); 585228940Sdelphij 586228940Sdelphij if ((vobj == NULL) || (vobj->resident_page_count == 0)) { 587228940Sdelphij vpg = NULL; 588228940Sdelphij goto nocache; 589228940Sdelphij } 590228940Sdelphij 591228940Sdelphij VM_OBJECT_LOCK(vobj); 592228940Sdelphijlookupvpg: 593228940Sdelphij if (((vpg = vm_page_lookup(vobj, idx)) != NULL) && 594228940Sdelphij vm_page_is_valid(vpg, offset, tlen)) { 595228940Sdelphij if (vm_page_sleep_if_busy(vpg, FALSE, "tmfsmw")) 596228940Sdelphij goto lookupvpg; 597228940Sdelphij vm_page_busy(vpg); 598228940Sdelphij vm_page_lock_queues(); 599228940Sdelphij vm_page_undirty(vpg); 600228940Sdelphij vm_page_unlock_queues(); 601228940Sdelphij VM_OBJECT_UNLOCK(vobj); 602228940Sdelphij sched_pin(); 603228940Sdelphij sf = sf_buf_alloc(vpg, SFB_CPUPRIVATE); 604228940Sdelphij va = (caddr_t)sf_buf_kva(sf); 605228940Sdelphij error = uiomove(va + offset, tlen, uio); 606228940Sdelphij sf_buf_free(sf); 607228940Sdelphij sched_unpin(); 608228940Sdelphij } else { 609228940Sdelphij VM_OBJECT_UNLOCK(vobj); 610228940Sdelphij vpg = NULL; 611228940Sdelphij } 612228940Sdelphijnocache: 613228940Sdelphij VM_OBJECT_LOCK(tobj); 614228940Sdelphij vm_object_pip_add(tobj, 1); 615228940Sdelphij tpg = vm_page_grab(tobj, idx, VM_ALLOC_WIRED | 616228940Sdelphij VM_ALLOC_ZERO | VM_ALLOC_NORMAL | VM_ALLOC_RETRY); 617228940Sdelphij if (tpg->valid != VM_PAGE_BITS_ALL) { 618228940Sdelphij int behind, ahead; 619228940Sdelphij if (vm_pager_has_page(tobj, idx, &behind, &ahead)) { 620228940Sdelphij error = vm_pager_get_pages(tobj, &tpg, 1, 0); 621228940Sdelphij if (error != 0) { 622228940Sdelphij printf("tmpfs get pages from pager error [write]\n"); 623228940Sdelphij goto out; 624228940Sdelphij } 625228940Sdelphij } else 626228940Sdelphij vm_page_zero_invalid(tpg, TRUE); 627228940Sdelphij } 628228940Sdelphij VM_OBJECT_UNLOCK(tobj); 629228940Sdelphij if (vpg == NULL) { 630228940Sdelphij sched_pin(); 631228940Sdelphij sf = sf_buf_alloc(tpg, SFB_CPUPRIVATE); 632228940Sdelphij va = (caddr_t)sf_buf_kva(sf); 633228940Sdelphij error = uiomove(va + offset, tlen, uio); 634228940Sdelphij sf_buf_free(sf); 635228940Sdelphij sched_unpin(); 636228940Sdelphij } else { 637228940Sdelphij KASSERT(vpg->valid == VM_PAGE_BITS_ALL, ("parts of vpg invalid")); 638228940Sdelphij pmap_copy_page(vpg, tpg); 639228940Sdelphij } 640246713Skib VM_OBJECT_LOCK(tobj); 641228940Sdelphijout: 642228940Sdelphij if (vobj != NULL) 643228940Sdelphij VM_OBJECT_LOCK(vobj); 644228940Sdelphij vm_page_lock_queues(); 645228940Sdelphij if (error == 0) { 646228940Sdelphij vm_page_set_validclean(tpg, offset, tlen); 647228940Sdelphij vm_page_zero_invalid(tpg, TRUE); 648228940Sdelphij vm_page_dirty(tpg); 649228940Sdelphij } 650228940Sdelphij vm_page_unwire(tpg, 0); 651228940Sdelphij vm_page_activate(tpg); 652228940Sdelphij vm_page_unlock_queues(); 653228940Sdelphij vm_page_wakeup(tpg); 654228940Sdelphij if (vpg != NULL) 655228940Sdelphij vm_page_wakeup(vpg); 656228940Sdelphij if (vobj != NULL) 657228940Sdelphij VM_OBJECT_UNLOCK(vobj); 658228940Sdelphij vm_object_pip_subtract(tobj, 1); 659228940Sdelphij VM_OBJECT_UNLOCK(tobj); 660228940Sdelphij 661228940Sdelphij return (error); 662228940Sdelphij} 663228940Sdelphij 664228940Sdelphijstatic int 665228940Sdelphijtmpfs_write(struct vop_write_args *v) 666228940Sdelphij{ 667228940Sdelphij struct vnode *vp = v->a_vp; 668228940Sdelphij struct uio *uio = v->a_uio; 669228940Sdelphij int ioflag = v->a_ioflag; 670228940Sdelphij struct thread *td = uio->uio_td; 671228940Sdelphij 672228940Sdelphij boolean_t extended; 673228940Sdelphij int error = 0; 674228940Sdelphij off_t oldsize; 675228940Sdelphij struct tmpfs_node *node; 676228940Sdelphij vm_object_t uobj; 677228940Sdelphij size_t len; 678228940Sdelphij int resid; 679228940Sdelphij 680228940Sdelphij node = VP_TO_TMPFS_NODE(vp); 681228940Sdelphij oldsize = node->tn_size; 682228940Sdelphij 683228940Sdelphij if (uio->uio_offset < 0 || vp->v_type != VREG) { 684228940Sdelphij error = EINVAL; 685228940Sdelphij goto out; 686228940Sdelphij } 687228940Sdelphij 688228940Sdelphij if (uio->uio_resid == 0) { 689228940Sdelphij error = 0; 690228940Sdelphij goto out; 691228940Sdelphij } 692228940Sdelphij 693228940Sdelphij if (ioflag & IO_APPEND) 694228940Sdelphij uio->uio_offset = node->tn_size; 695228940Sdelphij 696228940Sdelphij if (uio->uio_offset + uio->uio_resid > 697228940Sdelphij VFS_TO_TMPFS(vp->v_mount)->tm_maxfilesize) 698246713Skib return (EFBIG); 699246713Skib 700246713Skib if (vp->v_type == VREG && td != NULL) { 701246713Skib PROC_LOCK(td->td_proc); 702228940Sdelphij if (uio->uio_offset + uio->uio_resid > 703228940Sdelphij lim_cur(td->td_proc, RLIMIT_FSIZE)) { 704246713Skib psignal(td->td_proc, SIGXFSZ); 705246713Skib PROC_UNLOCK(td->td_proc); 706246713Skib return (EFBIG); 707246713Skib } 708246713Skib PROC_UNLOCK(td->td_proc); 709246713Skib } 710246713Skib 711228940Sdelphij extended = uio->uio_offset + uio->uio_resid > node->tn_size; 712228940Sdelphij if (extended) { 713228940Sdelphij error = tmpfs_reg_resize(vp, uio->uio_offset + uio->uio_resid); 714228940Sdelphij if (error != 0) 715228940Sdelphij goto out; 716228940Sdelphij } 717228940Sdelphij 718228940Sdelphij uobj = node->tn_reg.tn_aobj; 719228940Sdelphij while ((resid = uio->uio_resid) > 0) { 720228940Sdelphij if (node->tn_size <= uio->uio_offset) 721228940Sdelphij break; 722228940Sdelphij len = MIN(node->tn_size - uio->uio_offset, resid); 723228940Sdelphij if (len == 0) 724228940Sdelphij break; 725228940Sdelphij error = tmpfs_mappedwrite(vp->v_object, uobj, len, uio); 726228940Sdelphij if ((error != 0) || (resid == uio->uio_resid)) 727228940Sdelphij break; 728228940Sdelphij } 729228940Sdelphij 730228940Sdelphij node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED | 731228940Sdelphij (extended ? TMPFS_NODE_CHANGED : 0); 732228940Sdelphij 733228940Sdelphij if (node->tn_mode & (S_ISUID | S_ISGID)) { 734228940Sdelphij if (priv_check_cred(v->a_cred, PRIV_VFS_RETAINSUGID, 0)) 735228940Sdelphij node->tn_mode &= ~(S_ISUID | S_ISGID); 736228940Sdelphij } 737228940Sdelphij 738228940Sdelphij if (error != 0) 739228940Sdelphij (void)tmpfs_reg_resize(vp, oldsize); 740228940Sdelphij 741228940Sdelphijout: 742228940Sdelphij MPASS(IMPLIES(error == 0, uio->uio_resid == 0)); 743228940Sdelphij MPASS(IMPLIES(error != 0, oldsize == node->tn_size)); 744228940Sdelphij 745228940Sdelphij return error; 746228940Sdelphij} 747228940Sdelphij 748228940Sdelphij/* --------------------------------------------------------------------- */ 749228940Sdelphij 750228940Sdelphijstatic int 751228940Sdelphijtmpfs_fsync(struct vop_fsync_args *v) 752228940Sdelphij{ 753228940Sdelphij struct vnode *vp = v->a_vp; 754228940Sdelphij 755228940Sdelphij MPASS(VOP_ISLOCKED(vp, v->a_td)); 756228940Sdelphij 757228940Sdelphij tmpfs_update(vp); 758228940Sdelphij 759228940Sdelphij return 0; 760228940Sdelphij} 761228940Sdelphij 762228940Sdelphij/* --------------------------------------------------------------------- */ 763228940Sdelphij 764228940Sdelphijstatic int 765228940Sdelphijtmpfs_remove(struct vop_remove_args *v) 766228940Sdelphij{ 767228940Sdelphij struct vnode *dvp = v->a_dvp; 768228940Sdelphij struct vnode *vp = v->a_vp; 769228940Sdelphij 770228940Sdelphij int error; 771228940Sdelphij struct tmpfs_dirent *de; 772228940Sdelphij struct tmpfs_mount *tmp; 773228940Sdelphij struct tmpfs_node *dnode; 774228940Sdelphij struct tmpfs_node *node; 775228940Sdelphij 776228940Sdelphij MPASS(VOP_ISLOCKED(dvp, v->a_cnp->cn_thread)); 777228940Sdelphij MPASS(VOP_ISLOCKED(vp, v->a_cnp->cn_thread)); 778228940Sdelphij 779228940Sdelphij if (vp->v_type == VDIR) { 780228940Sdelphij error = EISDIR; 781228940Sdelphij goto out; 782228940Sdelphij } 783228940Sdelphij 784228940Sdelphij dnode = VP_TO_TMPFS_DIR(dvp); 785228940Sdelphij node = VP_TO_TMPFS_NODE(vp); 786228940Sdelphij tmp = VFS_TO_TMPFS(vp->v_mount); 787228940Sdelphij de = tmpfs_dir_search(dnode, node); 788228940Sdelphij MPASS(de != NULL); 789228940Sdelphij 790228940Sdelphij /* Files marked as immutable or append-only cannot be deleted. */ 791228940Sdelphij if ((node->tn_flags & (IMMUTABLE | APPEND | NOUNLINK)) || 792228940Sdelphij (dnode->tn_flags & APPEND)) { 793228940Sdelphij error = EPERM; 794228940Sdelphij goto out; 795228940Sdelphij } 796228940Sdelphij 797228940Sdelphij /* Remove the entry from the directory; as it is a file, we do not 798228940Sdelphij * have to change the number of hard links of the directory. */ 799228940Sdelphij tmpfs_dir_detach(dvp, de); 800228940Sdelphij 801228940Sdelphij /* Free the directory entry we just deleted. Note that the node 802228940Sdelphij * referred by it will not be removed until the vnode is really 803228940Sdelphij * reclaimed. */ 804228940Sdelphij tmpfs_free_dirent(tmp, de, TRUE); 805228940Sdelphij 806228940Sdelphij if (node->tn_links > 0) 807228940Sdelphij node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \ 808228940Sdelphij TMPFS_NODE_MODIFIED; 809228940Sdelphij error = 0; 810228940Sdelphij 811228940Sdelphijout: 812228940Sdelphij 813228940Sdelphij return error; 814228940Sdelphij} 815228940Sdelphij 816228940Sdelphij/* --------------------------------------------------------------------- */ 817228940Sdelphij 818228940Sdelphijstatic int 819228940Sdelphijtmpfs_link(struct vop_link_args *v) 820228940Sdelphij{ 821228940Sdelphij struct vnode *dvp = v->a_tdvp; 822228940Sdelphij struct vnode *vp = v->a_vp; 823228940Sdelphij struct componentname *cnp = v->a_cnp; 824228940Sdelphij 825228940Sdelphij int error; 826228940Sdelphij struct tmpfs_dirent *de; 827228940Sdelphij struct tmpfs_node *node; 828228940Sdelphij 829228940Sdelphij MPASS(VOP_ISLOCKED(dvp, cnp->cn_thread)); 830228940Sdelphij MPASS(cnp->cn_flags & HASBUF); 831228940Sdelphij MPASS(dvp != vp); /* XXX When can this be false? */ 832228940Sdelphij 833228940Sdelphij node = VP_TO_TMPFS_NODE(vp); 834228940Sdelphij 835228940Sdelphij /* XXX: Why aren't the following two tests done by the caller? */ 836228940Sdelphij 837228940Sdelphij /* Hard links of directories are forbidden. */ 838228940Sdelphij if (vp->v_type == VDIR) { 839228940Sdelphij error = EPERM; 840228940Sdelphij goto out; 841228940Sdelphij } 842228940Sdelphij 843228940Sdelphij /* Cannot create cross-device links. */ 844228940Sdelphij if (dvp->v_mount != vp->v_mount) { 845228940Sdelphij error = EXDEV; 846228940Sdelphij goto out; 847228940Sdelphij } 848228940Sdelphij 849228940Sdelphij /* Ensure that we do not overflow the maximum number of links imposed 850228940Sdelphij * by the system. */ 851228940Sdelphij MPASS(node->tn_links <= LINK_MAX); 852228940Sdelphij if (node->tn_links == LINK_MAX) { 853228940Sdelphij error = EMLINK; 854228940Sdelphij goto out; 855228940Sdelphij } 856228940Sdelphij 857228940Sdelphij /* We cannot create links of files marked immutable or append-only. */ 858228940Sdelphij if (node->tn_flags & (IMMUTABLE | APPEND)) { 859228940Sdelphij error = EPERM; 860228940Sdelphij goto out; 861228940Sdelphij } 862228940Sdelphij 863228940Sdelphij /* Allocate a new directory entry to represent the node. */ 864228940Sdelphij error = tmpfs_alloc_dirent(VFS_TO_TMPFS(vp->v_mount), node, 865228940Sdelphij cnp->cn_nameptr, cnp->cn_namelen, &de); 866228940Sdelphij if (error != 0) 867228940Sdelphij goto out; 868228940Sdelphij 869228940Sdelphij /* Insert the new directory entry into the appropriate directory. */ 870228940Sdelphij tmpfs_dir_attach(dvp, de); 871228940Sdelphij 872228940Sdelphij /* vp link count has changed, so update node times. */ 873228940Sdelphij node->tn_status |= TMPFS_NODE_CHANGED; 874228940Sdelphij tmpfs_update(vp); 875228940Sdelphij 876228940Sdelphij error = 0; 877228940Sdelphij 878228940Sdelphijout: 879228940Sdelphij return error; 880228940Sdelphij} 881228940Sdelphij 882228940Sdelphij/* --------------------------------------------------------------------- */ 883228940Sdelphij 884228940Sdelphijstatic int 885228940Sdelphijtmpfs_rename(struct vop_rename_args *v) 886228940Sdelphij{ 887228940Sdelphij struct vnode *fdvp = v->a_fdvp; 888228940Sdelphij struct vnode *fvp = v->a_fvp; 889228940Sdelphij struct componentname *fcnp = v->a_fcnp; 890228940Sdelphij struct vnode *tdvp = v->a_tdvp; 891228940Sdelphij struct vnode *tvp = v->a_tvp; 892228940Sdelphij struct componentname *tcnp = v->a_tcnp; 893228940Sdelphij 894228940Sdelphij char *newname; 895228940Sdelphij int error; 896228940Sdelphij struct tmpfs_dirent *de; 897228940Sdelphij struct tmpfs_node *fdnode; 898228940Sdelphij struct tmpfs_node *fnode; 899228940Sdelphij struct tmpfs_node *tnode; 900228940Sdelphij struct tmpfs_node *tdnode; 901228940Sdelphij 902228940Sdelphij MPASS(VOP_ISLOCKED(tdvp, tcnp->cn_thread)); 903228940Sdelphij MPASS(IMPLIES(tvp != NULL, VOP_ISLOCKED(tvp, tcnp->cn_thread))); 904228940Sdelphij MPASS(fcnp->cn_flags & HASBUF); 905228940Sdelphij MPASS(tcnp->cn_flags & HASBUF); 906228940Sdelphij 907228940Sdelphij tnode = (tvp == NULL) ? NULL : VP_TO_TMPFS_NODE(tvp); 908228940Sdelphij 909228940Sdelphij /* Disallow cross-device renames. 910228940Sdelphij * XXX Why isn't this done by the caller? */ 911228940Sdelphij if (fvp->v_mount != tdvp->v_mount || 912228940Sdelphij (tvp != NULL && fvp->v_mount != tvp->v_mount)) { 913228940Sdelphij error = EXDEV; 914228940Sdelphij goto out; 915228940Sdelphij } 916228940Sdelphij 917228940Sdelphij tdnode = VP_TO_TMPFS_DIR(tdvp); 918228940Sdelphij 919228940Sdelphij /* If source and target are the same file, there is nothing to do. */ 920228940Sdelphij if (fvp == tvp) { 921228940Sdelphij error = 0; 922228940Sdelphij goto out; 923228940Sdelphij } 924228940Sdelphij 925228940Sdelphij /* If we need to move the directory between entries, lock the 926228940Sdelphij * source so that we can safely operate on it. */ 927228940Sdelphij if (tdvp != fdvp) { 928228940Sdelphij error = vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY); 929228940Sdelphij if (error != 0) 930228940Sdelphij goto out; 931228940Sdelphij } 932228940Sdelphij fdnode = VP_TO_TMPFS_DIR(fdvp); 933228940Sdelphij fnode = VP_TO_TMPFS_NODE(fvp); 934228940Sdelphij de = tmpfs_dir_search(fdnode, fnode); 935228940Sdelphij 936228940Sdelphij /* Avoid manipulating '.' and '..' entries. */ 937228940Sdelphij if (de == NULL) { 938228940Sdelphij MPASS(fvp->v_type == VDIR); 939228940Sdelphij error = EINVAL; 940228940Sdelphij goto out_locked; 941228940Sdelphij } 942228940Sdelphij MPASS(de->td_node == fnode); 943228940Sdelphij 944228940Sdelphij /* If re-naming a directory to another preexisting directory 945228940Sdelphij * ensure that the target directory is empty so that its 946228940Sdelphij * removal causes no side effects. 947228940Sdelphij * Kern_rename gurantees the destination to be a directory 948228940Sdelphij * if the source is one. */ 949228940Sdelphij if (tvp != NULL) { 950228940Sdelphij MPASS(tnode != NULL); 951228940Sdelphij 952228940Sdelphij if ((tnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) || 953228940Sdelphij (tdnode->tn_flags & (APPEND | IMMUTABLE))) { 954228940Sdelphij error = EPERM; 955228940Sdelphij goto out_locked; 956228940Sdelphij } 957228940Sdelphij 958228940Sdelphij if (fnode->tn_type == VDIR && tnode->tn_type == VDIR) { 959228940Sdelphij if (tnode->tn_size > 0) { 960228940Sdelphij error = ENOTEMPTY; 961228940Sdelphij goto out_locked; 962228940Sdelphij } 963228940Sdelphij } else if (fnode->tn_type == VDIR && tnode->tn_type != VDIR) { 964228940Sdelphij error = ENOTDIR; 965228940Sdelphij goto out_locked; 966228940Sdelphij } else if (fnode->tn_type != VDIR && tnode->tn_type == VDIR) { 967228940Sdelphij error = EISDIR; 968228940Sdelphij goto out_locked; 969228940Sdelphij } else { 970228940Sdelphij MPASS(fnode->tn_type != VDIR && 971228940Sdelphij tnode->tn_type != VDIR); 972228940Sdelphij } 973228940Sdelphij } 974228940Sdelphij 975252852Sdelphij if ((fnode->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) 976228940Sdelphij || (fdnode->tn_flags & (APPEND | IMMUTABLE))) { 977228940Sdelphij error = EPERM; 978228940Sdelphij goto out_locked; 979228940Sdelphij } 980228940Sdelphij 981228940Sdelphij /* Ensure that we have enough memory to hold the new name, if it 982228940Sdelphij * has to be changed. */ 983228940Sdelphij if (fcnp->cn_namelen != tcnp->cn_namelen || 984228940Sdelphij memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen) != 0) { 985228940Sdelphij newname = malloc(tcnp->cn_namelen, M_TMPFSNAME, M_WAITOK); 986228940Sdelphij } else 987228940Sdelphij newname = NULL; 988228940Sdelphij 989228940Sdelphij /* If the node is being moved to another directory, we have to do 990228940Sdelphij * the move. */ 991228940Sdelphij if (fdnode != tdnode) { 992228940Sdelphij /* In case we are moving a directory, we have to adjust its 993228940Sdelphij * parent to point to the new parent. */ 994245768Sdelphij if (de->td_node->tn_type == VDIR) { 995228940Sdelphij struct tmpfs_node *n; 996228940Sdelphij 997228940Sdelphij /* Ensure the target directory is not a child of the 998228940Sdelphij * directory being moved. Otherwise, we'd end up 999228940Sdelphij * with stale nodes. */ 1000228940Sdelphij n = tdnode; 1001228940Sdelphij while (n != n->tn_dir.tn_parent) { 1002228940Sdelphij if (n == fnode) { 1003228940Sdelphij error = EINVAL; 1004228940Sdelphij if (newname != NULL) 1005228940Sdelphij free(newname, M_TMPFSNAME); 1006228940Sdelphij goto out_locked; 1007228940Sdelphij } 1008228940Sdelphij n = n->tn_dir.tn_parent; 1009228940Sdelphij } 1010228940Sdelphij 1011228940Sdelphij /* Adjust the parent pointer. */ 1012228940Sdelphij TMPFS_VALIDATE_DIR(fnode); 1013228940Sdelphij de->td_node->tn_dir.tn_parent = tdnode; 1014228940Sdelphij 1015228940Sdelphij /* As a result of changing the target of the '..' 1016228940Sdelphij * entry, the link count of the source and target 1017228940Sdelphij * directories has to be adjusted. */ 1018228940Sdelphij fdnode->tn_links--; 1019228940Sdelphij tdnode->tn_links++; 1020228940Sdelphij } 1021228940Sdelphij 1022228940Sdelphij /* Do the move: just remove the entry from the source directory 1023228940Sdelphij * and insert it into the target one. */ 1024228940Sdelphij tmpfs_dir_detach(fdvp, de); 1025228940Sdelphij tmpfs_dir_attach(tdvp, de); 1026228940Sdelphij } 1027228940Sdelphij 1028228940Sdelphij /* If the name has changed, we need to make it effective by changing 1029228940Sdelphij * it in the directory entry. */ 1030228940Sdelphij if (newname != NULL) { 1031228940Sdelphij MPASS(tcnp->cn_namelen <= MAXNAMLEN); 1032228940Sdelphij 1033228940Sdelphij free(de->td_name, M_TMPFSNAME); 1034228940Sdelphij de->td_namelen = (uint16_t)tcnp->cn_namelen; 1035228940Sdelphij memcpy(newname, tcnp->cn_nameptr, tcnp->cn_namelen); 1036228940Sdelphij de->td_name = newname; 1037228940Sdelphij 1038228940Sdelphij fnode->tn_status |= TMPFS_NODE_CHANGED; 1039228940Sdelphij tdnode->tn_status |= TMPFS_NODE_MODIFIED; 1040228940Sdelphij } 1041228940Sdelphij 1042228940Sdelphij /* If we are overwriting an entry, we have to remove the old one 1043228940Sdelphij * from the target directory. */ 1044228940Sdelphij if (tvp != NULL) { 1045228940Sdelphij /* Remove the old entry from the target directory. */ 1046228940Sdelphij de = tmpfs_dir_search(tdnode, tnode); 1047228940Sdelphij tmpfs_dir_detach(tdvp, de); 1048228940Sdelphij 1049228940Sdelphij /* Free the directory entry we just deleted. Note that the 1050255871Sscottl * node referred by it will not be removed until the vnode is 1051228940Sdelphij * really reclaimed. */ 1052228940Sdelphij tmpfs_free_dirent(VFS_TO_TMPFS(tvp->v_mount), de, TRUE); 1053228940Sdelphij } 1054228940Sdelphij 1055228940Sdelphij error = 0; 1056228940Sdelphij 1057228940Sdelphijout_locked: 1058228940Sdelphij if (fdnode != tdnode) 1059228940Sdelphij VOP_UNLOCK(fdvp, 0); 1060252852Sdelphij 1061228940Sdelphijout: 1062228940Sdelphij /* Release target nodes. */ 1063252852Sdelphij /* XXX: I don't understand when tdvp can be the same as tvp, but 1064228940Sdelphij * other code takes care of this... */ 1065252852Sdelphij if (tdvp == tvp) 1066228940Sdelphij vrele(tdvp); 1067228940Sdelphij else 1068228940Sdelphij vput(tdvp); 1069228940Sdelphij if (tvp != NULL) 1070228940Sdelphij vput(tvp); 1071228940Sdelphij 1072228940Sdelphij /* Release source nodes. */ 1073228940Sdelphij vrele(fdvp); 1074228940Sdelphij vrele(fvp); 1075228940Sdelphij 1076228940Sdelphij return error; 1077228940Sdelphij} 1078228940Sdelphij 1079228940Sdelphij/* --------------------------------------------------------------------- */ 1080228940Sdelphij 1081228940Sdelphijstatic int 1082228940Sdelphijtmpfs_mkdir(struct vop_mkdir_args *v) 1083228940Sdelphij{ 1084228940Sdelphij struct vnode *dvp = v->a_dvp; 1085228940Sdelphij struct vnode **vpp = v->a_vpp; 1086228940Sdelphij struct componentname *cnp = v->a_cnp; 1087228940Sdelphij struct vattr *vap = v->a_vap; 1088228940Sdelphij 1089228940Sdelphij MPASS(vap->va_type == VDIR); 1090228940Sdelphij 1091228940Sdelphij return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL); 1092228940Sdelphij} 1093228940Sdelphij 1094228940Sdelphij/* --------------------------------------------------------------------- */ 1095228940Sdelphij 1096228940Sdelphijstatic int 1097228940Sdelphijtmpfs_rmdir(struct vop_rmdir_args *v) 1098228940Sdelphij{ 1099228940Sdelphij struct vnode *dvp = v->a_dvp; 1100228940Sdelphij struct vnode *vp = v->a_vp; 1101228940Sdelphij 1102228940Sdelphij int error; 1103228940Sdelphij struct tmpfs_dirent *de; 1104228940Sdelphij struct tmpfs_mount *tmp; 1105228940Sdelphij struct tmpfs_node *dnode; 1106228940Sdelphij struct tmpfs_node *node; 1107228940Sdelphij 1108228940Sdelphij MPASS(VOP_ISLOCKED(dvp, v->a_cnp->cn_thread)); 1109228940Sdelphij MPASS(VOP_ISLOCKED(vp, v->a_cnp->cn_thread)); 1110228940Sdelphij 1111228940Sdelphij tmp = VFS_TO_TMPFS(dvp->v_mount); 1112228940Sdelphij dnode = VP_TO_TMPFS_DIR(dvp); 1113228940Sdelphij node = VP_TO_TMPFS_DIR(vp); 1114228940Sdelphij 1115228940Sdelphij /* Directories with more than two entries ('.' and '..') cannot be 1116228940Sdelphij * removed. */ 1117228940Sdelphij if (node->tn_size > 0) { 1118228940Sdelphij error = ENOTEMPTY; 1119228940Sdelphij goto out; 1120228940Sdelphij } 1121228940Sdelphij 1122228940Sdelphij if ((dnode->tn_flags & APPEND) 1123228940Sdelphij || (node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND))) { 1124228940Sdelphij error = EPERM; 1125228940Sdelphij goto out; 1126228940Sdelphij } 1127228940Sdelphij 1128228940Sdelphij /* This invariant holds only if we are not trying to remove "..". 1129228940Sdelphij * We checked for that above so this is safe now. */ 1130228940Sdelphij MPASS(node->tn_dir.tn_parent == dnode); 1131228940Sdelphij 1132228940Sdelphij /* Get the directory entry associated with node (vp). This was 1133228940Sdelphij * filled by tmpfs_lookup while looking up the entry. */ 1134228940Sdelphij de = tmpfs_dir_search(dnode, node); 1135228940Sdelphij MPASS(TMPFS_DIRENT_MATCHES(de, 1136228940Sdelphij v->a_cnp->cn_nameptr, 1137245768Sdelphij v->a_cnp->cn_namelen)); 1138228940Sdelphij 1139228940Sdelphij /* Check flags to see if we are allowed to remove the directory. */ 1140228940Sdelphij if (dnode->tn_flags & APPEND 1141228940Sdelphij || node->tn_flags & (NOUNLINK | IMMUTABLE | APPEND)) { 1142228940Sdelphij error = EPERM; 1143228940Sdelphij goto out; 1144228940Sdelphij } 1145228940Sdelphij 1146228940Sdelphij /* Detach the directory entry from the directory (dnode). */ 1147228940Sdelphij tmpfs_dir_detach(dvp, de); 1148228940Sdelphij 1149228940Sdelphij node->tn_links--; 1150228940Sdelphij node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_CHANGED | \ 1151228940Sdelphij TMPFS_NODE_MODIFIED; 1152228940Sdelphij node->tn_dir.tn_parent->tn_links--; 1153228940Sdelphij node->tn_dir.tn_parent->tn_status |= TMPFS_NODE_ACCESSED | \ 1154228940Sdelphij TMPFS_NODE_CHANGED | TMPFS_NODE_MODIFIED; 1155228940Sdelphij 1156228940Sdelphij cache_purge(dvp); 1157228940Sdelphij cache_purge(vp); 1158228940Sdelphij 1159228940Sdelphij /* Free the directory entry we just deleted. Note that the node 1160228940Sdelphij * referred by it will not be removed until the vnode is really 1161228940Sdelphij * reclaimed. */ 1162228940Sdelphij tmpfs_free_dirent(tmp, de, TRUE); 1163228940Sdelphij 1164228940Sdelphij /* Release the deleted vnode (will destroy the node, notify 1165228940Sdelphij * interested parties and clean it from the cache). */ 1166228940Sdelphij 1167228940Sdelphij dnode->tn_status |= TMPFS_NODE_CHANGED; 1168228940Sdelphij tmpfs_update(dvp); 1169228940Sdelphij 1170228940Sdelphij error = 0; 1171228940Sdelphij 1172228940Sdelphijout: 1173228940Sdelphij return error; 1174228940Sdelphij} 1175228940Sdelphij 1176228940Sdelphij/* --------------------------------------------------------------------- */ 1177228940Sdelphij 1178228940Sdelphijstatic int 1179228940Sdelphijtmpfs_symlink(struct vop_symlink_args *v) 1180228940Sdelphij{ 1181228940Sdelphij struct vnode *dvp = v->a_dvp; 1182228940Sdelphij struct vnode **vpp = v->a_vpp; 1183228940Sdelphij struct componentname *cnp = v->a_cnp; 1184245768Sdelphij struct vattr *vap = v->a_vap; 1185228940Sdelphij char *target = v->a_target; 1186228940Sdelphij 1187228940Sdelphij#ifdef notyet /* XXX FreeBSD BUG: kern_symlink is not setting VLNK */ 1188228940Sdelphij MPASS(vap->va_type == VLNK); 1189228940Sdelphij#else 1190228940Sdelphij vap->va_type = VLNK; 1191228940Sdelphij#endif 1192228940Sdelphij 1193228940Sdelphij return tmpfs_alloc_file(dvp, vpp, vap, cnp, target); 1194228940Sdelphij} 1195228940Sdelphij 1196228940Sdelphij/* --------------------------------------------------------------------- */ 1197228940Sdelphij 1198228940Sdelphijstatic int 1199228940Sdelphijtmpfs_readdir(struct vop_readdir_args *v) 1200228940Sdelphij{ 1201228940Sdelphij struct vnode *vp = v->a_vp; 1202228940Sdelphij struct uio *uio = v->a_uio; 1203228940Sdelphij int *eofflag = v->a_eofflag; 1204228940Sdelphij u_long **cookies = v->a_cookies; 1205228940Sdelphij int *ncookies = v->a_ncookies; 1206228940Sdelphij 1207228940Sdelphij int error; 1208228940Sdelphij off_t startoff; 1209228940Sdelphij off_t cnt = 0; 1210228940Sdelphij struct tmpfs_node *node; 1211228940Sdelphij 1212228940Sdelphij /* This operation only makes sense on directory nodes. */ 1213228940Sdelphij if (vp->v_type != VDIR) 1214228940Sdelphij return ENOTDIR; 1215228940Sdelphij 1216228940Sdelphij node = VP_TO_TMPFS_DIR(vp); 1217228940Sdelphij 1218228940Sdelphij startoff = uio->uio_offset; 1219228940Sdelphij 1220228940Sdelphij if (uio->uio_offset == TMPFS_DIRCOOKIE_DOT) { 1221228940Sdelphij error = tmpfs_dir_getdotdent(node, uio); 1222228940Sdelphij if (error != 0) 1223228940Sdelphij goto outok; 1224228940Sdelphij cnt++; 1225228940Sdelphij } 1226228940Sdelphij 1227228940Sdelphij if (uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT) { 1228228940Sdelphij error = tmpfs_dir_getdotdotdent(node, uio); 1229228940Sdelphij if (error != 0) 1230228940Sdelphij goto outok; 1231228940Sdelphij cnt++; 1232228940Sdelphij } 1233228940Sdelphij 1234228940Sdelphij error = tmpfs_dir_getdents(node, uio, &cnt); 1235228940Sdelphij 1236228940Sdelphijoutok: 1237228940Sdelphij MPASS(error >= -1); 1238228940Sdelphij 1239228940Sdelphij if (error == -1) 1240228940Sdelphij error = 0; 1241228940Sdelphij 1242228940Sdelphij if (eofflag != NULL) 1243228940Sdelphij *eofflag = 1244228940Sdelphij (error == 0 && uio->uio_offset == TMPFS_DIRCOOKIE_EOF); 1245228940Sdelphij 1246228940Sdelphij /* Update NFS-related variables. */ 1247228940Sdelphij if (error == 0 && cookies != NULL && ncookies != NULL) { 1248228940Sdelphij off_t i; 1249228940Sdelphij off_t off = startoff; 1250228940Sdelphij struct tmpfs_dirent *de = NULL; 1251228940Sdelphij 1252228940Sdelphij *ncookies = cnt; 1253228940Sdelphij *cookies = malloc(cnt * sizeof(off_t), M_TEMP, M_WAITOK); 1254228940Sdelphij 1255228940Sdelphij for (i = 0; i < cnt; i++) { 1256228940Sdelphij MPASS(off != TMPFS_DIRCOOKIE_EOF); 1257228940Sdelphij if (off == TMPFS_DIRCOOKIE_DOT) { 1258228940Sdelphij off = TMPFS_DIRCOOKIE_DOTDOT; 1259228940Sdelphij } else { 1260228940Sdelphij if (off == TMPFS_DIRCOOKIE_DOTDOT) { 1261228940Sdelphij de = TAILQ_FIRST(&node->tn_dir.tn_dirhead); 1262228940Sdelphij } else if (de != NULL) { 1263228940Sdelphij de = TAILQ_NEXT(de, td_entries); 1264228940Sdelphij } else { 1265228940Sdelphij de = tmpfs_dir_lookupbycookie(node, 1266228940Sdelphij off); 1267228940Sdelphij MPASS(de != NULL); 1268228940Sdelphij de = TAILQ_NEXT(de, td_entries); 1269228940Sdelphij } 1270228940Sdelphij if (de == NULL) 1271228940Sdelphij off = TMPFS_DIRCOOKIE_EOF; 1272228940Sdelphij else 1273228940Sdelphij off = tmpfs_dircookie(de); 1274228940Sdelphij } 1275228940Sdelphij 1276228940Sdelphij (*cookies)[i] = off; 1277228940Sdelphij } 1278228940Sdelphij MPASS(uio->uio_offset == off); 1279228940Sdelphij } 1280228940Sdelphij 1281228940Sdelphij return error; 1282228940Sdelphij} 1283228940Sdelphij 1284228940Sdelphij/* --------------------------------------------------------------------- */ 1285228940Sdelphij 1286228940Sdelphijstatic int 1287228940Sdelphijtmpfs_readlink(struct vop_readlink_args *v) 1288228940Sdelphij{ 1289228940Sdelphij struct vnode *vp = v->a_vp; 1290228940Sdelphij struct uio *uio = v->a_uio; 1291228940Sdelphij 1292228940Sdelphij int error; 1293228940Sdelphij struct tmpfs_node *node; 1294228940Sdelphij 1295228940Sdelphij MPASS(uio->uio_offset == 0); 1296228940Sdelphij MPASS(vp->v_type == VLNK); 1297228940Sdelphij 1298228940Sdelphij node = VP_TO_TMPFS_NODE(vp); 1299228940Sdelphij 1300228940Sdelphij error = uiomove(node->tn_link, MIN(node->tn_size, uio->uio_resid), 1301228940Sdelphij uio); 1302228940Sdelphij node->tn_status |= TMPFS_NODE_ACCESSED; 1303228940Sdelphij 1304228940Sdelphij return error; 1305228940Sdelphij} 1306228940Sdelphij 1307228940Sdelphij/* --------------------------------------------------------------------- */ 1308228940Sdelphij 1309228940Sdelphijstatic int 1310228940Sdelphijtmpfs_inactive(struct vop_inactive_args *v) 1311228940Sdelphij{ 1312228940Sdelphij struct vnode *vp = v->a_vp; 1313228940Sdelphij struct thread *l = v->a_td; 1314228940Sdelphij 1315228940Sdelphij struct tmpfs_node *node; 1316228940Sdelphij 1317228940Sdelphij MPASS(VOP_ISLOCKED(vp, l)); 1318228940Sdelphij 1319228940Sdelphij node = VP_TO_TMPFS_NODE(vp); 1320228940Sdelphij 1321228940Sdelphij if (node->tn_links == 0) 1322228940Sdelphij vrecycle(vp, l); 1323228940Sdelphij 1324228940Sdelphij return 0; 1325228940Sdelphij} 1326228940Sdelphij 1327228940Sdelphij/* --------------------------------------------------------------------- */ 1328228940Sdelphij 1329228940Sdelphijint 1330228940Sdelphijtmpfs_reclaim(struct vop_reclaim_args *v) 1331228940Sdelphij{ 1332228940Sdelphij struct vnode *vp = v->a_vp; 1333228940Sdelphij 1334228940Sdelphij struct tmpfs_mount *tmp; 1335228940Sdelphij struct tmpfs_node *node; 1336228940Sdelphij 1337228940Sdelphij node = VP_TO_TMPFS_NODE(vp); 1338228940Sdelphij tmp = VFS_TO_TMPFS(vp->v_mount); 1339228940Sdelphij 1340228940Sdelphij vnode_destroy_vobject(vp); 1341228940Sdelphij cache_purge(vp); 1342228940Sdelphij tmpfs_free_vp(vp); 1343228940Sdelphij 1344228940Sdelphij /* If the node referenced by this vnode was deleted by the user, 1345228940Sdelphij * we must free its associated data structures (now that the vnode 1346252852Sdelphij * is being reclaimed). */ 1347252852Sdelphij if (node->tn_links == 0) 1348252852Sdelphij tmpfs_free_node(tmp, node); 1349252852Sdelphij 1350252852Sdelphij MPASS(vp->v_data == NULL); 1351228940Sdelphij return 0; 1352252852Sdelphij} 1353252852Sdelphij 1354228940Sdelphij/* --------------------------------------------------------------------- */ 1355252852Sdelphij 1356252852Sdelphijstatic int 1357228940Sdelphijtmpfs_print(struct vop_print_args *v) 1358228940Sdelphij{ 1359228940Sdelphij struct vnode *vp = v->a_vp; 1360228940Sdelphij 1361228940Sdelphij struct tmpfs_node *node; 1362 1363 node = VP_TO_TMPFS_NODE(vp); 1364 1365 printf("tag VT_TMPFS, tmpfs_node %p, flags 0x%x, links %d\n", 1366 node, node->tn_flags, node->tn_links); 1367 printf("\tmode 0%o, owner %d, group %d, size %" PRIdMAX 1368 ", status 0x%x\n", 1369 node->tn_mode, node->tn_uid, node->tn_gid, 1370 (uintmax_t)node->tn_size, node->tn_status); 1371 1372 if (vp->v_type == VFIFO) 1373 fifo_printinfo(vp); 1374 1375 printf("\n"); 1376 1377 return 0; 1378} 1379 1380/* --------------------------------------------------------------------- */ 1381 1382static int 1383tmpfs_pathconf(struct vop_pathconf_args *v) 1384{ 1385 int name = v->a_name; 1386 register_t *retval = v->a_retval; 1387 1388 int error; 1389 1390 error = 0; 1391 1392 switch (name) { 1393 case _PC_LINK_MAX: 1394 *retval = LINK_MAX; 1395 break; 1396 1397 case _PC_NAME_MAX: 1398 *retval = NAME_MAX; 1399 break; 1400 1401 case _PC_PATH_MAX: 1402 *retval = PATH_MAX; 1403 break; 1404 1405 case _PC_PIPE_BUF: 1406 *retval = PIPE_BUF; 1407 break; 1408 1409 case _PC_CHOWN_RESTRICTED: 1410 *retval = 1; 1411 break; 1412 1413 case _PC_NO_TRUNC: 1414 *retval = 1; 1415 break; 1416 1417 case _PC_SYNC_IO: 1418 *retval = 1; 1419 break; 1420 1421 case _PC_FILESIZEBITS: 1422 *retval = 0; /* XXX Don't know which value should I return. */ 1423 break; 1424 1425 default: 1426 error = EINVAL; 1427 } 1428 1429 return error; 1430} 1431 1432/* --------------------------------------------------------------------- */ 1433 1434static int 1435tmpfs_advlock(struct vop_advlock_args *v) 1436{ 1437 struct vnode *vp = v->a_vp; 1438 1439 struct tmpfs_node *node; 1440 1441 node = VP_TO_TMPFS_NODE(vp); 1442 1443 return lf_advlock(v, &node->tn_lockf, node->tn_size); 1444} 1445 1446/* --------------------------------------------------------------------- */ 1447 1448static int 1449tmpfs_vptofh(struct vop_vptofh_args *ap) 1450{ 1451 struct tmpfs_fid *tfhp; 1452 struct tmpfs_node *node; 1453 1454 tfhp = (struct tmpfs_fid *)ap->a_fhp; 1455 node = VP_TO_TMPFS_NODE(ap->a_vp); 1456 1457 tfhp->tf_len = sizeof(struct tmpfs_fid); 1458 tfhp->tf_id = node->tn_id; 1459 tfhp->tf_gen = node->tn_gen; 1460 1461 return (0); 1462} 1463 1464/* --------------------------------------------------------------------- */ 1465 1466/* 1467 * vnode operations vector used for files stored in a tmpfs file system. 1468 */ 1469struct vop_vector tmpfs_vnodeop_entries = { 1470 .vop_default = &default_vnodeops, 1471 .vop_lookup = vfs_cache_lookup, 1472 .vop_cachedlookup = tmpfs_lookup, 1473 .vop_create = tmpfs_create, 1474 .vop_mknod = tmpfs_mknod, 1475 .vop_open = tmpfs_open, 1476 .vop_close = tmpfs_close, 1477 .vop_access = tmpfs_access, 1478 .vop_getattr = tmpfs_getattr, 1479 .vop_setattr = tmpfs_setattr, 1480 .vop_read = tmpfs_read, 1481 .vop_write = tmpfs_write, 1482 .vop_fsync = tmpfs_fsync, 1483 .vop_remove = tmpfs_remove, 1484 .vop_link = tmpfs_link, 1485 .vop_rename = tmpfs_rename, 1486 .vop_mkdir = tmpfs_mkdir, 1487 .vop_rmdir = tmpfs_rmdir, 1488 .vop_symlink = tmpfs_symlink, 1489 .vop_readdir = tmpfs_readdir, 1490 .vop_readlink = tmpfs_readlink, 1491 .vop_inactive = tmpfs_inactive, 1492 .vop_reclaim = tmpfs_reclaim, 1493 .vop_print = tmpfs_print, 1494 .vop_pathconf = tmpfs_pathconf, 1495 .vop_advlock = tmpfs_advlock, 1496 .vop_vptofh = tmpfs_vptofh, 1497 .vop_bmap = VOP_EOPNOTSUPP, 1498}; 1499 1500