nandfs_vnops.c revision 251171
1227825Stheraven/*- 2227825Stheraven * Copyright (c) 2010-2012 Semihalf 3227825Stheraven * Copyright (c) 2008, 2009 Reinoud Zandijk 4227825Stheraven * All rights reserved. 5227825Stheraven * 6227825Stheraven * Redistribution and use in source and binary forms, with or without 7227825Stheraven * modification, are permitted provided that the following conditions 8227825Stheraven * are met: 9227825Stheraven * 1. Redistributions of source code must retain the above copyright 10227825Stheraven * notice, this list of conditions and the following disclaimer. 11227825Stheraven * 2. Redistributions in binary form must reproduce the above copyright 12227825Stheraven * notice, this list of conditions and the following disclaimer in the 13227825Stheraven * documentation and/or other materials provided with the distribution. 14227825Stheraven * 15227825Stheraven * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16227825Stheraven * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17227825Stheraven * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18227825Stheraven * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19227825Stheraven * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20227825Stheraven * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21227825Stheraven * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22227825Stheraven * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23227825Stheraven * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24234976Stheraven * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25234976Stheraven * 26234976Stheraven * From: NetBSD: nilfs_vnops.c,v 1.2 2009/08/26 03:40:48 elad 27234976Stheraven */ 28227825Stheraven 29234976Stheraven#include <sys/cdefs.h> 30234976Stheraven__FBSDID("$FreeBSD: head/sys/fs/nandfs/nandfs_vnops.c 251171 2013-05-31 00:43:41Z jeff $"); 31234976Stheraven 32234976Stheraven#include <sys/param.h> 33234976Stheraven#include <sys/systm.h> 34234976Stheraven#include <sys/conf.h> 35234976Stheraven#include <sys/kernel.h> 36234976Stheraven#include <sys/lock.h> 37234976Stheraven#include <sys/lockf.h> 38227825Stheraven#include <sys/malloc.h> 39234976Stheraven#include <sys/mount.h> 40234976Stheraven#include <sys/mutex.h> 41234976Stheraven#include <sys/namei.h> 42234976Stheraven#include <sys/sysctl.h> 43227825Stheraven#include <sys/unistd.h> 44234976Stheraven#include <sys/vnode.h> 45234976Stheraven#include <sys/buf.h> 46234976Stheraven#include <sys/bio.h> 47234976Stheraven#include <sys/fcntl.h> 48234976Stheraven#include <sys/dirent.h> 49234976Stheraven#include <sys/rwlock.h> 50234976Stheraven#include <sys/stat.h> 51234976Stheraven#include <sys/priv.h> 52234976Stheraven 53227825Stheraven#include <vm/vm.h> 54234976Stheraven#include <vm/vm_extern.h> 55234976Stheraven#include <vm/vm_object.h> 56234976Stheraven#include <vm/vnode_pager.h> 57227825Stheraven 58234976Stheraven#include <machine/_inttypes.h> 59234976Stheraven 60234976Stheraven#include <fs/nandfs/nandfs_mount.h> 61227825Stheraven#include <fs/nandfs/nandfs.h> 62227825Stheraven#include <fs/nandfs/nandfs_subr.h> 63227825Stheraven 64227825Stheravenextern uma_zone_t nandfs_node_zone; 65227825Stheravenstatic void nandfs_read_filebuf(struct nandfs_node *, struct buf *); 66227825Stheravenstatic void nandfs_itimes_locked(struct vnode *); 67227825Stheravenstatic int nandfs_truncate(struct vnode *, uint64_t); 68227825Stheraven 69227825Stheravenstatic vop_pathconf_t nandfs_pathconf; 70227825Stheraven 71227825Stheraven#define UPDATE_CLOSE 0 72227825Stheraven#define UPDATE_WAIT 0 73227825Stheraven 74227825Stheravenstatic int 75227825Stheravennandfs_inactive(struct vop_inactive_args *ap) 76227825Stheraven{ 77227825Stheraven struct vnode *vp = ap->a_vp; 78227825Stheraven struct nandfs_node *node = VTON(vp); 79227825Stheraven int error = 0; 80227825Stheraven 81227825Stheraven DPRINTF(VNCALL, ("%s: vp:%p node:%p\n", __func__, vp, node)); 82227825Stheraven 83227825Stheraven if (node == NULL) { 84227825Stheraven DPRINTF(NODE, ("%s: inactive NULL node\n", __func__)); 85227825Stheraven return (0); 86227825Stheraven } 87227825Stheraven 88227825Stheraven if (node->nn_inode.i_mode != 0 && !(node->nn_inode.i_links_count)) { 89227825Stheraven nandfs_truncate(vp, 0); 90227825Stheraven error = nandfs_node_destroy(node); 91227825Stheraven if (error) 92227825Stheraven nandfs_error("%s: destroy node: %p\n", __func__, node); 93227825Stheraven node->nn_flags = 0; 94227825Stheraven vrecycle(vp); 95227825Stheraven } 96227825Stheraven 97227825Stheraven return (error); 98227825Stheraven} 99227825Stheraven 100227825Stheravenstatic int 101227825Stheravennandfs_reclaim(struct vop_reclaim_args *ap) 102227825Stheraven{ 103227825Stheraven struct vnode *vp = ap->a_vp; 104227825Stheraven struct nandfs_node *nandfs_node = VTON(vp); 105227825Stheraven struct nandfs_device *fsdev = nandfs_node->nn_nandfsdev; 106227825Stheraven uint64_t ino = nandfs_node->nn_ino; 107227825Stheraven 108227825Stheraven DPRINTF(VNCALL, ("%s: vp:%p node:%p\n", __func__, vp, nandfs_node)); 109227825Stheraven 110227825Stheraven /* Invalidate all entries to a particular vnode. */ 111227825Stheraven cache_purge(vp); 112232950Stheraven 113232950Stheraven /* Destroy the vm object and flush associated pages. */ 114227825Stheraven vnode_destroy_vobject(vp); 115227825Stheraven 116227825Stheraven /* Remove from vfs hash if not system vnode */ 117227825Stheraven if (!NANDFS_SYS_NODE(nandfs_node->nn_ino)) 118227825Stheraven vfs_hash_remove(vp); 119227825Stheraven 120227825Stheraven /* Dispose all node knowledge */ 121227825Stheraven nandfs_dispose_node(&nandfs_node); 122227825Stheraven 123227825Stheraven if (!NANDFS_SYS_NODE(ino)) 124227825Stheraven NANDFS_WRITEUNLOCK(fsdev); 125227825Stheraven 126227825Stheraven return (0); 127227825Stheraven} 128227825Stheraven 129227825Stheravenstatic int 130227825Stheravennandfs_read(struct vop_read_args *ap) 131227825Stheraven{ 132227825Stheraven register struct vnode *vp = ap->a_vp; 133227825Stheraven register struct nandfs_node *node = VTON(vp); 134227825Stheraven struct nandfs_device *nandfsdev = node->nn_nandfsdev; 135227825Stheraven struct uio *uio = ap->a_uio; 136227825Stheraven struct buf *bp; 137227825Stheraven uint64_t size; 138227825Stheraven uint32_t blocksize; 139227825Stheraven off_t bytesinfile; 140227825Stheraven ssize_t toread, off; 141227825Stheraven daddr_t lbn; 142234976Stheraven ssize_t resid; 143234976Stheraven int error = 0; 144234976Stheraven 145234976Stheraven if (uio->uio_resid == 0) 146227825Stheraven return (0); 147234976Stheraven 148234976Stheraven size = node->nn_inode.i_size; 149234976Stheraven if (uio->uio_offset >= size) 150234976Stheraven return (0); 151234976Stheraven 152234976Stheraven blocksize = nandfsdev->nd_blocksize; 153234976Stheraven bytesinfile = size - uio->uio_offset; 154234976Stheraven 155234976Stheraven resid = omin(uio->uio_resid, bytesinfile); 156227825Stheraven 157234976Stheraven while (resid) { 158234976Stheraven lbn = uio->uio_offset / blocksize; 159234976Stheraven off = uio->uio_offset & (blocksize - 1); 160234976Stheraven 161227825Stheraven toread = omin(resid, blocksize - off); 162234976Stheraven 163234976Stheraven DPRINTF(READ, ("nandfs_read bn: 0x%jx toread: 0x%zx (0x%x)\n", 164234976Stheraven (uintmax_t)lbn, toread, blocksize)); 165234976Stheraven 166234976Stheraven error = nandfs_bread(node, lbn, NOCRED, 0, &bp); 167234976Stheraven if (error) { 168234976Stheraven brelse(bp); 169234976Stheraven break; 170234976Stheraven } 171227825Stheraven 172234976Stheraven error = uiomove(bp->b_data + off, toread, uio); 173234976Stheraven if (error) { 174234976Stheraven brelse(bp); 175227825Stheraven break; 176234976Stheraven } 177234976Stheraven 178234976Stheraven brelse(bp); 179227825Stheraven resid -= toread; 180227825Stheraven } 181227825Stheraven 182227825Stheraven return (error); 183227825Stheraven} 184234976Stheraven 185227825Stheravenstatic int 186227825Stheravennandfs_write(struct vop_write_args *ap) 187227825Stheraven{ 188227825Stheraven struct nandfs_device *fsdev; 189227825Stheraven struct nandfs_node *node; 190234976Stheraven struct vnode *vp; 191227825Stheraven struct uio *uio; 192227825Stheraven struct buf *bp; 193227825Stheraven uint64_t file_size, vblk; 194227825Stheraven uint32_t blocksize; 195227825Stheraven ssize_t towrite, off; 196227825Stheraven daddr_t lbn; 197227825Stheraven ssize_t resid; 198227825Stheraven int error, ioflag, modified; 199234976Stheraven 200227825Stheraven vp = ap->a_vp; 201234976Stheraven uio = ap->a_uio; 202234976Stheraven ioflag = ap->a_ioflag; 203234976Stheraven node = VTON(vp); 204234976Stheraven fsdev = node->nn_nandfsdev; 205234976Stheraven 206234976Stheraven if (nandfs_fs_full(fsdev)) 207234976Stheraven return (ENOSPC); 208234976Stheraven 209234976Stheraven DPRINTF(WRITE, ("nandfs_write called %#zx at %#jx\n", 210227825Stheraven uio->uio_resid, (uintmax_t)uio->uio_offset)); 211234976Stheraven 212234976Stheraven if (uio->uio_offset < 0) 213234976Stheraven return (EINVAL); 214234976Stheraven if (uio->uio_resid == 0) 215234976Stheraven return (0); 216227825Stheraven 217234976Stheraven blocksize = fsdev->nd_blocksize; 218234976Stheraven file_size = node->nn_inode.i_size; 219234976Stheraven 220234976Stheraven switch (vp->v_type) { 221227825Stheraven case VREG: 222234976Stheraven if (ioflag & IO_APPEND) 223234976Stheraven uio->uio_offset = file_size; 224234976Stheraven break; 225234976Stheraven case VDIR: 226234976Stheraven return (EISDIR); 227234976Stheraven case VLNK: 228234976Stheraven break; 229234976Stheraven default: 230234976Stheraven panic("%s: bad file type vp: %p", __func__, vp); 231227825Stheraven } 232234976Stheraven 233234976Stheraven /* If explicitly asked to append, uio_offset can be wrong? */ 234234976Stheraven if (ioflag & IO_APPEND) 235227825Stheraven uio->uio_offset = file_size; 236227825Stheraven 237234976Stheraven resid = uio->uio_resid; 238227825Stheraven modified = error = 0; 239234976Stheraven 240227825Stheraven while (uio->uio_resid) { 241234976Stheraven lbn = uio->uio_offset / blocksize; 242234976Stheraven off = uio->uio_offset & (blocksize - 1); 243227825Stheraven 244227825Stheraven towrite = omin(uio->uio_resid, blocksize - off); 245227825Stheraven 246227825Stheraven DPRINTF(WRITE, ("%s: lbn: 0x%jd toread: 0x%zx (0x%x)\n", 247227825Stheraven __func__, (uintmax_t)lbn, towrite, blocksize)); 248227825Stheraven 249227825Stheraven error = nandfs_bmap_lookup(node, lbn, &vblk); 250227825Stheraven if (error) 251234976Stheraven break; 252227825Stheraven 253234976Stheraven DPRINTF(WRITE, ("%s: lbn: 0x%jd toread: 0x%zx (0x%x) " 254234976Stheraven "vblk=%jx\n", __func__, (uintmax_t)lbn, towrite, blocksize, 255234976Stheraven vblk)); 256234976Stheraven 257234976Stheraven if (vblk != 0) 258234976Stheraven error = nandfs_bread(node, lbn, NOCRED, 0, &bp); 259234976Stheraven else 260234976Stheraven error = nandfs_bcreate(node, lbn, NOCRED, 0, &bp); 261234976Stheraven 262227825Stheraven DPRINTF(WRITE, ("%s: vp %p bread bp %p lbn %#jx\n", __func__, 263234976Stheraven vp, bp, (uintmax_t)lbn)); 264234976Stheraven if (error) { 265234976Stheraven if (bp) 266234976Stheraven brelse(bp); 267234976Stheraven break; 268227825Stheraven } 269234976Stheraven 270234976Stheraven error = uiomove((char *)bp->b_data + off, (int)towrite, uio); 271234976Stheraven if (error) 272234976Stheraven break; 273227825Stheraven 274234976Stheraven error = nandfs_dirty_buf(bp, 0); 275234976Stheraven if (error) 276234976Stheraven break; 277234976Stheraven 278234976Stheraven modified++; 279234976Stheraven } 280234976Stheraven 281234976Stheraven /* XXX proper handling when only part of file was properly written */ 282234976Stheraven if (modified) { 283227825Stheraven if (resid > uio->uio_resid && ap->a_cred && 284234976Stheraven ap->a_cred->cr_uid != 0) 285234976Stheraven node->nn_inode.i_mode &= ~(ISUID | ISGID); 286234976Stheraven 287227825Stheraven if (file_size < uio->uio_offset + uio->uio_resid) { 288234976Stheraven node->nn_inode.i_size = uio->uio_offset + 289234976Stheraven uio->uio_resid; 290234976Stheraven node->nn_flags |= IN_CHANGE | IN_UPDATE; 291227825Stheraven vnode_pager_setsize(vp, uio->uio_offset + 292227825Stheraven uio->uio_resid); 293227825Stheraven nandfs_itimes(vp); 294227825Stheraven } 295227825Stheraven } 296227825Stheraven 297227825Stheraven DPRINTF(WRITE, ("%s: return:%d\n", __func__, error)); 298227825Stheraven 299234976Stheraven return (error); 300227825Stheraven} 301234976Stheraven 302234976Stheravenstatic int 303234976Stheravennandfs_lookup(struct vop_cachedlookup_args *ap) 304234976Stheraven{ 305234976Stheraven struct vnode *dvp, **vpp; 306234976Stheraven struct componentname *cnp; 307234976Stheraven struct ucred *cred; 308227825Stheraven struct thread *td; 309234976Stheraven struct nandfs_node *dir_node, *node; 310234976Stheraven struct nandfsmount *nmp; 311234976Stheraven uint64_t ino, off; 312234976Stheraven const char *name; 313234976Stheraven int namelen, nameiop, islastcn, mounted_ro; 314227825Stheraven int error, found; 315234976Stheraven 316234976Stheraven DPRINTF(VNCALL, ("%s\n", __func__)); 317234976Stheraven 318234976Stheraven dvp = ap->a_dvp; 319227825Stheraven vpp = ap->a_vpp; 320234976Stheraven *vpp = NULL; 321234976Stheraven 322234976Stheraven cnp = ap->a_cnp; 323234976Stheraven cred = cnp->cn_cred; 324234976Stheraven td = cnp->cn_thread; 325234976Stheraven 326234976Stheraven dir_node = VTON(dvp); 327234976Stheraven nmp = dir_node->nn_nmp; 328234976Stheraven 329227825Stheraven /* Simplify/clarification flags */ 330234976Stheraven nameiop = cnp->cn_nameiop; 331234976Stheraven islastcn = cnp->cn_flags & ISLASTCN; 332234976Stheraven mounted_ro = dvp->v_mount->mnt_flag & MNT_RDONLY; 333227825Stheraven 334234976Stheraven /* 335234976Stheraven * If requesting a modify on the last path element on a read-only 336234976Stheraven * filingsystem, reject lookup; 337227825Stheraven */ 338227825Stheraven if (islastcn && mounted_ro && (nameiop == DELETE || nameiop == RENAME)) 339227825Stheraven return (EROFS); 340227825Stheraven 341227825Stheraven if (dir_node->nn_inode.i_links_count == 0) 342227825Stheraven return (ENOENT); 343227825Stheraven 344227825Stheraven /* 345234976Stheraven * Obviously, the file is not (anymore) in the namecache, we have to 346227825Stheraven * search for it. There are three basic cases: '.', '..' and others. 347234976Stheraven * 348234976Stheraven * Following the guidelines of VOP_LOOKUP manpage and tmpfs. 349234976Stheraven */ 350234976Stheraven error = 0; 351234976Stheraven if ((cnp->cn_namelen == 1) && (cnp->cn_nameptr[0] == '.')) { 352234976Stheraven DPRINTF(LOOKUP, ("\tlookup '.'\n")); 353234976Stheraven /* Special case 1 '.' */ 354227825Stheraven VREF(dvp); 355234976Stheraven *vpp = dvp; 356234976Stheraven /* Done */ 357234976Stheraven } else if (cnp->cn_flags & ISDOTDOT) { 358234976Stheraven /* Special case 2 '..' */ 359234976Stheraven DPRINTF(LOOKUP, ("\tlookup '..'\n")); 360227825Stheraven 361234976Stheraven /* Get our node */ 362234976Stheraven name = ".."; 363234976Stheraven namelen = 2; 364234976Stheraven error = nandfs_lookup_name_in_dir(dvp, name, namelen, &ino, 365227825Stheraven &found, &off); 366234976Stheraven if (error) 367234976Stheraven goto out; 368234976Stheraven if (!found) 369234976Stheraven error = ENOENT; 370234976Stheraven 371234976Stheraven /* First unlock parent */ 372234976Stheraven VOP_UNLOCK(dvp, 0); 373234976Stheraven 374234976Stheraven if (error == 0) { 375227825Stheraven DPRINTF(LOOKUP, ("\tfound '..'\n")); 376234976Stheraven /* Try to create/reuse the node */ 377234976Stheraven error = nandfs_get_node(nmp, ino, &node); 378234976Stheraven 379227825Stheraven if (!error) { 380234976Stheraven DPRINTF(LOOKUP, 381234976Stheraven ("\tnode retrieved/created OK\n")); 382234976Stheraven *vpp = NTOV(node); 383227825Stheraven } 384227825Stheraven } 385227825Stheraven 386227825Stheraven /* Try to relock parent */ 387227825Stheraven vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 388227825Stheraven } else { 389227825Stheraven DPRINTF(LOOKUP, ("\tlookup file\n")); 390227825Stheraven /* All other files */ 391234976Stheraven /* Look up filename in the directory returning its inode */ 392227825Stheraven name = cnp->cn_nameptr; 393234976Stheraven namelen = cnp->cn_namelen; 394234976Stheraven error = nandfs_lookup_name_in_dir(dvp, name, namelen, 395234976Stheraven &ino, &found, &off); 396234976Stheraven if (error) 397234976Stheraven goto out; 398234976Stheraven if (!found) { 399234976Stheraven DPRINTF(LOOKUP, ("\tNOT found\n")); 400227825Stheraven /* 401234976Stheraven * UGH, didn't find name. If we're creating or 402234976Stheraven * renaming on the last name this is OK and we ought 403234976Stheraven * to return EJUSTRETURN if its allowed to be created. 404234976Stheraven */ 405234976Stheraven error = ENOENT; 406227825Stheraven if ((nameiop == CREATE || nameiop == RENAME) && 407234976Stheraven islastcn) { 408234976Stheraven error = VOP_ACCESS(dvp, VWRITE, cred, 409234976Stheraven td); 410234976Stheraven if (!error) { 411227825Stheraven /* keep the component name */ 412234976Stheraven cnp->cn_flags |= SAVENAME; 413234976Stheraven error = EJUSTRETURN; 414234976Stheraven } 415234976Stheraven } 416234976Stheraven /* Done */ 417234976Stheraven } else { 418234976Stheraven if (ino == NANDFS_WHT_INO) 419234976Stheraven cnp->cn_flags |= ISWHITEOUT; 420234976Stheraven 421227825Stheraven if ((cnp->cn_flags & ISWHITEOUT) && 422227825Stheraven (nameiop == LOOKUP)) 423234976Stheraven return (ENOENT); 424227825Stheraven 425234976Stheraven if ((nameiop == DELETE) && islastcn) { 426227825Stheraven if ((cnp->cn_flags & ISWHITEOUT) && 427234976Stheraven (cnp->cn_flags & DOWHITEOUT)) { 428234976Stheraven cnp->cn_flags |= SAVENAME; 429227825Stheraven dir_node->nn_diroff = off; 430234976Stheraven return (EJUSTRETURN); 431234976Stheraven } 432234976Stheraven 433227825Stheraven error = VOP_ACCESS(dvp, VWRITE, cred, 434227825Stheraven cnp->cn_thread); 435227825Stheraven if (error) 436249998Sdim return (error); 437227825Stheraven 438227825Stheraven /* Try to create/reuse the node */ 439227825Stheraven error = nandfs_get_node(nmp, ino, &node); 440227825Stheraven if (!error) { 441227825Stheraven *vpp = NTOV(node); 442234976Stheraven node->nn_diroff = off; 443234976Stheraven } 444234976Stheraven 445234976Stheraven if ((dir_node->nn_inode.i_mode & ISVTX) && 446227825Stheraven cred->cr_uid != 0 && 447234976Stheraven cred->cr_uid != dir_node->nn_inode.i_uid && 448234976Stheraven node->nn_inode.i_uid != cred->cr_uid) { 449234976Stheraven vput(*vpp); 450234976Stheraven *vpp = NULL; 451234976Stheraven return (EPERM); 452234976Stheraven } 453234976Stheraven } else if ((nameiop == RENAME) && islastcn) { 454234976Stheraven error = VOP_ACCESS(dvp, VWRITE, cred, 455234976Stheraven cnp->cn_thread); 456227825Stheraven if (error) 457234976Stheraven return (error); 458234976Stheraven 459234976Stheraven /* Try to create/reuse the node */ 460234976Stheraven error = nandfs_get_node(nmp, ino, &node); 461227825Stheraven if (!error) { 462234976Stheraven *vpp = NTOV(node); 463234976Stheraven node->nn_diroff = off; 464234976Stheraven } 465234976Stheraven } else { 466234976Stheraven /* Try to create/reuse the node */ 467234976Stheraven error = nandfs_get_node(nmp, ino, &node); 468234976Stheraven if (!error) { 469234976Stheraven *vpp = NTOV(node); 470234976Stheraven node->nn_diroff = off; 471227825Stheraven } 472234976Stheraven } 473234976Stheraven } 474234976Stheraven } 475227825Stheraven 476234976Stheravenout: 477234976Stheraven /* 478234976Stheraven * Store result in the cache if requested. If we are creating a file, 479227825Stheraven * the file might not be found and thus putting it into the namecache 480227825Stheraven * might be seen as negative caching. 481227825Stheraven */ 482246487Stheraven if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) 483246487Stheraven cache_enter(dvp, *vpp, cnp); 484246487Stheraven 485246487Stheraven return (error); 486246487Stheraven 487246487Stheraven} 488246487Stheraven 489246487Stheravenstatic int 490246487Stheravennandfs_getattr(struct vop_getattr_args *ap) 491246487Stheraven{ 492246487Stheraven struct vnode *vp = ap->a_vp; 493246487Stheraven struct vattr *vap = ap->a_vap; 494246487Stheraven struct nandfs_node *node = VTON(vp); 495246487Stheraven struct nandfs_inode *inode = &node->nn_inode; 496246487Stheraven 497246487Stheraven DPRINTF(VNCALL, ("%s: vp: %p\n", __func__, vp)); 498246487Stheraven nandfs_itimes(vp); 499246487Stheraven 500246487Stheraven /* Basic info */ 501246487Stheraven VATTR_NULL(vap); 502246487Stheraven vap->va_atime.tv_sec = inode->i_mtime; 503246487Stheraven vap->va_atime.tv_nsec = inode->i_mtime_nsec; 504246487Stheraven vap->va_mtime.tv_sec = inode->i_mtime; 505246487Stheraven vap->va_mtime.tv_nsec = inode->i_mtime_nsec; 506246487Stheraven vap->va_ctime.tv_sec = inode->i_ctime; 507246487Stheraven vap->va_ctime.tv_nsec = inode->i_ctime_nsec; 508246487Stheraven vap->va_type = IFTOVT(inode->i_mode); 509246487Stheraven vap->va_mode = inode->i_mode & ~S_IFMT; 510246487Stheraven vap->va_nlink = inode->i_links_count; 511246487Stheraven vap->va_uid = inode->i_uid; 512246487Stheraven vap->va_gid = inode->i_gid; 513246487Stheraven vap->va_rdev = inode->i_special; 514246487Stheraven vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 515246487Stheraven vap->va_fileid = node->nn_ino; 516246487Stheraven vap->va_size = inode->i_size; 517246487Stheraven vap->va_blocksize = node->nn_nandfsdev->nd_blocksize; 518246487Stheraven vap->va_gen = 0; 519246487Stheraven vap->va_flags = inode->i_flags; 520246487Stheraven vap->va_bytes = inode->i_blocks * vap->va_blocksize; 521246487Stheraven vap->va_filerev = 0; 522246487Stheraven vap->va_vaflags = 0; 523246487Stheraven 524246487Stheraven return (0); 525246487Stheraven} 526246487Stheraven 527246487Stheravenstatic int 528246487Stheravennandfs_vtruncbuf(struct vnode *vp, uint64_t nblks) 529249998Sdim{ 530227825Stheraven struct nandfs_device *nffsdev; 531227825Stheraven struct bufobj *bo; 532227825Stheraven struct buf *bp, *nbp; 533227825Stheraven 534227825Stheraven bo = &vp->v_bufobj; 535234976Stheraven nffsdev = VTON(vp)->nn_nandfsdev; 536234976Stheraven 537234976Stheraven ASSERT_VOP_LOCKED(vp, "nandfs_truncate"); 538234976Stheravenrestart: 539227825Stheraven BO_LOCK(bo); 540234976Stheravenrestart_locked: 541234976Stheraven TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, nbp) { 542234976Stheraven if (bp->b_lblkno < nblks) 543234976Stheraven continue; 544234976Stheraven if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) 545234976Stheraven goto restart_locked; 546234976Stheraven 547234976Stheraven bremfree(bp); 548234976Stheraven bp->b_flags |= (B_INVAL | B_RELBUF); 549227825Stheraven bp->b_flags &= ~(B_ASYNC | B_MANAGED); 550234976Stheraven BO_UNLOCK(bo); 551234976Stheraven brelse(bp); 552234976Stheraven BO_LOCK(bo); 553234976Stheraven } 554227825Stheraven 555234976Stheraven TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { 556234976Stheraven if (bp->b_lblkno < nblks) 557234976Stheraven continue; 558234976Stheraven if (BUF_LOCK(bp, 559234976Stheraven LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, 560234976Stheraven BO_LOCKPTR(bo)) == ENOLCK) 561234976Stheraven goto restart; 562234976Stheraven bp->b_flags |= (B_INVAL | B_RELBUF); 563234976Stheraven bp->b_flags &= ~(B_ASYNC | B_MANAGED); 564227825Stheraven brelse(bp); 565234976Stheraven nandfs_dirty_bufs_decrement(nffsdev); 566234976Stheraven BO_LOCK(bo); 567234976Stheraven } 568227825Stheraven 569234976Stheraven BO_UNLOCK(bo); 570234976Stheraven 571234976Stheraven return (0); 572227825Stheraven} 573227825Stheraven 574227825Stheravenstatic int 575246487Stheravennandfs_truncate(struct vnode *vp, uint64_t newsize) 576246487Stheraven{ 577246487Stheraven struct nandfs_device *nffsdev; 578246487Stheraven struct nandfs_node *node; 579246487Stheraven struct nandfs_inode *inode; 580246487Stheraven struct buf *bp = NULL; 581246487Stheraven uint64_t oblks, nblks, vblk, size, rest; 582246487Stheraven int error; 583246487Stheraven 584246487Stheraven node = VTON(vp); 585246487Stheraven nffsdev = node->nn_nandfsdev; 586246487Stheraven inode = &node->nn_inode; 587246487Stheraven 588246487Stheraven /* Calculate end of file */ 589246487Stheraven size = inode->i_size; 590246487Stheraven 591246487Stheraven if (newsize == size) { 592246487Stheraven node->nn_flags |= IN_CHANGE | IN_UPDATE; 593246487Stheraven nandfs_itimes(vp); 594246487Stheraven return (0); 595246487Stheraven } 596246487Stheraven 597246487Stheraven if (newsize > size) { 598246487Stheraven inode->i_size = newsize; 599246487Stheraven vnode_pager_setsize(vp, newsize); 600246487Stheraven node->nn_flags |= IN_CHANGE | IN_UPDATE; 601246487Stheraven nandfs_itimes(vp); 602246487Stheraven return (0); 603246487Stheraven } 604246487Stheraven 605246487Stheraven nblks = howmany(newsize, nffsdev->nd_blocksize); 606246487Stheraven oblks = howmany(size, nffsdev->nd_blocksize); 607246487Stheraven rest = newsize % nffsdev->nd_blocksize; 608246487Stheraven 609246487Stheraven if (rest) { 610246487Stheraven error = nandfs_bmap_lookup(node, nblks - 1, &vblk); 611246487Stheraven if (error) 612246487Stheraven return (error); 613246487Stheraven 614246487Stheraven if (vblk != 0) 615246487Stheraven error = nandfs_bread(node, nblks - 1, NOCRED, 0, &bp); 616246487Stheraven else 617246487Stheraven error = nandfs_bcreate(node, nblks - 1, NOCRED, 0, &bp); 618246487Stheraven 619246487Stheraven if (error) { 620246487Stheraven if (bp) 621246487Stheraven brelse(bp); 622249998Sdim return (error); 623227825Stheraven } 624227825Stheraven 625227825Stheraven bzero((char *)bp->b_data + rest, 626227825Stheraven (u_int)(nffsdev->nd_blocksize - rest)); 627227825Stheraven error = nandfs_dirty_buf(bp, 0); 628234976Stheraven if (error) 629234976Stheraven return (error); 630234976Stheraven } 631234976Stheraven 632227825Stheraven DPRINTF(VNCALL, ("%s: vp %p oblks %jx nblks %jx\n", __func__, vp, oblks, 633234976Stheraven nblks)); 634234976Stheraven 635234976Stheraven error = nandfs_bmap_truncate_mapping(node, oblks - 1, nblks - 1); 636234976Stheraven if (error) { 637234976Stheraven if (bp) 638234976Stheraven nandfs_undirty_buf(bp); 639234976Stheraven return (error); 640234976Stheraven } 641234976Stheraven 642227825Stheraven error = nandfs_vtruncbuf(vp, nblks); 643234976Stheraven if (error) { 644234976Stheraven if (bp) 645234976Stheraven nandfs_undirty_buf(bp); 646234976Stheraven return (error); 647227825Stheraven } 648234976Stheraven 649234976Stheraven inode->i_size = newsize; 650234976Stheraven vnode_pager_setsize(vp, newsize); 651234976Stheraven node->nn_flags |= IN_CHANGE | IN_UPDATE; 652234976Stheraven nandfs_itimes(vp); 653234976Stheraven 654234976Stheraven return (error); 655234976Stheraven} 656234976Stheraven 657227825Stheravenstatic void 658234976Stheravennandfs_itimes_locked(struct vnode *vp) 659234976Stheraven{ 660234976Stheraven struct nandfs_node *node; 661227825Stheraven struct nandfs_inode *inode; 662234976Stheraven struct timespec ts; 663234976Stheraven 664234976Stheraven ASSERT_VI_LOCKED(vp, __func__); 665227825Stheraven 666227825Stheraven node = VTON(vp); 667227825Stheraven inode = &node->nn_inode; 668246487Stheraven 669246487Stheraven if ((node->nn_flags & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0) 670246487Stheraven return; 671246487Stheraven 672246487Stheraven if (((vp->v_mount->mnt_kern_flag & 673246487Stheraven (MNTK_SUSPENDED | MNTK_SUSPEND)) == 0) || 674246487Stheraven (node->nn_flags & (IN_CHANGE | IN_UPDATE))) 675246487Stheraven node->nn_flags |= IN_MODIFIED; 676246487Stheraven 677246487Stheraven vfs_timestamp(&ts); 678246487Stheraven if (node->nn_flags & IN_UPDATE) { 679246487Stheraven inode->i_mtime = ts.tv_sec; 680246487Stheraven inode->i_mtime_nsec = ts.tv_nsec; 681246487Stheraven } 682246487Stheraven if (node->nn_flags & IN_CHANGE) { 683246487Stheraven inode->i_ctime = ts.tv_sec; 684246487Stheraven inode->i_ctime_nsec = ts.tv_nsec; 685246487Stheraven } 686246487Stheraven 687246487Stheraven node->nn_flags &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE); 688246487Stheraven} 689246487Stheraven 690246487Stheravenvoid 691246487Stheravennandfs_itimes(struct vnode *vp) 692246487Stheraven{ 693246487Stheraven 694246487Stheraven VI_LOCK(vp); 695246487Stheraven nandfs_itimes_locked(vp); 696246487Stheraven VI_UNLOCK(vp); 697246487Stheraven} 698246487Stheraven 699246487Stheravenstatic int 700246487Stheravennandfs_chmod(struct vnode *vp, int mode, struct ucred *cred, struct thread *td) 701246487Stheraven{ 702246487Stheraven struct nandfs_node *node = VTON(vp); 703246487Stheraven struct nandfs_inode *inode = &node->nn_inode; 704246487Stheraven uint16_t nmode; 705246487Stheraven int error = 0; 706246487Stheraven 707246487Stheraven DPRINTF(VNCALL, ("%s: vp %p, mode %x, cred %p, td %p\n", __func__, vp, 708246487Stheraven mode, cred, td)); 709246487Stheraven /* 710246487Stheraven * To modify the permissions on a file, must possess VADMIN 711246487Stheraven * for that file. 712246487Stheraven */ 713246487Stheraven if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) 714246487Stheraven return (error); 715249998Sdim 716227825Stheraven /* 717227825Stheraven * Privileged processes may set the sticky bit on non-directories, 718227825Stheraven * as well as set the setgid bit on a file with a group that the 719227825Stheraven * process is not a member of. Both of these are allowed in 720227825Stheraven * jail(8). 721234976Stheraven */ 722234976Stheraven if (vp->v_type != VDIR && (mode & S_ISTXT)) { 723234976Stheraven if (priv_check_cred(cred, PRIV_VFS_STICKYFILE, 0)) 724234976Stheraven return (EFTYPE); 725227825Stheraven } 726234976Stheraven if (!groupmember(inode->i_gid, cred) && (mode & ISGID)) { 727234976Stheraven error = priv_check_cred(cred, PRIV_VFS_SETGID, 0); 728234976Stheraven if (error) 729234976Stheraven return (error); 730234976Stheraven } 731234976Stheraven 732234976Stheraven /* 733234976Stheraven * Deny setting setuid if we are not the file owner. 734234976Stheraven */ 735227825Stheraven if ((mode & ISUID) && inode->i_uid != cred->cr_uid) { 736234976Stheraven error = priv_check_cred(cred, PRIV_VFS_ADMIN, 0); 737234976Stheraven if (error) 738234976Stheraven return (error); 739234976Stheraven } 740227825Stheraven 741234976Stheraven nmode = inode->i_mode; 742234976Stheraven nmode &= ~ALLPERMS; 743234976Stheraven nmode |= (mode & ALLPERMS); 744234976Stheraven inode->i_mode = nmode; 745234976Stheraven node->nn_flags |= IN_CHANGE; 746234976Stheraven 747234976Stheraven DPRINTF(VNCALL, ("%s: to mode %x\n", __func__, nmode)); 748234976Stheraven 749234976Stheraven return (error); 750227825Stheraven} 751234976Stheraven 752234976Stheravenstatic int 753234976Stheravennandfs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred, 754227825Stheraven struct thread *td) 755234976Stheraven{ 756234976Stheraven struct nandfs_node *node = VTON(vp); 757234976Stheraven struct nandfs_inode *inode = &node->nn_inode; 758227825Stheraven uid_t ouid; 759227825Stheraven gid_t ogid; 760246487Stheraven int error = 0; 761246487Stheraven 762246487Stheraven if (uid == (uid_t)VNOVAL) 763246487Stheraven uid = inode->i_uid; 764246487Stheraven if (gid == (gid_t)VNOVAL) 765246487Stheraven gid = inode->i_gid; 766246487Stheraven /* 767246487Stheraven * To modify the ownership of a file, must possess VADMIN for that 768246487Stheraven * file. 769246487Stheraven */ 770246487Stheraven if ((error = VOP_ACCESSX(vp, VWRITE_OWNER, cred, td))) 771246487Stheraven return (error); 772246487Stheraven /* 773246487Stheraven * To change the owner of a file, or change the group of a file to a 774246487Stheraven * group of which we are not a member, the caller must have 775246487Stheraven * privilege. 776246487Stheraven */ 777246487Stheraven if (((uid != inode->i_uid && uid != cred->cr_uid) || 778246487Stheraven (gid != inode->i_gid && !groupmember(gid, cred))) && 779246487Stheraven (error = priv_check_cred(cred, PRIV_VFS_CHOWN, 0))) 780246487Stheraven return (error); 781246487Stheraven ogid = inode->i_gid; 782246487Stheraven ouid = inode->i_uid; 783246487Stheraven 784246487Stheraven inode->i_gid = gid; 785246487Stheraven inode->i_uid = uid; 786246487Stheraven 787246487Stheraven node->nn_flags |= IN_CHANGE; 788246487Stheraven if ((inode->i_mode & (ISUID | ISGID)) && 789246487Stheraven (ouid != uid || ogid != gid)) { 790246487Stheraven if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)) { 791246487Stheraven inode->i_mode &= ~(ISUID | ISGID); 792246487Stheraven } 793246487Stheraven } 794246487Stheraven DPRINTF(VNCALL, ("%s: vp %p, cred %p, td %p - ret OK\n", __func__, vp, 795246487Stheraven cred, td)); 796246487Stheraven return (0); 797246487Stheraven} 798246487Stheraven 799246487Stheravenstatic int 800246487Stheravennandfs_setattr(struct vop_setattr_args *ap) 801246487Stheraven{ 802246487Stheraven struct vnode *vp = ap->a_vp; 803246487Stheraven struct nandfs_node *node = VTON(vp); 804246487Stheraven struct nandfs_inode *inode = &node->nn_inode; 805246487Stheraven struct vattr *vap = ap->a_vap; 806246487Stheraven struct ucred *cred = ap->a_cred; 807227825Stheraven struct thread *td = curthread; 808227825Stheraven uint32_t flags; 809227825Stheraven int error = 0; 810 811 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 812 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 813 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 814 (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { 815 DPRINTF(VNCALL, ("%s: unsettable attribute\n", __func__)); 816 return (EINVAL); 817 } 818 819 if (vap->va_flags != VNOVAL) { 820 DPRINTF(VNCALL, ("%s: vp:%p td:%p flags:%lx\n", __func__, vp, 821 td, vap->va_flags)); 822 823 if (vp->v_mount->mnt_flag & MNT_RDONLY) 824 return (EROFS); 825 /* 826 * Callers may only modify the file flags on objects they 827 * have VADMIN rights for. 828 */ 829 if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) 830 return (error); 831 /* 832 * Unprivileged processes are not permitted to unset system 833 * flags, or modify flags if any system flags are set. 834 * Privileged non-jail processes may not modify system flags 835 * if securelevel > 0 and any existing system flags are set. 836 * Privileged jail processes behave like privileged non-jail 837 * processes if the security.jail.chflags_allowed sysctl is 838 * is non-zero; otherwise, they behave like unprivileged 839 * processes. 840 */ 841 842 flags = inode->i_flags; 843 if (!priv_check_cred(cred, PRIV_VFS_SYSFLAGS, 0)) { 844 if (flags & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) { 845 error = securelevel_gt(cred, 0); 846 if (error) 847 return (error); 848 } 849 /* Snapshot flag cannot be set or cleared */ 850 if (((vap->va_flags & SF_SNAPSHOT) != 0 && 851 (flags & SF_SNAPSHOT) == 0) || 852 ((vap->va_flags & SF_SNAPSHOT) == 0 && 853 (flags & SF_SNAPSHOT) != 0)) 854 return (EPERM); 855 856 inode->i_flags = vap->va_flags; 857 } else { 858 if (flags & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND) || 859 (vap->va_flags & UF_SETTABLE) != vap->va_flags) 860 return (EPERM); 861 862 flags &= SF_SETTABLE; 863 flags |= (vap->va_flags & UF_SETTABLE); 864 inode->i_flags = flags; 865 } 866 node->nn_flags |= IN_CHANGE; 867 if (vap->va_flags & (IMMUTABLE | APPEND)) 868 return (0); 869 } 870 if (inode->i_flags & (IMMUTABLE | APPEND)) 871 return (EPERM); 872 873 if (vap->va_size != (u_quad_t)VNOVAL) { 874 DPRINTF(VNCALL, ("%s: vp:%p td:%p size:%jx\n", __func__, vp, td, 875 (uintmax_t)vap->va_size)); 876 877 switch (vp->v_type) { 878 case VDIR: 879 return (EISDIR); 880 case VLNK: 881 case VREG: 882 if (vp->v_mount->mnt_flag & MNT_RDONLY) 883 return (EROFS); 884 if ((inode->i_flags & SF_SNAPSHOT) != 0) 885 return (EPERM); 886 break; 887 default: 888 return (0); 889 } 890 891 if (vap->va_size > node->nn_nandfsdev->nd_maxfilesize) 892 return (EFBIG); 893 894 KASSERT((vp->v_type == VREG), ("Set size %d", vp->v_type)); 895 nandfs_truncate(vp, vap->va_size); 896 node->nn_flags |= IN_CHANGE; 897 898 return (0); 899 } 900 901 if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { 902 if (vp->v_mount->mnt_flag & MNT_RDONLY) 903 return (EROFS); 904 DPRINTF(VNCALL, ("%s: vp:%p td:%p uid/gid %x/%x\n", __func__, 905 vp, td, vap->va_uid, vap->va_gid)); 906 error = nandfs_chown(vp, vap->va_uid, vap->va_gid, cred, td); 907 if (error) 908 return (error); 909 } 910 911 if (vap->va_mode != (mode_t)VNOVAL) { 912 if (vp->v_mount->mnt_flag & MNT_RDONLY) 913 return (EROFS); 914 DPRINTF(VNCALL, ("%s: vp:%p td:%p mode %x\n", __func__, vp, td, 915 vap->va_mode)); 916 917 error = nandfs_chmod(vp, (int)vap->va_mode, cred, td); 918 if (error) 919 return (error); 920 } 921 if (vap->va_atime.tv_sec != VNOVAL || 922 vap->va_mtime.tv_sec != VNOVAL || 923 vap->va_birthtime.tv_sec != VNOVAL) { 924 DPRINTF(VNCALL, ("%s: vp:%p td:%p time a/m/b %jx/%jx/%jx\n", 925 __func__, vp, td, (uintmax_t)vap->va_atime.tv_sec, 926 (uintmax_t)vap->va_mtime.tv_sec, 927 (uintmax_t)vap->va_birthtime.tv_sec)); 928 929 if (vap->va_atime.tv_sec != VNOVAL) 930 node->nn_flags |= IN_ACCESS; 931 if (vap->va_mtime.tv_sec != VNOVAL) 932 node->nn_flags |= IN_CHANGE | IN_UPDATE; 933 if (vap->va_birthtime.tv_sec != VNOVAL) 934 node->nn_flags |= IN_MODIFIED; 935 nandfs_itimes(vp); 936 return (0); 937 } 938 939 return (0); 940} 941 942static int 943nandfs_open(struct vop_open_args *ap) 944{ 945 struct nandfs_node *node = VTON(ap->a_vp); 946 uint64_t filesize; 947 948 DPRINTF(VNCALL, ("nandfs_open called ap->a_mode %x\n", ap->a_mode)); 949 950 if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) 951 return (EOPNOTSUPP); 952 953 if ((node->nn_inode.i_flags & APPEND) && 954 (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) 955 return (EPERM); 956 957 filesize = node->nn_inode.i_size; 958 vnode_create_vobject(ap->a_vp, filesize, ap->a_td); 959 960 return (0); 961} 962 963static int 964nandfs_close(struct vop_close_args *ap) 965{ 966 struct vnode *vp = ap->a_vp; 967 struct nandfs_node *node = VTON(vp); 968 969 DPRINTF(VNCALL, ("%s: vp %p node %p\n", __func__, vp, node)); 970 971 mtx_lock(&vp->v_interlock); 972 if (vp->v_usecount > 1) 973 nandfs_itimes_locked(vp); 974 mtx_unlock(&vp->v_interlock); 975 976 return (0); 977} 978 979static int 980nandfs_check_possible(struct vnode *vp, struct vattr *vap, mode_t mode) 981{ 982 983 /* Check if we are allowed to write */ 984 switch (vap->va_type) { 985 case VDIR: 986 case VLNK: 987 case VREG: 988 /* 989 * Normal nodes: check if we're on a read-only mounted 990 * filingsystem and bomb out if we're trying to write. 991 */ 992 if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) 993 return (EROFS); 994 break; 995 case VBLK: 996 case VCHR: 997 case VSOCK: 998 case VFIFO: 999 /* 1000 * Special nodes: even on read-only mounted filingsystems 1001 * these are allowed to be written to if permissions allow. 1002 */ 1003 break; 1004 default: 1005 /* No idea what this is */ 1006 return (EINVAL); 1007 } 1008 1009 /* Noone may write immutable files */ 1010 if ((mode & VWRITE) && (VTON(vp)->nn_inode.i_flags & IMMUTABLE)) 1011 return (EPERM); 1012 1013 return (0); 1014} 1015 1016static int 1017nandfs_check_permitted(struct vnode *vp, struct vattr *vap, mode_t mode, 1018 struct ucred *cred) 1019{ 1020 1021 return (vaccess(vp->v_type, vap->va_mode, vap->va_uid, vap->va_gid, mode, 1022 cred, NULL)); 1023} 1024 1025static int 1026nandfs_advlock(struct vop_advlock_args *ap) 1027{ 1028 struct nandfs_node *nvp; 1029 quad_t size; 1030 1031 nvp = VTON(ap->a_vp); 1032 size = nvp->nn_inode.i_size; 1033 return (lf_advlock(ap, &(nvp->nn_lockf), size)); 1034} 1035 1036static int 1037nandfs_access(struct vop_access_args *ap) 1038{ 1039 struct vnode *vp = ap->a_vp; 1040 accmode_t accmode = ap->a_accmode; 1041 struct ucred *cred = ap->a_cred; 1042 struct vattr vap; 1043 int error; 1044 1045 DPRINTF(VNCALL, ("%s: vp:%p mode: %x\n", __func__, vp, accmode)); 1046 1047 error = VOP_GETATTR(vp, &vap, NULL); 1048 if (error) 1049 return (error); 1050 1051 error = nandfs_check_possible(vp, &vap, accmode); 1052 if (error) { 1053 return (error); 1054 } 1055 1056 error = nandfs_check_permitted(vp, &vap, accmode, cred); 1057 1058 return (error); 1059} 1060 1061static int 1062nandfs_print(struct vop_print_args *ap) 1063{ 1064 struct vnode *vp = ap->a_vp; 1065 struct nandfs_node *nvp = VTON(vp); 1066 1067 printf("\tvp=%p, nandfs_node=%p\n", vp, nvp); 1068 printf("nandfs inode %#jx\n", (uintmax_t)nvp->nn_ino); 1069 printf("flags = 0x%b\n", (u_int)nvp->nn_flags, PRINT_NODE_FLAGS); 1070 1071 return (0); 1072} 1073 1074static void 1075nandfs_read_filebuf(struct nandfs_node *node, struct buf *bp) 1076{ 1077 struct nandfs_device *nandfsdev = node->nn_nandfsdev; 1078 struct buf *nbp; 1079 nandfs_daddr_t vblk, pblk; 1080 nandfs_lbn_t from; 1081 uint32_t blocksize; 1082 int error = 0; 1083 int blk2dev = nandfsdev->nd_blocksize / DEV_BSIZE; 1084 1085 /* 1086 * Translate all the block sectors into a series of buffers to read 1087 * asynchronously from the nandfs device. Note that this lookup may 1088 * induce readin's too. 1089 */ 1090 1091 blocksize = nandfsdev->nd_blocksize; 1092 if (bp->b_bcount / blocksize != 1) 1093 panic("invalid b_count in bp %p\n", bp); 1094 1095 from = bp->b_blkno; 1096 1097 DPRINTF(READ, ("\tread in from inode %#jx blkno %#jx" 1098 " count %#lx\n", (uintmax_t)node->nn_ino, from, 1099 bp->b_bcount)); 1100 1101 /* Get virtual block numbers for the vnode's buffer span */ 1102 error = nandfs_bmap_lookup(node, from, &vblk); 1103 if (error) { 1104 bp->b_error = EINVAL; 1105 bp->b_ioflags |= BIO_ERROR; 1106 bufdone(bp); 1107 return; 1108 } 1109 1110 /* Translate virtual block numbers to physical block numbers */ 1111 error = nandfs_vtop(node, vblk, &pblk); 1112 if (error) { 1113 bp->b_error = EINVAL; 1114 bp->b_ioflags |= BIO_ERROR; 1115 bufdone(bp); 1116 return; 1117 } 1118 1119 /* Issue translated blocks */ 1120 bp->b_resid = bp->b_bcount; 1121 1122 /* Note virtual block 0 marks not mapped */ 1123 if (vblk == 0) { 1124 vfs_bio_clrbuf(bp); 1125 bufdone(bp); 1126 return; 1127 } 1128 1129 nbp = bp; 1130 nbp->b_blkno = pblk * blk2dev; 1131 bp->b_iooffset = dbtob(nbp->b_blkno); 1132 MPASS(bp->b_iooffset >= 0); 1133 BO_STRATEGY(&nandfsdev->nd_devvp->v_bufobj, nbp); 1134 nandfs_vblk_set(bp, vblk); 1135 DPRINTF(READ, ("read_filebuf : ino %#jx blk %#jx -> " 1136 "%#jx -> %#jx [bp %p]\n", (uintmax_t)node->nn_ino, 1137 (uintmax_t)(from), (uintmax_t)vblk, 1138 (uintmax_t)pblk, nbp)); 1139} 1140 1141static void 1142nandfs_write_filebuf(struct nandfs_node *node, struct buf *bp) 1143{ 1144 struct nandfs_device *nandfsdev = node->nn_nandfsdev; 1145 1146 bp->b_iooffset = dbtob(bp->b_blkno); 1147 MPASS(bp->b_iooffset >= 0); 1148 BO_STRATEGY(&nandfsdev->nd_devvp->v_bufobj, bp); 1149} 1150 1151static int 1152nandfs_strategy(struct vop_strategy_args *ap) 1153{ 1154 struct vnode *vp = ap->a_vp; 1155 struct buf *bp = ap->a_bp; 1156 struct nandfs_node *node = VTON(vp); 1157 1158 1159 /* check if we ought to be here */ 1160 KASSERT((vp->v_type != VBLK && vp->v_type != VCHR), 1161 ("nandfs_strategy on type %d", vp->v_type)); 1162 1163 /* Translate if needed and pass on */ 1164 if (bp->b_iocmd == BIO_READ) { 1165 nandfs_read_filebuf(node, bp); 1166 return (0); 1167 } 1168 1169 /* Send to segment collector */ 1170 nandfs_write_filebuf(node, bp); 1171 return (0); 1172} 1173 1174static int 1175nandfs_readdir(struct vop_readdir_args *ap) 1176{ 1177 struct uio *uio = ap->a_uio; 1178 struct vnode *vp = ap->a_vp; 1179 struct nandfs_node *node = VTON(vp); 1180 struct nandfs_dir_entry *ndirent; 1181 struct dirent dirent; 1182 struct buf *bp; 1183 uint64_t file_size, diroffset, transoffset, blkoff; 1184 uint64_t blocknr; 1185 uint32_t blocksize = node->nn_nandfsdev->nd_blocksize; 1186 uint8_t *pos, name_len; 1187 int error; 1188 1189 DPRINTF(READDIR, ("nandfs_readdir called\n")); 1190 1191 if (vp->v_type != VDIR) 1192 return (ENOTDIR); 1193 1194 file_size = node->nn_inode.i_size; 1195 DPRINTF(READDIR, ("nandfs_readdir filesize %jd resid %zd\n", 1196 (uintmax_t)file_size, uio->uio_resid )); 1197 1198 /* We are called just as long as we keep on pushing data in */ 1199 error = 0; 1200 if ((uio->uio_offset < file_size) && 1201 (uio->uio_resid >= sizeof(struct dirent))) { 1202 diroffset = uio->uio_offset; 1203 transoffset = diroffset; 1204 1205 blocknr = diroffset / blocksize; 1206 blkoff = diroffset % blocksize; 1207 error = nandfs_bread(node, blocknr, NOCRED, 0, &bp); 1208 if (error) { 1209 brelse(bp); 1210 return (EIO); 1211 } 1212 while (diroffset < file_size) { 1213 DPRINTF(READDIR, ("readdir : offset = %"PRIu64"\n", 1214 diroffset)); 1215 if (blkoff >= blocksize) { 1216 blkoff = 0; blocknr++; 1217 brelse(bp); 1218 error = nandfs_bread(node, blocknr, NOCRED, 0, 1219 &bp); 1220 if (error) { 1221 brelse(bp); 1222 return (EIO); 1223 } 1224 } 1225 1226 /* Read in one dirent */ 1227 pos = (uint8_t *)bp->b_data + blkoff; 1228 ndirent = (struct nandfs_dir_entry *)pos; 1229 1230 name_len = ndirent->name_len; 1231 memset(&dirent, 0, sizeof(struct dirent)); 1232 dirent.d_fileno = ndirent->inode; 1233 if (dirent.d_fileno) { 1234 dirent.d_type = ndirent->file_type; 1235 dirent.d_namlen = name_len; 1236 strncpy(dirent.d_name, ndirent->name, name_len); 1237 dirent.d_reclen = GENERIC_DIRSIZ(&dirent); 1238 DPRINTF(READDIR, ("copying `%*.*s`\n", name_len, 1239 name_len, dirent.d_name)); 1240 } 1241 1242 /* 1243 * If there isn't enough space in the uio to return a 1244 * whole dirent, break off read 1245 */ 1246 if (uio->uio_resid < GENERIC_DIRSIZ(&dirent)) 1247 break; 1248 1249 /* Transfer */ 1250 if (dirent.d_fileno) 1251 uiomove(&dirent, GENERIC_DIRSIZ(&dirent), uio); 1252 1253 /* Advance */ 1254 diroffset += ndirent->rec_len; 1255 blkoff += ndirent->rec_len; 1256 1257 /* Remember the last entry we transfered */ 1258 transoffset = diroffset; 1259 } 1260 brelse(bp); 1261 1262 /* Pass on last transfered offset */ 1263 uio->uio_offset = transoffset; 1264 } 1265 1266 if (ap->a_eofflag) 1267 *ap->a_eofflag = (uio->uio_offset >= file_size); 1268 1269 return (error); 1270} 1271 1272static int 1273nandfs_dirempty(struct vnode *dvp, uint64_t parentino, struct ucred *cred) 1274{ 1275 struct nandfs_node *dnode = VTON(dvp); 1276 struct nandfs_dir_entry *dirent; 1277 uint64_t file_size = dnode->nn_inode.i_size; 1278 uint64_t blockcount = dnode->nn_inode.i_blocks; 1279 uint64_t blocknr; 1280 uint32_t blocksize = dnode->nn_nandfsdev->nd_blocksize; 1281 uint32_t limit; 1282 uint32_t off; 1283 uint8_t *pos; 1284 struct buf *bp; 1285 int error; 1286 1287 DPRINTF(LOOKUP, ("%s: dvp %p parentino %#jx cred %p\n", __func__, dvp, 1288 (uintmax_t)parentino, cred)); 1289 1290 KASSERT((file_size != 0), ("nandfs_dirempty for NULL dir %p", dvp)); 1291 1292 blocknr = 0; 1293 while (blocknr < blockcount) { 1294 error = nandfs_bread(dnode, blocknr, NOCRED, 0, &bp); 1295 if (error) { 1296 brelse(bp); 1297 return (0); 1298 } 1299 1300 pos = (uint8_t *)bp->b_data; 1301 off = 0; 1302 1303 if (blocknr == (blockcount - 1)) 1304 limit = file_size % blocksize; 1305 else 1306 limit = blocksize; 1307 1308 while (off < limit) { 1309 dirent = (struct nandfs_dir_entry *)(pos + off); 1310 off += dirent->rec_len; 1311 1312 if (dirent->inode == 0) 1313 continue; 1314 1315 switch (dirent->name_len) { 1316 case 0: 1317 break; 1318 case 1: 1319 if (dirent->name[0] != '.') 1320 goto notempty; 1321 1322 KASSERT(dirent->inode == dnode->nn_ino, 1323 (".'s inode does not match dir")); 1324 break; 1325 case 2: 1326 if (dirent->name[0] != '.' && 1327 dirent->name[1] != '.') 1328 goto notempty; 1329 1330 KASSERT(dirent->inode == parentino, 1331 ("..'s inode does not match parent")); 1332 break; 1333 default: 1334 goto notempty; 1335 } 1336 } 1337 1338 brelse(bp); 1339 blocknr++; 1340 } 1341 1342 return (1); 1343notempty: 1344 brelse(bp); 1345 return (0); 1346} 1347 1348static int 1349nandfs_link(struct vop_link_args *ap) 1350{ 1351 struct vnode *tdvp = ap->a_tdvp; 1352 struct vnode *vp = ap->a_vp; 1353 struct componentname *cnp = ap->a_cnp; 1354 struct nandfs_node *node = VTON(vp); 1355 struct nandfs_inode *inode = &node->nn_inode; 1356 int error; 1357 1358 if (tdvp->v_mount != vp->v_mount) 1359 return (EXDEV); 1360 1361 if (inode->i_links_count >= LINK_MAX) 1362 return (EMLINK); 1363 1364 if (inode->i_flags & (IMMUTABLE | APPEND)) 1365 return (EPERM); 1366 1367 /* Update link count */ 1368 inode->i_links_count++; 1369 1370 /* Add dir entry */ 1371 error = nandfs_add_dirent(tdvp, node->nn_ino, cnp->cn_nameptr, 1372 cnp->cn_namelen, IFTODT(inode->i_mode)); 1373 if (error) { 1374 inode->i_links_count--; 1375 } 1376 1377 node->nn_flags |= IN_CHANGE; 1378 nandfs_itimes(vp); 1379 DPRINTF(VNCALL, ("%s: tdvp %p vp %p cnp %p\n", 1380 __func__, tdvp, vp, cnp)); 1381 1382 return (0); 1383} 1384 1385static int 1386nandfs_create(struct vop_create_args *ap) 1387{ 1388 struct vnode *dvp = ap->a_dvp; 1389 struct vnode **vpp = ap->a_vpp; 1390 struct componentname *cnp = ap->a_cnp; 1391 uint16_t mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); 1392 struct nandfs_node *dir_node = VTON(dvp); 1393 struct nandfsmount *nmp = dir_node->nn_nmp; 1394 struct nandfs_node *node; 1395 int error; 1396 1397 DPRINTF(VNCALL, ("%s: dvp %p\n", __func__, dvp)); 1398 1399 if (nandfs_fs_full(dir_node->nn_nandfsdev)) 1400 return (ENOSPC); 1401 1402 /* Create new vnode/inode */ 1403 error = nandfs_node_create(nmp, &node, mode); 1404 if (error) 1405 return (error); 1406 node->nn_inode.i_gid = dir_node->nn_inode.i_gid; 1407 node->nn_inode.i_uid = cnp->cn_cred->cr_uid; 1408 1409 /* Add new dir entry */ 1410 error = nandfs_add_dirent(dvp, node->nn_ino, cnp->cn_nameptr, 1411 cnp->cn_namelen, IFTODT(mode)); 1412 if (error) { 1413 if (nandfs_node_destroy(node)) { 1414 nandfs_error("%s: error destroying node %p\n", 1415 __func__, node); 1416 } 1417 return (error); 1418 } 1419 *vpp = NTOV(node); 1420 1421 DPRINTF(VNCALL, ("created file vp %p nandnode %p ino %jx\n", *vpp, node, 1422 (uintmax_t)node->nn_ino)); 1423 return (0); 1424} 1425 1426static int 1427nandfs_remove(struct vop_remove_args *ap) 1428{ 1429 struct vnode *vp = ap->a_vp; 1430 struct vnode *dvp = ap->a_dvp; 1431 struct nandfs_node *node = VTON(vp); 1432 struct nandfs_node *dnode = VTON(dvp); 1433 struct componentname *cnp = ap->a_cnp; 1434 1435 DPRINTF(VNCALL, ("%s: dvp %p vp %p nandnode %p ino %#jx link %d\n", 1436 __func__, dvp, vp, node, (uintmax_t)node->nn_ino, 1437 node->nn_inode.i_links_count)); 1438 1439 if (vp->v_type == VDIR) 1440 return (EISDIR); 1441 1442 /* Files marked as immutable or append-only cannot be deleted. */ 1443 if ((node->nn_inode.i_flags & (IMMUTABLE | APPEND | NOUNLINK)) || 1444 (dnode->nn_inode.i_flags & APPEND)) 1445 return (EPERM); 1446 1447 nandfs_remove_dirent(dvp, node, cnp); 1448 node->nn_inode.i_links_count--; 1449 node->nn_flags |= IN_CHANGE; 1450 1451 return (0); 1452} 1453 1454/* 1455 * Check if source directory is in the path of the target directory. 1456 * Target is supplied locked, source is unlocked. 1457 * The target is always vput before returning. 1458 */ 1459static int 1460nandfs_checkpath(struct nandfs_node *src, struct nandfs_node *dest, 1461 struct ucred *cred) 1462{ 1463 struct vnode *vp; 1464 int error, rootino; 1465 struct nandfs_dir_entry dirent; 1466 1467 vp = NTOV(dest); 1468 if (src->nn_ino == dest->nn_ino) { 1469 error = EEXIST; 1470 goto out; 1471 } 1472 rootino = NANDFS_ROOT_INO; 1473 error = 0; 1474 if (dest->nn_ino == rootino) 1475 goto out; 1476 1477 for (;;) { 1478 if (vp->v_type != VDIR) { 1479 error = ENOTDIR; 1480 break; 1481 } 1482 1483 error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirent, 1484 NANDFS_DIR_REC_LEN(2), (off_t)0, UIO_SYSSPACE, 1485 IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, 1486 NULL, NULL); 1487 if (error != 0) 1488 break; 1489 if (dirent.name_len != 2 || 1490 dirent.name[0] != '.' || 1491 dirent.name[1] != '.') { 1492 error = ENOTDIR; 1493 break; 1494 } 1495 if (dirent.inode == src->nn_ino) { 1496 error = EINVAL; 1497 break; 1498 } 1499 if (dirent.inode == rootino) 1500 break; 1501 vput(vp); 1502 if ((error = VFS_VGET(vp->v_mount, dirent.inode, 1503 LK_EXCLUSIVE, &vp)) != 0) { 1504 vp = NULL; 1505 break; 1506 } 1507 } 1508 1509out: 1510 if (error == ENOTDIR) 1511 printf("checkpath: .. not a directory\n"); 1512 if (vp != NULL) 1513 vput(vp); 1514 return (error); 1515} 1516 1517static int 1518nandfs_rename(struct vop_rename_args *ap) 1519{ 1520 struct vnode *tvp = ap->a_tvp; 1521 struct vnode *tdvp = ap->a_tdvp; 1522 struct vnode *fvp = ap->a_fvp; 1523 struct vnode *fdvp = ap->a_fdvp; 1524 struct componentname *tcnp = ap->a_tcnp; 1525 struct componentname *fcnp = ap->a_fcnp; 1526 int doingdirectory = 0, oldparent = 0, newparent = 0; 1527 int error = 0; 1528 1529 struct nandfs_node *fdnode, *fnode, *fnode1; 1530 struct nandfs_node *tdnode = VTON(tdvp); 1531 struct nandfs_node *tnode; 1532 1533 uint32_t tdflags, fflags, fdflags; 1534 uint16_t mode; 1535 1536 DPRINTF(VNCALL, ("%s: fdvp:%p fvp:%p tdvp:%p tdp:%p\n", __func__, fdvp, 1537 fvp, tdvp, tvp)); 1538 1539 /* 1540 * Check for cross-device rename. 1541 */ 1542 if ((fvp->v_mount != tdvp->v_mount) || 1543 (tvp && (fvp->v_mount != tvp->v_mount))) { 1544 error = EXDEV; 1545abortit: 1546 if (tdvp == tvp) 1547 vrele(tdvp); 1548 else 1549 vput(tdvp); 1550 if (tvp) 1551 vput(tvp); 1552 vrele(fdvp); 1553 vrele(fvp); 1554 return (error); 1555 } 1556 1557 tdflags = tdnode->nn_inode.i_flags; 1558 if (tvp && 1559 ((VTON(tvp)->nn_inode.i_flags & (NOUNLINK | IMMUTABLE | APPEND)) || 1560 (tdflags & APPEND))) { 1561 error = EPERM; 1562 goto abortit; 1563 } 1564 1565 /* 1566 * Renaming a file to itself has no effect. The upper layers should 1567 * not call us in that case. Temporarily just warn if they do. 1568 */ 1569 if (fvp == tvp) { 1570 printf("nandfs_rename: fvp == tvp (can't happen)\n"); 1571 error = 0; 1572 goto abortit; 1573 } 1574 1575 if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) 1576 goto abortit; 1577 1578 fdnode = VTON(fdvp); 1579 fnode = VTON(fvp); 1580 1581 if (fnode->nn_inode.i_links_count >= LINK_MAX) { 1582 VOP_UNLOCK(fvp, 0); 1583 error = EMLINK; 1584 goto abortit; 1585 } 1586 1587 fflags = fnode->nn_inode.i_flags; 1588 fdflags = fdnode->nn_inode.i_flags; 1589 1590 if ((fflags & (NOUNLINK | IMMUTABLE | APPEND)) || 1591 (fdflags & APPEND)) { 1592 VOP_UNLOCK(fvp, 0); 1593 error = EPERM; 1594 goto abortit; 1595 } 1596 1597 mode = fnode->nn_inode.i_mode; 1598 if ((mode & S_IFMT) == S_IFDIR) { 1599 /* 1600 * Avoid ".", "..", and aliases of "." for obvious reasons. 1601 */ 1602 1603 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') || 1604 (fdvp == fvp) || 1605 ((fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT) || 1606 (fnode->nn_flags & IN_RENAME)) { 1607 VOP_UNLOCK(fvp, 0); 1608 error = EINVAL; 1609 goto abortit; 1610 } 1611 fnode->nn_flags |= IN_RENAME; 1612 doingdirectory = 1; 1613 DPRINTF(VNCALL, ("%s: doingdirectory dvp %p\n", __func__, 1614 tdvp)); 1615 oldparent = fdnode->nn_ino; 1616 } 1617 1618 vrele(fdvp); 1619 1620 tnode = NULL; 1621 if (tvp) 1622 tnode = VTON(tvp); 1623 1624 /* 1625 * Bump link count on fvp while we are moving stuff around. If we 1626 * crash before completing the work, the link count may be wrong 1627 * but correctable. 1628 */ 1629 fnode->nn_inode.i_links_count++; 1630 1631 /* Check for in path moving XXX */ 1632 error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_thread); 1633 VOP_UNLOCK(fvp, 0); 1634 if (oldparent != tdnode->nn_ino) 1635 newparent = tdnode->nn_ino; 1636 if (doingdirectory && newparent) { 1637 if (error) /* write access check above */ 1638 goto bad; 1639 if (tnode != NULL) 1640 vput(tvp); 1641 1642 error = nandfs_checkpath(fnode, tdnode, tcnp->cn_cred); 1643 if (error) 1644 goto out; 1645 1646 VREF(tdvp); 1647 error = relookup(tdvp, &tvp, tcnp); 1648 if (error) 1649 goto out; 1650 vrele(tdvp); 1651 tdnode = VTON(tdvp); 1652 tnode = NULL; 1653 if (tvp) 1654 tnode = VTON(tvp); 1655 } 1656 1657 /* 1658 * If the target doesn't exist, link the target to the source and 1659 * unlink the source. Otherwise, rewrite the target directory to 1660 * reference the source and remove the original entry. 1661 */ 1662 1663 if (tvp == NULL) { 1664 /* 1665 * Account for ".." in new directory. 1666 */ 1667 if (doingdirectory && fdvp != tdvp) 1668 tdnode->nn_inode.i_links_count++; 1669 1670 DPRINTF(VNCALL, ("%s: new entry in dvp:%p\n", __func__, tdvp)); 1671 /* 1672 * Add name in new directory. 1673 */ 1674 error = nandfs_add_dirent(tdvp, fnode->nn_ino, tcnp->cn_nameptr, 1675 tcnp->cn_namelen, IFTODT(fnode->nn_inode.i_mode)); 1676 if (error) { 1677 if (doingdirectory && fdvp != tdvp) 1678 tdnode->nn_inode.i_links_count--; 1679 goto bad; 1680 } 1681 1682 vput(tdvp); 1683 } else { 1684 /* 1685 * If the parent directory is "sticky", then the user must 1686 * own the parent directory, or the destination of the rename, 1687 * otherwise the destination may not be changed (except by 1688 * root). This implements append-only directories. 1689 */ 1690 if ((tdnode->nn_inode.i_mode & S_ISTXT) && 1691 tcnp->cn_cred->cr_uid != 0 && 1692 tcnp->cn_cred->cr_uid != tdnode->nn_inode.i_uid && 1693 tnode->nn_inode.i_uid != tcnp->cn_cred->cr_uid) { 1694 error = EPERM; 1695 goto bad; 1696 } 1697 /* 1698 * Target must be empty if a directory and have no links 1699 * to it. Also, ensure source and target are compatible 1700 * (both directories, or both not directories). 1701 */ 1702 mode = tnode->nn_inode.i_mode; 1703 if ((mode & S_IFMT) == S_IFDIR) { 1704 if (!nandfs_dirempty(tvp, tdnode->nn_ino, 1705 tcnp->cn_cred)) { 1706 error = ENOTEMPTY; 1707 goto bad; 1708 } 1709 if (!doingdirectory) { 1710 error = ENOTDIR; 1711 goto bad; 1712 } 1713 /* 1714 * Update name cache since directory is going away. 1715 */ 1716 cache_purge(tdvp); 1717 } else if (doingdirectory) { 1718 error = EISDIR; 1719 goto bad; 1720 } 1721 1722 DPRINTF(VNCALL, ("%s: update entry dvp:%p\n", __func__, tdvp)); 1723 /* 1724 * Change name tcnp in tdvp to point at fvp. 1725 */ 1726 error = nandfs_update_dirent(tdvp, fnode, tnode); 1727 if (error) 1728 goto bad; 1729 1730 if (doingdirectory && !newparent) 1731 tdnode->nn_inode.i_links_count--; 1732 1733 vput(tdvp); 1734 1735 tnode->nn_inode.i_links_count--; 1736 vput(tvp); 1737 tnode = NULL; 1738 } 1739 1740 /* 1741 * Unlink the source. 1742 */ 1743 fcnp->cn_flags &= ~MODMASK; 1744 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; 1745 VREF(fdvp); 1746 error = relookup(fdvp, &fvp, fcnp); 1747 if (error == 0) 1748 vrele(fdvp); 1749 if (fvp != NULL) { 1750 fnode1 = VTON(fvp); 1751 fdnode = VTON(fdvp); 1752 } else { 1753 /* 1754 * From name has disappeared. 1755 */ 1756 if (doingdirectory) 1757 panic("nandfs_rename: lost dir entry"); 1758 vrele(ap->a_fvp); 1759 return (0); 1760 } 1761 1762 DPRINTF(VNCALL, ("%s: unlink source fnode:%p\n", __func__, fnode)); 1763 1764 /* 1765 * Ensure that the directory entry still exists and has not 1766 * changed while the new name has been entered. If the source is 1767 * a file then the entry may have been unlinked or renamed. In 1768 * either case there is no further work to be done. If the source 1769 * is a directory then it cannot have been rmdir'ed; its link 1770 * count of three would cause a rmdir to fail with ENOTEMPTY. 1771 * The IN_RENAME flag ensures that it cannot be moved by another 1772 * rename. 1773 */ 1774 if (fnode != fnode1) { 1775 if (doingdirectory) 1776 panic("nandfs: lost dir entry"); 1777 } else { 1778 /* 1779 * If the source is a directory with a 1780 * new parent, the link count of the old 1781 * parent directory must be decremented 1782 * and ".." set to point to the new parent. 1783 */ 1784 if (doingdirectory && newparent) { 1785 DPRINTF(VNCALL, ("%s: new parent %#jx -> %#jx\n", 1786 __func__, (uintmax_t) oldparent, 1787 (uintmax_t) newparent)); 1788 error = nandfs_update_parent_dir(fvp, newparent); 1789 if (!error) { 1790 fdnode->nn_inode.i_links_count--; 1791 fdnode->nn_flags |= IN_CHANGE; 1792 } 1793 } 1794 error = nandfs_remove_dirent(fdvp, fnode, fcnp); 1795 if (!error) { 1796 fnode->nn_inode.i_links_count--; 1797 fnode->nn_flags |= IN_CHANGE; 1798 } 1799 fnode->nn_flags &= ~IN_RENAME; 1800 } 1801 if (fdnode) 1802 vput(fdvp); 1803 if (fnode) 1804 vput(fvp); 1805 vrele(ap->a_fvp); 1806 return (error); 1807 1808bad: 1809 DPRINTF(VNCALL, ("%s: error:%d\n", __func__, error)); 1810 if (tnode) 1811 vput(NTOV(tnode)); 1812 vput(NTOV(tdnode)); 1813out: 1814 if (doingdirectory) 1815 fnode->nn_flags &= ~IN_RENAME; 1816 if (vn_lock(fvp, LK_EXCLUSIVE) == 0) { 1817 fnode->nn_inode.i_links_count--; 1818 fnode->nn_flags |= IN_CHANGE; 1819 fnode->nn_flags &= ~IN_RENAME; 1820 vput(fvp); 1821 } else 1822 vrele(fvp); 1823 return (error); 1824} 1825 1826static int 1827nandfs_mkdir(struct vop_mkdir_args *ap) 1828{ 1829 struct vnode *dvp = ap->a_dvp; 1830 struct vnode **vpp = ap->a_vpp; 1831 struct componentname *cnp = ap->a_cnp; 1832 struct nandfs_node *dir_node = VTON(dvp); 1833 struct nandfs_inode *dir_inode = &dir_node->nn_inode; 1834 struct nandfs_node *node; 1835 struct nandfsmount *nmp = dir_node->nn_nmp; 1836 uint16_t mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); 1837 int error; 1838 1839 DPRINTF(VNCALL, ("%s: dvp %p\n", __func__, dvp)); 1840 1841 if (nandfs_fs_full(dir_node->nn_nandfsdev)) 1842 return (ENOSPC); 1843 1844 if (dir_inode->i_links_count >= LINK_MAX) 1845 return (EMLINK); 1846 1847 error = nandfs_node_create(nmp, &node, mode); 1848 if (error) 1849 return (error); 1850 1851 node->nn_inode.i_gid = dir_node->nn_inode.i_gid; 1852 node->nn_inode.i_uid = cnp->cn_cred->cr_uid; 1853 1854 *vpp = NTOV(node); 1855 1856 error = nandfs_add_dirent(dvp, node->nn_ino, cnp->cn_nameptr, 1857 cnp->cn_namelen, IFTODT(mode)); 1858 if (error) { 1859 vput(*vpp); 1860 return (error); 1861 } 1862 1863 dir_node->nn_inode.i_links_count++; 1864 dir_node->nn_flags |= IN_CHANGE; 1865 1866 error = nandfs_init_dir(NTOV(node), node->nn_ino, dir_node->nn_ino); 1867 if (error) { 1868 vput(NTOV(node)); 1869 return (error); 1870 } 1871 1872 DPRINTF(VNCALL, ("created dir vp %p nandnode %p ino %jx\n", *vpp, node, 1873 (uintmax_t)node->nn_ino)); 1874 return (0); 1875} 1876 1877static int 1878nandfs_mknod(struct vop_mknod_args *ap) 1879{ 1880 struct vnode *dvp = ap->a_dvp; 1881 struct vnode **vpp = ap->a_vpp; 1882 struct vattr *vap = ap->a_vap; 1883 uint16_t mode = MAKEIMODE(vap->va_type, vap->va_mode); 1884 struct componentname *cnp = ap->a_cnp; 1885 struct nandfs_node *dir_node = VTON(dvp); 1886 struct nandfsmount *nmp = dir_node->nn_nmp; 1887 struct nandfs_node *node; 1888 int error; 1889 1890 if (nandfs_fs_full(dir_node->nn_nandfsdev)) 1891 return (ENOSPC); 1892 1893 error = nandfs_node_create(nmp, &node, mode); 1894 if (error) 1895 return (error); 1896 node->nn_inode.i_gid = dir_node->nn_inode.i_gid; 1897 node->nn_inode.i_uid = cnp->cn_cred->cr_uid; 1898 if (vap->va_rdev != VNOVAL) 1899 node->nn_inode.i_special = vap->va_rdev; 1900 1901 *vpp = NTOV(node); 1902 1903 if (nandfs_add_dirent(dvp, node->nn_ino, cnp->cn_nameptr, 1904 cnp->cn_namelen, IFTODT(mode))) { 1905 vput(*vpp); 1906 return (ENOTDIR); 1907 } 1908 1909 node->nn_flags |= IN_ACCESS | IN_CHANGE | IN_UPDATE; 1910 1911 return (0); 1912} 1913 1914static int 1915nandfs_symlink(struct vop_symlink_args *ap) 1916{ 1917 struct vnode **vpp = ap->a_vpp; 1918 struct vnode *dvp = ap->a_dvp; 1919 uint16_t mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); 1920 struct componentname *cnp = ap->a_cnp; 1921 struct nandfs_node *dir_node = VTON(dvp); 1922 struct nandfsmount *nmp = dir_node->nn_nmp; 1923 struct nandfs_node *node; 1924 int len, error; 1925 1926 if (nandfs_fs_full(dir_node->nn_nandfsdev)) 1927 return (ENOSPC); 1928 1929 error = nandfs_node_create(nmp, &node, S_IFLNK | mode); 1930 if (error) 1931 return (error); 1932 node->nn_inode.i_gid = dir_node->nn_inode.i_gid; 1933 node->nn_inode.i_uid = cnp->cn_cred->cr_uid; 1934 1935 *vpp = NTOV(node); 1936 1937 if (nandfs_add_dirent(dvp, node->nn_ino, cnp->cn_nameptr, 1938 cnp->cn_namelen, IFTODT(mode))) { 1939 vput(*vpp); 1940 return (ENOTDIR); 1941 } 1942 1943 1944 len = strlen(ap->a_target); 1945 error = vn_rdwr(UIO_WRITE, *vpp, ap->a_target, len, (off_t)0, 1946 UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK, 1947 cnp->cn_cred, NOCRED, NULL, NULL); 1948 if (error) 1949 vput(*vpp); 1950 1951 return (error); 1952} 1953 1954static int 1955nandfs_readlink(struct vop_readlink_args *ap) 1956{ 1957 struct vnode *vp = ap->a_vp; 1958 1959 return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred)); 1960} 1961 1962static int 1963nandfs_rmdir(struct vop_rmdir_args *ap) 1964{ 1965 struct vnode *vp = ap->a_vp; 1966 struct vnode *dvp = ap->a_dvp; 1967 struct componentname *cnp = ap->a_cnp; 1968 struct nandfs_node *node, *dnode; 1969 uint32_t dflag, flag; 1970 int error = 0; 1971 1972 node = VTON(vp); 1973 dnode = VTON(dvp); 1974 1975 /* Files marked as immutable or append-only cannot be deleted. */ 1976 if ((node->nn_inode.i_flags & (IMMUTABLE | APPEND | NOUNLINK)) || 1977 (dnode->nn_inode.i_flags & APPEND)) 1978 return (EPERM); 1979 1980 DPRINTF(VNCALL, ("%s: dvp %p vp %p nandnode %p ino %#jx\n", __func__, 1981 dvp, vp, node, (uintmax_t)node->nn_ino)); 1982 1983 if (node->nn_inode.i_links_count < 2) 1984 return (EINVAL); 1985 1986 if (!nandfs_dirempty(vp, dnode->nn_ino, cnp->cn_cred)) 1987 return (ENOTEMPTY); 1988 1989 /* Files marked as immutable or append-only cannot be deleted. */ 1990 dflag = dnode->nn_inode.i_flags; 1991 flag = node->nn_inode.i_flags; 1992 if ((dflag & APPEND) || 1993 (flag & (NOUNLINK | IMMUTABLE | APPEND))) { 1994 return (EPERM); 1995 } 1996 1997 if (vp->v_mountedhere != 0) 1998 return (EINVAL); 1999 2000 nandfs_remove_dirent(dvp, node, cnp); 2001 dnode->nn_inode.i_links_count -= 1; 2002 dnode->nn_flags |= IN_CHANGE; 2003 2004 cache_purge(dvp); 2005 2006 error = nandfs_truncate(vp, (uint64_t)0); 2007 if (error) 2008 return (error); 2009 2010 node->nn_inode.i_links_count -= 2; 2011 node->nn_flags |= IN_CHANGE; 2012 2013 cache_purge(vp); 2014 2015 return (error); 2016} 2017 2018static int 2019nandfs_fsync(struct vop_fsync_args *ap) 2020{ 2021 struct vnode *vp = ap->a_vp; 2022 struct nandfs_node *node = VTON(vp); 2023 int locked; 2024 2025 DPRINTF(VNCALL, ("%s: vp %p nandnode %p ino %#jx\n", __func__, vp, 2026 node, (uintmax_t)node->nn_ino)); 2027 2028 /* 2029 * Start syncing vnode only if inode was modified or 2030 * there are some dirty buffers 2031 */ 2032 if (VTON(vp)->nn_flags & IN_MODIFIED || 2033 vp->v_bufobj.bo_dirty.bv_cnt) { 2034 locked = VOP_ISLOCKED(vp); 2035 VOP_UNLOCK(vp, 0); 2036 nandfs_wakeup_wait_sync(node->nn_nandfsdev, SYNCER_FSYNC); 2037 VOP_LOCK(vp, locked | LK_RETRY); 2038 } 2039 2040 return (0); 2041} 2042 2043static int 2044nandfs_bmap(struct vop_bmap_args *ap) 2045{ 2046 struct vnode *vp = ap->a_vp; 2047 struct nandfs_node *nnode = VTON(vp); 2048 struct nandfs_device *nandfsdev = nnode->nn_nandfsdev; 2049 nandfs_daddr_t l2vmap, v2pmap; 2050 int error; 2051 int blk2dev = nandfsdev->nd_blocksize / DEV_BSIZE; 2052 2053 DPRINTF(VNCALL, ("%s: vp %p nandnode %p ino %#jx\n", __func__, vp, 2054 nnode, (uintmax_t)nnode->nn_ino)); 2055 2056 if (ap->a_bop != NULL) 2057 *ap->a_bop = &nandfsdev->nd_devvp->v_bufobj; 2058 if (ap->a_bnp == NULL) 2059 return (0); 2060 if (ap->a_runp != NULL) 2061 *ap->a_runp = 0; 2062 if (ap->a_runb != NULL) 2063 *ap->a_runb = 0; 2064 2065 /* 2066 * Translate all the block sectors into a series of buffers to read 2067 * asynchronously from the nandfs device. Note that this lookup may 2068 * induce readin's too. 2069 */ 2070 2071 /* Get virtual block numbers for the vnode's buffer span */ 2072 error = nandfs_bmap_lookup(nnode, ap->a_bn, &l2vmap); 2073 if (error) 2074 return (-1); 2075 2076 /* Translate virtual block numbers to physical block numbers */ 2077 error = nandfs_vtop(nnode, l2vmap, &v2pmap); 2078 if (error) 2079 return (-1); 2080 2081 /* Note virtual block 0 marks not mapped */ 2082 if (l2vmap == 0) 2083 *ap->a_bnp = -1; 2084 else 2085 *ap->a_bnp = v2pmap * blk2dev; /* in DEV_BSIZE */ 2086 2087 DPRINTF(VNCALL, ("%s: vp %p nandnode %p ino %#jx lblk %jx -> blk %jx\n", 2088 __func__, vp, nnode, (uintmax_t)nnode->nn_ino, (uintmax_t)ap->a_bn, 2089 (uintmax_t)*ap->a_bnp )); 2090 2091 return (0); 2092} 2093 2094static void 2095nandfs_force_syncer(struct nandfsmount *nmp) 2096{ 2097 2098 nmp->nm_flags |= NANDFS_FORCE_SYNCER; 2099 nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_FFORCE); 2100} 2101 2102static int 2103nandfs_ioctl(struct vop_ioctl_args *ap) 2104{ 2105 struct vnode *vp = ap->a_vp; 2106 u_long command = ap->a_command; 2107 caddr_t data = ap->a_data; 2108 struct nandfs_node *node = VTON(vp); 2109 struct nandfs_device *nandfsdev = node->nn_nandfsdev; 2110 struct nandfsmount *nmp = node->nn_nmp; 2111 uint64_t *tab, *cno; 2112 struct nandfs_seg_stat *nss; 2113 struct nandfs_cpmode *ncpm; 2114 struct nandfs_argv *nargv; 2115 struct nandfs_cpstat *ncp; 2116 int error; 2117 2118 DPRINTF(VNCALL, ("%s: %x\n", __func__, (uint32_t)command)); 2119 2120 error = priv_check(ap->a_td, PRIV_VFS_MOUNT); 2121 if (error) 2122 return (error); 2123 2124 if (nmp->nm_ronly) { 2125 switch (command) { 2126 case NANDFS_IOCTL_GET_FSINFO: 2127 case NANDFS_IOCTL_GET_SUSTAT: 2128 case NANDFS_IOCTL_GET_CPINFO: 2129 case NANDFS_IOCTL_GET_CPSTAT: 2130 case NANDFS_IOCTL_GET_SUINFO: 2131 case NANDFS_IOCTL_GET_VINFO: 2132 case NANDFS_IOCTL_GET_BDESCS: 2133 break; 2134 default: 2135 return (EROFS); 2136 } 2137 } 2138 2139 switch (command) { 2140 case NANDFS_IOCTL_GET_FSINFO: 2141 error = nandfs_get_fsinfo(nmp, (struct nandfs_fsinfo *)data); 2142 break; 2143 case NANDFS_IOCTL_GET_SUSTAT: 2144 nss = (struct nandfs_seg_stat *)data; 2145 error = nandfs_get_seg_stat(nandfsdev, nss); 2146 break; 2147 case NANDFS_IOCTL_CHANGE_CPMODE: 2148 ncpm = (struct nandfs_cpmode *)data; 2149 error = nandfs_chng_cpmode(nandfsdev->nd_cp_node, ncpm); 2150 nandfs_force_syncer(nmp); 2151 break; 2152 case NANDFS_IOCTL_GET_CPINFO: 2153 nargv = (struct nandfs_argv *)data; 2154 error = nandfs_get_cpinfo_ioctl(nandfsdev->nd_cp_node, nargv); 2155 break; 2156 case NANDFS_IOCTL_DELETE_CP: 2157 tab = (uint64_t *)data; 2158 error = nandfs_delete_cp(nandfsdev->nd_cp_node, tab[0], tab[1]); 2159 nandfs_force_syncer(nmp); 2160 break; 2161 case NANDFS_IOCTL_GET_CPSTAT: 2162 ncp = (struct nandfs_cpstat *)data; 2163 error = nandfs_get_cpstat(nandfsdev->nd_cp_node, ncp); 2164 break; 2165 case NANDFS_IOCTL_GET_SUINFO: 2166 nargv = (struct nandfs_argv *)data; 2167 error = nandfs_get_segment_info_ioctl(nandfsdev, nargv); 2168 break; 2169 case NANDFS_IOCTL_GET_VINFO: 2170 nargv = (struct nandfs_argv *)data; 2171 error = nandfs_get_dat_vinfo_ioctl(nandfsdev, nargv); 2172 break; 2173 case NANDFS_IOCTL_GET_BDESCS: 2174 nargv = (struct nandfs_argv *)data; 2175 error = nandfs_get_dat_bdescs_ioctl(nandfsdev, nargv); 2176 break; 2177 case NANDFS_IOCTL_SYNC: 2178 cno = (uint64_t *)data; 2179 nandfs_force_syncer(nmp); 2180 *cno = nandfsdev->nd_last_cno; 2181 error = 0; 2182 break; 2183 case NANDFS_IOCTL_MAKE_SNAP: 2184 cno = (uint64_t *)data; 2185 error = nandfs_make_snap(nandfsdev, cno); 2186 nandfs_force_syncer(nmp); 2187 break; 2188 case NANDFS_IOCTL_DELETE_SNAP: 2189 cno = (uint64_t *)data; 2190 error = nandfs_delete_snap(nandfsdev, *cno); 2191 nandfs_force_syncer(nmp); 2192 break; 2193 default: 2194 error = ENOTTY; 2195 break; 2196 } 2197 2198 return (error); 2199} 2200 2201/* 2202 * Whiteout vnode call 2203 */ 2204static int 2205nandfs_whiteout(struct vop_whiteout_args *ap) 2206{ 2207 struct vnode *dvp = ap->a_dvp; 2208 struct componentname *cnp = ap->a_cnp; 2209 int error = 0; 2210 2211 switch (ap->a_flags) { 2212 case LOOKUP: 2213 return (0); 2214 case CREATE: 2215 /* Create a new directory whiteout */ 2216#ifdef INVARIANTS 2217 if ((cnp->cn_flags & SAVENAME) == 0) 2218 panic("ufs_whiteout: missing name"); 2219#endif 2220 error = nandfs_add_dirent(dvp, NANDFS_WHT_INO, cnp->cn_nameptr, 2221 cnp->cn_namelen, DT_WHT); 2222 break; 2223 2224 case DELETE: 2225 /* Remove an existing directory whiteout */ 2226 cnp->cn_flags &= ~DOWHITEOUT; 2227 error = nandfs_remove_dirent(dvp, NULL, cnp); 2228 break; 2229 default: 2230 panic("nandf_whiteout: unknown op: %d", ap->a_flags); 2231 } 2232 2233 return (error); 2234} 2235 2236static int 2237nandfs_pathconf(struct vop_pathconf_args *ap) 2238{ 2239 int error; 2240 2241 error = 0; 2242 switch (ap->a_name) { 2243 case _PC_LINK_MAX: 2244 *ap->a_retval = LINK_MAX; 2245 break; 2246 case _PC_NAME_MAX: 2247 *ap->a_retval = NAME_MAX; 2248 break; 2249 case _PC_PATH_MAX: 2250 *ap->a_retval = PATH_MAX; 2251 break; 2252 case _PC_PIPE_BUF: 2253 *ap->a_retval = PIPE_BUF; 2254 break; 2255 case _PC_CHOWN_RESTRICTED: 2256 *ap->a_retval = 1; 2257 break; 2258 case _PC_NO_TRUNC: 2259 *ap->a_retval = 1; 2260 break; 2261 case _PC_ACL_EXTENDED: 2262 *ap->a_retval = 0; 2263 break; 2264 case _PC_ALLOC_SIZE_MIN: 2265 *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_bsize; 2266 break; 2267 case _PC_FILESIZEBITS: 2268 *ap->a_retval = 64; 2269 break; 2270 case _PC_REC_INCR_XFER_SIZE: 2271 *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize; 2272 break; 2273 case _PC_REC_MAX_XFER_SIZE: 2274 *ap->a_retval = -1; /* means ``unlimited'' */ 2275 break; 2276 case _PC_REC_MIN_XFER_SIZE: 2277 *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize; 2278 break; 2279 default: 2280 error = EINVAL; 2281 break; 2282 } 2283 return (error); 2284} 2285 2286static int 2287nandfs_vnlock1(struct vop_lock1_args *ap) 2288{ 2289 struct vnode *vp = ap->a_vp; 2290 struct nandfs_node *node = VTON(vp); 2291 int error, vi_locked; 2292 2293 /* 2294 * XXX can vnode go away while we are sleeping? 2295 */ 2296 vi_locked = mtx_owned(&vp->v_interlock); 2297 if (vi_locked) 2298 VI_UNLOCK(vp); 2299 error = NANDFS_WRITELOCKFLAGS(node->nn_nandfsdev, 2300 ap->a_flags & LK_NOWAIT); 2301 if (vi_locked && !error) 2302 VI_LOCK(vp); 2303 if (error) 2304 return (error); 2305 2306 error = vop_stdlock(ap); 2307 if (error) { 2308 NANDFS_WRITEUNLOCK(node->nn_nandfsdev); 2309 return (error); 2310 } 2311 2312 return (0); 2313} 2314 2315static int 2316nandfs_vnunlock(struct vop_unlock_args *ap) 2317{ 2318 struct vnode *vp = ap->a_vp; 2319 struct nandfs_node *node = VTON(vp); 2320 int error; 2321 2322 error = vop_stdunlock(ap); 2323 if (error) 2324 return (error); 2325 2326 NANDFS_WRITEUNLOCK(node->nn_nandfsdev); 2327 2328 return (0); 2329} 2330 2331/* 2332 * Global vfs data structures 2333 */ 2334struct vop_vector nandfs_vnodeops = { 2335 .vop_default = &default_vnodeops, 2336 .vop_access = nandfs_access, 2337 .vop_advlock = nandfs_advlock, 2338 .vop_bmap = nandfs_bmap, 2339 .vop_close = nandfs_close, 2340 .vop_create = nandfs_create, 2341 .vop_fsync = nandfs_fsync, 2342 .vop_getattr = nandfs_getattr, 2343 .vop_inactive = nandfs_inactive, 2344 .vop_cachedlookup = nandfs_lookup, 2345 .vop_ioctl = nandfs_ioctl, 2346 .vop_link = nandfs_link, 2347 .vop_lookup = vfs_cache_lookup, 2348 .vop_mkdir = nandfs_mkdir, 2349 .vop_mknod = nandfs_mknod, 2350 .vop_open = nandfs_open, 2351 .vop_pathconf = nandfs_pathconf, 2352 .vop_print = nandfs_print, 2353 .vop_read = nandfs_read, 2354 .vop_readdir = nandfs_readdir, 2355 .vop_readlink = nandfs_readlink, 2356 .vop_reclaim = nandfs_reclaim, 2357 .vop_remove = nandfs_remove, 2358 .vop_rename = nandfs_rename, 2359 .vop_rmdir = nandfs_rmdir, 2360 .vop_whiteout = nandfs_whiteout, 2361 .vop_write = nandfs_write, 2362 .vop_setattr = nandfs_setattr, 2363 .vop_strategy = nandfs_strategy, 2364 .vop_symlink = nandfs_symlink, 2365 .vop_lock1 = nandfs_vnlock1, 2366 .vop_unlock = nandfs_vnunlock, 2367}; 2368 2369struct vop_vector nandfs_system_vnodeops = { 2370 .vop_default = &default_vnodeops, 2371 .vop_close = nandfs_close, 2372 .vop_inactive = nandfs_inactive, 2373 .vop_reclaim = nandfs_reclaim, 2374 .vop_strategy = nandfs_strategy, 2375 .vop_fsync = nandfs_fsync, 2376 .vop_bmap = nandfs_bmap, 2377 .vop_access = VOP_PANIC, 2378 .vop_advlock = VOP_PANIC, 2379 .vop_create = VOP_PANIC, 2380 .vop_getattr = VOP_PANIC, 2381 .vop_cachedlookup = VOP_PANIC, 2382 .vop_ioctl = VOP_PANIC, 2383 .vop_link = VOP_PANIC, 2384 .vop_lookup = VOP_PANIC, 2385 .vop_mkdir = VOP_PANIC, 2386 .vop_mknod = VOP_PANIC, 2387 .vop_open = VOP_PANIC, 2388 .vop_pathconf = VOP_PANIC, 2389 .vop_print = VOP_PANIC, 2390 .vop_read = VOP_PANIC, 2391 .vop_readdir = VOP_PANIC, 2392 .vop_readlink = VOP_PANIC, 2393 .vop_remove = VOP_PANIC, 2394 .vop_rename = VOP_PANIC, 2395 .vop_rmdir = VOP_PANIC, 2396 .vop_whiteout = VOP_PANIC, 2397 .vop_write = VOP_PANIC, 2398 .vop_setattr = VOP_PANIC, 2399 .vop_symlink = VOP_PANIC, 2400}; 2401 2402static int 2403nandfsfifo_close(struct vop_close_args *ap) 2404{ 2405 struct vnode *vp = ap->a_vp; 2406 struct nandfs_node *node = VTON(vp); 2407 2408 DPRINTF(VNCALL, ("%s: vp %p node %p\n", __func__, vp, node)); 2409 2410 mtx_lock(&vp->v_interlock); 2411 if (vp->v_usecount > 1) 2412 nandfs_itimes_locked(vp); 2413 mtx_unlock(&vp->v_interlock); 2414 2415 return (fifo_specops.vop_close(ap)); 2416} 2417 2418struct vop_vector nandfs_fifoops = { 2419 .vop_default = &fifo_specops, 2420 .vop_fsync = VOP_PANIC, 2421 .vop_access = nandfs_access, 2422 .vop_close = nandfsfifo_close, 2423 .vop_getattr = nandfs_getattr, 2424 .vop_inactive = nandfs_inactive, 2425 .vop_print = nandfs_print, 2426 .vop_read = VOP_PANIC, 2427 .vop_reclaim = nandfs_reclaim, 2428 .vop_setattr = nandfs_setattr, 2429 .vop_write = VOP_PANIC, 2430 .vop_lock1 = nandfs_vnlock1, 2431 .vop_unlock = nandfs_vnunlock, 2432}; 2433 2434int 2435nandfs_vinit(struct vnode *vp, uint64_t ino) 2436{ 2437 struct nandfs_node *node; 2438 2439 ASSERT_VOP_LOCKED(vp, __func__); 2440 2441 node = VTON(vp); 2442 2443 /* Check if we're fetching the root */ 2444 if (ino == NANDFS_ROOT_INO) 2445 vp->v_vflag |= VV_ROOT; 2446 2447 if (ino != NANDFS_GC_INO) 2448 vp->v_type = IFTOVT(node->nn_inode.i_mode); 2449 else 2450 vp->v_type = VREG; 2451 2452 if (vp->v_type == VFIFO) 2453 vp->v_op = &nandfs_fifoops; 2454 2455 return (0); 2456} 2457